Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / tools / obexctl.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2013  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdbool.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <signal.h>
34 #include <sys/signalfd.h>
35 #include <inttypes.h>
36 #include <wordexp.h>
37
38 #include <readline/readline.h>
39 #include <readline/history.h>
40 #include <glib.h>
41
42 #include "gdbus/gdbus.h"
43 #include "client/display.h"
44
45 /* String display constants */
46 #define COLORED_NEW     COLOR_GREEN "NEW" COLOR_OFF
47 #define COLORED_CHG     COLOR_YELLOW "CHG" COLOR_OFF
48 #define COLORED_DEL     COLOR_RED "DEL" COLOR_OFF
49
50 #define PROMPT_ON       COLOR_BLUE "[obex]" COLOR_OFF "# "
51 #define PROMPT_OFF      "[obex]# "
52
53 #define OBEX_SESSION_INTERFACE "org.bluez.obex.Session1"
54 #define OBEX_TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
55 #define OBEX_CLIENT_INTERFACE "org.bluez.obex.Client1"
56 #define OBEX_OPP_INTERFACE "org.bluez.obex.ObjectPush1"
57 #define OBEX_FTP_INTERFACE "org.bluez.obex.FileTransfer1"
58 #define OBEX_PBAP_INTERFACE "org.bluez.obex.PhonebookAccess1"
59 #define OBEX_MAP_INTERFACE "org.bluez.obex.MessageAccess1"
60 #define OBEX_MSG_INTERFACE "org.bluez.obex.Message1"
61
62 static GMainLoop *main_loop;
63 static DBusConnection *dbus_conn;
64 static GDBusProxy *default_session;
65 static GSList *sessions = NULL;
66 static GSList *opps = NULL;
67 static GSList *ftps = NULL;
68 static GSList *pbaps = NULL;
69 static GSList *maps = NULL;
70 static GSList *msgs = NULL;
71 static GSList *transfers = NULL;
72 static GDBusProxy *client = NULL;
73
74 struct transfer_data {
75         uint64_t transferred;
76         uint64_t size;
77 };
78
79 static void connect_handler(DBusConnection *connection, void *user_data)
80 {
81         rl_set_prompt(PROMPT_ON);
82         printf("\r");
83         rl_on_new_line();
84         rl_redisplay();
85 }
86
87 static void disconnect_handler(DBusConnection *connection, void *user_data)
88 {
89         rl_set_prompt(PROMPT_OFF);
90         printf("\r");
91         rl_on_new_line();
92         rl_redisplay();
93 }
94
95 static void cmd_quit(int argc, char *argv[])
96 {
97         g_main_loop_quit(main_loop);
98 }
99
100 static void connect_reply(DBusMessage *message, void *user_data)
101 {
102         DBusError error;
103
104         dbus_error_init(&error);
105
106         if (dbus_set_error_from_message(&error, message) == TRUE) {
107                 rl_printf("Failed to connect: %s\n", error.name);
108                 dbus_error_free(&error);
109                 return;
110         }
111
112         rl_printf("Connection successful\n");
113 }
114
115 static void append_variant(DBusMessageIter *iter, int type, void *val)
116 {
117         DBusMessageIter value;
118         char sig[2] = { type, '\0' };
119
120         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
121
122         dbus_message_iter_append_basic(&value, type, val);
123
124         dbus_message_iter_close_container(iter, &value);
125 }
126
127 static void dict_append_entry(DBusMessageIter *dict, const char *key,
128                                                         int type, void *val)
129 {
130         DBusMessageIter entry;
131
132         if (type == DBUS_TYPE_STRING) {
133                 const char *str = *((const char **) val);
134                 if (str == NULL)
135                         return;
136         }
137
138         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
139                                                         NULL, &entry);
140
141         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
142
143         append_variant(&entry, type, val);
144
145         dbus_message_iter_close_container(dict, &entry);
146 }
147
148 struct connect_args {
149         char *dev;
150         char *target;
151 };
152
153 static void connect_args_free(void *data)
154 {
155         struct connect_args *args = data;
156
157         g_free(args->dev);
158         g_free(args->target);
159         g_free(args);
160 }
161
162 static void connect_setup(DBusMessageIter *iter, void *user_data)
163 {
164         struct connect_args *args = user_data;
165         DBusMessageIter dict;
166
167         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->dev);
168
169         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
170                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
171                                         DBUS_TYPE_STRING_AS_STRING
172                                         DBUS_TYPE_VARIANT_AS_STRING
173                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
174                                         &dict);
175
176         if (args->target == NULL)
177                 goto done;
178
179         dict_append_entry(&dict, "Target", DBUS_TYPE_STRING, &args->target);
180
181 done:
182         dbus_message_iter_close_container(iter, &dict);
183 }
184
185 static void cmd_connect(int argc, char *argv[])
186 {
187         struct connect_args *args;
188         const char *target = "opp";
189
190         if (argc < 2) {
191                 rl_printf("Missing device address argument\n");
192                 return;
193         }
194
195         if (!client) {
196                 rl_printf("Client proxy not available\n");
197                 return;
198         }
199
200         if (argc > 2)
201                 target = argv[2];
202
203         args = g_new0(struct connect_args, 1);
204         args->dev = g_strdup(argv[1]);
205         args->target = g_strdup(target);
206
207         if (g_dbus_proxy_method_call(client, "CreateSession", connect_setup,
208                         connect_reply, args, connect_args_free) == FALSE) {
209                 rl_printf("Failed to connect\n");
210                 return;
211         }
212
213         rl_printf("Attempting to connect to %s\n", argv[1]);
214 }
215
216 static void disconnect_reply(DBusMessage *message, void *user_data)
217 {
218         DBusError error;
219
220         dbus_error_init(&error);
221
222         if (dbus_set_error_from_message(&error, message) == TRUE) {
223                 rl_printf("Failed to disconnect: %s\n", error.name);
224                 dbus_error_free(&error);
225                 return;
226         }
227
228         rl_printf("Disconnection successful\n");
229 }
230
231 static void disconnect_setup(DBusMessageIter *iter, void *user_data)
232 {
233         GDBusProxy *proxy = user_data;
234         const char *path;
235
236         path = g_dbus_proxy_get_path(proxy);
237
238         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
239 }
240
241 static GDBusProxy *find_session(const char *path)
242 {
243         GSList *l;
244
245         for (l = sessions; l; l = g_slist_next(l)) {
246                 GDBusProxy *proxy = l->data;
247
248                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
249                         return proxy;
250         }
251
252         return NULL;
253 }
254
255 static void cmd_disconnect(int argc, char *argv[])
256 {
257         GDBusProxy *proxy;
258
259         if (argc > 1)
260                 proxy = find_session(argv[1]);
261         else
262                 proxy = default_session;
263
264         if (proxy == NULL) {
265                 rl_printf("Session not available\n");
266                 return;
267         }
268
269         if (g_dbus_proxy_method_call(client, "RemoveSession", disconnect_setup,
270                                 disconnect_reply, proxy, NULL) == FALSE) {
271                 rl_printf("Failed to disconnect\n");
272                 return;
273         }
274
275         rl_printf("Attempting to disconnect to %s\n",
276                                                 g_dbus_proxy_get_path(proxy));
277 }
278
279 static char *proxy_description(GDBusProxy *proxy, const char *title,
280                                                 const char *description)
281 {
282         const char *path;
283
284         path = g_dbus_proxy_get_path(proxy);
285
286         return g_strdup_printf("%s%s%s%s %s ",
287                                         description ? "[" : "",
288                                         description ? : "",
289                                         description ? "] " : "",
290                                         title, path);
291 }
292
293 static void print_proxy(GDBusProxy *proxy, const char *title,
294                                                         const char *description)
295 {
296         char *str;
297
298         str = proxy_description(proxy, title, description);
299
300         rl_printf("%s%s\n", str, default_session == proxy ? "[default]" : "");
301
302         g_free(str);
303 }
304
305 static void cmd_list(int argc, char *arg[])
306 {
307         GSList *l;
308
309         for (l = sessions; l; l = g_slist_next(l)) {
310                 GDBusProxy *proxy = l->data;
311                 print_proxy(proxy, "Session", NULL);
312         }
313 }
314
315 static bool check_default_session(void)
316 {
317         if (!default_session) {
318                 rl_printf("No default session available\n");
319                 return FALSE;
320         }
321
322         return TRUE;
323 }
324
325 static void print_iter(const char *label, const char *name,
326                                                 DBusMessageIter *iter)
327 {
328         dbus_bool_t valbool;
329         dbus_uint64_t valu64;
330         dbus_uint32_t valu32;
331         dbus_uint16_t valu16;
332         dbus_int16_t vals16;
333         const char *valstr;
334         DBusMessageIter subiter;
335
336         if (iter == NULL) {
337                 rl_printf("%s%s is nil\n", label, name);
338                 return;
339         }
340
341         switch (dbus_message_iter_get_arg_type(iter)) {
342         case DBUS_TYPE_INVALID:
343                 rl_printf("%s%s is invalid\n", label, name);
344                 break;
345         case DBUS_TYPE_STRING:
346         case DBUS_TYPE_OBJECT_PATH:
347                 dbus_message_iter_get_basic(iter, &valstr);
348                 rl_printf("%s%s: %s\n", label, name, valstr);
349                 break;
350         case DBUS_TYPE_BOOLEAN:
351                 dbus_message_iter_get_basic(iter, &valbool);
352                 rl_printf("%s%s: %s\n", label, name,
353                                         valbool == TRUE ? "yes" : "no");
354                 break;
355         case DBUS_TYPE_UINT64:
356                 dbus_message_iter_get_basic(iter, &valu64);
357                 rl_printf("%s%s: %" PRIu64 "\n", label, name, valu64);
358                 break;
359         case DBUS_TYPE_UINT32:
360                 dbus_message_iter_get_basic(iter, &valu32);
361                 rl_printf("%s%s: 0x%08x\n", label, name, valu32);
362                 break;
363         case DBUS_TYPE_UINT16:
364                 dbus_message_iter_get_basic(iter, &valu16);
365                 rl_printf("%s%s: 0x%04x\n", label, name, valu16);
366                 break;
367         case DBUS_TYPE_INT16:
368                 dbus_message_iter_get_basic(iter, &vals16);
369                 rl_printf("%s%s: %d\n", label, name, vals16);
370                 break;
371         case DBUS_TYPE_VARIANT:
372                 dbus_message_iter_recurse(iter, &subiter);
373                 print_iter(label, name, &subiter);
374                 break;
375         case DBUS_TYPE_ARRAY:
376                 dbus_message_iter_recurse(iter, &subiter);
377                 while (dbus_message_iter_get_arg_type(&subiter) !=
378                                                         DBUS_TYPE_INVALID) {
379                         print_iter(label, name, &subiter);
380                         dbus_message_iter_next(&subiter);
381                 }
382                 break;
383         case DBUS_TYPE_DICT_ENTRY:
384                 dbus_message_iter_recurse(iter, &subiter);
385                 dbus_message_iter_get_basic(&subiter, &valstr);
386                 dbus_message_iter_next(&subiter);
387                 print_iter(label, valstr, &subiter);
388                 break;
389         default:
390                 rl_printf("%s%s has unsupported type\n", label, name);
391                 break;
392         }
393 }
394
395 static void print_property(GDBusProxy *proxy, const char *name)
396 {
397         DBusMessageIter iter;
398
399         if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
400                 return;
401
402         print_iter("\t", name, &iter);
403 }
404
405 static void cmd_show(int argc, char *argv[])
406 {
407         GDBusProxy *proxy;
408
409         if (argc < 2) {
410                 if (check_default_session() == FALSE)
411                         return;
412
413                 proxy = default_session;
414         } else {
415                 proxy = find_session(argv[1]);
416                 if (!proxy) {
417                         rl_printf("Session %s not available\n", argv[1]);
418                         return;
419                 }
420         }
421
422         rl_printf("Session %s\n", g_dbus_proxy_get_path(proxy));
423
424         print_property(proxy, "Destination");
425         print_property(proxy, "Target");
426 }
427
428 static void set_default_session(GDBusProxy *proxy)
429 {
430         char *desc;
431         DBusMessageIter iter;
432
433         default_session = proxy;
434
435         if (!g_dbus_proxy_get_property(proxy, "Destination", &iter)) {
436                 desc = g_strdup(PROMPT_ON);
437                 goto done;
438         }
439
440         dbus_message_iter_get_basic(&iter, &desc);
441         desc = g_strdup_printf(COLOR_BLUE "[%s]" COLOR_OFF "# ", desc);
442
443 done:
444         rl_set_prompt(desc);
445         rl_redisplay();
446         g_free(desc);
447 }
448
449 static void cmd_select(int argc, char *argv[])
450 {
451         GDBusProxy *proxy;
452
453         if (argc < 2) {
454                 rl_printf("Missing session address argument\n");
455                 return;
456         }
457
458         proxy = find_session(argv[1]);
459         if (proxy == NULL) {
460                 rl_printf("Session %s not available\n", argv[1]);
461                 return;
462         }
463
464         if (default_session == proxy)
465                 return;
466
467         set_default_session(proxy);
468
469         print_proxy(proxy, "Session", NULL);
470 }
471
472 static GDBusProxy *find_transfer(const char *path)
473 {
474         GSList *l;
475
476         for (l = transfers; l; l = g_slist_next(l)) {
477                 GDBusProxy *proxy = l->data;
478
479                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
480                         return proxy;
481         }
482
483         return NULL;
484 }
485
486 static GDBusProxy *find_message(const char *path)
487 {
488         GSList *l;
489
490         for (l = msgs; l; l = g_slist_next(l)) {
491                 GDBusProxy *proxy = l->data;
492
493                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
494                         return proxy;
495         }
496
497         return NULL;
498 }
499
500 static void transfer_info(GDBusProxy *proxy, int argc, char *argv[])
501 {
502         rl_printf("Transfer %s\n", g_dbus_proxy_get_path(proxy));
503
504         print_property(proxy, "Session");
505         print_property(proxy, "Name");
506         print_property(proxy, "Type");
507         print_property(proxy, "Status");
508         print_property(proxy, "Time");
509         print_property(proxy, "Size");
510         print_property(proxy, "Transferred");
511         print_property(proxy, "Filename");
512 }
513
514 static void message_info(GDBusProxy *proxy, int argc, char *argv[])
515 {
516         rl_printf("Message %s\n", g_dbus_proxy_get_path(proxy));
517
518         print_property(proxy, "Folder");
519         print_property(proxy, "Subject");
520         print_property(proxy, "Timestamp");
521         print_property(proxy, "Sender");
522         print_property(proxy, "SenderAddress");
523         print_property(proxy, "ReplyTo");
524         print_property(proxy, "Recipient");
525         print_property(proxy, "RecipientAddress");
526         print_property(proxy, "Type");
527         print_property(proxy, "Size");
528         print_property(proxy, "Status");
529         print_property(proxy, "Priority");
530         print_property(proxy, "Read");
531         print_property(proxy, "Deleted");
532         print_property(proxy, "Sent");
533         print_property(proxy, "Protected");
534 }
535
536 static void cmd_info(int argc, char *argv[])
537 {
538         GDBusProxy *proxy;
539
540         if (argc < 2) {
541                 rl_printf("Missing object path argument\n");
542                 return;
543         }
544
545         proxy = find_transfer(argv[1]);
546         if (proxy) {
547                 transfer_info(proxy, argc, argv);
548                 return;
549         }
550
551         proxy = find_message(argv[1]);
552         if (proxy) {
553                 message_info(proxy, argc, argv);
554                 return;
555         }
556
557         rl_printf("Object %s not available\n", argv[1]);
558 }
559
560 static void cancel_reply(DBusMessage *message, void *user_data)
561 {
562         DBusError error;
563
564         dbus_error_init(&error);
565
566         if (dbus_set_error_from_message(&error, message) == TRUE) {
567                 rl_printf("Failed to cancel: %s\n", error.name);
568                 dbus_error_free(&error);
569                 return;
570         }
571
572         rl_printf("Cancel successful\n");
573 }
574
575 static void cmd_cancel(int argc, char *argv[])
576 {
577         GDBusProxy *proxy;
578
579         if (argc < 2) {
580                 rl_printf("Missing transfer address argument\n");
581                 return;
582         }
583
584         proxy = find_transfer(argv[1]);
585         if (!proxy) {
586                 rl_printf("Transfer %s not available\n", argv[1]);
587                 return;
588         }
589
590         if (g_dbus_proxy_method_call(proxy, "Cancel", NULL, cancel_reply, NULL,
591                                                         NULL) == FALSE) {
592                 rl_printf("Failed to cancel transfer\n");
593                 return;
594         }
595
596         rl_printf("Attempting to cancel transfer %s\n",
597                                                 g_dbus_proxy_get_path(proxy));
598 }
599
600 static void suspend_reply(DBusMessage *message, void *user_data)
601 {
602         DBusError error;
603
604         dbus_error_init(&error);
605
606         if (dbus_set_error_from_message(&error, message) == TRUE) {
607                 rl_printf("Failed to suspend: %s\n", error.name);
608                 dbus_error_free(&error);
609                 return;
610         }
611
612         rl_printf("Suspend successful\n");
613 }
614
615 static void cmd_suspend(int argc, char *argv[])
616 {
617         GDBusProxy *proxy;
618
619         if (argc < 2) {
620                 rl_printf("Missing transfer address argument\n");
621                 return;
622         }
623
624         proxy = find_transfer(argv[1]);
625         if (!proxy) {
626                 rl_printf("Transfer %s not available\n", argv[1]);
627                 return;
628         }
629
630         if (g_dbus_proxy_method_call(proxy, "Suspend", NULL, suspend_reply,
631                                                 NULL, NULL) == FALSE) {
632                 rl_printf("Failed to suspend transfer\n");
633                 return;
634         }
635
636         rl_printf("Attempting to suspend transfer %s\n",
637                                                 g_dbus_proxy_get_path(proxy));
638 }
639
640 static void resume_reply(DBusMessage *message, void *user_data)
641 {
642         DBusError error;
643
644         dbus_error_init(&error);
645
646         if (dbus_set_error_from_message(&error, message) == TRUE) {
647                 rl_printf("Failed to resume: %s\n", error.name);
648                 dbus_error_free(&error);
649                 return;
650         }
651
652         rl_printf("Resume successful\n");
653 }
654
655 static void cmd_resume(int argc, char *argv[])
656 {
657         GDBusProxy *proxy;
658
659         if (argc < 2) {
660                 rl_printf("Missing transfer address argument\n");
661                 return;
662         }
663
664         proxy = find_transfer(argv[1]);
665         if (!proxy) {
666                 rl_printf("Transfer %s not available\n", argv[1]);
667                 return;
668         }
669
670         if (g_dbus_proxy_method_call(proxy, "Resume", NULL, resume_reply,
671                                                 NULL, NULL) == FALSE) {
672                 rl_printf("Failed to resume transfer\n");
673                 return;
674         }
675
676         rl_printf("Attempting to resume transfer %s\n",
677                                                 g_dbus_proxy_get_path(proxy));
678 }
679
680 static GDBusProxy *find_opp(const char *path)
681 {
682         GSList *l;
683
684         for (l = opps; l; l = g_slist_next(l)) {
685                 GDBusProxy *proxy = l->data;
686
687                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
688                         return proxy;
689         }
690
691         return NULL;
692 }
693
694 static GDBusProxy *find_map(const char *path)
695 {
696         GSList *l;
697
698         for (l = maps; l; l = g_slist_next(l)) {
699                 GDBusProxy *proxy = l->data;
700
701                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
702                         return proxy;
703         }
704
705         return NULL;
706 }
707
708 static void print_dict_iter(DBusMessageIter *iter)
709 {
710         DBusMessageIter dict;
711         int ctype;
712
713         ctype = dbus_message_iter_get_arg_type(iter);
714         if (ctype != DBUS_TYPE_ARRAY)
715                 return;
716
717         dbus_message_iter_recurse(iter, &dict);
718
719         while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
720                                                         DBUS_TYPE_INVALID) {
721                 DBusMessageIter entry;
722                 const char *key;
723
724                 if (ctype != DBUS_TYPE_DICT_ENTRY)
725                         return;
726
727                 dbus_message_iter_recurse(&dict, &entry);
728                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
729                         return;
730
731                 dbus_message_iter_get_basic(&entry, &key);
732                 dbus_message_iter_next(&entry);
733
734                 print_iter("\t", key, &entry);
735
736                 dbus_message_iter_next(&dict);
737         }
738 }
739
740 static void print_transfer_iter(DBusMessageIter *iter)
741 {
742         const char *path;
743
744         dbus_message_iter_get_basic(iter, &path);
745
746         rl_printf("Transfer %s\n", path);
747
748         dbus_message_iter_next(iter);
749
750         print_dict_iter(iter);
751 }
752
753 static void send_reply(DBusMessage *message, void *user_data)
754 {
755         DBusMessageIter iter;
756         DBusError error;
757
758         dbus_error_init(&error);
759
760         if (dbus_set_error_from_message(&error, message) == TRUE) {
761                 rl_printf("Failed to send/pull: %s\n", error.name);
762                 dbus_error_free(&error);
763                 return;
764         }
765
766         dbus_message_iter_init(message, &iter);
767
768         print_transfer_iter(&iter);
769 }
770
771 static void send_setup(DBusMessageIter *iter, void *user_data)
772 {
773         const char *file = user_data;
774
775         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
776 }
777
778 static void opp_send(GDBusProxy *proxy, int argc, char *argv[])
779 {
780         if (argc < 2) {
781                 rl_printf("Missing file argument\n");
782                 return;
783         }
784
785         if (g_dbus_proxy_method_call(proxy, "SendFile", send_setup, send_reply,
786                                         g_strdup(argv[1]), g_free) == FALSE) {
787                 rl_printf("Failed to send\n");
788                 return;
789         }
790
791         rl_printf("Attempting to send %s to %s\n", argv[1],
792                                                 g_dbus_proxy_get_path(proxy));
793 }
794
795 static void opp_pull(GDBusProxy *proxy, int argc, char *argv[])
796 {
797         if (argc < 2) {
798                 rl_printf("Missing file argument\n");
799                 return;
800         }
801
802         if (g_dbus_proxy_method_call(proxy, "PullBusinessCard", send_setup,
803                         send_reply, g_strdup(argv[1]), g_free) == FALSE) {
804                 rl_printf("Failed to pull\n");
805                 return;
806         }
807
808         rl_printf("Attempting to pull %s from %s\n", argv[1],
809                                                 g_dbus_proxy_get_path(proxy));
810 }
811
812 static void push_reply(DBusMessage *message, void *user_data)
813 {
814         DBusMessageIter iter;
815         DBusError error;
816
817         dbus_error_init(&error);
818
819         if (dbus_set_error_from_message(&error, message) == TRUE) {
820                 rl_printf("Failed to PushMessage: %s\n", error.name);
821                 dbus_error_free(&error);
822                 return;
823         }
824
825         dbus_message_iter_init(message, &iter);
826
827         print_transfer_iter(&iter);
828 }
829
830 static void push_setup(DBusMessageIter *iter, void *user_data)
831 {
832         const char *file = user_data;
833         const char *folder = "";
834         DBusMessageIter dict;
835
836         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
837         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
838
839         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
840                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
841                                         DBUS_TYPE_STRING_AS_STRING
842                                         DBUS_TYPE_VARIANT_AS_STRING
843                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
844                                         &dict);
845
846         dbus_message_iter_close_container(iter, &dict);
847 }
848
849 static void map_send(GDBusProxy *proxy, int argc, char *argv[])
850 {
851         if (argc < 2) {
852                 rl_printf("Missing file argument\n");
853                 return;
854         }
855
856         if (g_dbus_proxy_method_call(proxy, "PushMessage", push_setup,
857                                         push_reply, g_strdup(argv[1]),
858                                         g_free) == FALSE) {
859                 rl_printf("Failed to send\n");
860                 return;
861         }
862
863         rl_printf("Attempting to send %s to %s\n", argv[1],
864                                                 g_dbus_proxy_get_path(proxy));
865 }
866
867 static void cmd_send(int argc, char *argv[])
868 {
869         GDBusProxy *proxy;
870
871         if (!check_default_session())
872                 return;
873
874         proxy = find_opp(g_dbus_proxy_get_path(default_session));
875         if (proxy) {
876                 opp_send(proxy, argc, argv);
877                 return;
878         }
879
880         proxy = find_map(g_dbus_proxy_get_path(default_session));
881         if (proxy) {
882                 map_send(proxy, argc, argv);
883                 return;
884         }
885
886         rl_printf("Command not supported\n");
887 }
888
889 static void cmd_pull(int argc, char *argv[])
890 {
891         GDBusProxy *proxy;
892
893         if (!check_default_session())
894                 return;
895
896         proxy = find_opp(g_dbus_proxy_get_path(default_session));
897         if (proxy) {
898                 opp_pull(proxy, argc, argv);
899                 return;
900         }
901
902         rl_printf("Command not supported\n");
903 }
904
905 static void change_folder_reply(DBusMessage *message, void *user_data)
906 {
907         DBusError error;
908
909         dbus_error_init(&error);
910
911         if (dbus_set_error_from_message(&error, message) == TRUE) {
912                 rl_printf("Failed to ChangeFolder: %s\n", error.name);
913                 dbus_error_free(&error);
914                 return;
915         }
916
917         rl_printf("ChangeFolder successful\n");
918 }
919
920 static void change_folder_setup(DBusMessageIter *iter, void *user_data)
921 {
922         const char *folder = user_data;
923
924         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
925 }
926
927 static void select_reply(DBusMessage *message, void *user_data)
928 {
929         DBusMessageIter iter;
930         DBusError error;
931
932         dbus_error_init(&error);
933
934         if (dbus_set_error_from_message(&error, message) == TRUE) {
935                 rl_printf("Failed to Select: %s\n", error.name);
936                 dbus_error_free(&error);
937                 return;
938         }
939
940         dbus_message_iter_init(message, &iter);
941
942         rl_printf("Select successful\n");
943 }
944
945 static void select_setup(DBusMessageIter *iter, void *user_data)
946 {
947         const char *folder = user_data;
948         const char *location = "int";
949
950         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &location);
951         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
952 }
953
954 static void setfolder_reply(DBusMessage *message, void *user_data)
955 {
956         DBusError error;
957
958         dbus_error_init(&error);
959
960         if (dbus_set_error_from_message(&error, message) == TRUE) {
961                 rl_printf("Failed to SetFolder: %s\n", error.name);
962                 dbus_error_free(&error);
963                 return;
964         }
965
966         rl_printf("SetFolder successful\n");
967 }
968
969 static void setfolder_setup(DBusMessageIter *iter, void *user_data)
970 {
971         const char *folder = user_data;
972
973         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
974 }
975
976 static GDBusProxy *find_ftp(const char *path)
977 {
978         GSList *l;
979
980         for (l = ftps; l; l = g_slist_next(l)) {
981                 GDBusProxy *proxy = l->data;
982
983                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
984                         return proxy;
985         }
986
987         return NULL;
988 }
989
990 static GDBusProxy *find_pbap(const char *path)
991 {
992         GSList *l;
993
994         for (l = pbaps; l; l = g_slist_next(l)) {
995                 GDBusProxy *proxy = l->data;
996
997                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
998                         return proxy;
999         }
1000
1001         return NULL;
1002 }
1003
1004 static void ftp_cd(GDBusProxy *proxy, int argc, char *argv[])
1005 {
1006         if (argc < 2) {
1007                 rl_printf("Missing path argument\n");
1008                 return;
1009         }
1010
1011         if (g_dbus_proxy_method_call(proxy, "ChangeFolder", change_folder_setup,
1012                                         change_folder_reply, g_strdup(argv[1]),
1013                                         g_free) == FALSE) {
1014                 rl_printf("Failed to ChangeFolder\n");
1015                 return;
1016         }
1017
1018         rl_printf("Attempting to ChangeFolder to %s\n", argv[1]);
1019 }
1020
1021 static void pbap_cd(GDBusProxy *proxy, int argc, char *argv[])
1022 {
1023         if (argc < 2) {
1024                 rl_printf("Missing path argument\n");
1025                 return;
1026         }
1027
1028         if (g_dbus_proxy_method_call(proxy, "Select", select_setup,
1029                                         select_reply, g_strdup(argv[1]),
1030                                         g_free) == FALSE) {
1031                 rl_printf("Failed to Select\n");
1032                 return;
1033         }
1034
1035         rl_printf("Attempting to Select to %s\n", argv[1]);
1036 }
1037
1038 static void map_cd(GDBusProxy *proxy, int argc, char *argv[])
1039 {
1040         if (argc < 2) {
1041                 rl_printf("Missing path argument\n");
1042                 return;
1043         }
1044
1045         if (g_dbus_proxy_method_call(proxy, "SetFolder", setfolder_setup,
1046                                         setfolder_reply, g_strdup(argv[1]),
1047                                         g_free) == FALSE) {
1048                 rl_printf("Failed to SetFolder\n");
1049                 return;
1050         }
1051
1052         rl_printf("Attempting to SetFolder to %s\n", argv[1]);
1053 }
1054
1055 static void cmd_cd(int argc, char *argv[])
1056 {
1057         GDBusProxy *proxy;
1058
1059         if (!check_default_session())
1060                 return;
1061
1062         proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1063         if (proxy) {
1064                 ftp_cd(proxy, argc, argv);
1065                 return;
1066         }
1067
1068         proxy = find_pbap(g_dbus_proxy_get_path(default_session));
1069         if (proxy) {
1070                 pbap_cd(proxy, argc, argv);
1071                 return;
1072         }
1073
1074         proxy = find_map(g_dbus_proxy_get_path(default_session));
1075         if (proxy) {
1076                 map_cd(proxy, argc, argv);
1077                 return;
1078         }
1079
1080         rl_printf("Command not supported\n");
1081 }
1082
1083 static void list_folder_reply(DBusMessage *message, void *user_data)
1084 {
1085         DBusMessageIter iter, array;
1086         DBusError error;
1087
1088         dbus_error_init(&error);
1089
1090         if (dbus_set_error_from_message(&error, message) == TRUE) {
1091                 rl_printf("Failed to ListFolder: %s\n", error.name);
1092                 dbus_error_free(&error);
1093                 return;
1094         }
1095
1096         dbus_message_iter_init(message, &iter);
1097
1098         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1099                 return;
1100
1101         dbus_message_iter_recurse(&iter, &array);
1102
1103         while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1104                 print_dict_iter(&array);
1105                 dbus_message_iter_next(&array);
1106         }
1107 }
1108
1109 static void ftp_ls(GDBusProxy *proxy, int argc, char *argv[])
1110 {
1111         if (g_dbus_proxy_method_call(proxy, "ListFolder", NULL,
1112                                                 list_folder_reply, NULL,
1113                                                 NULL) == FALSE) {
1114                 rl_printf("Failed to ls\n");
1115                 return;
1116         }
1117
1118         rl_printf("Attempting to ListFolder\n");
1119 }
1120
1121 static void parse_list_reply(DBusMessage *message)
1122 {
1123         DBusMessageIter iter, array;
1124
1125         dbus_message_iter_init(message, &iter);
1126
1127         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1128                 return;
1129
1130         dbus_message_iter_recurse(&iter, &array);
1131
1132         while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1133                 DBusMessageIter entry;
1134                 const char *vcard;
1135
1136                 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT)
1137                         return;
1138
1139                 dbus_message_iter_recurse(&array, &entry);
1140
1141                 dbus_message_iter_get_basic(&entry, &vcard);
1142                 dbus_message_iter_next(&entry);
1143                 print_iter("\t", vcard, &entry);
1144                 dbus_message_iter_next(&array);
1145         }
1146 }
1147
1148 static void list_reply(DBusMessage *message, void *user_data)
1149 {
1150         DBusError error;
1151
1152         dbus_error_init(&error);
1153
1154         if (dbus_set_error_from_message(&error, message) == TRUE) {
1155                 rl_printf("Failed to List: %s\n", error.name);
1156                 dbus_error_free(&error);
1157                 return;
1158         }
1159
1160         parse_list_reply(message);
1161 }
1162
1163 static void list_setup(DBusMessageIter *iter, void *user_data)
1164 {
1165         DBusMessageIter dict;
1166
1167         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1168                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1169                                         DBUS_TYPE_STRING_AS_STRING
1170                                         DBUS_TYPE_VARIANT_AS_STRING
1171                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1172                                         &dict);
1173
1174         dbus_message_iter_close_container(iter, &dict);
1175 }
1176
1177 static void search_reply(DBusMessage *message, void *user_data)
1178 {
1179         DBusError error;
1180
1181         dbus_error_init(&error);
1182
1183         if (dbus_set_error_from_message(&error, message) == TRUE) {
1184                 rl_printf("Failed to Search: %s\n", error.name);
1185                 dbus_error_free(&error);
1186                 return;
1187         }
1188
1189         parse_list_reply(message);
1190 }
1191
1192 static void search_setup(DBusMessageIter *iter, void *user_data)
1193 {
1194         const char *value = user_data;
1195         const char *field;
1196         DBusMessageIter dict;
1197
1198         field = isalpha(value[0]) ? "name" : "number";
1199
1200         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field);
1201         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &value);
1202
1203         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1204                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1205                                         DBUS_TYPE_STRING_AS_STRING
1206                                         DBUS_TYPE_VARIANT_AS_STRING
1207                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1208                                         &dict);
1209
1210         dbus_message_iter_close_container(iter, &dict);
1211 }
1212
1213 static void pbap_search(GDBusProxy *proxy, int argc, char *argv[])
1214 {
1215         if (g_dbus_proxy_method_call(proxy, "Search", search_setup,
1216                                         search_reply, g_strdup(argv[1]),
1217                                         g_free) == FALSE) {
1218                 rl_printf("Failed to Search\n");
1219                 return;
1220         }
1221
1222         rl_printf("Attempting to Search\n");
1223 }
1224
1225 static void list_folders_reply(DBusMessage *message, void *user_data)
1226 {
1227         DBusError error;
1228         DBusMessageIter iter, array;
1229
1230         dbus_error_init(&error);
1231
1232         if (dbus_set_error_from_message(&error, message) == TRUE) {
1233                 rl_printf("Failed to ListFolders: %s\n", error.name);
1234                 dbus_error_free(&error);
1235                 return;
1236         }
1237
1238         dbus_message_iter_init(message, &iter);
1239
1240         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1241                 return;
1242
1243         dbus_message_iter_recurse(&iter, &array);
1244
1245         while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1246                 print_dict_iter(&array);
1247                 dbus_message_iter_next(&array);
1248         }
1249 }
1250
1251 static void list_folders_setup(DBusMessageIter *iter, void *user_data)
1252 {
1253         DBusMessageIter dict;
1254
1255         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1256                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1257                                         DBUS_TYPE_STRING_AS_STRING
1258                                         DBUS_TYPE_VARIANT_AS_STRING
1259                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1260                                         &dict);
1261
1262         dbus_message_iter_close_container(iter, &dict);
1263 }
1264
1265 static void list_messages_reply(DBusMessage *message, void *user_data)
1266 {
1267         DBusError error;
1268         DBusMessageIter iter, array;
1269
1270         dbus_error_init(&error);
1271
1272         if (dbus_set_error_from_message(&error, message) == TRUE) {
1273                 rl_printf("Failed to ListFolders: %s\n", error.name);
1274                 dbus_error_free(&error);
1275                 return;
1276         }
1277
1278         dbus_message_iter_init(message, &iter);
1279
1280         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1281                 return;
1282
1283         dbus_message_iter_recurse(&iter, &array);
1284
1285         while ((dbus_message_iter_get_arg_type(&array)) ==
1286                                                 DBUS_TYPE_DICT_ENTRY) {
1287                 DBusMessageIter entry;
1288                 const char *obj;
1289
1290                 dbus_message_iter_recurse(&array, &entry);
1291                 dbus_message_iter_get_basic(&entry, &obj);
1292                 rl_printf("\t%s\n", obj);
1293                 dbus_message_iter_next(&array);
1294         }
1295 }
1296
1297 static void list_messages_setup(DBusMessageIter *iter, void *user_data)
1298 {
1299         const char *folder = user_data;
1300         DBusMessageIter dict;
1301
1302         if (strcmp(folder, "*") == 0)
1303                 folder = "";
1304
1305         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
1306
1307         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1308                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1309                                         DBUS_TYPE_STRING_AS_STRING
1310                                         DBUS_TYPE_VARIANT_AS_STRING
1311                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1312                                         &dict);
1313
1314         dbus_message_iter_close_container(iter, &dict);
1315 }
1316
1317 static void pbap_list(GDBusProxy *proxy, int argc, char *argv[])
1318 {
1319         if (g_dbus_proxy_method_call(proxy, "List", list_setup, list_reply,
1320                                                 NULL, NULL) == FALSE) {
1321                 rl_printf("Failed to List\n");
1322                 return;
1323         }
1324
1325         rl_printf("Attempting to List\n");
1326 }
1327
1328 static void get_size_reply(DBusMessage *message, void *user_data)
1329 {
1330         GDBusProxy *proxy = user_data;
1331         DBusError error;
1332         DBusMessageIter iter;
1333
1334         dbus_error_init(&error);
1335
1336         if (dbus_set_error_from_message(&error, message) == TRUE) {
1337                 rl_printf("Failed to GetSize: %s\n", error.name);
1338                 dbus_error_free(&error);
1339                 return;
1340         }
1341
1342         dbus_message_iter_init(message, &iter);
1343
1344         print_iter("\t", "Size", &iter);
1345
1346         pbap_list(proxy, 0, NULL);
1347 }
1348
1349 static void pbap_get_size(GDBusProxy *proxy, int argc, char *argv[])
1350 {
1351         if (g_dbus_proxy_method_call(proxy, "GetSize", NULL, get_size_reply,
1352                                                 proxy, NULL) == FALSE) {
1353                 rl_printf("Failed to GetSize\n");
1354                 return;
1355         }
1356
1357         rl_printf("Attempting to GetSize\n");
1358 }
1359
1360 static void pbap_ls(GDBusProxy *proxy, int argc, char *argv[])
1361 {
1362         if (argc > 1) {
1363                 if (strcmp("-l", argv[1]))
1364                         pbap_search(proxy, argc, argv);
1365                 else
1366                         pbap_get_size(proxy, argc, argv);
1367                 return;
1368         }
1369
1370         pbap_list(proxy, argc, argv);
1371 }
1372
1373 static void map_ls_messages(GDBusProxy *proxy, int argc, char *argv[])
1374 {
1375         if (g_dbus_proxy_method_call(proxy, "ListMessages", list_messages_setup,
1376                                         list_messages_reply, g_strdup(argv[1]),
1377                                         g_free) == FALSE) {
1378                 rl_printf("Failed to ListMessages\n");
1379                 return;
1380         }
1381
1382         rl_printf("Attempting to ListMessages\n");
1383 }
1384
1385 static void map_ls(GDBusProxy *proxy, int argc, char *argv[])
1386 {
1387         if (argc > 1) {
1388                 map_ls_messages(proxy, argc, argv);
1389                 return;
1390         }
1391
1392         if (g_dbus_proxy_method_call(proxy, "ListFolders", list_folders_setup,
1393                                                 list_folders_reply, NULL,
1394                                                 NULL) == FALSE) {
1395                 rl_printf("Failed to ListFolders\n");
1396                 return;
1397         }
1398
1399         rl_printf("Attempting to ListFolders\n");
1400 }
1401
1402 static void cmd_ls(int argc, char *argv[])
1403 {
1404         GDBusProxy *proxy;
1405
1406         if (!check_default_session())
1407                 return;
1408
1409         proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1410         if (proxy) {
1411                 ftp_ls(proxy, argc, argv);
1412                 return;
1413         }
1414
1415         proxy = find_pbap(g_dbus_proxy_get_path(default_session));
1416         if (proxy) {
1417                 pbap_ls(proxy, argc, argv);
1418                 return;
1419         }
1420
1421         proxy = find_map(g_dbus_proxy_get_path(default_session));
1422         if (proxy) {
1423                 map_ls(proxy, argc, argv);
1424                 return;
1425         }
1426
1427         rl_printf("Command not supported\n");
1428 }
1429
1430 struct cp_args {
1431         char *source;
1432         char *target;
1433 };
1434
1435 static void cp_free(void *data)
1436 {
1437         struct cp_args *args = data;
1438
1439         g_free(args->source);
1440         g_free(args->target);
1441         g_free(args);
1442 }
1443
1444 static struct cp_args *cp_new(char *argv[])
1445 {
1446         struct cp_args *args;
1447         const char *source;
1448         const char *target;
1449
1450         source = rindex(argv[1], ':');
1451         if (source == NULL)
1452                 source = argv[1];
1453         else
1454                 source++;
1455
1456         target = rindex(argv[2], ':');
1457         if (target == NULL)
1458                 target = argv[2];
1459         else
1460                 target++;
1461
1462         args = g_new0(struct cp_args, 1);
1463         args->source = g_strdup(source);
1464         args->target = g_strdup(target);
1465
1466         return args;
1467 }
1468
1469 static void cp_setup(DBusMessageIter *iter, void *user_data)
1470 {
1471         struct cp_args *args = user_data;
1472
1473         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
1474         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
1475 }
1476
1477 static void copy_file_reply(DBusMessage *message, void *user_data)
1478 {
1479         DBusError error;
1480
1481         dbus_error_init(&error);
1482
1483         if (dbus_set_error_from_message(&error, message) == TRUE) {
1484                 rl_printf("Failed to CopyFile: %s\n", error.name);
1485                 dbus_error_free(&error);
1486                 return;
1487         }
1488
1489         rl_printf("CopyFile successful\n");
1490 }
1491
1492 static void ftp_copy(GDBusProxy *proxy, int argc, char *argv[])
1493 {
1494         struct cp_args *args;
1495
1496         args = cp_new(argv);
1497
1498         if (g_dbus_proxy_method_call(proxy, "CopyFile", cp_setup,
1499                                 copy_file_reply, args, cp_free) == FALSE) {
1500                 rl_printf("Failed to CopyFile\n");
1501                 return;
1502         }
1503
1504         rl_printf("Attempting to CopyFile\n");
1505 }
1506
1507 static void get_file_reply(DBusMessage *message, void *user_data)
1508 {
1509         DBusError error;
1510         DBusMessageIter iter;
1511
1512         dbus_error_init(&error);
1513
1514         if (dbus_set_error_from_message(&error, message) == TRUE) {
1515                 rl_printf("Failed to GetFile: %s\n", error.name);
1516                 dbus_error_free(&error);
1517                 return;
1518         }
1519
1520         dbus_message_iter_init(message, &iter);
1521
1522         print_transfer_iter(&iter);
1523 }
1524
1525 static void get_file_setup(DBusMessageIter *iter, void *user_data)
1526 {
1527         struct cp_args *args = user_data;
1528
1529         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
1530         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
1531 }
1532
1533 static void ftp_get(GDBusProxy *proxy, int argc, char *argv[])
1534 {
1535         struct cp_args *args;
1536
1537         if (rindex(argv[2], ':') == NULL)
1538                 return ftp_copy(proxy, argc, argv);
1539
1540         args = cp_new(argv);
1541
1542         if (g_dbus_proxy_method_call(proxy, "GetFile", get_file_setup,
1543                                 get_file_reply, args, cp_free) == FALSE) {
1544                 rl_printf("Failed to GetFile\n");
1545                 return;
1546         }
1547
1548         rl_printf("Attempting to GetFile\n");
1549 }
1550
1551 static void put_file_reply(DBusMessage *message, void *user_data)
1552 {
1553         DBusError error;
1554         DBusMessageIter iter;
1555
1556         dbus_error_init(&error);
1557
1558         if (dbus_set_error_from_message(&error, message) == TRUE) {
1559                 rl_printf("Failed to PutFile: %s\n", error.name);
1560                 dbus_error_free(&error);
1561                 return;
1562         }
1563
1564         dbus_message_iter_init(message, &iter);
1565
1566         print_transfer_iter(&iter);
1567 }
1568
1569 static void ftp_put(GDBusProxy *proxy, int argc, char *argv[])
1570 {
1571         struct cp_args *args;
1572
1573         if (rindex(argv[2], ':') != NULL) {
1574                 rl_printf("Invalid target file argument\n");
1575                 return;
1576         }
1577
1578         args = cp_new(argv);
1579
1580         if (g_dbus_proxy_method_call(proxy, "PutFile", cp_setup, put_file_reply,
1581                                                 args, cp_free) == FALSE) {
1582                 rl_printf("Failed to PutFile\n");
1583                 return;
1584         }
1585
1586         rl_printf("Attempting to PutFile\n");
1587 }
1588
1589 static void ftp_cp(GDBusProxy *proxy, int argc, char *argv[])
1590 {
1591         if (argc < 2) {
1592                 rl_printf("Missing source file argument\n");
1593                 return;
1594         }
1595
1596         if (argc < 3) {
1597                 rl_printf("Missing target file argument\n");
1598                 return;
1599         }
1600
1601         if (rindex(argv[1], ':') == NULL)
1602                 return ftp_get(proxy, argc, argv);
1603
1604         return ftp_put(proxy, argc, argv);
1605 }
1606
1607 static void pull_all_reply(DBusMessage *message, void *user_data)
1608 {
1609         DBusError error;
1610
1611         dbus_error_init(&error);
1612
1613         if (dbus_set_error_from_message(&error, message) == TRUE) {
1614                 rl_printf("Failed to PullAll: %s\n", error.name);
1615                 dbus_error_free(&error);
1616                 return;
1617         }
1618
1619
1620         rl_printf("PullAll successful\n");
1621 }
1622
1623 static void pull_all_setup(DBusMessageIter *iter, void *user_data)
1624 {
1625         const char *file = user_data;
1626         DBusMessageIter dict;
1627
1628         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
1629
1630         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1631                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1632                                         DBUS_TYPE_STRING_AS_STRING
1633                                         DBUS_TYPE_VARIANT_AS_STRING
1634                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1635                                         &dict);
1636
1637         dbus_message_iter_close_container(iter, &dict);
1638 }
1639
1640 static void pbap_pull_all(GDBusProxy *proxy, int argc, char *argv[])
1641 {
1642         if (g_dbus_proxy_method_call(proxy, "PullAll", pull_all_setup,
1643                                         pull_all_reply, g_strdup(argv[2]),
1644                                         g_free) == FALSE) {
1645                 rl_printf("Failed to PullAll\n");
1646                 return;
1647         }
1648
1649         rl_printf("Attempting to PullAll\n");
1650 }
1651
1652 static void pull_reply(DBusMessage *message, void *user_data)
1653 {
1654         DBusError error;
1655
1656         dbus_error_init(&error);
1657
1658         if (dbus_set_error_from_message(&error, message) == TRUE) {
1659                 rl_printf("Failed to Pull: %s\n", error.name);
1660                 dbus_error_free(&error);
1661                 return;
1662         }
1663
1664
1665         rl_printf("Pull successful\n");
1666 }
1667
1668 static void pull_setup(DBusMessageIter *iter, void *user_data)
1669 {
1670         struct cp_args *args = user_data;
1671         DBusMessageIter dict;
1672
1673         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
1674         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
1675
1676         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1677                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1678                                         DBUS_TYPE_STRING_AS_STRING
1679                                         DBUS_TYPE_VARIANT_AS_STRING
1680                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1681                                         &dict);
1682
1683         dbus_message_iter_close_container(iter, &dict);
1684 }
1685
1686 static void pbap_pull(GDBusProxy *proxy, int argc, char *argv[])
1687 {
1688         struct cp_args *args;
1689
1690         args = cp_new(argv);
1691
1692         if (g_dbus_proxy_method_call(proxy, "Pull", pull_setup, pull_reply,
1693                                                 args, cp_free) == FALSE) {
1694                 rl_printf("Failed to Pull\n");
1695                 return;
1696         }
1697
1698         rl_printf("Attempting to Pull\n");
1699 }
1700
1701 static void pbap_cp(GDBusProxy *proxy, int argc, char *argv[])
1702 {
1703         if (argc < 2) {
1704                 rl_printf("Missing source file argument\n");
1705                 return;
1706         }
1707
1708         if (argc < 3) {
1709                 rl_printf("Missing target file argument\n");
1710                 return;
1711         }
1712
1713         if (strcmp(argv[1], "*") == 0)
1714                 return pbap_pull_all(proxy, argc, argv);
1715
1716         return pbap_pull(proxy, argc, argv);
1717 }
1718
1719 static void get_reply(DBusMessage *message, void *user_data)
1720 {
1721         DBusMessageIter iter;
1722         DBusError error;
1723
1724         dbus_error_init(&error);
1725
1726         if (dbus_set_error_from_message(&error, message) == TRUE) {
1727                 rl_printf("Failed to Get: %s\n", error.name);
1728                 dbus_error_free(&error);
1729                 return;
1730         }
1731
1732         dbus_message_iter_init(message, &iter);
1733
1734         print_transfer_iter(&iter);
1735 }
1736
1737 static void get_setup(DBusMessageIter *iter, void *user_data)
1738 {
1739         const char *file = user_data;
1740         dbus_bool_t attachment = TRUE;
1741
1742         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
1743         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &attachment);
1744 }
1745
1746 static void map_cp(GDBusProxy *proxy, int argc, char *argv[])
1747 {
1748         GDBusProxy *obj;
1749
1750         if (argc < 2) {
1751                 rl_printf("Missing message argument\n");
1752                 return;
1753         }
1754
1755         obj = find_message(argv[1]);
1756         if (obj == NULL) {
1757                 rl_printf("Invalid message argument\n");
1758                 return;
1759         }
1760
1761         if (argc < 3) {
1762                 rl_printf("Missing target file argument\n");
1763                 return;
1764         }
1765
1766         if (g_dbus_proxy_method_call(obj, "Get", get_setup, get_reply,
1767                                         g_strdup(argv[2]), g_free) == FALSE) {
1768                 rl_printf("Failed to Get\n");
1769                 return;
1770         }
1771
1772         rl_printf("Attempting to Get\n");
1773 }
1774
1775 static void cmd_cp(int argc, char *argv[])
1776 {
1777
1778         GDBusProxy *proxy;
1779
1780         if (!check_default_session())
1781                 return;
1782
1783         proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1784         if (proxy) {
1785                 ftp_cp(proxy, argc, argv);
1786                 return;
1787         }
1788
1789         proxy = find_pbap(g_dbus_proxy_get_path(default_session));
1790         if (proxy) {
1791                 pbap_cp(proxy, argc, argv);
1792                 return;
1793         }
1794
1795         proxy = find_map(g_dbus_proxy_get_path(default_session));
1796         if (proxy) {
1797                 map_cp(proxy, argc, argv);
1798                 return;
1799         }
1800
1801         rl_printf("Command not supported\n");
1802 }
1803
1804 static void move_file_reply(DBusMessage *message, void *user_data)
1805 {
1806         DBusError error;
1807
1808         dbus_error_init(&error);
1809
1810         if (dbus_set_error_from_message(&error, message) == TRUE) {
1811                 rl_printf("Failed to MoveFile: %s\n", error.name);
1812                 dbus_error_free(&error);
1813                 return;
1814         }
1815
1816         rl_printf("MoveFile successful\n");
1817 }
1818
1819 static void cmd_mv(int argc, char *argv[])
1820 {
1821         GDBusProxy *proxy;
1822         struct cp_args *args;
1823
1824         if (!check_default_session())
1825                 return;
1826
1827         if (argc < 2) {
1828                 rl_printf("Missing source file argument\n");
1829                 return;
1830         }
1831
1832         if (argc < 3) {
1833                 rl_printf("Missing target file argument\n");
1834                 return;
1835         }
1836
1837         proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1838         if (proxy == NULL) {
1839                 rl_printf("Command not supported\n");
1840                 return;
1841         }
1842
1843         args = cp_new(argv);
1844
1845         if (g_dbus_proxy_method_call(proxy, "MoveFile", cp_setup,
1846                                 move_file_reply, args, cp_free) == FALSE) {
1847                 rl_printf("Failed to MoveFile\n");
1848                 return;
1849         }
1850
1851         rl_printf("Attempting to MoveFile\n");
1852 }
1853
1854 static void delete_reply(DBusMessage *message, void *user_data)
1855 {
1856         DBusError error;
1857
1858         dbus_error_init(&error);
1859
1860         if (dbus_set_error_from_message(&error, message) == TRUE) {
1861                 rl_printf("Failed to Delete: %s\n", error.name);
1862                 dbus_error_free(&error);
1863                 return;
1864         }
1865
1866         rl_printf("Delete successful\n");
1867 }
1868
1869 static void delete_setup(DBusMessageIter *iter, void *user_data)
1870 {
1871         const char *file = user_data;
1872
1873         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
1874 }
1875
1876 static void ftp_rm(GDBusProxy *proxy, int argc, char *argv[])
1877 {
1878         if (argc < 2) {
1879                 rl_printf("Missing file argument\n");
1880                 return;
1881         }
1882
1883         if (g_dbus_proxy_method_call(proxy, "Delete", delete_setup,
1884                                         delete_reply, g_strdup(argv[1]),
1885                                         g_free) == FALSE) {
1886                 rl_printf("Failed to Delete\n");
1887                 return;
1888         }
1889
1890         rl_printf("Attempting to Delete\n");
1891 }
1892
1893 static void set_delete_reply(const DBusError *error, void *user_data)
1894 {
1895         if (dbus_error_is_set(error))
1896                 rl_printf("Failed to set Deleted: %s\n", error->name);
1897         else
1898                 rl_printf("Set Deleted successful\n");
1899 }
1900
1901 static void map_rm(GDBusProxy *proxy, int argc, char *argv[])
1902 {
1903         GDBusProxy *msg;
1904         dbus_bool_t value = TRUE;
1905
1906         if (argc < 2) {
1907                 rl_printf("Missing message argument\n");
1908                 return;
1909         }
1910
1911         msg = find_message(argv[1]);
1912         if (msg == NULL) {
1913                 rl_printf("Invalid message argument\n");
1914                 return;
1915         }
1916
1917         if (g_dbus_proxy_set_property_basic(msg, "Deleted", DBUS_TYPE_BOOLEAN,
1918                                                 &value, set_delete_reply,
1919                                                 NULL, NULL) == FALSE) {
1920                 rl_printf("Failed to set Deleted\n");
1921                 return;
1922         }
1923
1924         rl_printf("Attempting to set Deleted\n");
1925 }
1926
1927 static void cmd_rm(int argc, char *argv[])
1928 {
1929         GDBusProxy *proxy;
1930
1931         if (!check_default_session())
1932                 return;
1933
1934         proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1935         if (proxy) {
1936                 ftp_rm(proxy, argc, argv);
1937                 return;
1938         }
1939
1940         proxy = find_map(g_dbus_proxy_get_path(default_session));
1941         if (proxy) {
1942                 map_rm(proxy, argc, argv);
1943                 return;
1944         }
1945
1946         rl_printf("Command not supported\n");
1947 }
1948
1949 static void create_folder_reply(DBusMessage *message, void *user_data)
1950 {
1951         DBusError error;
1952
1953         dbus_error_init(&error);
1954
1955         if (dbus_set_error_from_message(&error, message) == TRUE) {
1956                 rl_printf("Failed to CreateFolder: %s\n", error.name);
1957                 dbus_error_free(&error);
1958                 return;
1959         }
1960
1961         rl_printf("CreateFolder successful\n");
1962 }
1963
1964 static void create_folder_setup(DBusMessageIter *iter, void *user_data)
1965 {
1966         const char *folder = user_data;
1967
1968         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
1969 }
1970
1971 static void cmd_mkdir(int argc, char *argv[])
1972 {
1973         GDBusProxy *proxy;
1974
1975         if (!check_default_session())
1976                 return;
1977
1978         if (argc < 2) {
1979                 rl_printf("Missing folder argument\n");
1980                 return;
1981         }
1982
1983         proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1984         if (proxy == NULL) {
1985                 rl_printf("Command not supported\n");
1986                 return;
1987         }
1988
1989         if (g_dbus_proxy_method_call(proxy, "CreateFolder", create_folder_setup,
1990                                         create_folder_reply, g_strdup(argv[1]),
1991                                         g_free) == FALSE) {
1992                 rl_printf("Failed to CreateFolder\n");
1993                 return;
1994         }
1995
1996         rl_printf("Attempting to CreateFolder\n");
1997 }
1998
1999 static const struct {
2000         const char *cmd;
2001         const char *arg;
2002         void (*func) (int argc, char *argv[]);
2003         const char *desc;
2004 } cmd_table[] = {
2005         { "connect",      "<dev> [uuid]", cmd_connect, "Connect session" },
2006         { "disconnect",   "[session]", cmd_disconnect, "Disconnect session" },
2007         { "list",         NULL,       cmd_list, "List available sessions" },
2008         { "show",         "[session]", cmd_show, "Session information" },
2009         { "select",       "<session>", cmd_select, "Select default session" },
2010         { "info",         "<object>", cmd_info, "Object information" },
2011         { "cancel",       "<transfer>", cmd_cancel, "Cancel transfer" },
2012         { "suspend",      "<transfer>", cmd_suspend, "Suspend transfer" },
2013         { "resume",       "<transfer>", cmd_resume, "Resume transfer" },
2014         { "send",         "<file>",   cmd_send, "Send file" },
2015         { "pull",         "<file>",   cmd_pull,
2016                                         "Pull Vobject & stores in file" },
2017         { "cd",           "<path>",   cmd_cd, "Change current folder" },
2018         { "ls",           "<options>", cmd_ls, "List current folder" },
2019         { "cp",          "<source file> <destination file>",   cmd_cp,
2020                                 "Copy source file to destination file" },
2021         { "mv",          "<source file> <destination file>",   cmd_mv,
2022                                 "Move source file to destination file" },
2023         { "rm",          "<file>",    cmd_rm, "Delete file" },
2024         { "mkdir",       "<folder>",    cmd_mkdir, "Create folder" },
2025         { "quit",         NULL,       cmd_quit, "Quit program" },
2026         { "exit",         NULL,       cmd_quit },
2027         { "help" },
2028         {}
2029 };
2030
2031 static char *cmd_generator(const char *text, int state)
2032 {
2033         static int index, len;
2034         const char *cmd;
2035
2036         if (!state) {
2037                 index = 0;
2038                 len = strlen(text);
2039         }
2040
2041         while ((cmd = cmd_table[index].cmd)) {
2042                 index++;
2043
2044                 if (!strncmp(cmd, text, len))
2045                         return strdup(cmd);
2046         }
2047
2048         return NULL;
2049 }
2050
2051 static char **cmd_completion(const char *text, int start, int end)
2052 {
2053         char **matches = NULL;
2054
2055         if (start == 0) {
2056                 rl_completion_display_matches_hook = NULL;
2057                 matches = rl_completion_matches(text, cmd_generator);
2058         }
2059
2060         if (!matches)
2061                 rl_attempted_completion_over = 1;
2062
2063         return matches;
2064 }
2065
2066 static void rl_handler(char *input)
2067 {
2068         wordexp_t w;
2069         int argc;
2070         char **argv;
2071         int i;
2072
2073         if (!input) {
2074                 rl_insert_text("quit");
2075                 rl_redisplay();
2076                 rl_crlf();
2077                 g_main_loop_quit(main_loop);
2078                 return;
2079         }
2080
2081         if (!strlen(input))
2082                 goto done;
2083
2084         add_history(input);
2085
2086         if (wordexp(input, &w, WRDE_NOCMD))
2087                 goto done;
2088
2089         if (w.we_wordc == 0)
2090                 goto free_we;
2091
2092         argv = w.we_wordv;
2093         argc = w.we_wordc;
2094
2095         for (i = 0; cmd_table[i].cmd; i++) {
2096                 if (strcmp(argv[0], cmd_table[i].cmd))
2097                         continue;
2098
2099                 if (cmd_table[i].func) {
2100                         cmd_table[i].func(argc, argv);
2101                         goto free_we;
2102                 }
2103         }
2104
2105         if (strcmp(argv[0], "help")) {
2106                 printf("Invalid command\n");
2107                 goto free_we;
2108         }
2109
2110         printf("Available commands:\n");
2111
2112         for (i = 0; cmd_table[i].cmd; i++) {
2113                 if (cmd_table[i].desc)
2114                         printf("  %s %-*s %s\n", cmd_table[i].cmd,
2115                                         (int)(25 - strlen(cmd_table[i].cmd)),
2116                                         cmd_table[i].arg ? : "",
2117                                         cmd_table[i].desc ? : "");
2118         }
2119
2120 free_we:
2121         wordfree(&w);
2122 done:
2123         free(input);
2124 }
2125
2126 static gboolean option_version = FALSE;
2127
2128 static GOptionEntry options[] = {
2129         { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
2130                                 "Show version information and exit" },
2131         { NULL },
2132 };
2133
2134 static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
2135                                                         gpointer user_data)
2136 {
2137         static unsigned int __terminated = 0;
2138         struct signalfd_siginfo si;
2139         ssize_t result;
2140         int fd;
2141
2142         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
2143                 g_main_loop_quit(main_loop);
2144                 return FALSE;
2145         }
2146
2147         fd = g_io_channel_unix_get_fd(channel);
2148
2149         result = read(fd, &si, sizeof(si));
2150         if (result != sizeof(si))
2151                 return FALSE;
2152
2153         switch (si.ssi_signo) {
2154         case SIGINT:
2155                 rl_replace_line("", 0);
2156                 rl_crlf();
2157                 rl_on_new_line();
2158                 rl_redisplay();
2159                 break;
2160         case SIGTERM:
2161                 if (__terminated == 0) {
2162                         rl_replace_line("", 0);
2163                         rl_crlf();
2164                         g_main_loop_quit(main_loop);
2165                 }
2166
2167                 __terminated = 1;
2168                 break;
2169         }
2170
2171         return TRUE;
2172 }
2173
2174 static guint setup_signalfd(void)
2175 {
2176         GIOChannel *channel;
2177         guint source;
2178         sigset_t mask;
2179         int fd;
2180
2181         sigemptyset(&mask);
2182         sigaddset(&mask, SIGINT);
2183         sigaddset(&mask, SIGTERM);
2184
2185         if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
2186                 perror("Failed to set signal mask");
2187                 return 0;
2188         }
2189
2190         fd = signalfd(-1, &mask, 0);
2191         if (fd < 0) {
2192                 perror("Failed to create signal descriptor");
2193                 return 0;
2194         }
2195
2196         channel = g_io_channel_unix_new(fd);
2197
2198         g_io_channel_set_close_on_unref(channel, TRUE);
2199         g_io_channel_set_encoding(channel, NULL, NULL);
2200         g_io_channel_set_buffered(channel, FALSE);
2201
2202         source = g_io_add_watch(channel,
2203                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2204                                 signal_handler, NULL);
2205
2206         g_io_channel_unref(channel);
2207
2208         return source;
2209 }
2210
2211 static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
2212                                                         gpointer user_data)
2213 {
2214         if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
2215                 g_main_loop_quit(main_loop);
2216                 return FALSE;
2217         }
2218
2219         rl_callback_read_char();
2220         return TRUE;
2221 }
2222
2223 static guint setup_standard_input(void)
2224 {
2225         GIOChannel *channel;
2226         guint source;
2227
2228         channel = g_io_channel_unix_new(fileno(stdin));
2229
2230         source = g_io_add_watch(channel,
2231                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2232                                 input_handler, NULL);
2233
2234         g_io_channel_unref(channel);
2235
2236         return source;
2237 }
2238
2239 static void client_added(GDBusProxy *proxy)
2240 {
2241         if (client == NULL)
2242                 client = proxy;
2243
2244         print_proxy(proxy, "Client", COLORED_NEW);
2245 }
2246
2247 static void session_added(GDBusProxy *proxy)
2248 {
2249         sessions = g_slist_append(sessions, proxy);
2250
2251         if (default_session == NULL)
2252                 set_default_session(proxy);
2253
2254         print_proxy(proxy, "Session", COLORED_NEW);
2255 }
2256
2257 static void print_transferred(struct transfer_data *data, const char *str,
2258                                                         DBusMessageIter *iter)
2259 {
2260         dbus_uint64_t valu64;
2261         uint64_t speed;
2262         int seconds, minutes;
2263
2264         dbus_message_iter_get_basic(iter, &valu64);
2265         speed = valu64 - data->transferred;
2266         data->transferred = valu64;
2267
2268         if (data->size == 0) {
2269                 rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s)\n",
2270                                                 str, valu64, speed / 1000);
2271                 return;
2272         }
2273
2274         seconds = (data->size - data->transferred) / speed;
2275         minutes = seconds / 60;
2276         seconds %= 60;
2277         rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s %02u:%02u)\n",
2278                                 str, valu64, speed / 1000, minutes, seconds);
2279 }
2280
2281 static void transfer_property_changed(GDBusProxy *proxy, const char *name,
2282                                         DBusMessageIter *iter, void *user_data)
2283 {
2284         struct transfer_data *data = user_data;
2285         char *str;
2286
2287         str = proxy_description(proxy, "Transfer", COLORED_CHG);
2288
2289         if (strcmp(name, "Transferred") == 0) {
2290                 print_transferred(data, str, iter);
2291                 goto done;
2292         }
2293
2294         if (strcmp(name, "Size") == 0)
2295                 dbus_message_iter_get_basic(iter, &data->size);
2296
2297         print_iter(str, name, iter);
2298
2299 done:
2300         g_free(str);
2301 }
2302
2303 static void transfer_destroy(GDBusProxy *proxy, void *user_data)
2304 {
2305         struct transfer_data *data = user_data;
2306
2307         g_free(data);
2308 }
2309
2310 static void transfer_added(GDBusProxy *proxy)
2311 {
2312         struct transfer_data *data;
2313         DBusMessageIter iter;
2314
2315         transfers = g_slist_append(transfers, proxy);
2316
2317         print_proxy(proxy, "Transfer", COLORED_NEW);
2318
2319         data = g_new0(struct transfer_data, 1);
2320
2321         if (g_dbus_proxy_get_property(proxy, "Transfered", &iter))
2322                 dbus_message_iter_get_basic(&iter, &data->transferred);
2323
2324         if (g_dbus_proxy_get_property(proxy, "Size", &iter))
2325                 dbus_message_iter_get_basic(&iter, &data->size);
2326
2327         g_dbus_proxy_set_property_watch(proxy, transfer_property_changed, data);
2328         g_dbus_proxy_set_removed_watch(proxy, transfer_destroy, data);
2329 }
2330
2331 static void opp_added(GDBusProxy *proxy)
2332 {
2333         opps = g_slist_append(opps, proxy);
2334
2335         print_proxy(proxy, "ObjectPush", COLORED_NEW);
2336 }
2337
2338 static void ftp_added(GDBusProxy *proxy)
2339 {
2340         ftps = g_slist_append(ftps, proxy);
2341
2342         print_proxy(proxy, "FileTransfer", COLORED_NEW);
2343 }
2344
2345 static void pbap_added(GDBusProxy *proxy)
2346 {
2347         pbaps = g_slist_append(pbaps, proxy);
2348
2349         print_proxy(proxy, "PhonebookAccess", COLORED_NEW);
2350 }
2351
2352 static void map_added(GDBusProxy *proxy)
2353 {
2354         maps = g_slist_append(maps, proxy);
2355
2356         print_proxy(proxy, "MessageAccess", COLORED_NEW);
2357 }
2358
2359 static void msg_added(GDBusProxy *proxy)
2360 {
2361         msgs = g_slist_append(msgs, proxy);
2362
2363         print_proxy(proxy, "Message", COLORED_NEW);
2364 }
2365
2366 static void proxy_added(GDBusProxy *proxy, void *user_data)
2367 {
2368         const char *interface;
2369
2370         interface = g_dbus_proxy_get_interface(proxy);
2371
2372         if (!strcmp(interface, OBEX_CLIENT_INTERFACE))
2373                 client_added(proxy);
2374         else if (!strcmp(interface, OBEX_SESSION_INTERFACE))
2375                 session_added(proxy);
2376         else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE))
2377                 transfer_added(proxy);
2378         else if (!strcmp(interface, OBEX_OPP_INTERFACE))
2379                 opp_added(proxy);
2380         else if (!strcmp(interface, OBEX_FTP_INTERFACE))
2381                 ftp_added(proxy);
2382         else if (!strcmp(interface, OBEX_PBAP_INTERFACE))
2383                 pbap_added(proxy);
2384         else if (!strcmp(interface, OBEX_MAP_INTERFACE))
2385                 map_added(proxy);
2386         else if (!strcmp(interface, OBEX_MSG_INTERFACE))
2387                 msg_added(proxy);
2388 }
2389
2390 static void client_removed(GDBusProxy *proxy)
2391 {
2392         print_proxy(proxy, "Client", COLORED_DEL);
2393
2394         if (client == proxy)
2395                 client = NULL;
2396 }
2397
2398 static void session_removed(GDBusProxy *proxy)
2399 {
2400         print_proxy(proxy, "Session", COLORED_DEL);
2401
2402         if (default_session == proxy)
2403                 set_default_session(NULL);
2404
2405         sessions = g_slist_remove(sessions, proxy);
2406 }
2407
2408 static void transfer_removed(GDBusProxy *proxy)
2409 {
2410         print_proxy(proxy, "Transfer", COLORED_DEL);
2411
2412         transfers = g_slist_remove(transfers, proxy);
2413 }
2414
2415 static void opp_removed(GDBusProxy *proxy)
2416 {
2417         print_proxy(proxy, "ObjectPush", COLORED_DEL);
2418
2419         opps = g_slist_remove(opps, proxy);
2420 }
2421
2422 static void ftp_removed(GDBusProxy *proxy)
2423 {
2424         print_proxy(proxy, "FileTransfer", COLORED_DEL);
2425
2426         ftps = g_slist_remove(ftps, proxy);
2427 }
2428
2429 static void pbap_removed(GDBusProxy *proxy)
2430 {
2431         print_proxy(proxy, "PhonebookAccess", COLORED_DEL);
2432
2433         pbaps = g_slist_remove(pbaps, proxy);
2434 }
2435
2436 static void map_removed(GDBusProxy *proxy)
2437 {
2438         print_proxy(proxy, "MessageAccess", COLORED_DEL);
2439
2440         maps = g_slist_remove(maps, proxy);
2441 }
2442
2443 static void msg_removed(GDBusProxy *proxy)
2444 {
2445         print_proxy(proxy, "Message", COLORED_DEL);
2446
2447         msgs = g_slist_remove(msgs, proxy);
2448 }
2449
2450 static void proxy_removed(GDBusProxy *proxy, void *user_data)
2451 {
2452         const char *interface;
2453
2454         interface = g_dbus_proxy_get_interface(proxy);
2455
2456         if (!strcmp(interface, OBEX_CLIENT_INTERFACE))
2457                 client_removed(proxy);
2458         else if (!strcmp(interface, OBEX_SESSION_INTERFACE))
2459                 session_removed(proxy);
2460         else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE))
2461                 transfer_removed(proxy);
2462         else if (!strcmp(interface, OBEX_OPP_INTERFACE))
2463                 opp_removed(proxy);
2464         else if (!strcmp(interface, OBEX_FTP_INTERFACE))
2465                 ftp_removed(proxy);
2466         else if (!strcmp(interface, OBEX_PBAP_INTERFACE))
2467                 pbap_removed(proxy);
2468         else if (!strcmp(interface, OBEX_MAP_INTERFACE))
2469                 map_removed(proxy);
2470         else if (!strcmp(interface, OBEX_MSG_INTERFACE))
2471                 msg_removed(proxy);
2472 }
2473
2474 static void session_property_changed(GDBusProxy *proxy, const char *name,
2475                                                 DBusMessageIter *iter)
2476 {
2477         char *str;
2478
2479         str = proxy_description(proxy, "Session", COLORED_CHG);
2480         print_iter(str, name, iter);
2481         g_free(str);
2482 }
2483
2484 static void property_changed(GDBusProxy *proxy, const char *name,
2485                                         DBusMessageIter *iter, void *user_data)
2486 {
2487         const char *interface;
2488
2489         interface = g_dbus_proxy_get_interface(proxy);
2490
2491         if (!strcmp(interface, OBEX_SESSION_INTERFACE))
2492                 session_property_changed(proxy, name, iter);
2493 }
2494
2495 int main(int argc, char *argv[])
2496 {
2497         GOptionContext *context;
2498         GError *error = NULL;
2499         GDBusClient *client;
2500         guint signal, input;
2501
2502         context = g_option_context_new(NULL);
2503         g_option_context_add_main_entries(context, options, NULL);
2504
2505         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
2506                 if (error != NULL) {
2507                         g_printerr("%s\n", error->message);
2508                         g_error_free(error);
2509                 } else
2510                         g_printerr("An unknown error occurred\n");
2511                 exit(1);
2512         }
2513
2514         g_option_context_free(context);
2515
2516         if (option_version == TRUE) {
2517                 printf("%s\n", VERSION);
2518                 exit(0);
2519         }
2520
2521         main_loop = g_main_loop_new(NULL, FALSE);
2522         dbus_conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
2523
2524         rl_attempted_completion_function = cmd_completion;
2525
2526         rl_erase_empty_line = 1;
2527         rl_callback_handler_install(NULL, rl_handler);
2528
2529         rl_set_prompt(PROMPT_OFF);
2530         rl_redisplay();
2531
2532         input = setup_standard_input();
2533         signal = setup_signalfd();
2534         client = g_dbus_client_new(dbus_conn, "org.bluez.obex",
2535                                                         "/org/bluez/obex");
2536
2537         g_dbus_client_set_connect_watch(client, connect_handler, NULL);
2538         g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
2539
2540         g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
2541                                                         property_changed, NULL);
2542
2543         g_main_loop_run(main_loop);
2544
2545         g_dbus_client_unref(client);
2546         g_source_remove(signal);
2547         g_source_remove(input);
2548
2549         rl_message("");
2550         rl_callback_handler_remove();
2551
2552         dbus_connection_unref(dbus_conn);
2553         g_main_loop_unref(main_loop);
2554
2555         return 0;
2556 }