Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / client / main.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2012  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 <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdbool.h>
33 #include <signal.h>
34 #include <sys/signalfd.h>
35 #include <wordexp.h>
36
37 #include <readline/readline.h>
38 #include <readline/history.h>
39 #include <glib.h>
40
41 #include "gdbus/gdbus.h"
42 #include "monitor/uuid.h"
43 #include "agent.h"
44 #include "display.h"
45 #include "gatt.h"
46
47 /* String display constants */
48 #define COLORED_NEW     COLOR_GREEN "NEW" COLOR_OFF
49 #define COLORED_CHG     COLOR_YELLOW "CHG" COLOR_OFF
50 #define COLORED_DEL     COLOR_RED "DEL" COLOR_OFF
51
52 #define PROMPT_ON       COLOR_BLUE "[bluetooth]" COLOR_OFF "# "
53 #define PROMPT_OFF      "[bluetooth]# "
54
55 static GMainLoop *main_loop;
56 static DBusConnection *dbus_conn;
57
58 static GDBusProxy *agent_manager;
59 static char *auto_register_agent = NULL;
60
61 static GDBusProxy *default_ctrl;
62 static GDBusProxy *default_dev;
63 static GDBusProxy *default_attr;
64 static GList *ctrl_list;
65 static GList *dev_list;
66
67 static guint input = 0;
68
69 static const char * const agent_arguments[] = {
70         "on",
71         "off",
72         "DisplayOnly",
73         "DisplayYesNo",
74         "KeyboardDisplay",
75         "KeyboardOnly",
76         "NoInputNoOutput",
77         NULL
78 };
79
80 static void proxy_leak(gpointer data)
81 {
82         printf("Leaking proxy %p\n", data);
83 }
84
85 static void connect_handler(DBusConnection *connection, void *user_data)
86 {
87         rl_set_prompt(PROMPT_ON);
88         printf("\r");
89         rl_on_new_line();
90         rl_redisplay();
91 }
92
93 static void disconnect_handler(DBusConnection *connection, void *user_data)
94 {
95         rl_set_prompt(PROMPT_OFF);
96         printf("\r");
97         rl_on_new_line();
98         rl_redisplay();
99
100         g_list_free(ctrl_list);
101         ctrl_list = NULL;
102
103         default_ctrl = NULL;
104
105         g_list_free(dev_list);
106         dev_list = NULL;
107 }
108
109 static void print_adapter(GDBusProxy *proxy, const char *description)
110 {
111         DBusMessageIter iter;
112         const char *address, *name;
113
114         if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
115                 return;
116
117         dbus_message_iter_get_basic(&iter, &address);
118
119         if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
120                 dbus_message_iter_get_basic(&iter, &name);
121         else
122                 name = "<unknown>";
123
124         rl_printf("%s%s%sController %s %s %s\n",
125                                 description ? "[" : "",
126                                 description ? : "",
127                                 description ? "] " : "",
128                                 address, name,
129                                 default_ctrl == proxy ? "[default]" : "");
130
131 }
132
133 static void print_device(GDBusProxy *proxy, const char *description)
134 {
135         DBusMessageIter iter;
136         const char *address, *name;
137
138         if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
139                 return;
140
141         dbus_message_iter_get_basic(&iter, &address);
142
143         if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
144                 dbus_message_iter_get_basic(&iter, &name);
145         else
146                 name = "<unknown>";
147
148         rl_printf("%s%s%sDevice %s %s\n",
149                                 description ? "[" : "",
150                                 description ? : "",
151                                 description ? "] " : "",
152                                 address, name);
153 }
154
155 static void print_iter(const char *label, const char *name,
156                                                 DBusMessageIter *iter)
157 {
158         dbus_bool_t valbool;
159         dbus_uint32_t valu32;
160         dbus_uint16_t valu16;
161         dbus_int16_t vals16;
162         unsigned char byte;
163         const char *valstr;
164         DBusMessageIter subiter;
165         char *entry;
166
167         if (iter == NULL) {
168                 rl_printf("%s%s is nil\n", label, name);
169                 return;
170         }
171
172         switch (dbus_message_iter_get_arg_type(iter)) {
173         case DBUS_TYPE_INVALID:
174                 rl_printf("%s%s is invalid\n", label, name);
175                 break;
176         case DBUS_TYPE_STRING:
177         case DBUS_TYPE_OBJECT_PATH:
178                 dbus_message_iter_get_basic(iter, &valstr);
179                 rl_printf("%s%s: %s\n", label, name, valstr);
180                 break;
181         case DBUS_TYPE_BOOLEAN:
182                 dbus_message_iter_get_basic(iter, &valbool);
183                 rl_printf("%s%s: %s\n", label, name,
184                                         valbool == TRUE ? "yes" : "no");
185                 break;
186         case DBUS_TYPE_UINT32:
187                 dbus_message_iter_get_basic(iter, &valu32);
188                 rl_printf("%s%s: 0x%06x\n", label, name, valu32);
189                 break;
190         case DBUS_TYPE_UINT16:
191                 dbus_message_iter_get_basic(iter, &valu16);
192                 rl_printf("%s%s: 0x%04x\n", label, name, valu16);
193                 break;
194         case DBUS_TYPE_INT16:
195                 dbus_message_iter_get_basic(iter, &vals16);
196                 rl_printf("%s%s: %d\n", label, name, vals16);
197                 break;
198         case DBUS_TYPE_BYTE:
199                 dbus_message_iter_get_basic(iter, &byte);
200                 rl_printf("%s%s: 0x%02x\n", label, name, byte);
201                 break;
202         case DBUS_TYPE_VARIANT:
203                 dbus_message_iter_recurse(iter, &subiter);
204                 print_iter(label, name, &subiter);
205                 break;
206         case DBUS_TYPE_ARRAY:
207                 dbus_message_iter_recurse(iter, &subiter);
208                 while (dbus_message_iter_get_arg_type(&subiter) !=
209                                                         DBUS_TYPE_INVALID) {
210                         print_iter(label, name, &subiter);
211                         dbus_message_iter_next(&subiter);
212                 }
213                 break;
214         case DBUS_TYPE_DICT_ENTRY:
215                 dbus_message_iter_recurse(iter, &subiter);
216                 entry = g_strconcat(name, " Key", NULL);
217                 print_iter(label, entry, &subiter);
218                 g_free(entry);
219
220                 entry = g_strconcat(name, " Value", NULL);
221                 dbus_message_iter_next(&subiter);
222                 print_iter(label, entry, &subiter);
223                 g_free(entry);
224                 break;
225         default:
226                 rl_printf("%s%s has unsupported type\n", label, name);
227                 break;
228         }
229 }
230
231 static void print_property(GDBusProxy *proxy, const char *name)
232 {
233         DBusMessageIter iter;
234
235         if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
236                 return;
237
238         print_iter("\t", name, &iter);
239 }
240
241 static void print_uuids(GDBusProxy *proxy)
242 {
243         DBusMessageIter iter, value;
244
245         if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
246                 return;
247
248         dbus_message_iter_recurse(&iter, &value);
249
250         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
251                 const char *uuid, *text;
252
253                 dbus_message_iter_get_basic(&value, &uuid);
254
255                 text = uuidstr_to_str(uuid);
256                 if (text) {
257                         char str[26];
258                         unsigned int n;
259
260                         str[sizeof(str) - 1] = '\0';
261
262                         n = snprintf(str, sizeof(str), "%s", text);
263                         if (n > sizeof(str) - 1) {
264                                 str[sizeof(str) - 2] = '.';
265                                 str[sizeof(str) - 3] = '.';
266                                 if (str[sizeof(str) - 4] == ' ')
267                                         str[sizeof(str) - 4] = '.';
268
269                                 n = sizeof(str) - 1;
270                         }
271
272                         rl_printf("\tUUID: %s%*c(%s)\n",
273                                                 str, 26 - n, ' ', uuid);
274                 } else
275                         rl_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
276
277                 dbus_message_iter_next(&value);
278         }
279 }
280
281 static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
282 {
283         DBusMessageIter iter;
284         const char *adapter, *path;
285
286         if (!master)
287                 return FALSE;
288
289         if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
290                 return FALSE;
291
292         dbus_message_iter_get_basic(&iter, &adapter);
293         path = g_dbus_proxy_get_path(master);
294
295         if (!strcmp(path, adapter))
296                 return TRUE;
297
298         return FALSE;
299 }
300
301 static gboolean service_is_child(GDBusProxy *service)
302 {
303         GList *l;
304         DBusMessageIter iter;
305         const char *device, *path;
306
307         if (g_dbus_proxy_get_property(service, "Device", &iter) == FALSE)
308                 return FALSE;
309
310         dbus_message_iter_get_basic(&iter, &device);
311
312         for (l = dev_list; l; l = g_list_next(l)) {
313                 GDBusProxy *proxy = l->data;
314
315                 path = g_dbus_proxy_get_path(proxy);
316
317                 if (!strcmp(path, device))
318                         return TRUE;
319         }
320
321         return FALSE;
322 }
323
324 static void proxy_added(GDBusProxy *proxy, void *user_data)
325 {
326         const char *interface;
327
328         interface = g_dbus_proxy_get_interface(proxy);
329
330         if (!strcmp(interface, "org.bluez.Device1")) {
331                 if (device_is_child(proxy, default_ctrl) == TRUE) {
332                         dev_list = g_list_append(dev_list, proxy);
333
334                         print_device(proxy, COLORED_NEW);
335                 }
336         } else if (!strcmp(interface, "org.bluez.Adapter1")) {
337                 ctrl_list = g_list_append(ctrl_list, proxy);
338
339                 if (!default_ctrl)
340                         default_ctrl = proxy;
341
342                 print_adapter(proxy, COLORED_NEW);
343         } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
344                 if (!agent_manager) {
345                         agent_manager = proxy;
346
347                         if (auto_register_agent)
348                                 agent_register(dbus_conn, agent_manager,
349                                                         auto_register_agent);
350                 }
351         } else if (!strcmp(interface, "org.bluez.GattService1")) {
352                 if (service_is_child(proxy))
353                         gatt_add_service(proxy);
354         } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
355                 gatt_add_characteristic(proxy);
356         } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
357                 gatt_add_descriptor(proxy);
358         } else if (!strcmp(interface, "org.bluez.GattManager1")) {
359                 gatt_add_manager(proxy);
360         }
361 }
362
363 static void set_default_device(GDBusProxy *proxy, const char *attribute)
364 {
365         char *desc = NULL;
366         DBusMessageIter iter;
367         const char *path;
368
369         default_dev = proxy;
370
371         if (proxy == NULL) {
372                 default_attr = NULL;
373                 goto done;
374         }
375
376         if (!g_dbus_proxy_get_property(proxy, "Alias", &iter)) {
377                 if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
378                         goto done;
379         }
380
381         path = g_dbus_proxy_get_path(proxy);
382
383         dbus_message_iter_get_basic(&iter, &desc);
384         desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
385                                 attribute ? ":" : "",
386                                 attribute ? attribute + strlen(path) : "");
387
388 done:
389         rl_set_prompt(desc ? desc : PROMPT_ON);
390         printf("\r");
391         rl_on_new_line();
392         rl_redisplay();
393         g_free(desc);
394 }
395
396 static void set_default_attribute(GDBusProxy *proxy)
397 {
398         const char *path;
399
400         default_attr = proxy;
401
402         path = g_dbus_proxy_get_path(proxy);
403
404         set_default_device(default_dev, path);
405 }
406
407 static void proxy_removed(GDBusProxy *proxy, void *user_data)
408 {
409         const char *interface;
410
411         interface = g_dbus_proxy_get_interface(proxy);
412
413         if (!strcmp(interface, "org.bluez.Device1")) {
414                 if (device_is_child(proxy, default_ctrl) == TRUE) {
415                         dev_list = g_list_remove(dev_list, proxy);
416
417                         print_device(proxy, COLORED_DEL);
418
419                         if (default_dev == proxy)
420                                 set_default_device(NULL, NULL);
421                 }
422         } else if (!strcmp(interface, "org.bluez.Adapter1")) {
423                 ctrl_list = g_list_remove(ctrl_list, proxy);
424
425                 print_adapter(proxy, COLORED_DEL);
426
427                 if (default_ctrl == proxy) {
428                         default_ctrl = NULL;
429                         set_default_device(NULL, NULL);
430
431                         g_list_free(dev_list);
432                         dev_list = NULL;
433                 }
434         } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
435                 if (agent_manager == proxy) {
436                         agent_manager = NULL;
437                         if (auto_register_agent)
438                                 agent_unregister(dbus_conn, NULL);
439                 }
440         } else if (!strcmp(interface, "org.bluez.GattService1")) {
441                 gatt_remove_service(proxy);
442
443                 if (default_attr == proxy)
444                         set_default_attribute(NULL);
445         } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
446                 gatt_remove_characteristic(proxy);
447
448                 if (default_attr == proxy)
449                         set_default_attribute(NULL);
450         } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
451                 gatt_remove_descriptor(proxy);
452
453                 if (default_attr == proxy)
454                         set_default_attribute(NULL);
455         } else if (!strcmp(interface, "org.bluez.GattManager1")) {
456                 gatt_remove_manager(proxy);
457         }
458 }
459
460 static void property_changed(GDBusProxy *proxy, const char *name,
461                                         DBusMessageIter *iter, void *user_data)
462 {
463         const char *interface;
464
465         interface = g_dbus_proxy_get_interface(proxy);
466
467         if (!strcmp(interface, "org.bluez.Device1")) {
468                 if (device_is_child(proxy, default_ctrl) == TRUE) {
469                         DBusMessageIter addr_iter;
470                         char *str;
471
472                         if (g_dbus_proxy_get_property(proxy, "Address",
473                                                         &addr_iter) == TRUE) {
474                                 const char *address;
475
476                                 dbus_message_iter_get_basic(&addr_iter,
477                                                                 &address);
478                                 str = g_strdup_printf("[" COLORED_CHG
479                                                 "] Device %s ", address);
480                         } else
481                                 str = g_strdup("");
482
483                         if (strcmp(name, "Connected") == 0) {
484                                 dbus_bool_t connected;
485
486                                 dbus_message_iter_get_basic(iter, &connected);
487
488                                 if (connected && default_dev == NULL)
489                                         set_default_device(proxy, NULL);
490                                 else if (!connected && default_dev == proxy)
491                                         set_default_device(NULL, NULL);
492                         }
493
494                         print_iter(str, name, iter);
495                         g_free(str);
496                 }
497         } else if (!strcmp(interface, "org.bluez.Adapter1")) {
498                 DBusMessageIter addr_iter;
499                 char *str;
500
501                 if (g_dbus_proxy_get_property(proxy, "Address",
502                                                 &addr_iter) == TRUE) {
503                         const char *address;
504
505                         dbus_message_iter_get_basic(&addr_iter, &address);
506                         str = g_strdup_printf("[" COLORED_CHG
507                                                 "] Controller %s ", address);
508                 } else
509                         str = g_strdup("");
510
511                 print_iter(str, name, iter);
512                 g_free(str);
513         } else if (proxy == default_attr) {
514                 char *str;
515
516                 str = g_strdup_printf("[" COLORED_CHG "] Attribute %s ",
517                                                 g_dbus_proxy_get_path(proxy));
518
519                 print_iter(str, name, iter);
520                 g_free(str);
521         }
522 }
523
524 static void message_handler(DBusConnection *connection,
525                                         DBusMessage *message, void *user_data)
526 {
527         rl_printf("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
528                                         dbus_message_get_member(message));
529 }
530
531 static GDBusProxy *find_proxy_by_address(GList *source, const char *address)
532 {
533         GList *list;
534
535         for (list = g_list_first(source); list; list = g_list_next(list)) {
536                 GDBusProxy *proxy = list->data;
537                 DBusMessageIter iter;
538                 const char *str;
539
540                 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
541                         continue;
542
543                 dbus_message_iter_get_basic(&iter, &str);
544
545                 if (!strcmp(str, address))
546                         return proxy;
547         }
548
549         return NULL;
550 }
551
552 static gboolean check_default_ctrl(void)
553 {
554         if (!default_ctrl) {
555                 rl_printf("No default controller available\n");
556                 return FALSE;
557         }
558
559         return TRUE;
560 }
561
562 static gboolean parse_argument_on_off(const char *arg, dbus_bool_t *value)
563 {
564         if (!arg || !strlen(arg)) {
565                 rl_printf("Missing on/off argument\n");
566                 return FALSE;
567         }
568
569         if (!strcmp(arg, "on") || !strcmp(arg, "yes")) {
570                 *value = TRUE;
571                 return TRUE;
572         }
573
574         if (!strcmp(arg, "off") || !strcmp(arg, "no")) {
575                 *value = FALSE;
576                 return TRUE;
577         }
578
579         rl_printf("Invalid argument %s\n", arg);
580         return FALSE;
581 }
582
583 static gboolean parse_argument_agent(const char *arg, dbus_bool_t *value,
584                                                         const char **capability)
585 {
586         const char * const *opt;
587
588         if (arg == NULL || strlen(arg) == 0) {
589                 rl_printf("Missing on/off/capability argument\n");
590                 return FALSE;
591         }
592
593         if (strcmp(arg, "on") == 0 || strcmp(arg, "yes") == 0) {
594                 *value = TRUE;
595                 *capability = "";
596                 return TRUE;
597         }
598
599         if (strcmp(arg, "off") == 0 || strcmp(arg, "no") == 0) {
600                 *value = FALSE;
601                 return TRUE;
602         }
603
604         for (opt = agent_arguments; *opt; opt++) {
605                 if (strcmp(arg, *opt) == 0) {
606                         *value = TRUE;
607                         *capability = *opt;
608                         return TRUE;
609                 }
610         }
611
612         rl_printf("Invalid argument %s\n", arg);
613         return FALSE;
614 }
615
616 static void cmd_list(const char *arg)
617 {
618         GList *list;
619
620         for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
621                 GDBusProxy *proxy = list->data;
622                 print_adapter(proxy, NULL);
623         }
624 }
625
626 static void cmd_show(const char *arg)
627 {
628         GDBusProxy *proxy;
629         DBusMessageIter iter;
630         const char *address;
631
632         if (!arg || !strlen(arg)) {
633                 if (check_default_ctrl() == FALSE)
634                         return;
635
636                 proxy = default_ctrl;
637         } else {
638                 proxy = find_proxy_by_address(ctrl_list, arg);
639                 if (!proxy) {
640                         rl_printf("Controller %s not available\n", arg);
641                         return;
642                 }
643         }
644
645         if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
646                 return;
647
648         dbus_message_iter_get_basic(&iter, &address);
649         rl_printf("Controller %s\n", address);
650
651         print_property(proxy, "Name");
652         print_property(proxy, "Alias");
653         print_property(proxy, "Class");
654         print_property(proxy, "Powered");
655         print_property(proxy, "Discoverable");
656         print_property(proxy, "Pairable");
657         print_uuids(proxy);
658         print_property(proxy, "Modalias");
659         print_property(proxy, "Discovering");
660 #ifdef __TIZEN_PATCH__
661         print_property(proxy, "Advertising");
662 #endif
663 }
664
665 static void cmd_select(const char *arg)
666 {
667         GDBusProxy *proxy;
668
669         if (!arg || !strlen(arg)) {
670                 rl_printf("Missing controller address argument\n");
671                 return;
672         }
673
674         proxy = find_proxy_by_address(ctrl_list, arg);
675         if (!proxy) {
676                 rl_printf("Controller %s not available\n", arg);
677                 return;
678         }
679
680         if (default_ctrl == proxy)
681                 return;
682
683         default_ctrl = proxy;
684         print_adapter(proxy, NULL);
685
686         g_list_free(dev_list);
687         dev_list = NULL;
688 }
689
690 static void cmd_devices(const char *arg)
691 {
692         GList *list;
693
694         for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
695                 GDBusProxy *proxy = list->data;
696                 print_device(proxy, NULL);
697         }
698 }
699
700 static void cmd_paired_devices(const char *arg)
701 {
702         GList *list;
703
704         for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
705                 GDBusProxy *proxy = list->data;
706                 DBusMessageIter iter;
707                 dbus_bool_t paired;
708
709                 if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == FALSE)
710                         continue;
711
712                 dbus_message_iter_get_basic(&iter, &paired);
713                 if (!paired)
714                         continue;
715
716                 print_device(proxy, NULL);
717         }
718 }
719
720 static void generic_callback(const DBusError *error, void *user_data)
721 {
722         char *str = user_data;
723
724         if (dbus_error_is_set(error))
725                 rl_printf("Failed to set %s: %s\n", str, error->name);
726         else
727                 rl_printf("Changing %s succeeded\n", str);
728 }
729
730 static void cmd_system_alias(const char *arg)
731 {
732         char *name;
733
734         if (!arg || !strlen(arg)) {
735                 rl_printf("Missing name argument\n");
736                 return;
737         }
738
739         if (check_default_ctrl() == FALSE)
740                 return;
741
742         name = g_strdup(arg);
743
744         if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
745                                         DBUS_TYPE_STRING, &name,
746                                         generic_callback, name, g_free) == TRUE)
747                 return;
748
749         g_free(name);
750 }
751
752 static void cmd_reset_alias(const char *arg)
753 {
754         char *name;
755
756         if (check_default_ctrl() == FALSE)
757                 return;
758
759         name = g_strdup("");
760
761         if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
762                                         DBUS_TYPE_STRING, &name,
763                                         generic_callback, name, g_free) == TRUE)
764                 return;
765
766         g_free(name);
767 }
768
769 static void cmd_power(const char *arg)
770 {
771         dbus_bool_t powered;
772         char *str;
773
774         if (parse_argument_on_off(arg, &powered) == FALSE)
775                 return;
776
777         if (check_default_ctrl() == FALSE)
778                 return;
779
780         str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
781
782         if (g_dbus_proxy_set_property_basic(default_ctrl, "Powered",
783                                         DBUS_TYPE_BOOLEAN, &powered,
784                                         generic_callback, str, g_free) == TRUE)
785                 return;
786
787         g_free(str);
788 }
789
790 static void cmd_pairable(const char *arg)
791 {
792         dbus_bool_t pairable;
793         char *str;
794
795         if (parse_argument_on_off(arg, &pairable) == FALSE)
796                 return;
797
798         if (check_default_ctrl() == FALSE)
799                 return;
800
801         str = g_strdup_printf("pairable %s", pairable == TRUE ? "on" : "off");
802
803         if (g_dbus_proxy_set_property_basic(default_ctrl, "Pairable",
804                                         DBUS_TYPE_BOOLEAN, &pairable,
805                                         generic_callback, str, g_free) == TRUE)
806                 return;
807
808         g_free(str);
809 }
810
811 static void cmd_discoverable(const char *arg)
812 {
813         dbus_bool_t discoverable;
814         char *str;
815
816         if (parse_argument_on_off(arg, &discoverable) == FALSE)
817                 return;
818
819         if (check_default_ctrl() == FALSE)
820                 return;
821
822         str = g_strdup_printf("discoverable %s",
823                                 discoverable == TRUE ? "on" : "off");
824
825         if (g_dbus_proxy_set_property_basic(default_ctrl, "Discoverable",
826                                         DBUS_TYPE_BOOLEAN, &discoverable,
827                                         generic_callback, str, g_free) == TRUE)
828                 return;
829
830         g_free(str);
831 }
832
833 static void cmd_agent(const char *arg)
834 {
835         dbus_bool_t enable;
836         const char *capability;
837
838         if (parse_argument_agent(arg, &enable, &capability) == FALSE)
839                 return;
840
841         if (enable == TRUE) {
842                 g_free(auto_register_agent);
843                 auto_register_agent = g_strdup(capability);
844
845                 if (agent_manager)
846                         agent_register(dbus_conn, agent_manager,
847                                                 auto_register_agent);
848                 else
849                         rl_printf("Agent registration enabled\n");
850         } else {
851                 g_free(auto_register_agent);
852                 auto_register_agent = NULL;
853
854                 if (agent_manager)
855                         agent_unregister(dbus_conn, agent_manager);
856                 else
857                         rl_printf("Agent registration disabled\n");
858         }
859 }
860
861 static void cmd_default_agent(const char *arg)
862 {
863         agent_default(dbus_conn, agent_manager);
864 }
865
866 static void start_discovery_reply(DBusMessage *message, void *user_data)
867 {
868         dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
869         DBusError error;
870
871         dbus_error_init(&error);
872
873         if (dbus_set_error_from_message(&error, message) == TRUE) {
874                 rl_printf("Failed to %s discovery: %s\n",
875                                 enable == TRUE ? "start" : "stop", error.name);
876                 dbus_error_free(&error);
877                 return;
878         }
879
880         rl_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped");
881 }
882
883 static void cmd_scan(const char *arg)
884 {
885         dbus_bool_t enable;
886         const char *method;
887
888         if (parse_argument_on_off(arg, &enable) == FALSE)
889                 return;
890
891         if (check_default_ctrl() == FALSE)
892                 return;
893
894         if (enable == TRUE)
895                 method = "StartDiscovery";
896         else
897                 method = "StopDiscovery";
898
899         if (g_dbus_proxy_method_call(default_ctrl, method,
900                                 NULL, start_discovery_reply,
901                                 GUINT_TO_POINTER(enable), NULL) == FALSE) {
902                 rl_printf("Failed to %s discovery\n",
903                                         enable == TRUE ? "start" : "stop");
904                 return;
905         }
906 }
907
908 static void append_variant(DBusMessageIter *iter, int type, void *val)
909 {
910         DBusMessageIter value;
911         char sig[2] = { type, '\0' };
912
913         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
914
915         dbus_message_iter_append_basic(&value, type, val);
916
917         dbus_message_iter_close_container(iter, &value);
918 }
919
920 static void dict_append_entry(DBusMessageIter *dict, const char *key,
921                                                         int type, void *val)
922 {
923         DBusMessageIter entry;
924
925         if (type == DBUS_TYPE_STRING) {
926                 const char *str = *((const char **) val);
927
928                 if (str == NULL)
929                         return;
930         }
931
932         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
933                                                         NULL, &entry);
934
935         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
936
937         append_variant(&entry, type, val);
938
939         dbus_message_iter_close_container(dict, &entry);
940 }
941
942 #define DISTANCE_VAL_INVALID    0x7FFF
943
944 struct set_discovery_filter_args {
945         char *transport;
946         dbus_uint16_t rssi;
947         dbus_int16_t pathloss;
948         GSList *uuids;
949 };
950
951 static void set_discovery_filter_setup(DBusMessageIter *iter,
952                                            void *user_data)
953 {
954         struct set_discovery_filter_args *args = user_data;
955         DBusMessageIter dict;
956
957         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
958                             DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
959                             DBUS_TYPE_STRING_AS_STRING
960                             DBUS_TYPE_VARIANT_AS_STRING
961                             DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
962
963         if (args->uuids != NULL) {
964                 DBusMessageIter entry, value, arrayIter;
965                 char *uuids = "UUIDs";
966                 GSList *l;
967
968                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
969                                                  NULL, &entry);
970                 /* dict key */
971                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
972                                                &uuids);
973
974                 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
975                                                  "as", &value);
976
977                 dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, "s",
978                                                  &arrayIter);
979
980                 for (l = args->uuids; l != NULL; l = g_slist_next(l))
981                         /* list->data contains string representation of uuid */
982                         dbus_message_iter_append_basic(&arrayIter,
983                                                        DBUS_TYPE_STRING,
984                                                        &l->data);
985
986                 dbus_message_iter_close_container(&value, &arrayIter);
987
988                 /* close vararg*/
989                 dbus_message_iter_close_container(&entry, &value);
990
991                 /* close entry */
992                 dbus_message_iter_close_container(&dict, &entry);
993         }
994
995         if (args->pathloss != DISTANCE_VAL_INVALID)
996                 dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
997                                   &args->pathloss);
998
999         if (args->rssi != DISTANCE_VAL_INVALID)
1000                 dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, &args->rssi);
1001
1002         if (args->transport != NULL)
1003                 dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
1004                                   &args->transport);
1005
1006         dbus_message_iter_close_container(iter, &dict);
1007 }
1008
1009
1010 static void set_discovery_filter_reply(DBusMessage *message,
1011                                        void *user_data)
1012 {
1013         DBusError error;
1014
1015         dbus_error_init(&error);
1016         if (dbus_set_error_from_message(&error, message) == TRUE) {
1017                 rl_printf("SetDiscoveryFilter failed: %s\n", error.name);
1018                 dbus_error_free(&error);
1019                 return;
1020         }
1021
1022         rl_printf("SetDiscoveryFilter success\n");
1023 }
1024
1025 static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
1026 static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1027 static GSList *filtered_scan_uuids;
1028 static char *filtered_scan_transport;
1029
1030 static void cmd_set_scan_filter_commit(void)
1031 {
1032         struct set_discovery_filter_args args;
1033
1034         args.uuids = NULL;
1035         args.pathloss = filtered_scan_pathloss;
1036         args.rssi = filtered_scan_rssi;
1037         args.transport = filtered_scan_transport;
1038         args.uuids = filtered_scan_uuids;
1039
1040         if (check_default_ctrl() == FALSE)
1041                 return;
1042
1043         if (g_dbus_proxy_method_call(default_ctrl, "SetDiscoveryFilter",
1044                 set_discovery_filter_setup, set_discovery_filter_reply,
1045                 &args, NULL) == FALSE) {
1046                 rl_printf("Failed to set discovery filter\n");
1047                 return;
1048         }
1049 }
1050
1051 static void cmd_set_scan_filter_uuids(const char *arg)
1052 {
1053         char *uuid_str, *saveptr, *uuids, *uuidstmp;
1054
1055         g_slist_free_full(filtered_scan_uuids, g_free);
1056         filtered_scan_uuids = NULL;
1057
1058         if (!arg || !strlen(arg))
1059                 return;
1060
1061         uuids = g_strdup(arg);
1062         for (uuidstmp = uuids; ; uuidstmp = NULL) {
1063                 uuid_str = strtok_r(uuidstmp, " \t", &saveptr);
1064                 if (uuid_str == NULL)
1065                         break;
1066             filtered_scan_uuids = g_slist_append(filtered_scan_uuids,
1067                                                         strdup(uuid_str));
1068         }
1069
1070         g_free(uuids);
1071
1072         cmd_set_scan_filter_commit();
1073 }
1074
1075 static void cmd_set_scan_filter_rssi(const char *arg)
1076 {
1077         filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1078
1079         if (!arg || !strlen(arg))
1080                 filtered_scan_rssi = DISTANCE_VAL_INVALID;
1081         else
1082                 filtered_scan_rssi = atoi(arg);
1083
1084         cmd_set_scan_filter_commit();
1085 }
1086
1087 static void cmd_set_scan_filter_pathloss(const char *arg)
1088 {
1089         filtered_scan_rssi = DISTANCE_VAL_INVALID;
1090
1091         if (!arg || !strlen(arg))
1092                 filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1093         else
1094                 filtered_scan_pathloss = atoi(arg);
1095
1096         cmd_set_scan_filter_commit();
1097 }
1098
1099 static void cmd_set_scan_filter_transport(const char *arg)
1100 {
1101         g_free(filtered_scan_transport);
1102
1103         if (!arg || !strlen(arg))
1104                 filtered_scan_transport = NULL;
1105         else
1106                 filtered_scan_transport = g_strdup(arg);
1107
1108         cmd_set_scan_filter_commit();
1109 }
1110
1111 static void cmd_set_scan_filter_clear(const char *arg)
1112 {
1113         /* set default values for all options */
1114         filtered_scan_rssi = DISTANCE_VAL_INVALID;
1115         filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1116         g_slist_free_full(filtered_scan_uuids, g_free);
1117         filtered_scan_uuids = NULL;
1118         g_free(filtered_scan_transport);
1119         filtered_scan_transport = NULL;
1120
1121         cmd_set_scan_filter_commit();
1122 }
1123
1124 static struct GDBusProxy *find_device(const char *arg)
1125 {
1126         GDBusProxy *proxy;
1127
1128         if (!arg || !strlen(arg)) {
1129                 if (default_dev)
1130                         return default_dev;
1131                 rl_printf("Missing device address argument\n");
1132                 return NULL;
1133         }
1134
1135         proxy = find_proxy_by_address(dev_list, arg);
1136         if (!proxy) {
1137                 rl_printf("Device %s not available\n", arg);
1138                 return NULL;
1139         }
1140
1141         return proxy;
1142 }
1143
1144 static void cmd_info(const char *arg)
1145 {
1146         GDBusProxy *proxy;
1147         DBusMessageIter iter;
1148         const char *address;
1149
1150         proxy = find_device(arg);
1151         if (!proxy)
1152                 return;
1153
1154         if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
1155                 return;
1156
1157         dbus_message_iter_get_basic(&iter, &address);
1158         rl_printf("Device %s\n", address);
1159
1160         print_property(proxy, "Name");
1161         print_property(proxy, "Alias");
1162         print_property(proxy, "Class");
1163         print_property(proxy, "Appearance");
1164         print_property(proxy, "Icon");
1165         print_property(proxy, "Paired");
1166         print_property(proxy, "Trusted");
1167         print_property(proxy, "Blocked");
1168         print_property(proxy, "Connected");
1169         print_property(proxy, "LegacyPairing");
1170         print_uuids(proxy);
1171         print_property(proxy, "Modalias");
1172 #ifdef __TIZEN_PATCH__
1173         print_property(proxy, "Flag");
1174         print_property(proxy, "ManufacturerDataLen");
1175 #endif
1176         print_property(proxy, "ManufacturerData");
1177         print_property(proxy, "ServiceData");
1178         print_property(proxy, "RSSI");
1179         print_property(proxy, "TxPower");
1180 }
1181
1182 static void pair_reply(DBusMessage *message, void *user_data)
1183 {
1184         DBusError error;
1185
1186         dbus_error_init(&error);
1187
1188         if (dbus_set_error_from_message(&error, message) == TRUE) {
1189                 rl_printf("Failed to pair: %s\n", error.name);
1190                 dbus_error_free(&error);
1191                 return;
1192         }
1193
1194         rl_printf("Pairing successful\n");
1195 }
1196
1197 static void cmd_pair(const char *arg)
1198 {
1199         GDBusProxy *proxy;
1200
1201         proxy = find_device(arg);
1202         if (!proxy)
1203                 return;
1204
1205         if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
1206                                                         NULL, NULL) == FALSE) {
1207                 rl_printf("Failed to pair\n");
1208                 return;
1209         }
1210
1211         rl_printf("Attempting to pair with %s\n", arg);
1212 }
1213
1214 static void cmd_trust(const char *arg)
1215 {
1216         GDBusProxy *proxy;
1217         dbus_bool_t trusted;
1218         char *str;
1219
1220         proxy = find_device(arg);
1221         if (!proxy)
1222                 return;
1223
1224         trusted = TRUE;
1225
1226         str = g_strdup_printf("%s trust", arg);
1227
1228         if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1229                                         DBUS_TYPE_BOOLEAN, &trusted,
1230                                         generic_callback, str, g_free) == TRUE)
1231                 return;
1232
1233         g_free(str);
1234 }
1235
1236 static void cmd_untrust(const char *arg)
1237 {
1238         GDBusProxy *proxy;
1239         dbus_bool_t trusted;
1240         char *str;
1241
1242         proxy = find_device(arg);
1243         if (!proxy)
1244                 return;
1245
1246         trusted = FALSE;
1247
1248         str = g_strdup_printf("%s untrust", arg);
1249
1250         if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1251                                         DBUS_TYPE_BOOLEAN, &trusted,
1252                                         generic_callback, str, g_free) == TRUE)
1253                 return;
1254
1255         g_free(str);
1256 }
1257
1258 static void cmd_block(const char *arg)
1259 {
1260         GDBusProxy *proxy;
1261         dbus_bool_t blocked;
1262         char *str;
1263
1264         proxy = find_device(arg);
1265         if (!proxy)
1266                 return;
1267
1268         blocked = TRUE;
1269
1270         str = g_strdup_printf("%s block", arg);
1271
1272         if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1273                                         DBUS_TYPE_BOOLEAN, &blocked,
1274                                         generic_callback, str, g_free) == TRUE)
1275                 return;
1276
1277         g_free(str);
1278 }
1279
1280 static void cmd_unblock(const char *arg)
1281 {
1282         GDBusProxy *proxy;
1283         dbus_bool_t blocked;
1284         char *str;
1285
1286         proxy = find_device(arg);
1287         if (!proxy)
1288                 return;
1289
1290         blocked = FALSE;
1291
1292         str = g_strdup_printf("%s unblock", arg);
1293
1294         if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1295                                         DBUS_TYPE_BOOLEAN, &blocked,
1296                                         generic_callback, str, g_free) == TRUE)
1297                 return;
1298
1299         g_free(str);
1300 }
1301
1302 static void remove_device_reply(DBusMessage *message, void *user_data)
1303 {
1304         DBusError error;
1305
1306         dbus_error_init(&error);
1307
1308         if (dbus_set_error_from_message(&error, message) == TRUE) {
1309                 rl_printf("Failed to remove device: %s\n", error.name);
1310                 dbus_error_free(&error);
1311                 return;
1312         }
1313
1314         rl_printf("Device has been removed\n");
1315 }
1316
1317 static void remove_device_setup(DBusMessageIter *iter, void *user_data)
1318 {
1319         const char *path = user_data;
1320
1321         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
1322 }
1323
1324 static void cmd_remove(const char *arg)
1325 {
1326         GDBusProxy *proxy;
1327         char *path;
1328
1329         if (!arg || !strlen(arg)) {
1330                 rl_printf("Missing device address argument\n");
1331                 return;
1332         }
1333
1334         if (check_default_ctrl() == FALSE)
1335                 return;
1336
1337         proxy = find_proxy_by_address(dev_list, arg);
1338         if (!proxy) {
1339                 rl_printf("Device %s not available\n", arg);
1340                 return;
1341         }
1342
1343         path = g_strdup(g_dbus_proxy_get_path(proxy));
1344
1345         if (g_dbus_proxy_method_call(default_ctrl, "RemoveDevice",
1346                                                 remove_device_setup,
1347                                                 remove_device_reply,
1348                                                 path, g_free) == FALSE) {
1349                 rl_printf("Failed to remove device\n");
1350                 g_free(path);
1351                 return;
1352         }
1353 }
1354
1355 static void connect_reply(DBusMessage *message, void *user_data)
1356 {
1357         GDBusProxy *proxy = user_data;
1358         DBusError error;
1359
1360         dbus_error_init(&error);
1361
1362         if (dbus_set_error_from_message(&error, message) == TRUE) {
1363                 rl_printf("Failed to connect: %s\n", error.name);
1364                 dbus_error_free(&error);
1365                 return;
1366         }
1367
1368         rl_printf("Connection successful\n");
1369
1370         set_default_device(proxy, NULL);
1371 }
1372
1373 static void cmd_connect(const char *arg)
1374 {
1375         GDBusProxy *proxy;
1376
1377         if (!arg || !strlen(arg)) {
1378                 rl_printf("Missing device address argument\n");
1379                 return;
1380         }
1381
1382         proxy = find_proxy_by_address(dev_list, arg);
1383         if (!proxy) {
1384                 rl_printf("Device %s not available\n", arg);
1385                 return;
1386         }
1387
1388         if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
1389                                                         proxy, NULL) == FALSE) {
1390                 rl_printf("Failed to connect\n");
1391                 return;
1392         }
1393
1394         rl_printf("Attempting to connect to %s\n", arg);
1395 }
1396
1397 static void disconn_reply(DBusMessage *message, void *user_data)
1398 {
1399         GDBusProxy *proxy = user_data;
1400         DBusError error;
1401
1402         dbus_error_init(&error);
1403
1404         if (dbus_set_error_from_message(&error, message) == TRUE) {
1405                 rl_printf("Failed to disconnect: %s\n", error.name);
1406                 dbus_error_free(&error);
1407                 return;
1408         }
1409
1410         rl_printf("Successful disconnected\n");
1411
1412         if (proxy != default_dev)
1413                 return;
1414
1415         set_default_device(NULL, NULL);
1416 }
1417
1418 static void cmd_disconn(const char *arg)
1419 {
1420         GDBusProxy *proxy;
1421
1422         proxy = find_device(arg);
1423         if (!proxy)
1424                 return;
1425
1426         if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
1427                                                         proxy, NULL) == FALSE) {
1428                 rl_printf("Failed to disconnect\n");
1429                 return;
1430         }
1431         if (strlen(arg) == 0) {
1432                 DBusMessageIter iter;
1433
1434                 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == TRUE)
1435                         dbus_message_iter_get_basic(&iter, &arg);
1436         }
1437         rl_printf("Attempting to disconnect from %s\n", arg);
1438 }
1439
1440 static void cmd_list_attributes(const char *arg)
1441 {
1442         GDBusProxy *proxy;
1443
1444         proxy = find_device(arg);
1445         if (!proxy)
1446                 return;
1447
1448         gatt_list_attributes(g_dbus_proxy_get_path(proxy));
1449 }
1450
1451 static void cmd_select_attribute(const char *arg)
1452 {
1453         GDBusProxy *proxy;
1454
1455         if (!arg || !strlen(arg)) {
1456                 rl_printf("Missing attribute argument\n");
1457                 return;
1458         }
1459
1460         if (!default_dev) {
1461                 rl_printf("No device connected\n");
1462                 return;
1463         }
1464
1465         proxy = gatt_select_attribute(arg);
1466         if (proxy)
1467                 set_default_attribute(proxy);
1468 }
1469
1470 static struct GDBusProxy *find_attribute(const char *arg)
1471 {
1472         GDBusProxy *proxy;
1473
1474         if (!arg || !strlen(arg)) {
1475                 if (default_attr)
1476                         return default_attr;
1477                 rl_printf("Missing attribute argument\n");
1478                 return NULL;
1479         }
1480
1481         proxy = gatt_select_attribute(arg);
1482         if (!proxy) {
1483                 rl_printf("Attribute %s not available\n", arg);
1484                 return NULL;
1485         }
1486
1487         return proxy;
1488 }
1489
1490 static void cmd_attribute_info(const char *arg)
1491 {
1492         GDBusProxy *proxy;
1493         DBusMessageIter iter;
1494         const char *iface, *uuid, *text;
1495
1496         proxy = find_attribute(arg);
1497         if (!proxy)
1498                 return;
1499
1500         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
1501                 return;
1502
1503         dbus_message_iter_get_basic(&iter, &uuid);
1504
1505         text = uuidstr_to_str(uuid);
1506         if (!text)
1507                 text = g_dbus_proxy_get_path(proxy);
1508
1509         iface = g_dbus_proxy_get_interface(proxy);
1510         if (!strcmp(iface, "org.bluez.GattService1")) {
1511                 rl_printf("Service - %s\n", text);
1512
1513                 print_property(proxy, "UUID");
1514                 print_property(proxy, "Primary");
1515                 print_property(proxy, "Characteristics");
1516                 print_property(proxy, "Includes");
1517         } else if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
1518                 rl_printf("Characteristic - %s\n", text);
1519
1520                 print_property(proxy, "UUID");
1521                 print_property(proxy, "Service");
1522                 print_property(proxy, "Value");
1523                 print_property(proxy, "Notifying");
1524                 print_property(proxy, "Flags");
1525                 print_property(proxy, "Descriptors");
1526         } else if (!strcmp(iface, "org.bluez.GattDescriptor1")) {
1527                 rl_printf("Descriptor - %s\n", text);
1528
1529                 print_property(proxy, "UUID");
1530                 print_property(proxy, "Characteristic");
1531                 print_property(proxy, "Value");
1532         }
1533 }
1534
1535 static void cmd_read(const char *arg)
1536 {
1537         if (!default_attr) {
1538                 rl_printf("No attribute selected\n");
1539                 return;
1540         }
1541
1542         gatt_read_attribute(default_attr);
1543 }
1544
1545 static void cmd_write(const char *arg)
1546 {
1547         if (!arg || !strlen(arg)) {
1548                 rl_printf("Missing data argument\n");
1549                 return;
1550         }
1551
1552         if (!default_attr) {
1553                 rl_printf("No attribute selected\n");
1554                 return;
1555         }
1556
1557         gatt_write_attribute(default_attr, arg);
1558 }
1559
1560 static void cmd_notify(const char *arg)
1561 {
1562         dbus_bool_t enable;
1563
1564         if (parse_argument_on_off(arg, &enable) == FALSE)
1565                 return;
1566
1567         if (!default_attr) {
1568                 rl_printf("No attribute selected\n");
1569                 return;
1570         }
1571
1572         gatt_notify_attribute(default_attr, enable ? true : false);
1573 }
1574
1575 static void cmd_register_profile(const char *arg)
1576 {
1577         wordexp_t w;
1578
1579         if (check_default_ctrl() == FALSE)
1580                 return;
1581
1582         if (wordexp(arg, &w, WRDE_NOCMD)) {
1583                 rl_printf("Invalid argument\n");
1584                 return;
1585         }
1586
1587         if (w.we_wordc == 0) {
1588                 rl_printf("Missing argument\n");
1589                 return;
1590         }
1591
1592         gatt_register_profile(dbus_conn, default_ctrl, &w);
1593
1594         wordfree(&w);
1595 }
1596
1597 static void cmd_unregister_profile(const char *arg)
1598 {
1599         if (check_default_ctrl() == FALSE)
1600                 return;
1601
1602         gatt_unregister_profile(dbus_conn, default_ctrl);
1603 }
1604
1605 static void cmd_version(const char *arg)
1606 {
1607         rl_printf("Version %s\n", VERSION);
1608 }
1609
1610 static void cmd_quit(const char *arg)
1611 {
1612         g_main_loop_quit(main_loop);
1613 }
1614
1615 static char *generic_generator(const char *text, int state,
1616                                         GList *source, const char *property)
1617 {
1618         static int index, len;
1619         GList *list;
1620
1621         if (!state) {
1622                 index = 0;
1623                 len = strlen(text);
1624         }
1625
1626         for (list = g_list_nth(source, index); list;
1627                                                 list = g_list_next(list)) {
1628                 GDBusProxy *proxy = list->data;
1629                 DBusMessageIter iter;
1630                 const char *str;
1631
1632                 index++;
1633
1634                 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
1635                         continue;
1636
1637                 dbus_message_iter_get_basic(&iter, &str);
1638
1639                 if (!strncmp(str, text, len))
1640                         return strdup(str);
1641         }
1642
1643         return NULL;
1644 }
1645
1646 static char *ctrl_generator(const char *text, int state)
1647 {
1648         return generic_generator(text, state, ctrl_list, "Address");
1649 }
1650
1651 static char *dev_generator(const char *text, int state)
1652 {
1653         return generic_generator(text, state, dev_list, "Address");
1654 }
1655
1656 static char *attribute_generator(const char *text, int state)
1657 {
1658         return gatt_attribute_generator(text, state);
1659 }
1660
1661 static char *capability_generator(const char *text, int state)
1662 {
1663         static int index, len;
1664         const char *arg;
1665
1666         if (!state) {
1667                 index = 0;
1668                 len = strlen(text);
1669         }
1670
1671         while ((arg = agent_arguments[index])) {
1672                 index++;
1673
1674                 if (!strncmp(arg, text, len))
1675                         return strdup(arg);
1676         }
1677
1678         return NULL;
1679 }
1680
1681 static const struct {
1682         const char *cmd;
1683         const char *arg;
1684         void (*func) (const char *arg);
1685         const char *desc;
1686         char * (*gen) (const char *text, int state);
1687         void (*disp) (char **matches, int num_matches, int max_length);
1688 } cmd_table[] = {
1689         { "list",         NULL,       cmd_list, "List available controllers" },
1690         { "show",         "[ctrl]",   cmd_show, "Controller information",
1691                                                         ctrl_generator },
1692         { "select",       "<ctrl>",   cmd_select, "Select default controller",
1693                                                         ctrl_generator },
1694         { "devices",      NULL,       cmd_devices, "List available devices" },
1695         { "paired-devices", NULL,     cmd_paired_devices,
1696                                         "List paired devices"},
1697         { "system-alias", "<name>",   cmd_system_alias },
1698         { "reset-alias",  NULL,       cmd_reset_alias },
1699         { "power",        "<on/off>", cmd_power, "Set controller power" },
1700         { "pairable",     "<on/off>", cmd_pairable,
1701                                         "Set controller pairable mode" },
1702         { "discoverable", "<on/off>", cmd_discoverable,
1703                                         "Set controller discoverable mode" },
1704         { "agent",        "<on/off/capability>", cmd_agent,
1705                                 "Enable/disable agent with given capability",
1706                                                         capability_generator},
1707         { "default-agent",NULL,       cmd_default_agent,
1708                                 "Set agent as the default one" },
1709         { "set-scan-filter-uuids", "[uuid1 uuid2 ...]",
1710                         cmd_set_scan_filter_uuids, "Set scan filter uuids" },
1711         { "set-scan-filter-rssi", "[rssi]", cmd_set_scan_filter_rssi,
1712                                 "Set scan filter rssi, and clears pathloss" },
1713         { "set-scan-filter-pathloss", "[pathloss]",
1714                                                 cmd_set_scan_filter_pathloss,
1715                                 "Set scan filter pathloss, and clears rssi" },
1716         { "set-scan-filter-transport", "[transport]",
1717                 cmd_set_scan_filter_transport, "Set scan filter transport" },
1718         { "set-scan-filter-clear", "", cmd_set_scan_filter_clear,
1719                                                 "Clears discovery filter." },
1720         { "scan",         "<on/off>", cmd_scan, "Scan for devices" },
1721         { "info",         "[dev]",    cmd_info, "Device information",
1722                                                         dev_generator },
1723         { "pair",         "[dev]",    cmd_pair, "Pair with device",
1724                                                         dev_generator },
1725         { "trust",        "[dev]",    cmd_trust, "Trust device",
1726                                                         dev_generator },
1727         { "untrust",      "[dev]",    cmd_untrust, "Untrust device",
1728                                                         dev_generator },
1729         { "block",        "[dev]",    cmd_block, "Block device",
1730                                                                 dev_generator },
1731         { "unblock",      "[dev]",    cmd_unblock, "Unblock device",
1732                                                                 dev_generator },
1733         { "remove",       "<dev>",    cmd_remove, "Remove device",
1734                                                         dev_generator },
1735         { "connect",      "<dev>",    cmd_connect, "Connect device",
1736                                                         dev_generator },
1737         { "disconnect",   "[dev]",    cmd_disconn, "Disconnect device",
1738                                                         dev_generator },
1739         { "list-attributes", "[dev]", cmd_list_attributes, "List attributes",
1740                                                         dev_generator },
1741         { "select-attribute", "<attribute>",  cmd_select_attribute,
1742                                 "Select attribute", attribute_generator },
1743         { "attribute-info", "[attribute]",  cmd_attribute_info,
1744                                 "Select attribute", attribute_generator },
1745         { "read",         NULL,       cmd_read, "Read attribute value" },
1746         { "write",        "<data=[xx xx ...]>", cmd_write,
1747                                                 "Write attribute value" },
1748         { "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
1749         { "register-profile", "<UUID ...>", cmd_register_profile,
1750                                                 "Register profile to connect" },
1751         { "unregister-profile", NULL, cmd_unregister_profile,
1752                                                 "Unregister profile" },
1753         { "version",      NULL,       cmd_version, "Display version" },
1754         { "quit",         NULL,       cmd_quit, "Quit program" },
1755         { "exit",         NULL,       cmd_quit },
1756         { "help" },
1757         { }
1758 };
1759
1760 static char *cmd_generator(const char *text, int state)
1761 {
1762         static int index, len;
1763         const char *cmd;
1764
1765         if (!state) {
1766                 index = 0;
1767                 len = strlen(text);
1768         }
1769
1770         while ((cmd = cmd_table[index].cmd)) {
1771                 index++;
1772
1773                 if (!strncmp(cmd, text, len))
1774                         return strdup(cmd);
1775         }
1776
1777         return NULL;
1778 }
1779
1780 static char **cmd_completion(const char *text, int start, int end)
1781 {
1782         char **matches = NULL;
1783
1784         if (agent_completion() == TRUE) {
1785                 rl_attempted_completion_over = 1;
1786                 return NULL;
1787         }
1788
1789         if (start > 0) {
1790                 int i;
1791
1792                 for (i = 0; cmd_table[i].cmd; i++) {
1793                         if (strncmp(cmd_table[i].cmd,
1794                                         rl_line_buffer, start - 1))
1795                                 continue;
1796
1797                         if (!cmd_table[i].gen)
1798                                 continue;
1799
1800                         rl_completion_display_matches_hook = cmd_table[i].disp;
1801                         matches = rl_completion_matches(text, cmd_table[i].gen);
1802                         break;
1803                 }
1804         } else {
1805                 rl_completion_display_matches_hook = NULL;
1806                 matches = rl_completion_matches(text, cmd_generator);
1807         }
1808
1809         if (!matches)
1810                 rl_attempted_completion_over = 1;
1811
1812         return matches;
1813 }
1814
1815 static void rl_handler(char *input)
1816 {
1817         char *cmd, *arg;
1818         int i;
1819
1820         if (!input) {
1821                 rl_insert_text("quit");
1822                 rl_redisplay();
1823                 rl_crlf();
1824                 g_main_loop_quit(main_loop);
1825                 return;
1826         }
1827
1828         if (!strlen(input))
1829                 goto done;
1830
1831         if (agent_input(dbus_conn, input) == TRUE)
1832                 goto done;
1833
1834         add_history(input);
1835
1836         cmd = strtok_r(input, " ", &arg);
1837         if (!cmd)
1838                 goto done;
1839
1840         if (arg) {
1841                 int len = strlen(arg);
1842                 if (len > 0 && arg[len - 1] == ' ')
1843                         arg[len - 1] = '\0';
1844         }
1845
1846         for (i = 0; cmd_table[i].cmd; i++) {
1847                 if (strcmp(cmd, cmd_table[i].cmd))
1848                         continue;
1849
1850                 if (cmd_table[i].func) {
1851                         cmd_table[i].func(arg);
1852                         goto done;
1853                 }
1854         }
1855
1856         if (strcmp(cmd, "help")) {
1857                 printf("Invalid command\n");
1858                 goto done;
1859         }
1860
1861         printf("Available commands:\n");
1862
1863         for (i = 0; cmd_table[i].cmd; i++) {
1864                 if (cmd_table[i].desc)
1865                         printf("  %s %-*s %s\n", cmd_table[i].cmd,
1866                                         (int)(25 - strlen(cmd_table[i].cmd)),
1867                                         cmd_table[i].arg ? : "",
1868                                         cmd_table[i].desc ? : "");
1869         }
1870
1871 done:
1872         free(input);
1873 }
1874
1875 static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
1876                                                         gpointer user_data)
1877 {
1878         if (condition & G_IO_IN) {
1879                 rl_callback_read_char();
1880                 return TRUE;
1881         }
1882
1883         if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1884                 g_main_loop_quit(main_loop);
1885                 return FALSE;
1886         }
1887
1888         return TRUE;
1889 }
1890
1891 static guint setup_standard_input(void)
1892 {
1893         GIOChannel *channel;
1894         guint source;
1895
1896         channel = g_io_channel_unix_new(fileno(stdin));
1897
1898         source = g_io_add_watch(channel,
1899                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
1900                                 input_handler, NULL);
1901
1902         g_io_channel_unref(channel);
1903
1904         return source;
1905 }
1906
1907 static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
1908                                                         gpointer user_data)
1909 {
1910         static bool terminated = false;
1911         struct signalfd_siginfo si;
1912         ssize_t result;
1913         int fd;
1914
1915         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
1916                 g_main_loop_quit(main_loop);
1917                 return FALSE;
1918         }
1919
1920         fd = g_io_channel_unix_get_fd(channel);
1921
1922         result = read(fd, &si, sizeof(si));
1923         if (result != sizeof(si))
1924                 return FALSE;
1925
1926         switch (si.ssi_signo) {
1927         case SIGINT:
1928                 if (input) {
1929                         rl_replace_line("", 0);
1930                         rl_crlf();
1931                         rl_on_new_line();
1932                         rl_redisplay();
1933                         break;
1934                 }
1935
1936                 /*
1937                  * If input was not yet setup up that means signal was received
1938                  * while daemon was not yet running. Since user is not able
1939                  * to terminate client by CTRL-D or typing exit treat this as
1940                  * exit and fall through.
1941                  */
1942         case SIGTERM:
1943                 if (!terminated) {
1944                         rl_replace_line("", 0);
1945                         rl_crlf();
1946                         g_main_loop_quit(main_loop);
1947                 }
1948
1949                 terminated = true;
1950                 break;
1951         }
1952
1953         return TRUE;
1954 }
1955
1956 static guint setup_signalfd(void)
1957 {
1958         GIOChannel *channel;
1959         guint source;
1960         sigset_t mask;
1961         int fd;
1962
1963         sigemptyset(&mask);
1964         sigaddset(&mask, SIGINT);
1965         sigaddset(&mask, SIGTERM);
1966
1967         if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
1968                 perror("Failed to set signal mask");
1969                 return 0;
1970         }
1971
1972         fd = signalfd(-1, &mask, 0);
1973         if (fd < 0) {
1974                 perror("Failed to create signal descriptor");
1975                 return 0;
1976         }
1977
1978         channel = g_io_channel_unix_new(fd);
1979
1980         g_io_channel_set_close_on_unref(channel, TRUE);
1981         g_io_channel_set_encoding(channel, NULL, NULL);
1982         g_io_channel_set_buffered(channel, FALSE);
1983
1984         source = g_io_add_watch(channel,
1985                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
1986                                 signal_handler, NULL);
1987
1988         g_io_channel_unref(channel);
1989
1990         return source;
1991 }
1992
1993 static gboolean option_version = FALSE;
1994
1995 static gboolean parse_agent(const char *key, const char *value,
1996                                         gpointer user_data, GError **error)
1997 {
1998         if (value)
1999                 auto_register_agent = g_strdup(value);
2000         else
2001                 auto_register_agent = g_strdup("");
2002
2003         return TRUE;
2004 }
2005
2006 static GOptionEntry options[] = {
2007         { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
2008                                 "Show version information and exit" },
2009         { "agent", 'a', G_OPTION_FLAG_OPTIONAL_ARG,
2010                                 G_OPTION_ARG_CALLBACK, parse_agent,
2011                                 "Register agent handler", "CAPABILITY" },
2012         { NULL },
2013 };
2014
2015 static void client_ready(GDBusClient *client, void *user_data)
2016 {
2017         guint *input = user_data;
2018
2019         *input = setup_standard_input();
2020 }
2021
2022 int main(int argc, char *argv[])
2023 {
2024         GOptionContext *context;
2025         GError *error = NULL;
2026         GDBusClient *client;
2027         guint signal;
2028
2029         context = g_option_context_new(NULL);
2030         g_option_context_add_main_entries(context, options, NULL);
2031
2032         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
2033                 if (error != NULL) {
2034                         g_printerr("%s\n", error->message);
2035                         g_error_free(error);
2036                 } else
2037                         g_printerr("An unknown error occurred\n");
2038                 exit(1);
2039         }
2040
2041         g_option_context_free(context);
2042
2043         if (option_version == TRUE) {
2044                 printf("%s\n", VERSION);
2045                 exit(0);
2046         }
2047
2048         main_loop = g_main_loop_new(NULL, FALSE);
2049         dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
2050
2051         rl_attempted_completion_function = cmd_completion;
2052
2053         rl_erase_empty_line = 1;
2054         rl_callback_handler_install(NULL, rl_handler);
2055
2056         rl_set_prompt(PROMPT_OFF);
2057         rl_redisplay();
2058
2059         signal = setup_signalfd();
2060         client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
2061
2062         g_dbus_client_set_connect_watch(client, connect_handler, NULL);
2063         g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
2064         g_dbus_client_set_signal_watch(client, message_handler, NULL);
2065
2066         g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
2067                                                         property_changed, NULL);
2068
2069         input = 0;
2070         g_dbus_client_set_ready_watch(client, client_ready, &input);
2071
2072         g_main_loop_run(main_loop);
2073
2074         g_dbus_client_unref(client);
2075         g_source_remove(signal);
2076         if (input > 0)
2077                 g_source_remove(input);
2078
2079         rl_message("");
2080         rl_callback_handler_remove();
2081
2082         dbus_connection_unref(dbus_conn);
2083         g_main_loop_unref(main_loop);
2084
2085         g_list_free_full(ctrl_list, proxy_leak);
2086         g_list_free_full(dev_list, proxy_leak);
2087
2088         g_free(auto_register_agent);
2089
2090         return 0;
2091 }