3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
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.
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.
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
34 #include <sys/signalfd.h>
37 #include <readline/readline.h>
38 #include <readline/history.h>
42 #include <client/display.h>
44 /* String display constants */
45 #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
46 #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
47 #define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
49 #define PROMPT_ON COLOR_BLUE "[obex]" COLOR_OFF "# "
50 #define PROMPT_OFF "[obex]# "
52 #define OBEX_SESSION_INTERFACE "org.bluez.obex.Session1"
53 #define OBEX_TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
54 #define OBEX_CLIENT_INTERFACE "org.bluez.obex.Client1"
55 #define OBEX_OPP_INTERFACE "org.bluez.obex.ObjectPush1"
56 #define OBEX_FTP_INTERFACE "org.bluez.obex.FileTransfer1"
57 #define OBEX_PBAP_INTERFACE "org.bluez.obex.PhonebookAccess1"
58 #define OBEX_MAP_INTERFACE "org.bluez.obex.MessageAccess1"
59 #define OBEX_MSG_INTERFACE "org.bluez.obex.Message1"
61 static GMainLoop *main_loop;
62 static DBusConnection *dbus_conn;
63 static GDBusProxy *default_session;
64 static GSList *sessions = NULL;
65 static GSList *opps = NULL;
66 static GSList *ftps = NULL;
67 static GSList *pbaps = NULL;
68 static GSList *maps = NULL;
69 static GSList *msgs = NULL;
70 static GSList *transfers = NULL;
71 static GDBusProxy *client = NULL;
73 struct transfer_data {
78 static void connect_handler(DBusConnection *connection, void *user_data)
80 rl_set_prompt(PROMPT_ON);
86 static void disconnect_handler(DBusConnection *connection, void *user_data)
88 rl_set_prompt(PROMPT_OFF);
94 static void cmd_quit(int argc, char *argv[])
96 g_main_loop_quit(main_loop);
99 static void connect_reply(DBusMessage *message, void *user_data)
103 dbus_error_init(&error);
105 if (dbus_set_error_from_message(&error, message) == TRUE) {
106 rl_printf("Failed to connect: %s\n", error.name);
107 dbus_error_free(&error);
111 rl_printf("Connection successful\n");
114 static void append_variant(DBusMessageIter *iter, int type, void *val)
116 DBusMessageIter value;
117 char sig[2] = { type, '\0' };
119 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
121 dbus_message_iter_append_basic(&value, type, val);
123 dbus_message_iter_close_container(iter, &value);
126 static void dict_append_entry(DBusMessageIter *dict, const char *key,
129 DBusMessageIter entry;
131 if (type == DBUS_TYPE_STRING) {
132 const char *str = *((const char **) val);
137 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
140 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
142 append_variant(&entry, type, val);
144 dbus_message_iter_close_container(dict, &entry);
147 struct connect_args {
152 static void connect_args_free(void *data)
154 struct connect_args *args = data;
157 g_free(args->target);
161 static void connect_setup(DBusMessageIter *iter, void *user_data)
163 struct connect_args *args = user_data;
164 DBusMessageIter dict;
166 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->dev);
168 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
169 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
170 DBUS_TYPE_STRING_AS_STRING
171 DBUS_TYPE_VARIANT_AS_STRING
172 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
175 if (args->target == NULL)
178 dict_append_entry(&dict, "Target", DBUS_TYPE_STRING, &args->target);
181 dbus_message_iter_close_container(iter, &dict);
184 static void cmd_connect(int argc, char *argv[])
186 struct connect_args *args;
187 const char *target = "opp";
190 rl_printf("Missing device address argument\n");
195 rl_printf("Client proxy not available\n");
202 args = g_new0(struct connect_args, 1);
203 args->dev = g_strdup(argv[1]);
204 args->target = g_strdup(target);
206 if (g_dbus_proxy_method_call(client, "CreateSession", connect_setup,
207 connect_reply, args, connect_args_free) == FALSE) {
208 rl_printf("Failed to connect\n");
212 rl_printf("Attempting to connect to %s\n", argv[1]);
215 static void disconnect_reply(DBusMessage *message, void *user_data)
219 dbus_error_init(&error);
221 if (dbus_set_error_from_message(&error, message) == TRUE) {
222 rl_printf("Failed to disconnect: %s\n", error.name);
223 dbus_error_free(&error);
227 rl_printf("Disconnection successful\n");
230 static void disconnect_setup(DBusMessageIter *iter, void *user_data)
232 GDBusProxy *proxy = user_data;
235 path = g_dbus_proxy_get_path(proxy);
237 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
240 static GDBusProxy *find_session(const char *path)
244 for (l = sessions; l; l = g_slist_next(l)) {
245 GDBusProxy *proxy = l->data;
247 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
254 static void cmd_disconnect(int argc, char *argv[])
259 proxy = find_session(argv[1]);
261 proxy = default_session;
264 rl_printf("Session not available\n");
268 if (g_dbus_proxy_method_call(client, "RemoveSession", disconnect_setup,
269 disconnect_reply, proxy, NULL) == FALSE) {
270 rl_printf("Failed to disconnect\n");
274 rl_printf("Attempting to disconnect to %s\n",
275 g_dbus_proxy_get_path(proxy));
278 static char *proxy_description(GDBusProxy *proxy, const char *title,
279 const char *description)
283 path = g_dbus_proxy_get_path(proxy);
285 return g_strdup_printf("%s%s%s%s %s ",
286 description ? "[" : "",
288 description ? "] " : "",
292 static void print_proxy(GDBusProxy *proxy, const char *title,
293 const char *description)
297 str = proxy_description(proxy, title, description);
299 rl_printf("%s%s\n", str, default_session == proxy ? "[default]" : "");
304 static void cmd_list(int argc, char *arg[])
308 for (l = sessions; l; l = g_slist_next(l)) {
309 GDBusProxy *proxy = l->data;
310 print_proxy(proxy, "Session", NULL);
314 static bool check_default_session(void)
316 if (!default_session) {
317 rl_printf("No default session available\n");
324 static void print_iter(const char *label, const char *name,
325 DBusMessageIter *iter)
328 dbus_uint64_t valu64;
329 dbus_uint32_t valu32;
330 dbus_uint16_t valu16;
333 DBusMessageIter subiter;
336 rl_printf("%s%s is nil\n", label, name);
340 switch (dbus_message_iter_get_arg_type(iter)) {
341 case DBUS_TYPE_INVALID:
342 rl_printf("%s%s is invalid\n", label, name);
344 case DBUS_TYPE_STRING:
345 case DBUS_TYPE_OBJECT_PATH:
346 dbus_message_iter_get_basic(iter, &valstr);
347 rl_printf("%s%s: %s\n", label, name, valstr);
349 case DBUS_TYPE_BOOLEAN:
350 dbus_message_iter_get_basic(iter, &valbool);
351 rl_printf("%s%s: %s\n", label, name,
352 valbool == TRUE ? "yes" : "no");
354 case DBUS_TYPE_UINT64:
355 dbus_message_iter_get_basic(iter, &valu64);
356 rl_printf("%s%s: %" PRIu64 "\n", label, name, valu64);
358 case DBUS_TYPE_UINT32:
359 dbus_message_iter_get_basic(iter, &valu32);
360 rl_printf("%s%s: 0x%08x\n", label, name, valu32);
362 case DBUS_TYPE_UINT16:
363 dbus_message_iter_get_basic(iter, &valu16);
364 rl_printf("%s%s: 0x%04x\n", label, name, valu16);
366 case DBUS_TYPE_INT16:
367 dbus_message_iter_get_basic(iter, &vals16);
368 rl_printf("%s%s: %d\n", label, name, vals16);
370 case DBUS_TYPE_VARIANT:
371 dbus_message_iter_recurse(iter, &subiter);
372 print_iter(label, name, &subiter);
374 case DBUS_TYPE_ARRAY:
375 dbus_message_iter_recurse(iter, &subiter);
376 while (dbus_message_iter_get_arg_type(&subiter) !=
378 print_iter(label, name, &subiter);
379 dbus_message_iter_next(&subiter);
382 case DBUS_TYPE_DICT_ENTRY:
383 dbus_message_iter_recurse(iter, &subiter);
384 dbus_message_iter_get_basic(&subiter, &valstr);
385 dbus_message_iter_next(&subiter);
386 print_iter(label, valstr, &subiter);
389 rl_printf("%s%s has unsupported type\n", label, name);
394 static void print_property(GDBusProxy *proxy, const char *name)
396 DBusMessageIter iter;
398 if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
401 print_iter("\t", name, &iter);
404 static void cmd_show(int argc, char *argv[])
409 if (check_default_session() == FALSE)
412 proxy = default_session;
414 proxy = find_session(argv[1]);
416 rl_printf("Session %s not available\n", argv[1]);
421 rl_printf("Session %s\n", g_dbus_proxy_get_path(proxy));
423 print_property(proxy, "Destination");
424 print_property(proxy, "Target");
427 static void set_default_session(GDBusProxy *proxy)
430 DBusMessageIter iter;
432 default_session = proxy;
434 if (!g_dbus_proxy_get_property(proxy, "Destination", &iter)) {
435 desc = g_strdup(PROMPT_ON);
439 dbus_message_iter_get_basic(&iter, &desc);
440 desc = g_strdup_printf(COLOR_BLUE "[%s]" COLOR_OFF "# ", desc);
448 static void cmd_select(int argc, char *argv[])
453 rl_printf("Missing session address argument\n");
457 proxy = find_session(argv[1]);
459 rl_printf("Session %s not available\n", argv[1]);
463 if (default_session == proxy)
466 set_default_session(proxy);
468 print_proxy(proxy, "Session", NULL);
471 static GDBusProxy *find_transfer(const char *path)
475 for (l = transfers; l; l = g_slist_next(l)) {
476 GDBusProxy *proxy = l->data;
478 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
485 static GDBusProxy *find_message(const char *path)
489 for (l = msgs; l; l = g_slist_next(l)) {
490 GDBusProxy *proxy = l->data;
492 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
499 static void transfer_info(GDBusProxy *proxy, int argc, char *argv[])
501 rl_printf("Transfer %s\n", g_dbus_proxy_get_path(proxy));
503 print_property(proxy, "Session");
504 print_property(proxy, "Name");
505 print_property(proxy, "Type");
506 print_property(proxy, "Status");
507 print_property(proxy, "Time");
508 print_property(proxy, "Size");
509 print_property(proxy, "Transferred");
510 print_property(proxy, "Filename");
513 static void message_info(GDBusProxy *proxy, int argc, char *argv[])
515 rl_printf("Message %s\n", g_dbus_proxy_get_path(proxy));
517 print_property(proxy, "Folder");
518 print_property(proxy, "Subject");
519 print_property(proxy, "Timestamp");
520 print_property(proxy, "Sender");
521 print_property(proxy, "SenderAddress");
522 print_property(proxy, "ReplyTo");
523 print_property(proxy, "Recipient");
524 print_property(proxy, "RecipientAddress");
525 print_property(proxy, "Type");
526 print_property(proxy, "Size");
527 print_property(proxy, "Status");
528 print_property(proxy, "Priority");
529 print_property(proxy, "Read");
530 print_property(proxy, "Deleted");
531 print_property(proxy, "Sent");
532 print_property(proxy, "Protected");
535 static void cmd_info(int argc, char *argv[])
540 rl_printf("Missing object path argument\n");
544 proxy = find_transfer(argv[1]);
546 transfer_info(proxy, argc, argv);
550 proxy = find_message(argv[1]);
552 message_info(proxy, argc, argv);
556 rl_printf("Object %s not available\n", argv[1]);
559 static void cancel_reply(DBusMessage *message, void *user_data)
563 dbus_error_init(&error);
565 if (dbus_set_error_from_message(&error, message) == TRUE) {
566 rl_printf("Failed to cancel: %s\n", error.name);
567 dbus_error_free(&error);
571 rl_printf("Cancel successful\n");
574 static void cmd_cancel(int argc, char *argv[])
579 rl_printf("Missing transfer address argument\n");
583 proxy = find_transfer(argv[1]);
585 rl_printf("Transfer %s not available\n", argv[1]);
589 if (g_dbus_proxy_method_call(proxy, "Cancel", NULL, cancel_reply, NULL,
591 rl_printf("Failed to cancel transfer\n");
595 rl_printf("Attempting to cancel transfer %s\n",
596 g_dbus_proxy_get_path(proxy));
599 static void suspend_reply(DBusMessage *message, void *user_data)
603 dbus_error_init(&error);
605 if (dbus_set_error_from_message(&error, message) == TRUE) {
606 rl_printf("Failed to suspend: %s\n", error.name);
607 dbus_error_free(&error);
611 rl_printf("Suspend successful\n");
614 static void cmd_suspend(int argc, char *argv[])
619 rl_printf("Missing transfer address argument\n");
623 proxy = find_transfer(argv[1]);
625 rl_printf("Transfer %s not available\n", argv[1]);
629 if (g_dbus_proxy_method_call(proxy, "Suspend", NULL, suspend_reply,
630 NULL, NULL) == FALSE) {
631 rl_printf("Failed to suspend transfer\n");
635 rl_printf("Attempting to suspend transfer %s\n",
636 g_dbus_proxy_get_path(proxy));
639 static void resume_reply(DBusMessage *message, void *user_data)
643 dbus_error_init(&error);
645 if (dbus_set_error_from_message(&error, message) == TRUE) {
646 rl_printf("Failed to resume: %s\n", error.name);
647 dbus_error_free(&error);
651 rl_printf("Resume successful\n");
654 static void cmd_resume(int argc, char *argv[])
659 rl_printf("Missing transfer address argument\n");
663 proxy = find_transfer(argv[1]);
665 rl_printf("Transfer %s not available\n", argv[1]);
669 if (g_dbus_proxy_method_call(proxy, "Resume", NULL, resume_reply,
670 NULL, NULL) == FALSE) {
671 rl_printf("Failed to resume transfer\n");
675 rl_printf("Attempting to resume transfer %s\n",
676 g_dbus_proxy_get_path(proxy));
679 static GDBusProxy *find_opp(const char *path)
683 for (l = opps; l; l = g_slist_next(l)) {
684 GDBusProxy *proxy = l->data;
686 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
693 static GDBusProxy *find_map(const char *path)
697 for (l = maps; l; l = g_slist_next(l)) {
698 GDBusProxy *proxy = l->data;
700 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
707 static void print_dict_iter(DBusMessageIter *iter)
709 DBusMessageIter dict;
712 ctype = dbus_message_iter_get_arg_type(iter);
713 if (ctype != DBUS_TYPE_ARRAY)
716 dbus_message_iter_recurse(iter, &dict);
718 while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
720 DBusMessageIter entry;
723 if (ctype != DBUS_TYPE_DICT_ENTRY)
726 dbus_message_iter_recurse(&dict, &entry);
727 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
730 dbus_message_iter_get_basic(&entry, &key);
731 dbus_message_iter_next(&entry);
733 print_iter("\t", key, &entry);
735 dbus_message_iter_next(&dict);
739 static void print_transfer_iter(DBusMessageIter *iter)
743 dbus_message_iter_get_basic(iter, &path);
745 rl_printf("Transfer %s\n", path);
747 dbus_message_iter_next(iter);
749 print_dict_iter(iter);
752 static void send_reply(DBusMessage *message, void *user_data)
754 DBusMessageIter iter;
757 dbus_error_init(&error);
759 if (dbus_set_error_from_message(&error, message) == TRUE) {
760 rl_printf("Failed to send: %s\n", error.name);
761 dbus_error_free(&error);
765 dbus_message_iter_init(message, &iter);
767 print_transfer_iter(&iter);
770 static void send_setup(DBusMessageIter *iter, void *user_data)
772 const char *file = user_data;
774 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
777 static void opp_send(GDBusProxy *proxy, int argc, char *argv[])
780 rl_printf("Missing file argument\n");
784 if (g_dbus_proxy_method_call(proxy, "SendFile", send_setup, send_reply,
785 g_strdup(argv[1]), g_free) == FALSE) {
786 rl_printf("Failed to send\n");
790 rl_printf("Attempting to send %s to %s\n", argv[1],
791 g_dbus_proxy_get_path(proxy));
794 static void push_reply(DBusMessage *message, void *user_data)
796 DBusMessageIter iter;
799 dbus_error_init(&error);
801 if (dbus_set_error_from_message(&error, message) == TRUE) {
802 rl_printf("Failed to PushMessage: %s\n", error.name);
803 dbus_error_free(&error);
807 dbus_message_iter_init(message, &iter);
809 print_transfer_iter(&iter);
812 static void push_setup(DBusMessageIter *iter, void *user_data)
814 const char *file = user_data;
815 const char *folder = "";
816 DBusMessageIter dict;
818 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
819 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
821 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
822 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
823 DBUS_TYPE_STRING_AS_STRING
824 DBUS_TYPE_VARIANT_AS_STRING
825 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
828 dbus_message_iter_close_container(iter, &dict);
831 static void map_send(GDBusProxy *proxy, int argc, char *argv[])
834 rl_printf("Missing file argument\n");
838 if (g_dbus_proxy_method_call(proxy, "PushMessage", push_setup,
839 push_reply, g_strdup(argv[1]),
841 rl_printf("Failed to send\n");
845 rl_printf("Attempting to send %s to %s\n", argv[1],
846 g_dbus_proxy_get_path(proxy));
849 static void cmd_send(int argc, char *argv[])
853 if (!check_default_session())
856 proxy = find_opp(g_dbus_proxy_get_path(default_session));
858 opp_send(proxy, argc, argv);
862 proxy = find_map(g_dbus_proxy_get_path(default_session));
864 map_send(proxy, argc, argv);
868 rl_printf("Command not supported\n");
871 static void change_folder_reply(DBusMessage *message, void *user_data)
875 dbus_error_init(&error);
877 if (dbus_set_error_from_message(&error, message) == TRUE) {
878 rl_printf("Failed to ChangeFolder: %s\n", error.name);
879 dbus_error_free(&error);
883 rl_printf("ChangeFolder successful\n");
886 static void change_folder_setup(DBusMessageIter *iter, void *user_data)
888 const char *folder = user_data;
890 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
893 static void select_reply(DBusMessage *message, void *user_data)
895 DBusMessageIter iter;
898 dbus_error_init(&error);
900 if (dbus_set_error_from_message(&error, message) == TRUE) {
901 rl_printf("Failed to Select: %s\n", error.name);
902 dbus_error_free(&error);
906 dbus_message_iter_init(message, &iter);
908 rl_printf("Select successful\n");
911 static void select_setup(DBusMessageIter *iter, void *user_data)
913 const char *folder = user_data;
914 const char *location = "int";
916 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &location);
917 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
920 static void setfolder_reply(DBusMessage *message, void *user_data)
924 dbus_error_init(&error);
926 if (dbus_set_error_from_message(&error, message) == TRUE) {
927 rl_printf("Failed to SetFolder: %s\n", error.name);
928 dbus_error_free(&error);
932 rl_printf("SetFolder successful\n");
935 static void setfolder_setup(DBusMessageIter *iter, void *user_data)
937 const char *folder = user_data;
939 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
942 static GDBusProxy *find_ftp(const char *path)
946 for (l = ftps; l; l = g_slist_next(l)) {
947 GDBusProxy *proxy = l->data;
949 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
956 static GDBusProxy *find_pbap(const char *path)
960 for (l = pbaps; l; l = g_slist_next(l)) {
961 GDBusProxy *proxy = l->data;
963 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
970 static void ftp_cd(GDBusProxy *proxy, int argc, char *argv[])
973 rl_printf("Missing path argument\n");
977 if (g_dbus_proxy_method_call(proxy, "ChangeFolder", change_folder_setup,
978 change_folder_reply, g_strdup(argv[1]),
980 rl_printf("Failed to ChangeFolder\n");
984 rl_printf("Attempting to ChangeFolder to %s\n", argv[1]);
987 static void pbap_cd(GDBusProxy *proxy, int argc, char *argv[])
990 rl_printf("Missing path argument\n");
994 if (g_dbus_proxy_method_call(proxy, "Select", select_setup,
995 select_reply, g_strdup(argv[1]),
997 rl_printf("Failed to Select\n");
1001 rl_printf("Attempting to Select to %s\n", argv[1]);
1004 static void map_cd(GDBusProxy *proxy, int argc, char *argv[])
1007 rl_printf("Missing path argument\n");
1011 if (g_dbus_proxy_method_call(proxy, "SetFolder", setfolder_setup,
1012 setfolder_reply, g_strdup(argv[1]),
1014 rl_printf("Failed to SetFolder\n");
1018 rl_printf("Attempting to SetFolder to %s\n", argv[1]);
1021 static void cmd_cd(int argc, char *argv[])
1025 if (!check_default_session())
1028 proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1030 ftp_cd(proxy, argc, argv);
1034 proxy = find_pbap(g_dbus_proxy_get_path(default_session));
1036 pbap_cd(proxy, argc, argv);
1040 proxy = find_map(g_dbus_proxy_get_path(default_session));
1042 map_cd(proxy, argc, argv);
1046 rl_printf("Command not supported\n");
1049 static void list_folder_reply(DBusMessage *message, void *user_data)
1051 DBusMessageIter iter, array;
1054 dbus_error_init(&error);
1056 if (dbus_set_error_from_message(&error, message) == TRUE) {
1057 rl_printf("Failed to ListFolder: %s\n", error.name);
1058 dbus_error_free(&error);
1062 dbus_message_iter_init(message, &iter);
1064 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1067 dbus_message_iter_recurse(&iter, &array);
1069 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1070 print_dict_iter(&array);
1071 dbus_message_iter_next(&array);
1075 static void ftp_ls(GDBusProxy *proxy, int argc, char *argv[])
1077 if (g_dbus_proxy_method_call(proxy, "ListFolder", NULL,
1078 list_folder_reply, NULL,
1080 rl_printf("Failed to ls\n");
1084 rl_printf("Attempting to ListFolder\n");
1087 static void parse_list_reply(DBusMessage *message)
1089 DBusMessageIter iter, array;
1091 dbus_message_iter_init(message, &iter);
1093 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1096 dbus_message_iter_recurse(&iter, &array);
1098 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1099 DBusMessageIter entry;
1102 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT)
1105 dbus_message_iter_recurse(&array, &entry);
1107 dbus_message_iter_get_basic(&entry, &vcard);
1108 dbus_message_iter_next(&entry);
1109 print_iter("\t", vcard, &entry);
1110 dbus_message_iter_next(&array);
1114 static void list_reply(DBusMessage *message, void *user_data)
1118 dbus_error_init(&error);
1120 if (dbus_set_error_from_message(&error, message) == TRUE) {
1121 rl_printf("Failed to List: %s\n", error.name);
1122 dbus_error_free(&error);
1126 parse_list_reply(message);
1129 static void list_setup(DBusMessageIter *iter, void *user_data)
1131 DBusMessageIter dict;
1133 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1134 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1135 DBUS_TYPE_STRING_AS_STRING
1136 DBUS_TYPE_VARIANT_AS_STRING
1137 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1140 dbus_message_iter_close_container(iter, &dict);
1143 static void search_reply(DBusMessage *message, void *user_data)
1147 dbus_error_init(&error);
1149 if (dbus_set_error_from_message(&error, message) == TRUE) {
1150 rl_printf("Failed to Search: %s\n", error.name);
1151 dbus_error_free(&error);
1155 parse_list_reply(message);
1158 static void search_setup(DBusMessageIter *iter, void *user_data)
1160 const char *value = user_data;
1162 DBusMessageIter dict;
1164 field = isalpha(value[0]) ? "name" : "number";
1166 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field);
1167 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &value);
1169 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1170 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1171 DBUS_TYPE_STRING_AS_STRING
1172 DBUS_TYPE_VARIANT_AS_STRING
1173 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1176 dbus_message_iter_close_container(iter, &dict);
1179 static void pbap_search(GDBusProxy *proxy, int argc, char *argv[])
1181 if (g_dbus_proxy_method_call(proxy, "Search", search_setup,
1182 search_reply, g_strdup(argv[1]),
1184 rl_printf("Failed to Search\n");
1188 rl_printf("Attempting to Search\n");
1191 static void list_folders_reply(DBusMessage *message, void *user_data)
1194 DBusMessageIter iter, array;
1196 dbus_error_init(&error);
1198 if (dbus_set_error_from_message(&error, message) == TRUE) {
1199 rl_printf("Failed to ListFolders: %s\n", error.name);
1200 dbus_error_free(&error);
1204 dbus_message_iter_init(message, &iter);
1206 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1209 dbus_message_iter_recurse(&iter, &array);
1211 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1212 print_dict_iter(&array);
1213 dbus_message_iter_next(&array);
1217 static void list_folders_setup(DBusMessageIter *iter, void *user_data)
1219 DBusMessageIter dict;
1221 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1222 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1223 DBUS_TYPE_STRING_AS_STRING
1224 DBUS_TYPE_VARIANT_AS_STRING
1225 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1228 dbus_message_iter_close_container(iter, &dict);
1231 static void list_messages_reply(DBusMessage *message, void *user_data)
1234 DBusMessageIter iter, array;
1237 dbus_error_init(&error);
1239 if (dbus_set_error_from_message(&error, message) == TRUE) {
1240 rl_printf("Failed to ListFolders: %s\n", error.name);
1241 dbus_error_free(&error);
1245 dbus_message_iter_init(message, &iter);
1247 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1250 dbus_message_iter_recurse(&iter, &array);
1252 while ((ctype = dbus_message_iter_get_arg_type(&array)) ==
1253 DBUS_TYPE_DICT_ENTRY) {
1254 DBusMessageIter entry;
1257 dbus_message_iter_recurse(&array, &entry);
1258 dbus_message_iter_get_basic(&entry, &obj);
1259 rl_printf("\t%s\n", obj);
1260 dbus_message_iter_next(&array);
1264 static void list_messages_setup(DBusMessageIter *iter, void *user_data)
1266 const char *folder = user_data;
1267 DBusMessageIter dict;
1269 if (strcmp(folder, "*") == 0)
1272 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
1274 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1275 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1276 DBUS_TYPE_STRING_AS_STRING
1277 DBUS_TYPE_VARIANT_AS_STRING
1278 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1281 dbus_message_iter_close_container(iter, &dict);
1284 static void pbap_ls(GDBusProxy *proxy, int argc, char *argv[])
1287 pbap_search(proxy, argc, argv);
1291 if (g_dbus_proxy_method_call(proxy, "List", list_setup, list_reply,
1292 NULL, NULL) == FALSE) {
1293 rl_printf("Failed to List\n");
1297 rl_printf("Attempting to List\n");
1300 static void map_ls_messages(GDBusProxy *proxy, int argc, char *argv[])
1302 if (g_dbus_proxy_method_call(proxy, "ListMessages", list_messages_setup,
1303 list_messages_reply, g_strdup(argv[1]),
1305 rl_printf("Failed to ListMessages\n");
1309 rl_printf("Attempting to ListMessages\n");
1312 static void map_ls(GDBusProxy *proxy, int argc, char *argv[])
1315 map_ls_messages(proxy, argc, argv);
1319 if (g_dbus_proxy_method_call(proxy, "ListFolders", list_folders_setup,
1320 list_folders_reply, NULL,
1322 rl_printf("Failed to ListFolders\n");
1326 rl_printf("Attempting to ListFolders\n");
1329 static void cmd_ls(int argc, char *argv[])
1333 if (!check_default_session())
1336 proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1338 ftp_ls(proxy, argc, argv);
1342 proxy = find_pbap(g_dbus_proxy_get_path(default_session));
1344 pbap_ls(proxy, argc, argv);
1348 proxy = find_map(g_dbus_proxy_get_path(default_session));
1350 map_ls(proxy, argc, argv);
1354 rl_printf("Command not supported\n");
1362 static void cp_free(void *data)
1364 struct cp_args *args = data;
1366 g_free(args->source);
1367 g_free(args->target);
1371 static struct cp_args *cp_new(char *argv[])
1373 struct cp_args *args;
1377 source = rindex(argv[1], ':');
1383 target = rindex(argv[2], ':');
1389 args = g_new0(struct cp_args, 1);
1390 args->source = g_strdup(source);
1391 args->target = g_strdup(target);
1396 static void cp_setup(DBusMessageIter *iter, void *user_data)
1398 struct cp_args *args = user_data;
1400 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
1401 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
1404 static void copy_file_reply(DBusMessage *message, void *user_data)
1408 dbus_error_init(&error);
1410 if (dbus_set_error_from_message(&error, message) == TRUE) {
1411 rl_printf("Failed to CopyFile: %s\n", error.name);
1412 dbus_error_free(&error);
1416 rl_printf("CopyFile successful\n");
1419 static void ftp_copy(GDBusProxy *proxy, int argc, char *argv[])
1421 struct cp_args *args;
1423 args = cp_new(argv);
1425 if (g_dbus_proxy_method_call(proxy, "CopyFile", cp_setup,
1426 copy_file_reply, args, cp_free) == FALSE) {
1427 rl_printf("Failed to CopyFile\n");
1431 rl_printf("Attempting to CopyFile\n");
1434 static void get_file_reply(DBusMessage *message, void *user_data)
1437 DBusMessageIter iter;
1439 dbus_error_init(&error);
1441 if (dbus_set_error_from_message(&error, message) == TRUE) {
1442 rl_printf("Failed to GetFile: %s\n", error.name);
1443 dbus_error_free(&error);
1447 dbus_message_iter_init(message, &iter);
1449 print_transfer_iter(&iter);
1452 static void get_file_setup(DBusMessageIter *iter, void *user_data)
1454 struct cp_args *args = user_data;
1456 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
1457 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
1460 static void ftp_get(GDBusProxy *proxy, int argc, char *argv[])
1462 struct cp_args *args;
1464 if (rindex(argv[2], ':') == NULL)
1465 return ftp_copy(proxy, argc, argv);
1467 args = cp_new(argv);
1469 if (g_dbus_proxy_method_call(proxy, "GetFile", get_file_setup,
1470 get_file_reply, args, cp_free) == FALSE) {
1471 rl_printf("Failed to GetFile\n");
1475 rl_printf("Attempting to GetFile\n");
1478 static void put_file_reply(DBusMessage *message, void *user_data)
1481 DBusMessageIter iter;
1483 dbus_error_init(&error);
1485 if (dbus_set_error_from_message(&error, message) == TRUE) {
1486 rl_printf("Failed to PutFile: %s\n", error.name);
1487 dbus_error_free(&error);
1491 dbus_message_iter_init(message, &iter);
1493 print_transfer_iter(&iter);
1496 static void ftp_put(GDBusProxy *proxy, int argc, char *argv[])
1498 struct cp_args *args;
1500 if (rindex(argv[2], ':') != NULL) {
1501 rl_printf("Invalid target file argument\n");
1505 args = cp_new(argv);
1507 if (g_dbus_proxy_method_call(proxy, "PutFile", cp_setup, put_file_reply,
1508 args, cp_free) == FALSE) {
1509 rl_printf("Failed to PutFile\n");
1513 rl_printf("Attempting to PutFile\n");
1516 static void ftp_cp(GDBusProxy *proxy, int argc, char *argv[])
1519 rl_printf("Missing source file argument\n");
1524 rl_printf("Missing target file argument\n");
1528 if (rindex(argv[1], ':') == NULL)
1529 return ftp_get(proxy, argc, argv);
1531 return ftp_put(proxy, argc, argv);
1534 static void pull_all_reply(DBusMessage *message, void *user_data)
1538 dbus_error_init(&error);
1540 if (dbus_set_error_from_message(&error, message) == TRUE) {
1541 rl_printf("Failed to PullAll: %s\n", error.name);
1542 dbus_error_free(&error);
1547 rl_printf("PullAll successful\n");
1550 static void pull_all_setup(DBusMessageIter *iter, void *user_data)
1552 const char *file = user_data;
1553 DBusMessageIter dict;
1555 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
1557 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1558 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1559 DBUS_TYPE_STRING_AS_STRING
1560 DBUS_TYPE_VARIANT_AS_STRING
1561 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1564 dbus_message_iter_close_container(iter, &dict);
1567 static void pbap_pull_all(GDBusProxy *proxy, int argc, char *argv[])
1569 if (g_dbus_proxy_method_call(proxy, "PullAll", pull_all_setup,
1570 pull_all_reply, g_strdup(argv[2]),
1572 rl_printf("Failed to PullAll\n");
1576 rl_printf("Attempting to PullAll\n");
1579 static void pull_reply(DBusMessage *message, void *user_data)
1583 dbus_error_init(&error);
1585 if (dbus_set_error_from_message(&error, message) == TRUE) {
1586 rl_printf("Failed to Pull: %s\n", error.name);
1587 dbus_error_free(&error);
1592 rl_printf("Pull successful\n");
1595 static void pull_setup(DBusMessageIter *iter, void *user_data)
1597 struct cp_args *args = user_data;
1598 DBusMessageIter dict;
1600 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
1601 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
1603 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1604 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1605 DBUS_TYPE_STRING_AS_STRING
1606 DBUS_TYPE_VARIANT_AS_STRING
1607 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1610 dbus_message_iter_close_container(iter, &dict);
1613 static void pbap_pull(GDBusProxy *proxy, int argc, char *argv[])
1615 struct cp_args *args;
1617 args = cp_new(argv);
1619 if (g_dbus_proxy_method_call(proxy, "Pull", pull_setup, pull_reply,
1620 args, cp_free) == FALSE) {
1621 rl_printf("Failed to Pull\n");
1625 rl_printf("Attempting to Pull\n");
1628 static void pbap_cp(GDBusProxy *proxy, int argc, char *argv[])
1631 rl_printf("Missing source file argument\n");
1636 rl_printf("Missing target file argument\n");
1640 if (strcmp(argv[1], "*") == 0)
1641 return pbap_pull_all(proxy, argc, argv);
1643 return pbap_pull(proxy, argc, argv);
1646 static void get_reply(DBusMessage *message, void *user_data)
1648 DBusMessageIter iter;
1651 dbus_error_init(&error);
1653 if (dbus_set_error_from_message(&error, message) == TRUE) {
1654 rl_printf("Failed to Get: %s\n", error.name);
1655 dbus_error_free(&error);
1659 dbus_message_iter_init(message, &iter);
1661 print_transfer_iter(&iter);
1664 static void get_setup(DBusMessageIter *iter, void *user_data)
1666 const char *file = user_data;
1667 dbus_bool_t attachment = TRUE;
1669 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
1670 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &attachment);
1673 static void map_cp(GDBusProxy *proxy, int argc, char *argv[])
1678 rl_printf("Missing message argument\n");
1682 obj = find_message(argv[1]);
1684 rl_printf("Invalid message argument\n");
1689 rl_printf("Missing target file argument\n");
1693 if (g_dbus_proxy_method_call(obj, "Get", get_setup, get_reply,
1694 g_strdup(argv[2]), g_free) == FALSE) {
1695 rl_printf("Failed to Get\n");
1699 rl_printf("Attempting to Get\n");
1702 static void cmd_cp(int argc, char *argv[])
1707 if (!check_default_session())
1710 proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1712 ftp_cp(proxy, argc, argv);
1716 proxy = find_pbap(g_dbus_proxy_get_path(default_session));
1718 pbap_cp(proxy, argc, argv);
1722 proxy = find_map(g_dbus_proxy_get_path(default_session));
1724 map_cp(proxy, argc, argv);
1728 rl_printf("Command not supported\n");
1731 static void move_file_reply(DBusMessage *message, void *user_data)
1735 dbus_error_init(&error);
1737 if (dbus_set_error_from_message(&error, message) == TRUE) {
1738 rl_printf("Failed to MoveFile: %s\n", error.name);
1739 dbus_error_free(&error);
1743 rl_printf("MoveFile successful\n");
1746 static void cmd_mv(int argc, char *argv[])
1749 struct cp_args *args;
1751 if (!check_default_session())
1755 rl_printf("Missing source file argument\n");
1760 rl_printf("Missing target file argument\n");
1764 proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1765 if (proxy == NULL) {
1766 rl_printf("Command not supported\n");
1770 args = cp_new(argv);
1772 if (g_dbus_proxy_method_call(proxy, "MoveFile", cp_setup,
1773 move_file_reply, args, cp_free) == FALSE) {
1774 rl_printf("Failed to MoveFile\n");
1778 rl_printf("Attempting to MoveFile\n");
1781 static void delete_reply(DBusMessage *message, void *user_data)
1785 dbus_error_init(&error);
1787 if (dbus_set_error_from_message(&error, message) == TRUE) {
1788 rl_printf("Failed to Delete: %s\n", error.name);
1789 dbus_error_free(&error);
1793 rl_printf("Delete successful\n");
1796 static void delete_setup(DBusMessageIter *iter, void *user_data)
1798 const char *file = user_data;
1800 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
1803 static void ftp_rm(GDBusProxy *proxy, int argc, char *argv[])
1806 rl_printf("Missing file argument\n");
1810 if (g_dbus_proxy_method_call(proxy, "Delete", delete_setup,
1811 delete_reply, g_strdup(argv[1]),
1813 rl_printf("Failed to Delete\n");
1817 rl_printf("Attempting to Delete\n");
1820 static void set_delete_reply(const DBusError *error, void *user_data)
1822 if (dbus_error_is_set(error))
1823 rl_printf("Failed to set Deleted: %s\n", error->name);
1825 rl_printf("Set Deleted successful\n");
1828 static void map_rm(GDBusProxy *proxy, int argc, char *argv[])
1831 dbus_bool_t value = TRUE;
1834 rl_printf("Missing message argument\n");
1838 msg = find_message(argv[1]);
1840 rl_printf("Invalid message argument\n");
1844 if (g_dbus_proxy_set_property_basic(msg, "Deleted", DBUS_TYPE_BOOLEAN,
1845 &value, set_delete_reply,
1846 NULL, NULL) == FALSE) {
1847 rl_printf("Failed to set Deleted\n");
1851 rl_printf("Attempting to set Deleted\n");
1854 static void cmd_rm(int argc, char *argv[])
1858 if (!check_default_session())
1861 proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1863 ftp_rm(proxy, argc, argv);
1867 proxy = find_map(g_dbus_proxy_get_path(default_session));
1869 map_rm(proxy, argc, argv);
1873 rl_printf("Command not supported\n");
1876 static void create_folder_reply(DBusMessage *message, void *user_data)
1880 dbus_error_init(&error);
1882 if (dbus_set_error_from_message(&error, message) == TRUE) {
1883 rl_printf("Failed to CreateFolder: %s\n", error.name);
1884 dbus_error_free(&error);
1888 rl_printf("CreateFolder successful\n");
1891 static void create_folder_setup(DBusMessageIter *iter, void *user_data)
1893 const char *folder = user_data;
1895 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
1898 static void cmd_mkdir(int argc, char *argv[])
1902 if (!check_default_session())
1906 rl_printf("Missing folder argument\n");
1910 proxy = find_ftp(g_dbus_proxy_get_path(default_session));
1911 if (proxy == NULL) {
1912 rl_printf("Command not supported\n");
1916 if (g_dbus_proxy_method_call(proxy, "CreateFolder", create_folder_setup,
1917 create_folder_reply, g_strdup(argv[1]),
1919 rl_printf("Failed to CreateFolder\n");
1923 rl_printf("Attempting to CreateFolder\n");
1926 static const struct {
1929 void (*func) (int argc, char *argv[]);
1932 { "connect", "<dev> [uuid]", cmd_connect, "Connect session" },
1933 { "disconnect", "[session]", cmd_disconnect, "Disconnect session" },
1934 { "list", NULL, cmd_list, "List available sessions" },
1935 { "show", "[session]", cmd_show, "Session information" },
1936 { "select", "<session>", cmd_select, "Select default session" },
1937 { "info", "<object>", cmd_info, "Object information" },
1938 { "cancel", "<transfer>", cmd_cancel, "Cancel transfer" },
1939 { "suspend", "<transfer>", cmd_suspend, "Suspend transfer" },
1940 { "resume", "<transfer>", cmd_resume, "Resume transfer" },
1941 { "send", "<file>", cmd_send, "Send file" },
1942 { "cd", "<path>", cmd_cd, "Change current folder" },
1943 { "ls", NULL, cmd_ls, "List current folder" },
1944 { "cp", "<source file> <destination file>", cmd_cp,
1945 "Copy source file to destination file" },
1946 { "mv", "<source file> <destination file>", cmd_mv,
1947 "Move source file to destination file" },
1948 { "rm", "<file>", cmd_rm, "Delete file" },
1949 { "mkdir", "<folder>", cmd_mkdir, "Create folder" },
1950 { "quit", NULL, cmd_quit, "Quit program" },
1951 { "exit", NULL, cmd_quit },
1956 static char *cmd_generator(const char *text, int state)
1958 static int index, len;
1966 while ((cmd = cmd_table[index].cmd)) {
1969 if (!strncmp(cmd, text, len))
1976 static char **cmd_completion(const char *text, int start, int end)
1978 char **matches = NULL;
1981 rl_completion_display_matches_hook = NULL;
1982 matches = rl_completion_matches(text, cmd_generator);
1986 rl_attempted_completion_over = 1;
1991 static void rl_handler(char *input)
1998 rl_insert_text("quit");
2001 g_main_loop_quit(main_loop);
2011 argv = g_strsplit(input, " ", -1);
2015 for (argc = 0; argv[argc];)
2021 for (i = 0; cmd_table[i].cmd; i++) {
2022 if (strcmp(argv[0], cmd_table[i].cmd))
2025 if (cmd_table[i].func) {
2026 cmd_table[i].func(argc, argv);
2031 if (strcmp(argv[0], "help")) {
2032 printf("Invalid command\n");
2036 printf("Available commands:\n");
2038 for (i = 0; cmd_table[i].cmd; i++) {
2039 if (cmd_table[i].desc)
2040 printf(" %s %-*s %s\n", cmd_table[i].cmd,
2041 (int)(25 - strlen(cmd_table[i].cmd)),
2042 cmd_table[i].arg ? : "",
2043 cmd_table[i].desc ? : "");
2051 static gboolean option_version = FALSE;
2053 static GOptionEntry options[] = {
2054 { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
2055 "Show version information and exit" },
2059 static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
2062 static unsigned int __terminated = 0;
2063 struct signalfd_siginfo si;
2067 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
2068 g_main_loop_quit(main_loop);
2072 fd = g_io_channel_unix_get_fd(channel);
2074 result = read(fd, &si, sizeof(si));
2075 if (result != sizeof(si))
2078 switch (si.ssi_signo) {
2080 rl_replace_line("", 0);
2086 if (__terminated == 0) {
2087 rl_replace_line("", 0);
2089 g_main_loop_quit(main_loop);
2099 static guint setup_signalfd(void)
2101 GIOChannel *channel;
2107 sigaddset(&mask, SIGINT);
2108 sigaddset(&mask, SIGTERM);
2110 if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
2111 perror("Failed to set signal mask");
2115 fd = signalfd(-1, &mask, 0);
2117 perror("Failed to create signal descriptor");
2121 channel = g_io_channel_unix_new(fd);
2123 g_io_channel_set_close_on_unref(channel, TRUE);
2124 g_io_channel_set_encoding(channel, NULL, NULL);
2125 g_io_channel_set_buffered(channel, FALSE);
2127 source = g_io_add_watch(channel,
2128 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2129 signal_handler, NULL);
2131 g_io_channel_unref(channel);
2136 static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
2139 if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
2140 g_main_loop_quit(main_loop);
2144 rl_callback_read_char();
2148 static guint setup_standard_input(void)
2150 GIOChannel *channel;
2153 channel = g_io_channel_unix_new(fileno(stdin));
2155 source = g_io_add_watch(channel,
2156 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2157 input_handler, NULL);
2159 g_io_channel_unref(channel);
2164 static void client_added(GDBusProxy *proxy)
2169 print_proxy(proxy, "Client", COLORED_NEW);
2172 static void session_added(GDBusProxy *proxy)
2174 sessions = g_slist_append(sessions, proxy);
2176 if (default_session == NULL)
2177 set_default_session(proxy);
2179 print_proxy(proxy, "Session", COLORED_NEW);
2182 static void print_transferred(struct transfer_data *data, const char *str,
2183 DBusMessageIter *iter)
2185 dbus_uint64_t valu64;
2187 int seconds, minutes;
2189 dbus_message_iter_get_basic(iter, &valu64);
2190 speed = valu64 - data->transferred;
2191 data->transferred = valu64;
2193 if (data->size == 0) {
2194 rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s)\n",
2195 str, valu64, speed / 1000);
2199 seconds = (data->size - data->transferred) / speed;
2200 minutes = seconds / 60;
2202 rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s %02u:%02u)\n",
2203 str, valu64, speed / 1000, minutes, seconds);
2206 static void transfer_property_changed(GDBusProxy *proxy, const char *name,
2207 DBusMessageIter *iter, void *user_data)
2209 struct transfer_data *data = user_data;
2212 str = proxy_description(proxy, "Transfer", COLORED_CHG);
2214 if (strcmp(name, "Transferred") == 0) {
2215 print_transferred(data, str, iter);
2219 if (strcmp(name, "Size") == 0)
2220 dbus_message_iter_get_basic(iter, &data->size);
2222 print_iter(str, name, iter);
2228 static void transfer_destroy(GDBusProxy *proxy, void *user_data)
2230 struct transfer_data *data = user_data;
2235 static void transfer_added(GDBusProxy *proxy)
2237 struct transfer_data *data;
2238 DBusMessageIter iter;
2240 transfers = g_slist_append(transfers, proxy);
2242 print_proxy(proxy, "Transfer", COLORED_NEW);
2244 data = g_new0(struct transfer_data, 1);
2246 if (g_dbus_proxy_get_property(proxy, "Transfered", &iter))
2247 dbus_message_iter_get_basic(&iter, &data->transferred);
2249 if (g_dbus_proxy_get_property(proxy, "Size", &iter))
2250 dbus_message_iter_get_basic(&iter, &data->size);
2252 g_dbus_proxy_set_property_watch(proxy, transfer_property_changed, data);
2253 g_dbus_proxy_set_removed_watch(proxy, transfer_destroy, data);
2256 static void opp_added(GDBusProxy *proxy)
2258 opps = g_slist_append(opps, proxy);
2260 print_proxy(proxy, "ObjectPush", COLORED_NEW);
2263 static void ftp_added(GDBusProxy *proxy)
2265 ftps = g_slist_append(ftps, proxy);
2267 print_proxy(proxy, "FileTransfer", COLORED_NEW);
2270 static void pbap_added(GDBusProxy *proxy)
2272 pbaps = g_slist_append(pbaps, proxy);
2274 print_proxy(proxy, "PhonebookAccess", COLORED_NEW);
2277 static void map_added(GDBusProxy *proxy)
2279 maps = g_slist_append(maps, proxy);
2281 print_proxy(proxy, "MessageAccess", COLORED_NEW);
2284 static void msg_added(GDBusProxy *proxy)
2286 msgs = g_slist_append(msgs, proxy);
2288 print_proxy(proxy, "Message", COLORED_NEW);
2291 static void proxy_added(GDBusProxy *proxy, void *user_data)
2293 const char *interface;
2295 interface = g_dbus_proxy_get_interface(proxy);
2297 if (!strcmp(interface, OBEX_CLIENT_INTERFACE))
2298 client_added(proxy);
2299 else if (!strcmp(interface, OBEX_SESSION_INTERFACE))
2300 session_added(proxy);
2301 else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE))
2302 transfer_added(proxy);
2303 else if (!strcmp(interface, OBEX_OPP_INTERFACE))
2305 else if (!strcmp(interface, OBEX_FTP_INTERFACE))
2307 else if (!strcmp(interface, OBEX_PBAP_INTERFACE))
2309 else if (!strcmp(interface, OBEX_MAP_INTERFACE))
2311 else if (!strcmp(interface, OBEX_MSG_INTERFACE))
2315 static void client_removed(GDBusProxy *proxy)
2317 print_proxy(proxy, "Client", COLORED_DEL);
2319 if (client == proxy)
2323 static void session_removed(GDBusProxy *proxy)
2325 print_proxy(proxy, "Session", COLORED_DEL);
2327 if (default_session == proxy)
2328 set_default_session(NULL);
2330 sessions = g_slist_remove(sessions, proxy);
2333 static void transfer_removed(GDBusProxy *proxy)
2335 print_proxy(proxy, "Transfer", COLORED_DEL);
2337 transfers = g_slist_remove(transfers, proxy);
2340 static void opp_removed(GDBusProxy *proxy)
2342 print_proxy(proxy, "ObjectPush", COLORED_DEL);
2344 opps = g_slist_remove(opps, proxy);
2347 static void ftp_removed(GDBusProxy *proxy)
2349 print_proxy(proxy, "FileTransfer", COLORED_DEL);
2351 ftps = g_slist_remove(ftps, proxy);
2354 static void pbap_removed(GDBusProxy *proxy)
2356 print_proxy(proxy, "PhonebookAccess", COLORED_DEL);
2358 pbaps = g_slist_remove(pbaps, proxy);
2361 static void map_removed(GDBusProxy *proxy)
2363 print_proxy(proxy, "MessageAccess", COLORED_DEL);
2365 maps = g_slist_remove(maps, proxy);
2368 static void msg_removed(GDBusProxy *proxy)
2370 print_proxy(proxy, "Message", COLORED_DEL);
2372 msgs = g_slist_remove(msgs, proxy);
2375 static void proxy_removed(GDBusProxy *proxy, void *user_data)
2377 const char *interface;
2379 interface = g_dbus_proxy_get_interface(proxy);
2381 if (!strcmp(interface, OBEX_CLIENT_INTERFACE))
2382 client_removed(proxy);
2383 else if (!strcmp(interface, OBEX_SESSION_INTERFACE))
2384 session_removed(proxy);
2385 else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE))
2386 transfer_removed(proxy);
2387 else if (!strcmp(interface, OBEX_OPP_INTERFACE))
2389 else if (!strcmp(interface, OBEX_FTP_INTERFACE))
2391 else if (!strcmp(interface, OBEX_PBAP_INTERFACE))
2392 pbap_removed(proxy);
2393 else if (!strcmp(interface, OBEX_MAP_INTERFACE))
2395 else if (!strcmp(interface, OBEX_MSG_INTERFACE))
2399 static void session_property_changed(GDBusProxy *proxy, const char *name,
2400 DBusMessageIter *iter)
2404 str = proxy_description(proxy, "Session", COLORED_CHG);
2405 print_iter(str, name, iter);
2409 static void property_changed(GDBusProxy *proxy, const char *name,
2410 DBusMessageIter *iter, void *user_data)
2412 const char *interface;
2414 interface = g_dbus_proxy_get_interface(proxy);
2416 if (!strcmp(interface, OBEX_SESSION_INTERFACE))
2417 session_property_changed(proxy, name, iter);
2420 int main(int argc, char *argv[])
2422 GOptionContext *context;
2423 GError *error = NULL;
2424 GDBusClient *client;
2425 guint signal, input;
2427 context = g_option_context_new(NULL);
2428 g_option_context_add_main_entries(context, options, NULL);
2430 if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
2431 if (error != NULL) {
2432 g_printerr("%s\n", error->message);
2433 g_error_free(error);
2435 g_printerr("An unknown error occurred\n");
2439 g_option_context_free(context);
2441 if (option_version == TRUE) {
2442 printf("%s\n", VERSION);
2446 main_loop = g_main_loop_new(NULL, FALSE);
2447 dbus_conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
2449 rl_attempted_completion_function = cmd_completion;
2451 rl_erase_empty_line = 1;
2452 rl_callback_handler_install(NULL, rl_handler);
2454 rl_set_prompt(PROMPT_OFF);
2457 input = setup_standard_input();
2458 signal = setup_signalfd();
2459 client = g_dbus_client_new(dbus_conn, "org.bluez.obex",
2462 g_dbus_client_set_connect_watch(client, connect_handler, NULL);
2463 g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
2465 g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
2466 property_changed, NULL);
2468 g_main_loop_run(main_loop);
2470 g_dbus_client_unref(client);
2471 g_source_remove(signal);
2472 g_source_remove(input);
2475 rl_callback_handler_remove();
2477 dbus_connection_unref(dbus_conn);
2478 g_main_loop_unref(main_loop);