24509f636d7142d061a0b1d57079e273b7c2bd00
[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 <wordexp.h>
34
35 #include <glib.h>
36
37 #include "src/shared/shell.h"
38 #include "src/shared/util.h"
39 #include "gdbus/gdbus.h"
40 #include "agent.h"
41 #include "gatt.h"
42 #include "advertising.h"
43
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
48
49 #define PROMPT_ON       COLOR_BLUE "[bluetooth]" COLOR_OFF "# "
50 #define PROMPT_OFF      "Waiting to connect to bluetoothd..."
51
52 static DBusConnection *dbus_conn;
53
54 static GDBusProxy *agent_manager;
55 static char *auto_register_agent = NULL;
56
57 struct adapter {
58         GDBusProxy *proxy;
59         GDBusProxy *ad_proxy;
60         GList *devices;
61 };
62
63 static struct adapter *default_ctrl;
64 static GDBusProxy *default_dev;
65 static GDBusProxy *default_attr;
66 static GList *ctrl_list;
67 static GList *battery_proxies;
68
69 static const char *agent_arguments[] = {
70         "on",
71         "off",
72         "DisplayOnly",
73         "DisplayYesNo",
74         "KeyboardDisplay",
75         "KeyboardOnly",
76         "NoInputNoOutput",
77         NULL
78 };
79
80 static const char *ad_arguments[] = {
81         "on",
82         "off",
83         "peripheral",
84         "broadcast",
85         NULL
86 };
87
88 static void proxy_leak(gpointer data)
89 {
90         printf("Leaking proxy %p\n", data);
91 }
92
93 static void setup_standard_input(void)
94 {
95         bt_shell_attach(fileno(stdin));
96 }
97
98 static void connect_handler(DBusConnection *connection, void *user_data)
99 {
100         bt_shell_set_prompt(PROMPT_ON);
101 }
102
103 static void disconnect_handler(DBusConnection *connection, void *user_data)
104 {
105         bt_shell_detach();
106
107         bt_shell_set_prompt(PROMPT_OFF);
108
109         g_list_free_full(ctrl_list, proxy_leak);
110         g_list_free_full(battery_proxies, proxy_leak);
111         ctrl_list = NULL;
112         battery_proxies = NULL;
113
114         default_ctrl = NULL;
115 }
116
117 static void print_adapter(GDBusProxy *proxy, const char *description)
118 {
119         DBusMessageIter iter;
120         const char *address, *name;
121
122         if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
123                 return;
124
125         dbus_message_iter_get_basic(&iter, &address);
126
127         if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
128                 dbus_message_iter_get_basic(&iter, &name);
129         else
130                 name = "<unknown>";
131
132         bt_shell_printf("%s%s%sController %s %s %s\n",
133                                 description ? "[" : "",
134                                 description ? : "",
135                                 description ? "] " : "",
136                                 address, name,
137                                 default_ctrl &&
138                                 default_ctrl->proxy == proxy ?
139                                 "[default]" : "");
140
141 }
142
143 static void print_device(GDBusProxy *proxy, const char *description)
144 {
145         DBusMessageIter iter;
146         const char *address, *name;
147
148         if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
149                 return;
150
151         dbus_message_iter_get_basic(&iter, &address);
152
153         if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
154                 dbus_message_iter_get_basic(&iter, &name);
155         else
156                 name = "<unknown>";
157
158         bt_shell_printf("%s%s%sDevice %s %s\n",
159                                 description ? "[" : "",
160                                 description ? : "",
161                                 description ? "] " : "",
162                                 address, name);
163 }
164
165 static void print_fixed_iter(const char *label, const char *name,
166                                                 DBusMessageIter *iter)
167 {
168         dbus_bool_t *valbool;
169         dbus_uint32_t *valu32;
170         dbus_uint16_t *valu16;
171         dbus_int16_t *vals16;
172         unsigned char *byte;
173         int len;
174
175         switch (dbus_message_iter_get_arg_type(iter)) {
176         case DBUS_TYPE_BOOLEAN:
177                 dbus_message_iter_get_fixed_array(iter, &valbool, &len);
178
179                 if (len <= 0)
180                         return;
181
182                 bt_shell_printf("%s%s:\n", label, name);
183                 bt_shell_hexdump((void *)valbool, len * sizeof(*valbool));
184
185                 break;
186         case DBUS_TYPE_UINT32:
187                 dbus_message_iter_get_fixed_array(iter, &valu32, &len);
188
189                 if (len <= 0)
190                         return;
191
192                 bt_shell_printf("%s%s:\n", label, name);
193                 bt_shell_hexdump((void *)valu32, len * sizeof(*valu32));
194
195                 break;
196         case DBUS_TYPE_UINT16:
197                 dbus_message_iter_get_fixed_array(iter, &valu16, &len);
198
199                 if (len <= 0)
200                         return;
201
202                 bt_shell_printf("%s%s:\n", label, name);
203                 bt_shell_hexdump((void *)valu16, len * sizeof(*valu16));
204
205                 break;
206         case DBUS_TYPE_INT16:
207                 dbus_message_iter_get_fixed_array(iter, &vals16, &len);
208
209                 if (len <= 0)
210                         return;
211
212                 bt_shell_printf("%s%s:\n", label, name);
213                 bt_shell_hexdump((void *)vals16, len * sizeof(*vals16));
214
215                 break;
216         case DBUS_TYPE_BYTE:
217                 dbus_message_iter_get_fixed_array(iter, &byte, &len);
218
219                 if (len <= 0)
220                         return;
221
222                 bt_shell_printf("%s%s:\n", label, name);
223                 bt_shell_hexdump((void *)byte, len * sizeof(*byte));
224
225                 break;
226         default:
227                 return;
228         };
229 }
230
231 static void print_iter(const char *label, const char *name,
232                                                 DBusMessageIter *iter)
233 {
234         dbus_bool_t valbool;
235         dbus_uint32_t valu32;
236         dbus_uint16_t valu16;
237         dbus_int16_t vals16;
238         unsigned char byte;
239         const char *valstr;
240         DBusMessageIter subiter;
241         char *entry;
242
243         if (iter == NULL) {
244                 bt_shell_printf("%s%s is nil\n", label, name);
245                 return;
246         }
247
248         switch (dbus_message_iter_get_arg_type(iter)) {
249         case DBUS_TYPE_INVALID:
250                 bt_shell_printf("%s%s is invalid\n", label, name);
251                 break;
252         case DBUS_TYPE_STRING:
253         case DBUS_TYPE_OBJECT_PATH:
254                 dbus_message_iter_get_basic(iter, &valstr);
255                 bt_shell_printf("%s%s: %s\n", label, name, valstr);
256                 break;
257         case DBUS_TYPE_BOOLEAN:
258                 dbus_message_iter_get_basic(iter, &valbool);
259                 bt_shell_printf("%s%s: %s\n", label, name,
260                                         valbool == TRUE ? "yes" : "no");
261                 break;
262         case DBUS_TYPE_UINT32:
263                 dbus_message_iter_get_basic(iter, &valu32);
264                 bt_shell_printf("%s%s: 0x%08x\n", label, name, valu32);
265                 break;
266         case DBUS_TYPE_UINT16:
267                 dbus_message_iter_get_basic(iter, &valu16);
268                 bt_shell_printf("%s%s: 0x%04x\n", label, name, valu16);
269                 break;
270         case DBUS_TYPE_INT16:
271                 dbus_message_iter_get_basic(iter, &vals16);
272                 bt_shell_printf("%s%s: %d\n", label, name, vals16);
273                 break;
274         case DBUS_TYPE_BYTE:
275                 dbus_message_iter_get_basic(iter, &byte);
276                 bt_shell_printf("%s%s: 0x%02x (%d)\n", label, name, byte, byte);
277                 break;
278         case DBUS_TYPE_VARIANT:
279                 dbus_message_iter_recurse(iter, &subiter);
280                 print_iter(label, name, &subiter);
281                 break;
282         case DBUS_TYPE_ARRAY:
283                 dbus_message_iter_recurse(iter, &subiter);
284
285                 if (dbus_type_is_fixed(
286                                 dbus_message_iter_get_arg_type(&subiter))) {
287                         print_fixed_iter(label, name, &subiter);
288                         break;
289                 }
290
291                 while (dbus_message_iter_get_arg_type(&subiter) !=
292                                                         DBUS_TYPE_INVALID) {
293                         print_iter(label, name, &subiter);
294                         dbus_message_iter_next(&subiter);
295                 }
296                 break;
297         case DBUS_TYPE_DICT_ENTRY:
298                 dbus_message_iter_recurse(iter, &subiter);
299                 entry = g_strconcat(name, " Key", NULL);
300                 print_iter(label, entry, &subiter);
301                 g_free(entry);
302
303                 entry = g_strconcat(name, " Value", NULL);
304                 dbus_message_iter_next(&subiter);
305                 print_iter(label, entry, &subiter);
306                 g_free(entry);
307                 break;
308         default:
309                 bt_shell_printf("%s%s has unsupported type\n", label, name);
310                 break;
311         }
312 }
313
314 static void print_property_with_label(GDBusProxy *proxy, const char *name,
315                                         const char *label)
316 {
317         DBusMessageIter iter;
318
319         if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
320                 return;
321
322         print_iter("\t", label ? label : name, &iter);
323 }
324
325 static void print_property(GDBusProxy *proxy, const char *name)
326 {
327         print_property_with_label(proxy, name, NULL);
328 }
329
330 static void print_uuid(const char *uuid)
331 {
332         const char *text;
333
334         text = bt_uuidstr_to_str(uuid);
335         if (text) {
336                 char str[26];
337                 unsigned int n;
338
339                 str[sizeof(str) - 1] = '\0';
340
341                 n = snprintf(str, sizeof(str), "%s", text);
342                 if (n > sizeof(str) - 1) {
343                         str[sizeof(str) - 2] = '.';
344                         str[sizeof(str) - 3] = '.';
345                         if (str[sizeof(str) - 4] == ' ')
346                                 str[sizeof(str) - 4] = '.';
347
348                         n = sizeof(str) - 1;
349                 }
350
351                 bt_shell_printf("\tUUID: %s%*c(%s)\n", str, 26 - n, ' ', uuid);
352         } else
353                 bt_shell_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
354 }
355
356 static void print_uuids(GDBusProxy *proxy)
357 {
358         DBusMessageIter iter, value;
359
360         if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
361                 return;
362
363         dbus_message_iter_recurse(&iter, &value);
364
365         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
366                 const char *uuid;
367
368                 dbus_message_iter_get_basic(&value, &uuid);
369
370                 print_uuid(uuid);
371
372                 dbus_message_iter_next(&value);
373         }
374 }
375
376 static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
377 {
378         DBusMessageIter iter;
379         const char *adapter, *path;
380
381         if (!master)
382                 return FALSE;
383
384         if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
385                 return FALSE;
386
387         dbus_message_iter_get_basic(&iter, &adapter);
388         path = g_dbus_proxy_get_path(master);
389
390         if (!strcmp(path, adapter))
391                 return TRUE;
392
393         return FALSE;
394 }
395
396 static gboolean service_is_child(GDBusProxy *service)
397 {
398         DBusMessageIter iter;
399         const char *device;
400
401         if (g_dbus_proxy_get_property(service, "Device", &iter) == FALSE)
402                 return FALSE;
403
404         dbus_message_iter_get_basic(&iter, &device);
405
406         if (!default_ctrl)
407                 return FALSE;
408
409         return g_dbus_proxy_lookup(default_ctrl->devices, NULL, device,
410                                         "org.bluez.Device1") != NULL;
411 }
412
413 static struct adapter *find_parent(GDBusProxy *device)
414 {
415         GList *list;
416
417         for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
418                 struct adapter *adapter = list->data;
419
420                 if (device_is_child(device, adapter->proxy) == TRUE)
421                         return adapter;
422         }
423         return NULL;
424 }
425
426 static void set_default_device(GDBusProxy *proxy, const char *attribute)
427 {
428         char *desc = NULL;
429         DBusMessageIter iter;
430         const char *path;
431
432         default_dev = proxy;
433
434         if (proxy == NULL) {
435                 default_attr = NULL;
436                 goto done;
437         }
438
439         if (!g_dbus_proxy_get_property(proxy, "Alias", &iter)) {
440                 if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
441                         goto done;
442         }
443
444         path = g_dbus_proxy_get_path(proxy);
445
446         dbus_message_iter_get_basic(&iter, &desc);
447         desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
448                                 attribute ? ":" : "",
449                                 attribute ? attribute + strlen(path) : "");
450
451 done:
452         bt_shell_set_prompt(desc ? desc : PROMPT_ON);
453         g_free(desc);
454 }
455
456 static void battery_added(GDBusProxy *proxy)
457 {
458         battery_proxies = g_list_append(battery_proxies, proxy);
459 }
460
461 static void battery_removed(GDBusProxy *proxy)
462 {
463         battery_proxies = g_list_remove(battery_proxies, proxy);
464 }
465
466 static void device_added(GDBusProxy *proxy)
467 {
468         DBusMessageIter iter;
469         struct adapter *adapter = find_parent(proxy);
470
471         if (!adapter) {
472                 /* TODO: Error */
473                 return;
474         }
475
476         adapter->devices = g_list_append(adapter->devices, proxy);
477         print_device(proxy, COLORED_NEW);
478         bt_shell_set_env(g_dbus_proxy_get_path(proxy), proxy);
479
480         if (default_dev)
481                 return;
482
483         if (g_dbus_proxy_get_property(proxy, "Connected", &iter)) {
484                 dbus_bool_t connected;
485
486                 dbus_message_iter_get_basic(&iter, &connected);
487
488                 if (connected)
489                         set_default_device(proxy, NULL);
490         }
491 }
492
493 static struct adapter *find_ctrl(GList *source, const char *path);
494
495 static struct adapter *adapter_new(GDBusProxy *proxy)
496 {
497         struct adapter *adapter = g_malloc0(sizeof(struct adapter));
498
499         ctrl_list = g_list_append(ctrl_list, adapter);
500
501         if (!default_ctrl)
502                 default_ctrl = adapter;
503
504         return adapter;
505 }
506
507 static void adapter_added(GDBusProxy *proxy)
508 {
509         struct adapter *adapter;
510         adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
511         if (!adapter)
512                 adapter = adapter_new(proxy);
513
514         adapter->proxy = proxy;
515
516         print_adapter(proxy, COLORED_NEW);
517         bt_shell_set_env(g_dbus_proxy_get_path(proxy), proxy);
518 }
519
520 static void ad_manager_added(GDBusProxy *proxy)
521 {
522         struct adapter *adapter;
523         adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
524         if (!adapter)
525                 adapter = adapter_new(proxy);
526
527         adapter->ad_proxy = proxy;
528 }
529
530 static void proxy_added(GDBusProxy *proxy, void *user_data)
531 {
532         const char *interface;
533
534         interface = g_dbus_proxy_get_interface(proxy);
535
536         if (!strcmp(interface, "org.bluez.Device1")) {
537                 device_added(proxy);
538         } else if (!strcmp(interface, "org.bluez.Adapter1")) {
539                 adapter_added(proxy);
540         } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
541                 if (!agent_manager) {
542                         agent_manager = proxy;
543
544                         if (auto_register_agent &&
545                                         !bt_shell_get_env("NON_INTERACTIVE"))
546                                 agent_register(dbus_conn, agent_manager,
547                                                         auto_register_agent);
548                 }
549         } else if (!strcmp(interface, "org.bluez.GattService1")) {
550                 if (service_is_child(proxy))
551                         gatt_add_service(proxy);
552         } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
553                 gatt_add_characteristic(proxy);
554         } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
555                 gatt_add_descriptor(proxy);
556         } else if (!strcmp(interface, "org.bluez.GattManager1")) {
557                 gatt_add_manager(proxy);
558         } else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1")) {
559                 ad_manager_added(proxy);
560         } else if (!strcmp(interface, "org.bluez.Battery1")) {
561                 battery_added(proxy);
562         }
563 }
564
565 static void set_default_attribute(GDBusProxy *proxy)
566 {
567         const char *path;
568
569         default_attr = proxy;
570
571         path = g_dbus_proxy_get_path(proxy);
572
573         set_default_device(default_dev, path);
574 }
575
576 static void device_removed(GDBusProxy *proxy)
577 {
578         struct adapter *adapter = find_parent(proxy);
579         if (!adapter) {
580                 /* TODO: Error */
581                 return;
582         }
583
584         adapter->devices = g_list_remove(adapter->devices, proxy);
585
586         print_device(proxy, COLORED_DEL);
587         bt_shell_set_env(g_dbus_proxy_get_path(proxy), NULL);
588
589         if (default_dev == proxy)
590                 set_default_device(NULL, NULL);
591 }
592
593 static void adapter_removed(GDBusProxy *proxy)
594 {
595         GList *ll;
596
597         for (ll = g_list_first(ctrl_list); ll; ll = g_list_next(ll)) {
598                 struct adapter *adapter = ll->data;
599
600                 if (adapter->proxy == proxy) {
601                         print_adapter(proxy, COLORED_DEL);
602                         bt_shell_set_env(g_dbus_proxy_get_path(proxy), NULL);
603
604                         if (default_ctrl && default_ctrl->proxy == proxy) {
605                                 default_ctrl = NULL;
606                                 set_default_device(NULL, NULL);
607                         }
608
609                         ctrl_list = g_list_remove_link(ctrl_list, ll);
610                         g_list_free(adapter->devices);
611                         g_free(adapter);
612                         g_list_free(ll);
613                         return;
614                 }
615         }
616 }
617
618 static void proxy_removed(GDBusProxy *proxy, void *user_data)
619 {
620         const char *interface;
621
622         interface = g_dbus_proxy_get_interface(proxy);
623
624         if (!strcmp(interface, "org.bluez.Device1")) {
625                 device_removed(proxy);
626         } else if (!strcmp(interface, "org.bluez.Adapter1")) {
627                 adapter_removed(proxy);
628         } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
629                 if (agent_manager == proxy) {
630                         agent_manager = NULL;
631                         if (auto_register_agent)
632                                 agent_unregister(dbus_conn, NULL);
633                 }
634         } else if (!strcmp(interface, "org.bluez.GattService1")) {
635                 gatt_remove_service(proxy);
636
637                 if (default_attr == proxy)
638                         set_default_attribute(NULL);
639         } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
640                 gatt_remove_characteristic(proxy);
641
642                 if (default_attr == proxy)
643                         set_default_attribute(NULL);
644         } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
645                 gatt_remove_descriptor(proxy);
646
647                 if (default_attr == proxy)
648                         set_default_attribute(NULL);
649         } else if (!strcmp(interface, "org.bluez.GattManager1")) {
650                 gatt_remove_manager(proxy);
651         } else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1")) {
652                 ad_unregister(dbus_conn, NULL);
653         } else if (!strcmp(interface, "org.bluez.Battery1")) {
654                 battery_removed(proxy);
655         }
656 }
657
658 static struct adapter *find_ctrl(GList *source, const char *path)
659 {
660         GList *list;
661
662         for (list = g_list_first(source); list; list = g_list_next(list)) {
663                 struct adapter *adapter = list->data;
664
665                 if (!strcasecmp(g_dbus_proxy_get_path(adapter->proxy), path))
666                         return adapter;
667         }
668
669         return NULL;
670 }
671
672 static void property_changed(GDBusProxy *proxy, const char *name,
673                                         DBusMessageIter *iter, void *user_data)
674 {
675         const char *interface;
676         struct adapter *ctrl;
677
678         interface = g_dbus_proxy_get_interface(proxy);
679
680         if (!strcmp(interface, "org.bluez.Device1")) {
681                 if (default_ctrl && device_is_child(proxy,
682                                         default_ctrl->proxy) == TRUE) {
683                         DBusMessageIter addr_iter;
684                         char *str;
685
686                         if (g_dbus_proxy_get_property(proxy, "Address",
687                                                         &addr_iter) == TRUE) {
688                                 const char *address;
689
690                                 dbus_message_iter_get_basic(&addr_iter,
691                                                                 &address);
692                                 str = g_strdup_printf("[" COLORED_CHG
693                                                 "] Device %s ", address);
694                         } else
695                                 str = g_strdup("");
696
697                         if (strcmp(name, "Connected") == 0) {
698                                 dbus_bool_t connected;
699
700                                 dbus_message_iter_get_basic(iter, &connected);
701
702                                 if (connected && default_dev == NULL)
703                                         set_default_device(proxy, NULL);
704                                 else if (!connected && default_dev == proxy)
705                                         set_default_device(NULL, NULL);
706                         }
707
708                         print_iter(str, name, iter);
709                         g_free(str);
710                 }
711         } else if (!strcmp(interface, "org.bluez.Adapter1")) {
712                 DBusMessageIter addr_iter;
713                 char *str;
714
715                 if (g_dbus_proxy_get_property(proxy, "Address",
716                                                 &addr_iter) == TRUE) {
717                         const char *address;
718
719                         dbus_message_iter_get_basic(&addr_iter, &address);
720                         str = g_strdup_printf("[" COLORED_CHG
721                                                 "] Controller %s ", address);
722                 } else
723                         str = g_strdup("");
724
725                 print_iter(str, name, iter);
726                 g_free(str);
727         } else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1")) {
728                 DBusMessageIter addr_iter;
729                 char *str;
730
731                 ctrl = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
732                 if (!ctrl)
733                         return;
734
735                 if (g_dbus_proxy_get_property(ctrl->proxy, "Address",
736                                                 &addr_iter) == TRUE) {
737                         const char *address;
738
739                         dbus_message_iter_get_basic(&addr_iter, &address);
740                         str = g_strdup_printf("[" COLORED_CHG
741                                                 "] Controller %s ",
742                                                 address);
743                 } else
744                         str = g_strdup("");
745
746                 print_iter(str, name, iter);
747                 g_free(str);
748         } else if (proxy == default_attr) {
749                 char *str;
750
751                 str = g_strdup_printf("[" COLORED_CHG "] Attribute %s ",
752                                                 g_dbus_proxy_get_path(proxy));
753
754                 print_iter(str, name, iter);
755                 g_free(str);
756         }
757 }
758
759 static void message_handler(DBusConnection *connection,
760                                         DBusMessage *message, void *user_data)
761 {
762         bt_shell_printf("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
763                                         dbus_message_get_member(message));
764 }
765
766 static struct adapter *find_ctrl_by_address(GList *source, const char *address)
767 {
768         GList *list;
769
770         for (list = g_list_first(source); list; list = g_list_next(list)) {
771                 struct adapter *adapter = list->data;
772                 DBusMessageIter iter;
773                 const char *str;
774
775                 if (g_dbus_proxy_get_property(adapter->proxy,
776                                         "Address", &iter) == FALSE)
777                         continue;
778
779                 dbus_message_iter_get_basic(&iter, &str);
780
781                 if (!strcasecmp(str, address))
782                         return adapter;
783         }
784
785         return NULL;
786 }
787
788 static GDBusProxy *find_battery_by_path(GList *source, const char *path)
789 {
790         GList *list;
791
792         for (list = g_list_first(source); list; list = g_list_next(list)) {
793                 GDBusProxy *proxy = list->data;
794
795                 if (strcmp(g_dbus_proxy_get_path(proxy), path) == 0)
796                         return proxy;
797         }
798
799         return NULL;
800 }
801
802 static GDBusProxy *find_proxy_by_address(GList *source, const char *address)
803 {
804         GList *list;
805
806         for (list = g_list_first(source); list; list = g_list_next(list)) {
807                 GDBusProxy *proxy = list->data;
808                 DBusMessageIter iter;
809                 const char *str;
810
811                 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
812                         continue;
813
814                 dbus_message_iter_get_basic(&iter, &str);
815
816                 if (!strcasecmp(str, address))
817                         return proxy;
818         }
819
820         return NULL;
821 }
822
823 static gboolean check_default_ctrl(void)
824 {
825         if (!default_ctrl) {
826                 bt_shell_printf("No default controller available\n");
827                 return FALSE;
828         }
829
830         return TRUE;
831 }
832
833 static gboolean parse_argument(int argc, char *argv[], const char **arg_table,
834                                         const char *msg, dbus_bool_t *value,
835                                         const char **option)
836 {
837         const char **opt;
838
839         if (!strcmp(argv[1], "help")) {
840                 for (opt = arg_table; opt && *opt; opt++)
841                         bt_shell_printf("%s\n", *opt);
842                 bt_shell_noninteractive_quit(EXIT_SUCCESS);
843                 return FALSE;
844         }
845
846         if (!strcmp(argv[1], "on") || !strcmp(argv[1], "yes")) {
847                 *value = TRUE;
848                 if (option)
849                         *option = "";
850                 return TRUE;
851         }
852
853         if (!strcmp(argv[1], "off") || !strcmp(argv[1], "no")) {
854                 *value = FALSE;
855                 return TRUE;
856         }
857
858         for (opt = arg_table; opt && *opt; opt++) {
859                 if (strcmp(argv[1], *opt) == 0) {
860                         *value = TRUE;
861                         *option = *opt;
862                         return TRUE;
863                 }
864         }
865
866         bt_shell_printf("Invalid argument %s\n", argv[1]);
867         return FALSE;
868 }
869
870 static void cmd_list(int argc, char *argv[])
871 {
872         GList *list;
873
874         for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
875                 struct adapter *adapter = list->data;
876                 print_adapter(adapter->proxy, NULL);
877         }
878
879         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
880 }
881
882 static void cmd_show(int argc, char *argv[])
883 {
884         struct adapter *adapter;
885         DBusMessageIter iter;
886         const char *address;
887
888         if (argc < 2 || !strlen(argv[1])) {
889                 if (check_default_ctrl() == FALSE)
890                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
891
892                 adapter = default_ctrl;
893         } else {
894                 adapter = find_ctrl_by_address(ctrl_list, argv[1]);
895                 if (!adapter) {
896                         bt_shell_printf("Controller %s not available\n",
897                                                                 argv[1]);
898                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
899                 }
900         }
901
902         if (!g_dbus_proxy_get_property(adapter->proxy, "Address", &iter))
903                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
904
905         dbus_message_iter_get_basic(&iter, &address);
906
907         if (g_dbus_proxy_get_property(adapter->proxy, "AddressType", &iter)) {
908                 const char *type;
909
910                 dbus_message_iter_get_basic(&iter, &type);
911
912                 bt_shell_printf("Controller %s (%s)\n", address, type);
913         } else {
914                 bt_shell_printf("Controller %s\n", address);
915         }
916
917         print_property(adapter->proxy, "Name");
918         print_property(adapter->proxy, "Alias");
919         print_property(adapter->proxy, "Class");
920         print_property(adapter->proxy, "Powered");
921         print_property(adapter->proxy, "Discoverable");
922         print_property(adapter->proxy, "DiscoverableTimeout");
923         print_property(adapter->proxy, "Pairable");
924         print_uuids(adapter->proxy);
925         print_property(adapter->proxy, "Modalias");
926         print_property(adapter->proxy, "Discovering");
927
928 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
929         print_property(adapter->proxy, "Advertising");
930 #endif
931
932         if (adapter->ad_proxy) {
933                 bt_shell_printf("Advertising Features:\n");
934                 print_property(adapter->ad_proxy, "ActiveInstances");
935                 print_property(adapter->ad_proxy, "SupportedInstances");
936                 print_property(adapter->ad_proxy, "SupportedIncludes");
937                 print_property(adapter->ad_proxy, "SupportedSecondaryChannels");
938         }
939
940         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
941 }
942
943 static void cmd_select(int argc, char *argv[])
944 {
945         struct adapter *adapter;
946
947         adapter = find_ctrl_by_address(ctrl_list, argv[1]);
948         if (!adapter) {
949                 bt_shell_printf("Controller %s not available\n", argv[1]);
950                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
951         }
952
953         if (default_ctrl && default_ctrl->proxy == adapter->proxy)
954                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
955
956         default_ctrl = adapter;
957         print_adapter(adapter->proxy, NULL);
958
959         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
960 }
961
962 static void cmd_devices(int argc, char *argv[])
963 {
964         GList *ll;
965
966         if (check_default_ctrl() == FALSE)
967                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
968
969         for (ll = g_list_first(default_ctrl->devices);
970                         ll; ll = g_list_next(ll)) {
971                 GDBusProxy *proxy = ll->data;
972                 print_device(proxy, NULL);
973         }
974
975         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
976 }
977
978 static void cmd_paired_devices(int argc, char *argv[])
979 {
980         GList *ll;
981
982         if (check_default_ctrl() == FALSE)
983                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
984
985         for (ll = g_list_first(default_ctrl->devices);
986                         ll; ll = g_list_next(ll)) {
987                 GDBusProxy *proxy = ll->data;
988                 DBusMessageIter iter;
989                 dbus_bool_t paired;
990
991                 if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == FALSE)
992                         continue;
993
994                 dbus_message_iter_get_basic(&iter, &paired);
995                 if (!paired)
996                         continue;
997
998                 print_device(proxy, NULL);
999         }
1000
1001         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1002 }
1003
1004 static void generic_callback(const DBusError *error, void *user_data)
1005 {
1006         char *str = user_data;
1007
1008         if (dbus_error_is_set(error)) {
1009                 bt_shell_printf("Failed to set %s: %s\n", str, error->name);
1010                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1011         } else {
1012                 bt_shell_printf("Changing %s succeeded\n", str);
1013                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1014         }
1015 }
1016
1017 static void cmd_system_alias(int argc, char *argv[])
1018 {
1019         char *name;
1020
1021         if (check_default_ctrl() == FALSE)
1022                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1023
1024         name = g_strdup(argv[1]);
1025
1026         if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Alias",
1027                                         DBUS_TYPE_STRING, &name,
1028                                         generic_callback, name, g_free) == TRUE)
1029                 return;
1030
1031         g_free(name);
1032 }
1033
1034 static void cmd_reset_alias(int argc, char *argv[])
1035 {
1036         char *name;
1037
1038         if (check_default_ctrl() == FALSE)
1039                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1040
1041         name = g_strdup("");
1042
1043         if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Alias",
1044                                         DBUS_TYPE_STRING, &name,
1045                                         generic_callback, name, g_free) == TRUE)
1046                 return;
1047
1048         g_free(name);
1049 }
1050
1051 static void cmd_power(int argc, char *argv[])
1052 {
1053         dbus_bool_t powered;
1054         char *str;
1055
1056         if (!parse_argument(argc, argv, NULL, NULL, &powered, NULL))
1057                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1058
1059         if (check_default_ctrl() == FALSE)
1060                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1061
1062         str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
1063
1064         if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Powered",
1065                                         DBUS_TYPE_BOOLEAN, &powered,
1066                                         generic_callback, str, g_free) == TRUE)
1067                 return;
1068
1069         g_free(str);
1070 }
1071
1072 static void cmd_pairable(int argc, char *argv[])
1073 {
1074         dbus_bool_t pairable;
1075         char *str;
1076
1077         if (!parse_argument(argc, argv, NULL, NULL, &pairable, NULL))
1078                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1079
1080         if (check_default_ctrl() == FALSE)
1081                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1082
1083         str = g_strdup_printf("pairable %s", pairable == TRUE ? "on" : "off");
1084
1085         if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Pairable",
1086                                         DBUS_TYPE_BOOLEAN, &pairable,
1087                                         generic_callback, str, g_free) == TRUE)
1088                 return;
1089
1090         g_free(str);
1091
1092         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1093 }
1094
1095 static void cmd_discoverable(int argc, char *argv[])
1096 {
1097         dbus_bool_t discoverable;
1098         char *str;
1099
1100         if (!parse_argument(argc, argv, NULL, NULL, &discoverable, NULL))
1101                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1102
1103         if (check_default_ctrl() == FALSE)
1104                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1105
1106         str = g_strdup_printf("discoverable %s",
1107                                 discoverable == TRUE ? "on" : "off");
1108
1109         if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Discoverable",
1110                                         DBUS_TYPE_BOOLEAN, &discoverable,
1111                                         generic_callback, str, g_free) == TRUE)
1112                 return;
1113
1114         g_free(str);
1115
1116         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1117 }
1118
1119 static void cmd_discoverable_timeout(int argc, char *argv[])
1120 {
1121         uint32_t value;
1122         char *endptr = NULL;
1123         char *str;
1124
1125         if (argc < 2) {
1126                 DBusMessageIter iter;
1127
1128                 if (!g_dbus_proxy_get_property(default_ctrl->proxy,
1129                                         "DiscoverableTimeout", &iter)) {
1130                         bt_shell_printf("Unable to get DiscoverableTimeout\n");
1131                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1132                 }
1133
1134                 dbus_message_iter_get_basic(&iter, &value);
1135
1136                 bt_shell_printf("DiscoverableTimeout: %d seconds\n", value);
1137
1138                 return;
1139         }
1140
1141         value = strtol(argv[1], &endptr, 0);
1142         if (!endptr || *endptr != '\0' || value > UINT32_MAX) {
1143                 bt_shell_printf("Invalid argument\n");
1144                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1145         }
1146
1147         str = g_strdup_printf("discoverable-timeout %d", value);
1148
1149         if (g_dbus_proxy_set_property_basic(default_ctrl->proxy,
1150                                         "DiscoverableTimeout",
1151                                         DBUS_TYPE_UINT32, &value,
1152                                         generic_callback, str, g_free))
1153                 return;
1154
1155         g_free(str);
1156
1157         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1158 }
1159
1160 static void cmd_agent(int argc, char *argv[])
1161 {
1162         dbus_bool_t enable;
1163         const char *capability;
1164
1165         if (!parse_argument(argc, argv, agent_arguments, "capability",
1166                                                 &enable, &capability))
1167                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1168
1169         if (enable == TRUE) {
1170                 g_free(auto_register_agent);
1171                 auto_register_agent = g_strdup(capability);
1172
1173                 if (agent_manager)
1174                         agent_register(dbus_conn, agent_manager,
1175                                                 auto_register_agent);
1176                 else
1177                         bt_shell_printf("Agent registration enabled\n");
1178         } else {
1179                 g_free(auto_register_agent);
1180                 auto_register_agent = NULL;
1181
1182                 if (agent_manager)
1183                         agent_unregister(dbus_conn, agent_manager);
1184                 else
1185                         bt_shell_printf("Agent registration disabled\n");
1186         }
1187
1188         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1189 }
1190
1191 static void cmd_default_agent(int argc, char *argv[])
1192 {
1193         agent_default(dbus_conn, agent_manager);
1194 }
1195
1196 #define DISTANCE_VAL_INVALID    0x7FFF
1197
1198 static struct set_discovery_filter_args {
1199         char *transport;
1200         char *pattern;
1201         dbus_uint16_t rssi;
1202         dbus_int16_t pathloss;
1203         char **uuids;
1204         size_t uuids_len;
1205         dbus_bool_t duplicate;
1206         dbus_bool_t discoverable;
1207         bool set;
1208         bool active;
1209 } filter = {
1210         .rssi = DISTANCE_VAL_INVALID,
1211         .pathloss = DISTANCE_VAL_INVALID,
1212         .set = true,
1213 };
1214
1215 static void start_discovery_reply(DBusMessage *message, void *user_data)
1216 {
1217         dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
1218         DBusError error;
1219
1220         dbus_error_init(&error);
1221
1222         if (dbus_set_error_from_message(&error, message) == TRUE) {
1223                 bt_shell_printf("Failed to %s discovery: %s\n",
1224                                 enable == TRUE ? "start" : "stop", error.name);
1225                 dbus_error_free(&error);
1226                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1227         }
1228
1229         bt_shell_printf("Discovery %s\n", enable ? "started" : "stopped");
1230
1231         filter.active = enable;
1232         /* Leave the discovery running even on noninteractive mode */
1233 }
1234
1235 static void clear_discovery_filter(DBusMessageIter *iter, void *user_data)
1236 {
1237         DBusMessageIter dict;
1238
1239         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1240                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1241                                 DBUS_TYPE_STRING_AS_STRING
1242                                 DBUS_TYPE_VARIANT_AS_STRING
1243                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
1244
1245         dbus_message_iter_close_container(iter, &dict);
1246 }
1247
1248 static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
1249 {
1250         struct set_discovery_filter_args *args = user_data;
1251         DBusMessageIter dict;
1252
1253         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1254                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1255                                 DBUS_TYPE_STRING_AS_STRING
1256                                 DBUS_TYPE_VARIANT_AS_STRING
1257                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
1258
1259         g_dbus_dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING,
1260                                                         &args->uuids,
1261                                                         args->uuids_len);
1262
1263         if (args->pathloss != DISTANCE_VAL_INVALID)
1264                 g_dbus_dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
1265                                                 &args->pathloss);
1266
1267         if (args->rssi != DISTANCE_VAL_INVALID)
1268                 g_dbus_dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16,
1269                                                 &args->rssi);
1270
1271         if (args->transport != NULL)
1272                 g_dbus_dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
1273                                                 &args->transport);
1274
1275         if (args->duplicate)
1276                 g_dbus_dict_append_entry(&dict, "DuplicateData",
1277                                                 DBUS_TYPE_BOOLEAN,
1278                                                 &args->duplicate);
1279
1280         if (args->discoverable)
1281                 g_dbus_dict_append_entry(&dict, "Discoverable",
1282                                                 DBUS_TYPE_BOOLEAN,
1283                                                 &args->discoverable);
1284
1285         if (args->pattern != NULL)
1286                 g_dbus_dict_append_entry(&dict, "Pattern", DBUS_TYPE_STRING,
1287                                                 &args->pattern);
1288
1289         dbus_message_iter_close_container(iter, &dict);
1290 }
1291
1292
1293 static void set_discovery_filter_reply(DBusMessage *message, void *user_data)
1294 {
1295         DBusError error;
1296
1297         dbus_error_init(&error);
1298         if (dbus_set_error_from_message(&error, message) == TRUE) {
1299                 bt_shell_printf("SetDiscoveryFilter failed: %s\n", error.name);
1300                 dbus_error_free(&error);
1301                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1302         }
1303
1304         filter.set = true;
1305
1306         bt_shell_printf("SetDiscoveryFilter success\n");
1307
1308         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1309 }
1310
1311 static void set_discovery_filter(bool cleared)
1312 {
1313         GDBusSetupFunction func;
1314
1315         if (check_default_ctrl() == FALSE || filter.set)
1316                 return;
1317
1318         func = cleared ? clear_discovery_filter : set_discovery_filter_setup;
1319
1320         if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter",
1321                                         func, set_discovery_filter_reply,
1322                                         &filter, NULL) == FALSE) {
1323                 bt_shell_printf("Failed to set discovery filter\n");
1324                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1325         }
1326
1327         filter.set = true;
1328 }
1329
1330 static void cmd_scan(int argc, char *argv[])
1331 {
1332         dbus_bool_t enable;
1333         const char *method;
1334
1335         if (!parse_argument(argc, argv, NULL, NULL, &enable, NULL))
1336                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1337
1338         if (check_default_ctrl() == FALSE)
1339                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1340
1341         if (enable == TRUE) {
1342                 set_discovery_filter(false);
1343                 method = "StartDiscovery";
1344         } else
1345                 method = "StopDiscovery";
1346
1347         if (g_dbus_proxy_method_call(default_ctrl->proxy, method,
1348                                 NULL, start_discovery_reply,
1349                                 GUINT_TO_POINTER(enable), NULL) == FALSE) {
1350                 bt_shell_printf("Failed to %s discovery\n",
1351                                         enable == TRUE ? "start" : "stop");
1352                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1353         }
1354 }
1355
1356 static void cmd_scan_filter_uuids(int argc, char *argv[])
1357 {
1358         if (argc < 2 || !strlen(argv[1])) {
1359                 char **uuid;
1360
1361                 for (uuid = filter.uuids; uuid && *uuid; uuid++)
1362                         print_uuid(*uuid);
1363
1364                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1365         }
1366
1367         g_strfreev(filter.uuids);
1368         filter.uuids = NULL;
1369         filter.uuids_len = 0;
1370
1371         if (!strcmp(argv[1], "all"))
1372                 goto commit;
1373
1374         filter.uuids = g_strdupv(&argv[1]);
1375         if (!filter.uuids) {
1376                 bt_shell_printf("Failed to parse input\n");
1377                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1378         }
1379
1380         filter.uuids_len = g_strv_length(filter.uuids);
1381
1382 commit:
1383         filter.set = false;
1384
1385         if (filter.active)
1386                 set_discovery_filter(false);
1387 }
1388
1389 static void cmd_scan_filter_rssi(int argc, char *argv[])
1390 {
1391         if (argc < 2 || !strlen(argv[1])) {
1392                 if (filter.rssi != DISTANCE_VAL_INVALID)
1393                         bt_shell_printf("RSSI: %d\n", filter.rssi);
1394                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1395         }
1396
1397         filter.pathloss = DISTANCE_VAL_INVALID;
1398         filter.rssi = atoi(argv[1]);
1399
1400         filter.set = false;
1401
1402         if (filter.active)
1403                 set_discovery_filter(false);
1404 }
1405
1406 static void cmd_scan_filter_pathloss(int argc, char *argv[])
1407 {
1408         if (argc < 2 || !strlen(argv[1])) {
1409                 if (filter.pathloss != DISTANCE_VAL_INVALID)
1410                         bt_shell_printf("Pathloss: %d\n",
1411                                                 filter.pathloss);
1412                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1413         }
1414
1415         filter.rssi = DISTANCE_VAL_INVALID;
1416         filter.pathloss = atoi(argv[1]);
1417
1418         filter.set = false;
1419
1420         if (filter.active)
1421                 set_discovery_filter(false);
1422 }
1423
1424 static void cmd_scan_filter_transport(int argc, char *argv[])
1425 {
1426         if (argc < 2 || !strlen(argv[1])) {
1427                 if (filter.transport)
1428                         bt_shell_printf("Transport: %s\n",
1429                                         filter.transport);
1430                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1431         }
1432
1433         g_free(filter.transport);
1434         filter.transport = g_strdup(argv[1]);
1435
1436         filter.set = false;
1437
1438         if (filter.active)
1439                 set_discovery_filter(false);
1440 }
1441
1442 static void cmd_scan_filter_duplicate_data(int argc, char *argv[])
1443 {
1444         if (argc < 2 || !strlen(argv[1])) {
1445                 bt_shell_printf("DuplicateData: %s\n",
1446                                 filter.duplicate ? "on" : "off");
1447                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1448         }
1449
1450         if (!strcmp(argv[1], "on"))
1451                 filter.duplicate = true;
1452         else if (!strcmp(argv[1], "off"))
1453                 filter.duplicate = false;
1454         else {
1455                 bt_shell_printf("Invalid option: %s\n", argv[1]);
1456                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1457         }
1458
1459         filter.set = false;
1460
1461         if (filter.active)
1462                 set_discovery_filter(false);
1463 }
1464
1465 static void cmd_scan_filter_discoverable(int argc, char *argv[])
1466 {
1467         if (argc < 2 || !strlen(argv[1])) {
1468                 bt_shell_printf("Discoverable: %s\n",
1469                                 filter.discoverable ? "on" : "off");
1470                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1471         }
1472
1473         if (!strcmp(argv[1], "on"))
1474                 filter.discoverable = true;
1475         else if (!strcmp(argv[1], "off"))
1476                 filter.discoverable = false;
1477         else {
1478                 bt_shell_printf("Invalid option: %s\n", argv[1]);
1479                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1480         }
1481
1482         filter.set = false;
1483
1484         if (filter.active)
1485                 set_discovery_filter(false);
1486 }
1487
1488 static void cmd_scan_filter_pattern(int argc, char *argv[])
1489 {
1490         if (argc < 2 || !strlen(argv[1])) {
1491                 bt_shell_printf("Pattern: %s\n", filter.pattern);
1492                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1493         }
1494
1495         free(filter.pattern);
1496         filter.pattern = strdup(argv[1]);
1497
1498         filter.set = false;
1499
1500         if (filter.active)
1501                 set_discovery_filter(false);
1502 }
1503
1504 static void filter_clear_uuids(void)
1505 {
1506         g_strfreev(filter.uuids);
1507         filter.uuids = NULL;
1508         filter.uuids_len = 0;
1509 }
1510
1511 static void filter_clear_rssi(void)
1512 {
1513         filter.rssi = DISTANCE_VAL_INVALID;
1514 }
1515
1516 static void filter_clear_pathloss(void)
1517 {
1518         filter.pathloss = DISTANCE_VAL_INVALID;
1519 }
1520
1521 static void filter_clear_transport(void)
1522 {
1523         g_free(filter.transport);
1524         filter.transport = NULL;
1525 }
1526
1527 static void filter_clear_duplicate(void)
1528 {
1529         filter.duplicate = false;
1530 }
1531
1532 static void filter_clear_discoverable(void)
1533 {
1534         filter.discoverable = false;
1535 }
1536
1537 static void filter_clear_pattern(void)
1538 {
1539         free(filter.pattern);
1540         filter.pattern = NULL;
1541 }
1542
1543 struct clear_entry {
1544         const char *name;
1545         void (*clear) (void);
1546 };
1547
1548 static const struct clear_entry filter_clear[] = {
1549         { "uuids", filter_clear_uuids },
1550         { "rssi", filter_clear_rssi },
1551         { "pathloss", filter_clear_pathloss },
1552         { "transport", filter_clear_transport },
1553         { "duplicate-data", filter_clear_duplicate },
1554         { "discoverable", filter_clear_discoverable },
1555         { "pattern", filter_clear_pattern },
1556         {}
1557 };
1558
1559 static char *filter_clear_generator(const char *text, int state)
1560 {
1561         static int index, len;
1562         const char *arg;
1563
1564         if (!state) {
1565                 index = 0;
1566                 len = strlen(text);
1567         }
1568
1569         while ((arg = filter_clear[index].name)) {
1570                 index++;
1571
1572                 if (!strncmp(arg, text, len))
1573                         return strdup(arg);
1574         }
1575
1576         return NULL;
1577 }
1578
1579 static gboolean data_clear(const struct clear_entry *entry_table,
1580                                                         const char *name)
1581 {
1582         const struct clear_entry *entry;
1583         bool all = false;
1584
1585         if (!name || !strlen(name) || !strcmp("all", name))
1586                 all = true;
1587
1588         for (entry = entry_table; entry && entry->name; entry++) {
1589                 if (all || !strcmp(entry->name, name)) {
1590                         entry->clear();
1591                         if (!all)
1592                                 goto done;
1593                 }
1594         }
1595
1596         if (!all) {
1597                 bt_shell_printf("Invalid argument %s\n", name);
1598                 return FALSE;
1599         }
1600
1601 done:
1602         return TRUE;
1603 }
1604
1605 static void cmd_scan_filter_clear(int argc, char *argv[])
1606 {
1607         bool all = false;
1608
1609         if (argc < 2 || !strlen(argv[1]))
1610                 all = true;
1611
1612         if (!data_clear(filter_clear, all ? "all" : argv[1]))
1613                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1614
1615         filter.set = false;
1616
1617         if (check_default_ctrl() == FALSE)
1618                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1619
1620         set_discovery_filter(all);
1621 }
1622
1623 static struct GDBusProxy *find_device(int argc, char *argv[])
1624 {
1625         GDBusProxy *proxy;
1626
1627         if (argc < 2 || !strlen(argv[1])) {
1628                 if (default_dev)
1629                         return default_dev;
1630                 bt_shell_printf("Missing device address argument\n");
1631                 return NULL;
1632         }
1633
1634         if (check_default_ctrl() == FALSE)
1635                 return NULL;
1636
1637         proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
1638         if (!proxy) {
1639                 bt_shell_printf("Device %s not available\n", argv[1]);
1640                 return NULL;
1641         }
1642
1643         return proxy;
1644 }
1645
1646 static void cmd_info(int argc, char *argv[])
1647 {
1648         GDBusProxy *proxy;
1649         GDBusProxy *battery_proxy;
1650         DBusMessageIter iter;
1651         const char *address;
1652
1653         proxy = find_device(argc, argv);
1654         if (!proxy)
1655                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1656
1657         if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
1658                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1659
1660         dbus_message_iter_get_basic(&iter, &address);
1661
1662         if (g_dbus_proxy_get_property(proxy, "AddressType", &iter) == TRUE) {
1663                 const char *type;
1664
1665                 dbus_message_iter_get_basic(&iter, &type);
1666
1667                 bt_shell_printf("Device %s (%s)\n", address, type);
1668         } else {
1669                 bt_shell_printf("Device %s\n", address);
1670         }
1671
1672         print_property(proxy, "Name");
1673         print_property(proxy, "Alias");
1674         print_property(proxy, "Class");
1675         print_property(proxy, "Appearance");
1676         print_property(proxy, "Icon");
1677         print_property(proxy, "Paired");
1678         print_property(proxy, "Trusted");
1679         print_property(proxy, "Blocked");
1680         print_property(proxy, "Connected");
1681         print_property(proxy, "LegacyPairing");
1682         print_uuids(proxy);
1683         print_property(proxy, "Modalias");
1684 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1685         print_property(proxy, "LegacyManufacturerDataLen");
1686 #endif
1687         print_property(proxy, "ManufacturerData");
1688         print_property(proxy, "ServiceData");
1689         print_property(proxy, "RSSI");
1690         print_property(proxy, "TxPower");
1691         print_property(proxy, "AdvertisingFlags");
1692         print_property(proxy, "AdvertisingData");
1693
1694         battery_proxy = find_battery_by_path(battery_proxies,
1695                                         g_dbus_proxy_get_path(proxy));
1696         print_property_with_label(battery_proxy, "Percentage",
1697                                         "Battery Percentage");
1698
1699         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1700 }
1701
1702 static void pair_reply(DBusMessage *message, void *user_data)
1703 {
1704         DBusError error;
1705
1706         dbus_error_init(&error);
1707
1708         if (dbus_set_error_from_message(&error, message) == TRUE) {
1709                 bt_shell_printf("Failed to pair: %s\n", error.name);
1710                 dbus_error_free(&error);
1711                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1712         }
1713
1714         bt_shell_printf("Pairing successful\n");
1715
1716         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1717 }
1718
1719 static const char *proxy_address(GDBusProxy *proxy)
1720 {
1721         DBusMessageIter iter;
1722         const char *addr;
1723
1724         if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
1725                 return NULL;
1726
1727         dbus_message_iter_get_basic(&iter, &addr);
1728
1729         return addr;
1730 }
1731
1732 static void cmd_pair(int argc, char *argv[])
1733 {
1734         GDBusProxy *proxy;
1735
1736         proxy = find_device(argc, argv);
1737         if (!proxy)
1738                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1739
1740         if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
1741                                                         NULL, NULL) == FALSE) {
1742                 bt_shell_printf("Failed to pair\n");
1743                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1744         }
1745
1746         bt_shell_printf("Attempting to pair with %s\n", proxy_address(proxy));
1747 }
1748
1749 static void cmd_trust(int argc, char *argv[])
1750 {
1751         GDBusProxy *proxy;
1752         dbus_bool_t trusted;
1753         char *str;
1754
1755         proxy = find_device(argc, argv);
1756         if (!proxy)
1757                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1758
1759         trusted = TRUE;
1760
1761         str = g_strdup_printf("%s trust", proxy_address(proxy));
1762
1763         if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1764                                         DBUS_TYPE_BOOLEAN, &trusted,
1765                                         generic_callback, str, g_free) == TRUE)
1766                 return;
1767
1768         g_free(str);
1769
1770         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1771 }
1772
1773 static void cmd_untrust(int argc, char *argv[])
1774 {
1775         GDBusProxy *proxy;
1776         dbus_bool_t trusted;
1777         char *str;
1778
1779         proxy = find_device(argc, argv);
1780         if (!proxy)
1781                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1782
1783         trusted = FALSE;
1784
1785         str = g_strdup_printf("%s untrust", proxy_address(proxy));
1786
1787         if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1788                                         DBUS_TYPE_BOOLEAN, &trusted,
1789                                         generic_callback, str, g_free) == TRUE)
1790                 return;
1791
1792         g_free(str);
1793
1794         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1795 }
1796
1797 static void cmd_block(int argc, char *argv[])
1798 {
1799         GDBusProxy *proxy;
1800         dbus_bool_t blocked;
1801         char *str;
1802
1803         proxy = find_device(argc, argv);
1804         if (!proxy)
1805                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1806
1807         blocked = TRUE;
1808
1809         str = g_strdup_printf("%s block", proxy_address(proxy));
1810
1811         if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1812                                         DBUS_TYPE_BOOLEAN, &blocked,
1813                                         generic_callback, str, g_free) == TRUE)
1814                 return;
1815
1816         g_free(str);
1817
1818         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1819 }
1820
1821 static void cmd_unblock(int argc, char *argv[])
1822 {
1823         GDBusProxy *proxy;
1824         dbus_bool_t blocked;
1825         char *str;
1826
1827         proxy = find_device(argc, argv);
1828         if (!proxy)
1829                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1830
1831         blocked = FALSE;
1832
1833         str = g_strdup_printf("%s unblock", proxy_address(proxy));
1834
1835         if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1836                                         DBUS_TYPE_BOOLEAN, &blocked,
1837                                         generic_callback, str, g_free) == TRUE)
1838                 return;
1839
1840         g_free(str);
1841
1842         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1843 }
1844
1845 static void remove_device_reply(DBusMessage *message, void *user_data)
1846 {
1847         DBusError error;
1848
1849         dbus_error_init(&error);
1850
1851         if (dbus_set_error_from_message(&error, message) == TRUE) {
1852                 bt_shell_printf("Failed to remove device: %s\n", error.name);
1853                 dbus_error_free(&error);
1854                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1855         }
1856
1857         bt_shell_printf("Device has been removed\n");
1858         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1859 }
1860
1861 static void remove_device_setup(DBusMessageIter *iter, void *user_data)
1862 {
1863         const char *path = user_data;
1864
1865         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
1866 }
1867
1868 static void remove_device(GDBusProxy *proxy)
1869 {
1870         char *path;
1871
1872         if (!default_ctrl)
1873                 return;
1874
1875         path = g_strdup(g_dbus_proxy_get_path(proxy));
1876
1877         if (g_dbus_proxy_method_call(default_ctrl->proxy, "RemoveDevice",
1878                                                 remove_device_setup,
1879                                                 remove_device_reply,
1880                                                 path, g_free) == FALSE) {
1881                 bt_shell_printf("Failed to remove device\n");
1882                 g_free(path);
1883                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1884         }
1885 }
1886
1887 static void cmd_remove(int argc, char *argv[])
1888 {
1889         GDBusProxy *proxy;
1890
1891         if (check_default_ctrl() == FALSE)
1892                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1893
1894         if (strcmp(argv[1], "*") == 0) {
1895                 GList *list;
1896
1897                 for (list = default_ctrl->devices; list;
1898                                                 list = g_list_next(list)) {
1899                         GDBusProxy *proxy = list->data;
1900
1901                         remove_device(proxy);
1902                 }
1903                 return;
1904         }
1905
1906         proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
1907         if (!proxy) {
1908                 bt_shell_printf("Device %s not available\n", argv[1]);
1909                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1910         }
1911
1912         remove_device(proxy);
1913 }
1914
1915 static void connect_reply(DBusMessage *message, void *user_data)
1916 {
1917         GDBusProxy *proxy = user_data;
1918         DBusError error;
1919
1920         dbus_error_init(&error);
1921
1922         if (dbus_set_error_from_message(&error, message) == TRUE) {
1923                 bt_shell_printf("Failed to connect: %s\n", error.name);
1924                 dbus_error_free(&error);
1925                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1926         }
1927
1928         bt_shell_printf("Connection successful\n");
1929
1930         set_default_device(proxy, NULL);
1931         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1932 }
1933
1934 static void cmd_connect(int argc, char *argv[])
1935 {
1936         GDBusProxy *proxy;
1937
1938         if (check_default_ctrl() == FALSE)
1939                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1940
1941         proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
1942         if (!proxy) {
1943                 bt_shell_printf("Device %s not available\n", argv[1]);
1944                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1945         }
1946
1947         if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
1948                                                         proxy, NULL) == FALSE) {
1949                 bt_shell_printf("Failed to connect\n");
1950                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1951         }
1952
1953         bt_shell_printf("Attempting to connect to %s\n", argv[1]);
1954 }
1955
1956 static void disconn_reply(DBusMessage *message, void *user_data)
1957 {
1958         GDBusProxy *proxy = user_data;
1959         DBusError error;
1960
1961         dbus_error_init(&error);
1962
1963         if (dbus_set_error_from_message(&error, message) == TRUE) {
1964                 bt_shell_printf("Failed to disconnect: %s\n", error.name);
1965                 dbus_error_free(&error);
1966                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1967         }
1968
1969         bt_shell_printf("Successful disconnected\n");
1970
1971         if (proxy == default_dev)
1972                 set_default_device(NULL, NULL);
1973
1974         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1975 }
1976
1977 static void cmd_disconn(int argc, char *argv[])
1978 {
1979         GDBusProxy *proxy;
1980
1981         proxy = find_device(argc, argv);
1982         if (!proxy)
1983                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1984
1985         if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
1986                                                         proxy, NULL) == FALSE) {
1987                 bt_shell_printf("Failed to disconnect\n");
1988                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1989         }
1990
1991         bt_shell_printf("Attempting to disconnect from %s\n",
1992                                                 proxy_address(proxy));
1993 }
1994
1995 static void cmd_list_attributes(int argc, char *argv[])
1996 {
1997         GDBusProxy *proxy;
1998         const char *path;
1999
2000         if (argc > 1 && !strcmp(argv[1], "local")) {
2001                 path = argv[1];
2002                 goto done;
2003         }
2004
2005         proxy = find_device(argc, argv);
2006         if (!proxy)
2007                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2008
2009         path = g_dbus_proxy_get_path(proxy);
2010
2011 done:
2012         gatt_list_attributes(path);
2013
2014         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2015 }
2016
2017 static void cmd_set_alias(int argc, char *argv[])
2018 {
2019         char *name;
2020
2021         if (!default_dev) {
2022                 bt_shell_printf("No device connected\n");
2023                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2024         }
2025
2026         name = g_strdup(argv[1]);
2027
2028         if (g_dbus_proxy_set_property_basic(default_dev, "Alias",
2029                                         DBUS_TYPE_STRING, &name,
2030                                         generic_callback, name, g_free) == TRUE)
2031                 return;
2032
2033         g_free(name);
2034
2035         return bt_shell_noninteractive_quit(EXIT_FAILURE);
2036 }
2037
2038 static void cmd_select_attribute(int argc, char *argv[])
2039 {
2040         GDBusProxy *proxy;
2041
2042         if (!default_dev) {
2043                 bt_shell_printf("No device connected\n");
2044                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2045         }
2046
2047         proxy = gatt_select_attribute(default_attr, argv[1]);
2048         if (proxy) {
2049                 set_default_attribute(proxy);
2050                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2051         }
2052
2053         return bt_shell_noninteractive_quit(EXIT_FAILURE);
2054 }
2055
2056 static struct GDBusProxy *find_attribute(int argc, char *argv[])
2057 {
2058         GDBusProxy *proxy;
2059
2060         if (argc < 2 || !strlen(argv[1])) {
2061                 if (default_attr)
2062                         return default_attr;
2063                 bt_shell_printf("Missing attribute argument\n");
2064                 return NULL;
2065         }
2066
2067         proxy = gatt_select_attribute(default_attr, argv[1]);
2068         if (!proxy) {
2069                 bt_shell_printf("Attribute %s not available\n", argv[1]);
2070                 return NULL;
2071         }
2072
2073         return proxy;
2074 }
2075
2076 static void cmd_attribute_info(int argc, char *argv[])
2077 {
2078         GDBusProxy *proxy;
2079         DBusMessageIter iter;
2080         const char *iface, *uuid, *text;
2081
2082         proxy = find_attribute(argc, argv);
2083         if (!proxy)
2084                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2085
2086         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
2087                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2088
2089         dbus_message_iter_get_basic(&iter, &uuid);
2090
2091         text = bt_uuidstr_to_str(uuid);
2092         if (!text)
2093                 text = g_dbus_proxy_get_path(proxy);
2094
2095         iface = g_dbus_proxy_get_interface(proxy);
2096         if (!strcmp(iface, "org.bluez.GattService1")) {
2097                 bt_shell_printf("Service - %s\n", text);
2098
2099                 print_property(proxy, "UUID");
2100                 print_property(proxy, "Primary");
2101                 print_property(proxy, "Characteristics");
2102                 print_property(proxy, "Includes");
2103         } else if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
2104                 bt_shell_printf("Characteristic - %s\n", text);
2105
2106                 print_property(proxy, "UUID");
2107                 print_property(proxy, "Service");
2108                 print_property(proxy, "Value");
2109                 print_property(proxy, "Notifying");
2110                 print_property(proxy, "Flags");
2111                 print_property(proxy, "Descriptors");
2112         } else if (!strcmp(iface, "org.bluez.GattDescriptor1")) {
2113                 bt_shell_printf("Descriptor - %s\n", text);
2114
2115                 print_property(proxy, "UUID");
2116                 print_property(proxy, "Characteristic");
2117                 print_property(proxy, "Value");
2118         }
2119
2120         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2121 }
2122
2123 static void cmd_read(int argc, char *argv[])
2124 {
2125         if (!default_attr) {
2126                 bt_shell_printf("No attribute selected\n");
2127                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2128         }
2129
2130         gatt_read_attribute(default_attr, argc, argv);
2131 }
2132
2133 static void cmd_write(int argc, char *argv[])
2134 {
2135         if (!default_attr) {
2136                 bt_shell_printf("No attribute selected\n");
2137                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2138         }
2139
2140         gatt_write_attribute(default_attr, argc, argv);
2141 }
2142
2143 static void cmd_acquire_write(int argc, char *argv[])
2144 {
2145         if (!default_attr) {
2146                 bt_shell_printf("No attribute selected\n");
2147                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2148         }
2149
2150         gatt_acquire_write(default_attr, argv[1]);
2151 }
2152
2153 static void cmd_release_write(int argc, char *argv[])
2154 {
2155         if (!default_attr) {
2156                 bt_shell_printf("No attribute selected\n");
2157                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2158         }
2159
2160         gatt_release_write(default_attr, argv[1]);
2161 }
2162
2163 static void cmd_acquire_notify(int argc, char *argv[])
2164 {
2165         if (!default_attr) {
2166                 bt_shell_printf("No attribute selected\n");
2167                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2168         }
2169
2170         gatt_acquire_notify(default_attr, argv[1]);
2171 }
2172
2173 static void cmd_release_notify(int argc, char *argv[])
2174 {
2175         if (!default_attr) {
2176                 bt_shell_printf("No attribute selected\n");
2177                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2178         }
2179
2180         gatt_release_notify(default_attr, argv[1]);
2181 }
2182
2183 static void cmd_notify(int argc, char *argv[])
2184 {
2185         dbus_bool_t enable;
2186
2187         if (!parse_argument(argc, argv, NULL, NULL, &enable, NULL))
2188                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2189
2190         if (!default_attr) {
2191                 bt_shell_printf("No attribute selected\n");
2192                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2193         }
2194
2195         gatt_notify_attribute(default_attr, enable ? true : false);
2196 }
2197
2198 static void cmd_clone(int argc, char *argv[])
2199 {
2200         GDBusProxy *proxy;
2201
2202         proxy = default_attr ? default_attr : default_dev;
2203         if (!proxy) {
2204                 bt_shell_printf("Not connected\n");
2205                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2206         }
2207
2208         gatt_clone_attribute(proxy, argc, argv);
2209 }
2210
2211 static void cmd_register_app(int argc, char *argv[])
2212 {
2213         if (check_default_ctrl() == FALSE)
2214                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2215
2216         gatt_register_app(dbus_conn, default_ctrl->proxy, argc, argv);
2217 }
2218
2219 static void cmd_unregister_app(int argc, char *argv[])
2220 {
2221         if (check_default_ctrl() == FALSE)
2222                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2223
2224         gatt_unregister_app(dbus_conn, default_ctrl->proxy);
2225 }
2226
2227 static void cmd_register_service(int argc, char *argv[])
2228 {
2229         if (check_default_ctrl() == FALSE)
2230                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2231
2232         gatt_register_service(dbus_conn, default_ctrl->proxy, argc, argv);
2233 }
2234
2235 static void cmd_register_includes(int argc, char *argv[])
2236 {
2237         if (check_default_ctrl() == FALSE)
2238                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2239
2240         gatt_register_include(dbus_conn, default_ctrl->proxy, argc, argv);
2241 }
2242
2243 static void cmd_unregister_includes(int argc, char *argv[])
2244 {
2245         if (check_default_ctrl() == FALSE)
2246                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2247
2248         gatt_unregister_include(dbus_conn, default_ctrl->proxy, argc, argv);
2249 }
2250
2251 static void cmd_unregister_service(int argc, char *argv[])
2252 {
2253         if (check_default_ctrl() == FALSE)
2254                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2255
2256         gatt_unregister_service(dbus_conn, default_ctrl->proxy, argc, argv);
2257 }
2258
2259 static void cmd_register_characteristic(int argc, char *argv[])
2260 {
2261         if (check_default_ctrl() == FALSE)
2262                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2263
2264         gatt_register_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
2265 }
2266
2267 static void cmd_unregister_characteristic(int argc, char *argv[])
2268 {
2269         if (check_default_ctrl() == FALSE)
2270                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2271
2272         gatt_unregister_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
2273 }
2274
2275 static void cmd_register_descriptor(int argc, char *argv[])
2276 {
2277         if (check_default_ctrl() == FALSE)
2278                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2279
2280         gatt_register_desc(dbus_conn, default_ctrl->proxy, argc, argv);
2281 }
2282
2283 static void cmd_unregister_descriptor(int argc, char *argv[])
2284 {
2285         if (check_default_ctrl() == FALSE)
2286                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2287
2288         gatt_unregister_desc(dbus_conn, default_ctrl->proxy, argc, argv);
2289 }
2290
2291 static char *generic_generator(const char *text, int state,
2292                                         GList *source, const char *property)
2293 {
2294         static int index, len;
2295         GList *list;
2296
2297         if (!state) {
2298                 index = 0;
2299                 len = strlen(text);
2300         }
2301
2302         for (list = g_list_nth(source, index); list;
2303                                                 list = g_list_next(list)) {
2304                 GDBusProxy *proxy = list->data;
2305                 DBusMessageIter iter;
2306                 const char *str;
2307
2308                 index++;
2309
2310                 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
2311                         continue;
2312
2313                 dbus_message_iter_get_basic(&iter, &str);
2314
2315                 if (!strncasecmp(str, text, len))
2316                         return strdup(str);
2317         }
2318
2319         return NULL;
2320 }
2321
2322 static char *ctrl_generator(const char *text, int state)
2323 {
2324         static int index = 0;
2325         static int len = 0;
2326         GList *list;
2327
2328         if (!state) {
2329                 index = 0;
2330                 len = strlen(text);
2331         }
2332
2333         for (list = g_list_nth(ctrl_list, index); list;
2334                                                 list = g_list_next(list)) {
2335                 struct adapter *adapter = list->data;
2336                 DBusMessageIter iter;
2337                 const char *str;
2338
2339                 index++;
2340
2341                 if (g_dbus_proxy_get_property(adapter->proxy,
2342                                         "Address", &iter) == FALSE)
2343                         continue;
2344
2345                 dbus_message_iter_get_basic(&iter, &str);
2346
2347                 if (!strncasecmp(str, text, len))
2348                         return strdup(str);
2349         }
2350
2351         return NULL;
2352 }
2353
2354 static char *dev_generator(const char *text, int state)
2355 {
2356         return generic_generator(text, state,
2357                         default_ctrl ? default_ctrl->devices : NULL, "Address");
2358 }
2359
2360 static char *attribute_generator(const char *text, int state)
2361 {
2362         return gatt_attribute_generator(text, state);
2363 }
2364
2365 static char *argument_generator(const char *text, int state,
2366                                         const char *args_list[])
2367 {
2368         static int index, len;
2369         const char *arg;
2370
2371         if (!state) {
2372                 index = 0;
2373                 len = strlen(text);
2374         }
2375
2376         while ((arg = args_list[index])) {
2377                 index++;
2378
2379                 if (!strncmp(arg, text, len))
2380                         return strdup(arg);
2381         }
2382
2383         return NULL;
2384 }
2385
2386 static char *capability_generator(const char *text, int state)
2387 {
2388         return argument_generator(text, state, agent_arguments);
2389 }
2390
2391 static void cmd_advertise(int argc, char *argv[])
2392 {
2393         dbus_bool_t enable;
2394         const char *type;
2395
2396         if (!parse_argument(argc, argv, ad_arguments, "type",
2397                                         &enable, &type))
2398                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2399
2400         if (!default_ctrl || !default_ctrl->ad_proxy) {
2401                 bt_shell_printf("LEAdvertisingManager not found\n");
2402                 bt_shell_noninteractive_quit(EXIT_FAILURE);
2403         }
2404
2405         if (enable == TRUE)
2406                 ad_register(dbus_conn, default_ctrl->ad_proxy, type);
2407         else
2408                 ad_unregister(dbus_conn, default_ctrl->ad_proxy);
2409 }
2410
2411 static char *ad_generator(const char *text, int state)
2412 {
2413         return argument_generator(text, state, ad_arguments);
2414 }
2415
2416 static void cmd_advertise_uuids(int argc, char *argv[])
2417 {
2418         ad_advertise_uuids(dbus_conn, argc, argv);
2419 }
2420
2421 static void cmd_advertise_service(int argc, char *argv[])
2422 {
2423         ad_advertise_service(dbus_conn, argc, argv);
2424 }
2425
2426 static void cmd_advertise_manufacturer(int argc, char *argv[])
2427 {
2428         ad_advertise_manufacturer(dbus_conn, argc, argv);
2429 }
2430
2431 static void cmd_advertise_data(int argc, char *argv[])
2432 {
2433         ad_advertise_data(dbus_conn, argc, argv);
2434 }
2435
2436 static void cmd_advertise_discoverable(int argc, char *argv[])
2437 {
2438         dbus_bool_t discoverable;
2439
2440         if (argc < 2) {
2441                 ad_advertise_discoverable(dbus_conn, NULL);
2442                 return;
2443         }
2444
2445         if (!parse_argument(argc, argv, NULL, NULL, &discoverable, NULL))
2446                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2447
2448         ad_advertise_discoverable(dbus_conn, &discoverable);
2449 }
2450
2451 static void cmd_advertise_discoverable_timeout(int argc, char *argv[])
2452 {
2453         long int value;
2454         char *endptr = NULL;
2455
2456         if (argc < 2) {
2457                 ad_advertise_discoverable_timeout(dbus_conn, NULL);
2458                 return;
2459         }
2460
2461         value = strtol(argv[1], &endptr, 0);
2462         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2463                 bt_shell_printf("Invalid argument\n");
2464                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2465         }
2466
2467         ad_advertise_discoverable_timeout(dbus_conn, &value);
2468 }
2469
2470 static void cmd_advertise_tx_power(int argc, char *argv[])
2471 {
2472         dbus_bool_t powered;
2473
2474         if (argc < 2) {
2475                 ad_advertise_tx_power(dbus_conn, NULL);
2476                 return;
2477         }
2478
2479         if (!parse_argument(argc, argv, NULL, NULL, &powered, NULL))
2480                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2481
2482         ad_advertise_tx_power(dbus_conn, &powered);
2483 }
2484
2485 static void cmd_advertise_name(int argc, char *argv[])
2486 {
2487         if (argc < 2) {
2488                 ad_advertise_local_name(dbus_conn, NULL);
2489                 return;
2490         }
2491
2492         if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) {
2493                 ad_advertise_name(dbus_conn, true);
2494                 return;
2495         }
2496
2497         if (strcmp(argv[1], "off") == 0 || strcmp(argv[1], "no") == 0) {
2498                 ad_advertise_name(dbus_conn, false);
2499                 return;
2500         }
2501
2502         ad_advertise_local_name(dbus_conn, argv[1]);
2503 }
2504
2505 static void cmd_advertise_appearance(int argc, char *argv[])
2506 {
2507         long int value;
2508         char *endptr = NULL;
2509
2510         if (argc < 2) {
2511                 ad_advertise_local_appearance(dbus_conn, NULL);
2512                 return;
2513         }
2514
2515         if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) {
2516                 ad_advertise_appearance(dbus_conn, true);
2517                 return;
2518         }
2519
2520         if (strcmp(argv[1], "off") == 0 || strcmp(argv[1], "no") == 0) {
2521                 ad_advertise_appearance(dbus_conn, false);
2522                 return;
2523         }
2524
2525         value = strtol(argv[1], &endptr, 0);
2526         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2527                 bt_shell_printf("Invalid argument\n");
2528                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2529         }
2530
2531         ad_advertise_local_appearance(dbus_conn, &value);
2532 }
2533
2534 static void cmd_advertise_duration(int argc, char *argv[])
2535 {
2536         long int value;
2537         char *endptr = NULL;
2538
2539         if (argc < 2) {
2540                 ad_advertise_duration(dbus_conn, NULL);
2541                 return;
2542         }
2543
2544         value = strtol(argv[1], &endptr, 0);
2545         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2546                 bt_shell_printf("Invalid argument\n");
2547                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2548         }
2549
2550         ad_advertise_duration(dbus_conn, &value);
2551 }
2552
2553 static void cmd_advertise_timeout(int argc, char *argv[])
2554 {
2555         long int value;
2556         char *endptr = NULL;
2557
2558         if (argc < 2) {
2559                 ad_advertise_timeout(dbus_conn, NULL);
2560                 return;
2561         }
2562
2563         value = strtol(argv[1], &endptr, 0);
2564         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2565                 bt_shell_printf("Invalid argument\n");
2566                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2567         }
2568
2569         ad_advertise_timeout(dbus_conn, &value);
2570 }
2571
2572 static void cmd_advertise_secondary(int argc, char *argv[])
2573 {
2574         if (argc < 2) {
2575                 ad_advertise_secondary(dbus_conn, NULL);
2576                 return;
2577         }
2578
2579         ad_advertise_secondary(dbus_conn, argv[1]);
2580 }
2581
2582 static void ad_clear_uuids(void)
2583 {
2584         ad_disable_uuids(dbus_conn);
2585 }
2586
2587 static void ad_clear_service(void)
2588 {
2589         ad_disable_service(dbus_conn);
2590 }
2591
2592 static void ad_clear_manufacturer(void)
2593 {
2594         ad_disable_manufacturer(dbus_conn);
2595 }
2596
2597 static void ad_clear_data(void)
2598 {
2599         ad_disable_data(dbus_conn);
2600 }
2601
2602 static void ad_clear_tx_power(void)
2603 {
2604         dbus_bool_t powered = false;
2605
2606         ad_advertise_tx_power(dbus_conn, &powered);
2607 }
2608
2609 static void ad_clear_name(void)
2610 {
2611         ad_advertise_name(dbus_conn, false);
2612 }
2613
2614 static void ad_clear_appearance(void)
2615 {
2616         ad_advertise_appearance(dbus_conn, false);
2617 }
2618
2619 static void ad_clear_duration(void)
2620 {
2621         long int value = 0;
2622
2623         ad_advertise_duration(dbus_conn, &value);
2624 }
2625
2626 static void ad_clear_timeout(void)
2627 {
2628         long int value = 0;
2629
2630         ad_advertise_timeout(dbus_conn, &value);
2631 }
2632
2633 static void ad_clear_secondary(void)
2634 {
2635         const char *value = "";
2636
2637         ad_advertise_secondary(dbus_conn, value);
2638 }
2639
2640 static const struct clear_entry ad_clear[] = {
2641         { "uuids",              ad_clear_uuids },
2642         { "service",            ad_clear_service },
2643         { "manufacturer",       ad_clear_manufacturer },
2644         { "data",               ad_clear_data },
2645         { "tx-power",           ad_clear_tx_power },
2646         { "name",               ad_clear_name },
2647         { "appearance",         ad_clear_appearance },
2648         { "duration",           ad_clear_duration },
2649         { "timeout",            ad_clear_timeout },
2650         { "secondary",          ad_clear_secondary },
2651         {}
2652 };
2653
2654 static void cmd_ad_clear(int argc, char *argv[])
2655 {
2656         bool all = false;
2657
2658         if (argc < 2 || !strlen(argv[1]))
2659                 all = true;
2660
2661         if(!data_clear(ad_clear, all ? "all" : argv[1]))
2662                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2663 }
2664
2665 static const struct bt_shell_menu advertise_menu = {
2666         .name = "advertise",
2667         .desc = "Advertise Options Submenu",
2668         .entries = {
2669         { "uuids", "[uuid1 uuid2 ...]", cmd_advertise_uuids,
2670                         "Set/Get advertise uuids" },
2671         { "service", "[uuid] [data=xx xx ...]", cmd_advertise_service,
2672                         "Set/Get advertise service data" },
2673         { "manufacturer", "[id] [data=xx xx ...]",
2674                         cmd_advertise_manufacturer,
2675                         "Set/Get advertise manufacturer data" },
2676         { "data", "[type] [data=xx xx ...]", cmd_advertise_data,
2677                         "Set/Get advertise data" },
2678         { "discoverable", "[on/off]", cmd_advertise_discoverable,
2679                         "Set/Get advertise discoverable" },
2680         { "discoverable-timeout", "[seconds]",
2681                         cmd_advertise_discoverable_timeout,
2682                         "Set/Get advertise discoverable timeout" },
2683         { "tx-power", "[on/off]", cmd_advertise_tx_power,
2684                         "Show/Enable/Disable TX power to be advertised",
2685                                                         NULL },
2686         { "name", "[on/off/name]", cmd_advertise_name,
2687                         "Configure local name to be advertised" },
2688         { "appearance", "[on/off/value]", cmd_advertise_appearance,
2689                         "Configure custom appearance to be advertised" },
2690         { "duration", "[seconds]", cmd_advertise_duration,
2691                         "Set/Get advertise duration" },
2692         { "timeout", "[seconds]", cmd_advertise_timeout,
2693                         "Set/Get advertise timeout" },
2694         { "secondary", "[1M/2M/Coded]", cmd_advertise_secondary,
2695                         "Set/Get advertise secondary channel" },
2696         { "clear", "[uuids/service/manufacturer/config-name...]", cmd_ad_clear,
2697                         "Clear advertise config" },
2698         { } },
2699 };
2700
2701 static const struct bt_shell_menu scan_menu = {
2702         .name = "scan",
2703         .desc = "Scan Options Submenu",
2704         .entries = {
2705         { "uuids", "[all/uuid1 uuid2 ...]", cmd_scan_filter_uuids,
2706                                 "Set/Get UUIDs filter" },
2707         { "rssi", "[rssi]", cmd_scan_filter_rssi,
2708                                 "Set/Get RSSI filter, and clears pathloss" },
2709         { "pathloss", "[pathloss]", cmd_scan_filter_pathloss,
2710                                 "Set/Get Pathloss filter, and clears RSSI" },
2711         { "transport", "[transport]", cmd_scan_filter_transport,
2712                                 "Set/Get transport filter" },
2713         { "duplicate-data", "[on/off]", cmd_scan_filter_duplicate_data,
2714                                 "Set/Get duplicate data filter",
2715                                 NULL },
2716         { "discoverable", "[on/off]", cmd_scan_filter_discoverable,
2717                                 "Set/Get discoverable filter",
2718                                 NULL },
2719         { "pattern", "[value]", cmd_scan_filter_pattern,
2720                                 "Set/Get pattern filter",
2721                                 NULL },
2722         { "clear",
2723         "[uuids/rssi/pathloss/transport/duplicate-data/discoverable/pattern]",
2724                                 cmd_scan_filter_clear,
2725                                 "Clears discovery filter.",
2726                                 filter_clear_generator },
2727         { } },
2728 };
2729
2730 static const struct bt_shell_menu gatt_menu = {
2731         .name = "gatt",
2732         .desc = "Generic Attribute Submenu",
2733         .entries = {
2734         { "list-attributes", "[dev/local]", cmd_list_attributes,
2735                                 "List attributes", dev_generator },
2736         { "select-attribute", "<attribute/UUID>",  cmd_select_attribute,
2737                                 "Select attribute", attribute_generator },
2738         { "attribute-info", "[attribute/UUID]",  cmd_attribute_info,
2739                                 "Select attribute", attribute_generator },
2740         { "read", "[offset]", cmd_read, "Read attribute value" },
2741         { "write", "<data=xx xx ...> [offset] [type]", cmd_write,
2742                                                 "Write attribute value" },
2743         { "acquire-write", NULL, cmd_acquire_write,
2744                                         "Acquire Write file descriptor" },
2745         { "release-write", NULL, cmd_release_write,
2746                                         "Release Write file descriptor" },
2747         { "acquire-notify", NULL, cmd_acquire_notify,
2748                                         "Acquire Notify file descriptor" },
2749         { "release-notify", NULL, cmd_release_notify,
2750                                         "Release Notify file descriptor" },
2751         { "notify",       "<on/off>", cmd_notify, "Notify attribute value",
2752                                                         NULL },
2753         { "clone",        "[dev/attribute/UUID]", cmd_clone,
2754                                                 "Clone a device or attribute" },
2755         { "register-application", "[UUID ...]", cmd_register_app,
2756                                                 "Register profile to connect" },
2757         { "unregister-application", NULL, cmd_unregister_app,
2758                                                 "Unregister profile" },
2759         { "register-service", "<UUID> [handle]", cmd_register_service,
2760                                         "Register application service."  },
2761         { "unregister-service", "<UUID/object>", cmd_unregister_service,
2762                                         "Unregister application service" },
2763         { "register-includes", "<UUID> [handle]", cmd_register_includes,
2764                                         "Register as Included service in." },
2765         { "unregister-includes", "<Service-UUID><Inc-UUID>",
2766                         cmd_unregister_includes,
2767                                  "Unregister Included service." },
2768         { "register-characteristic",
2769                         "<UUID> <Flags=read,write,notify...> [handle]",
2770                         cmd_register_characteristic,
2771                         "Register application characteristic" },
2772         { "unregister-characteristic", "<UUID/object>",
2773                                 cmd_unregister_characteristic,
2774                                 "Unregister application characteristic" },
2775         { "register-descriptor", "<UUID> <Flags=read,write...> [handle]",
2776                                         cmd_register_descriptor,
2777                                         "Register application descriptor" },
2778         { "unregister-descriptor", "<UUID/object>",
2779                                         cmd_unregister_descriptor,
2780                                         "Unregister application descriptor" },
2781         { } },
2782 };
2783
2784 static const struct bt_shell_menu main_menu = {
2785         .name = "main",
2786         .entries = {
2787         { "list",         NULL,       cmd_list, "List available controllers" },
2788         { "show",         "[ctrl]",   cmd_show, "Controller information",
2789                                                         ctrl_generator },
2790         { "select",       "<ctrl>",   cmd_select, "Select default controller",
2791                                                         ctrl_generator },
2792         { "devices",      NULL,       cmd_devices, "List available devices" },
2793         { "paired-devices", NULL,     cmd_paired_devices,
2794                                         "List paired devices"},
2795         { "system-alias", "<name>",   cmd_system_alias,
2796                                         "Set controller alias" },
2797         { "reset-alias",  NULL,       cmd_reset_alias,
2798                                         "Reset controller alias" },
2799         { "power",        "<on/off>", cmd_power, "Set controller power",
2800                                                         NULL },
2801         { "pairable",     "<on/off>", cmd_pairable,
2802                                         "Set controller pairable mode",
2803                                                         NULL },
2804         { "discoverable", "<on/off>", cmd_discoverable,
2805                                         "Set controller discoverable mode",
2806                                                         NULL },
2807         { "discoverable-timeout", "[value]", cmd_discoverable_timeout,
2808                                         "Set discoverable timeout", NULL },
2809         { "agent",        "<on/off/capability>", cmd_agent,
2810                                 "Enable/disable agent with given capability",
2811                                                         capability_generator},
2812         { "default-agent",NULL,       cmd_default_agent,
2813                                 "Set agent as the default one" },
2814         { "advertise",    "<on/off/type>", cmd_advertise,
2815                                 "Enable/disable advertising with given type",
2816                                                         ad_generator},
2817         { "set-alias",    "<alias>",  cmd_set_alias, "Set device alias" },
2818         { "scan",         "<on/off>", cmd_scan, "Scan for devices", NULL },
2819         { "info",         "[dev]",    cmd_info, "Device information",
2820                                                         dev_generator },
2821         { "pair",         "[dev]",    cmd_pair, "Pair with device",
2822                                                         dev_generator },
2823         { "trust",        "[dev]",    cmd_trust, "Trust device",
2824                                                         dev_generator },
2825         { "untrust",      "[dev]",    cmd_untrust, "Untrust device",
2826                                                         dev_generator },
2827         { "block",        "[dev]",    cmd_block, "Block device",
2828                                                                 dev_generator },
2829         { "unblock",      "[dev]",    cmd_unblock, "Unblock device",
2830                                                                 dev_generator },
2831         { "remove",       "<dev>",    cmd_remove, "Remove device",
2832                                                         dev_generator },
2833         { "connect",      "<dev>",    cmd_connect, "Connect device",
2834                                                         dev_generator },
2835         { "disconnect",   "[dev]",    cmd_disconn, "Disconnect device",
2836                                                         dev_generator },
2837         { } },
2838 };
2839
2840 static const struct option options[] = {
2841         { "agent",      required_argument, 0, 'a' },
2842         { 0, 0, 0, 0 }
2843 };
2844
2845 static const char *agent_option;
2846
2847 static const char **optargs[] = {
2848         &agent_option
2849 };
2850
2851 static const char *help[] = {
2852         "Register agent handler: <capability>"
2853 };
2854
2855 static const struct bt_shell_opt opt = {
2856         .options = options,
2857         .optno = sizeof(options) / sizeof(struct option),
2858         .optstr = "a:",
2859         .optarg = optargs,
2860         .help = help,
2861 };
2862
2863 static void client_ready(GDBusClient *client, void *user_data)
2864 {
2865         setup_standard_input();
2866 }
2867
2868 int main(int argc, char *argv[])
2869 {
2870         GDBusClient *client;
2871         int status;
2872
2873         bt_shell_init(argc, argv, &opt);
2874         bt_shell_set_menu(&main_menu);
2875         bt_shell_add_submenu(&advertise_menu);
2876         bt_shell_add_submenu(&scan_menu);
2877         bt_shell_add_submenu(&gatt_menu);
2878         bt_shell_set_prompt(PROMPT_OFF);
2879
2880         if (agent_option)
2881                 auto_register_agent = g_strdup(agent_option);
2882         else
2883                 auto_register_agent = g_strdup("");
2884
2885         dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
2886         g_dbus_attach_object_manager(dbus_conn);
2887
2888         bt_shell_set_env("DBUS_CONNECTION", dbus_conn);
2889
2890         client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
2891
2892         g_dbus_client_set_connect_watch(client, connect_handler, NULL);
2893         g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
2894         g_dbus_client_set_signal_watch(client, message_handler, NULL);
2895
2896         g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
2897                                                         property_changed, NULL);
2898
2899         g_dbus_client_set_ready_watch(client, client_ready, NULL);
2900
2901         status = bt_shell_run();
2902
2903         g_dbus_client_unref(client);
2904
2905         dbus_connection_unref(dbus_conn);
2906
2907         g_list_free_full(ctrl_list, proxy_leak);
2908
2909         g_free(auto_register_agent);
2910
2911         return status;
2912 }