client: Display wake allowed property with info
[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, "WakeAllowed");
1682         print_property(proxy, "LegacyPairing");
1683         print_uuids(proxy);
1684         print_property(proxy, "Modalias");
1685 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1686         print_property(proxy, "LegacyManufacturerDataLen");
1687 #endif
1688         print_property(proxy, "ManufacturerData");
1689         print_property(proxy, "ServiceData");
1690         print_property(proxy, "RSSI");
1691         print_property(proxy, "TxPower");
1692         print_property(proxy, "AdvertisingFlags");
1693         print_property(proxy, "AdvertisingData");
1694
1695         battery_proxy = find_battery_by_path(battery_proxies,
1696                                         g_dbus_proxy_get_path(proxy));
1697         print_property_with_label(battery_proxy, "Percentage",
1698                                         "Battery Percentage");
1699
1700         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1701 }
1702
1703 static void pair_reply(DBusMessage *message, void *user_data)
1704 {
1705         DBusError error;
1706
1707         dbus_error_init(&error);
1708
1709         if (dbus_set_error_from_message(&error, message) == TRUE) {
1710                 bt_shell_printf("Failed to pair: %s\n", error.name);
1711                 dbus_error_free(&error);
1712                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1713         }
1714
1715         bt_shell_printf("Pairing successful\n");
1716
1717         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1718 }
1719
1720 static const char *proxy_address(GDBusProxy *proxy)
1721 {
1722         DBusMessageIter iter;
1723         const char *addr;
1724
1725         if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
1726                 return NULL;
1727
1728         dbus_message_iter_get_basic(&iter, &addr);
1729
1730         return addr;
1731 }
1732
1733 static void cmd_pair(int argc, char *argv[])
1734 {
1735         GDBusProxy *proxy;
1736
1737         proxy = find_device(argc, argv);
1738         if (!proxy)
1739                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1740
1741         if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
1742                                                         NULL, NULL) == FALSE) {
1743                 bt_shell_printf("Failed to pair\n");
1744                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1745         }
1746
1747         bt_shell_printf("Attempting to pair with %s\n", proxy_address(proxy));
1748 }
1749
1750 static void cmd_trust(int argc, char *argv[])
1751 {
1752         GDBusProxy *proxy;
1753         dbus_bool_t trusted;
1754         char *str;
1755
1756         proxy = find_device(argc, argv);
1757         if (!proxy)
1758                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1759
1760         trusted = TRUE;
1761
1762         str = g_strdup_printf("%s trust", proxy_address(proxy));
1763
1764         if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1765                                         DBUS_TYPE_BOOLEAN, &trusted,
1766                                         generic_callback, str, g_free) == TRUE)
1767                 return;
1768
1769         g_free(str);
1770
1771         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1772 }
1773
1774 static void cmd_untrust(int argc, char *argv[])
1775 {
1776         GDBusProxy *proxy;
1777         dbus_bool_t trusted;
1778         char *str;
1779
1780         proxy = find_device(argc, argv);
1781         if (!proxy)
1782                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1783
1784         trusted = FALSE;
1785
1786         str = g_strdup_printf("%s untrust", proxy_address(proxy));
1787
1788         if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1789                                         DBUS_TYPE_BOOLEAN, &trusted,
1790                                         generic_callback, str, g_free) == TRUE)
1791                 return;
1792
1793         g_free(str);
1794
1795         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1796 }
1797
1798 static void cmd_block(int argc, char *argv[])
1799 {
1800         GDBusProxy *proxy;
1801         dbus_bool_t blocked;
1802         char *str;
1803
1804         proxy = find_device(argc, argv);
1805         if (!proxy)
1806                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1807
1808         blocked = TRUE;
1809
1810         str = g_strdup_printf("%s block", proxy_address(proxy));
1811
1812         if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1813                                         DBUS_TYPE_BOOLEAN, &blocked,
1814                                         generic_callback, str, g_free) == TRUE)
1815                 return;
1816
1817         g_free(str);
1818
1819         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1820 }
1821
1822 static void cmd_unblock(int argc, char *argv[])
1823 {
1824         GDBusProxy *proxy;
1825         dbus_bool_t blocked;
1826         char *str;
1827
1828         proxy = find_device(argc, argv);
1829         if (!proxy)
1830                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1831
1832         blocked = FALSE;
1833
1834         str = g_strdup_printf("%s unblock", proxy_address(proxy));
1835
1836         if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1837                                         DBUS_TYPE_BOOLEAN, &blocked,
1838                                         generic_callback, str, g_free) == TRUE)
1839                 return;
1840
1841         g_free(str);
1842
1843         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1844 }
1845
1846 static void remove_device_reply(DBusMessage *message, void *user_data)
1847 {
1848         DBusError error;
1849
1850         dbus_error_init(&error);
1851
1852         if (dbus_set_error_from_message(&error, message) == TRUE) {
1853                 bt_shell_printf("Failed to remove device: %s\n", error.name);
1854                 dbus_error_free(&error);
1855                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1856         }
1857
1858         bt_shell_printf("Device has been removed\n");
1859         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1860 }
1861
1862 static void remove_device_setup(DBusMessageIter *iter, void *user_data)
1863 {
1864         const char *path = user_data;
1865
1866         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
1867 }
1868
1869 static void remove_device(GDBusProxy *proxy)
1870 {
1871         char *path;
1872
1873         if (!default_ctrl)
1874                 return;
1875
1876         path = g_strdup(g_dbus_proxy_get_path(proxy));
1877
1878         if (g_dbus_proxy_method_call(default_ctrl->proxy, "RemoveDevice",
1879                                                 remove_device_setup,
1880                                                 remove_device_reply,
1881                                                 path, g_free) == FALSE) {
1882                 bt_shell_printf("Failed to remove device\n");
1883                 g_free(path);
1884                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1885         }
1886 }
1887
1888 static void cmd_remove(int argc, char *argv[])
1889 {
1890         GDBusProxy *proxy;
1891
1892         if (check_default_ctrl() == FALSE)
1893                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1894
1895         if (strcmp(argv[1], "*") == 0) {
1896                 GList *list;
1897
1898                 for (list = default_ctrl->devices; list;
1899                                                 list = g_list_next(list)) {
1900                         GDBusProxy *proxy = list->data;
1901
1902                         remove_device(proxy);
1903                 }
1904                 return;
1905         }
1906
1907         proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
1908         if (!proxy) {
1909                 bt_shell_printf("Device %s not available\n", argv[1]);
1910                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1911         }
1912
1913         remove_device(proxy);
1914 }
1915
1916 static void connect_reply(DBusMessage *message, void *user_data)
1917 {
1918         GDBusProxy *proxy = user_data;
1919         DBusError error;
1920
1921         dbus_error_init(&error);
1922
1923         if (dbus_set_error_from_message(&error, message) == TRUE) {
1924                 bt_shell_printf("Failed to connect: %s\n", error.name);
1925                 dbus_error_free(&error);
1926                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1927         }
1928
1929         bt_shell_printf("Connection successful\n");
1930
1931         set_default_device(proxy, NULL);
1932         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1933 }
1934
1935 static void cmd_connect(int argc, char *argv[])
1936 {
1937         GDBusProxy *proxy;
1938
1939         if (check_default_ctrl() == FALSE)
1940                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1941
1942         proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
1943         if (!proxy) {
1944                 bt_shell_printf("Device %s not available\n", argv[1]);
1945                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1946         }
1947
1948         if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
1949                                                         proxy, NULL) == FALSE) {
1950                 bt_shell_printf("Failed to connect\n");
1951                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1952         }
1953
1954         bt_shell_printf("Attempting to connect to %s\n", argv[1]);
1955 }
1956
1957 static void disconn_reply(DBusMessage *message, void *user_data)
1958 {
1959         GDBusProxy *proxy = user_data;
1960         DBusError error;
1961
1962         dbus_error_init(&error);
1963
1964         if (dbus_set_error_from_message(&error, message) == TRUE) {
1965                 bt_shell_printf("Failed to disconnect: %s\n", error.name);
1966                 dbus_error_free(&error);
1967                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1968         }
1969
1970         bt_shell_printf("Successful disconnected\n");
1971
1972         if (proxy == default_dev)
1973                 set_default_device(NULL, NULL);
1974
1975         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1976 }
1977
1978 static void cmd_disconn(int argc, char *argv[])
1979 {
1980         GDBusProxy *proxy;
1981
1982         proxy = find_device(argc, argv);
1983         if (!proxy)
1984                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1985
1986         if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
1987                                                         proxy, NULL) == FALSE) {
1988                 bt_shell_printf("Failed to disconnect\n");
1989                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1990         }
1991
1992         bt_shell_printf("Attempting to disconnect from %s\n",
1993                                                 proxy_address(proxy));
1994 }
1995
1996 static void cmd_list_attributes(int argc, char *argv[])
1997 {
1998         GDBusProxy *proxy;
1999         const char *path;
2000
2001         if (argc > 1 && !strcmp(argv[1], "local")) {
2002                 path = argv[1];
2003                 goto done;
2004         }
2005
2006         proxy = find_device(argc, argv);
2007         if (!proxy)
2008                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2009
2010         path = g_dbus_proxy_get_path(proxy);
2011
2012 done:
2013         gatt_list_attributes(path);
2014
2015         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2016 }
2017
2018 static void cmd_set_alias(int argc, char *argv[])
2019 {
2020         char *name;
2021
2022         if (!default_dev) {
2023                 bt_shell_printf("No device connected\n");
2024                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2025         }
2026
2027         name = g_strdup(argv[1]);
2028
2029         if (g_dbus_proxy_set_property_basic(default_dev, "Alias",
2030                                         DBUS_TYPE_STRING, &name,
2031                                         generic_callback, name, g_free) == TRUE)
2032                 return;
2033
2034         g_free(name);
2035
2036         return bt_shell_noninteractive_quit(EXIT_FAILURE);
2037 }
2038
2039 static void cmd_select_attribute(int argc, char *argv[])
2040 {
2041         GDBusProxy *proxy;
2042
2043         if (!default_dev) {
2044                 bt_shell_printf("No device connected\n");
2045                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2046         }
2047
2048         proxy = gatt_select_attribute(default_attr, argv[1]);
2049         if (proxy) {
2050                 set_default_attribute(proxy);
2051                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2052         }
2053
2054         return bt_shell_noninteractive_quit(EXIT_FAILURE);
2055 }
2056
2057 static struct GDBusProxy *find_attribute(int argc, char *argv[])
2058 {
2059         GDBusProxy *proxy;
2060
2061         if (argc < 2 || !strlen(argv[1])) {
2062                 if (default_attr)
2063                         return default_attr;
2064                 bt_shell_printf("Missing attribute argument\n");
2065                 return NULL;
2066         }
2067
2068         proxy = gatt_select_attribute(default_attr, argv[1]);
2069         if (!proxy) {
2070                 bt_shell_printf("Attribute %s not available\n", argv[1]);
2071                 return NULL;
2072         }
2073
2074         return proxy;
2075 }
2076
2077 static void cmd_attribute_info(int argc, char *argv[])
2078 {
2079         GDBusProxy *proxy;
2080         DBusMessageIter iter;
2081         const char *iface, *uuid, *text;
2082
2083         proxy = find_attribute(argc, argv);
2084         if (!proxy)
2085                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2086
2087         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
2088                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2089
2090         dbus_message_iter_get_basic(&iter, &uuid);
2091
2092         text = bt_uuidstr_to_str(uuid);
2093         if (!text)
2094                 text = g_dbus_proxy_get_path(proxy);
2095
2096         iface = g_dbus_proxy_get_interface(proxy);
2097         if (!strcmp(iface, "org.bluez.GattService1")) {
2098                 bt_shell_printf("Service - %s\n", text);
2099
2100                 print_property(proxy, "UUID");
2101                 print_property(proxy, "Primary");
2102                 print_property(proxy, "Characteristics");
2103                 print_property(proxy, "Includes");
2104         } else if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
2105                 bt_shell_printf("Characteristic - %s\n", text);
2106
2107                 print_property(proxy, "UUID");
2108                 print_property(proxy, "Service");
2109                 print_property(proxy, "Value");
2110                 print_property(proxy, "Notifying");
2111                 print_property(proxy, "Flags");
2112                 print_property(proxy, "Descriptors");
2113         } else if (!strcmp(iface, "org.bluez.GattDescriptor1")) {
2114                 bt_shell_printf("Descriptor - %s\n", text);
2115
2116                 print_property(proxy, "UUID");
2117                 print_property(proxy, "Characteristic");
2118                 print_property(proxy, "Value");
2119         }
2120
2121         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2122 }
2123
2124 static void cmd_read(int argc, char *argv[])
2125 {
2126         if (!default_attr) {
2127                 bt_shell_printf("No attribute selected\n");
2128                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2129         }
2130
2131         gatt_read_attribute(default_attr, argc, argv);
2132 }
2133
2134 static void cmd_write(int argc, char *argv[])
2135 {
2136         if (!default_attr) {
2137                 bt_shell_printf("No attribute selected\n");
2138                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2139         }
2140
2141         gatt_write_attribute(default_attr, argc, argv);
2142 }
2143
2144 static void cmd_acquire_write(int argc, char *argv[])
2145 {
2146         if (!default_attr) {
2147                 bt_shell_printf("No attribute selected\n");
2148                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2149         }
2150
2151         gatt_acquire_write(default_attr, argv[1]);
2152 }
2153
2154 static void cmd_release_write(int argc, char *argv[])
2155 {
2156         if (!default_attr) {
2157                 bt_shell_printf("No attribute selected\n");
2158                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2159         }
2160
2161         gatt_release_write(default_attr, argv[1]);
2162 }
2163
2164 static void cmd_acquire_notify(int argc, char *argv[])
2165 {
2166         if (!default_attr) {
2167                 bt_shell_printf("No attribute selected\n");
2168                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2169         }
2170
2171         gatt_acquire_notify(default_attr, argv[1]);
2172 }
2173
2174 static void cmd_release_notify(int argc, char *argv[])
2175 {
2176         if (!default_attr) {
2177                 bt_shell_printf("No attribute selected\n");
2178                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2179         }
2180
2181         gatt_release_notify(default_attr, argv[1]);
2182 }
2183
2184 static void cmd_notify(int argc, char *argv[])
2185 {
2186         dbus_bool_t enable;
2187
2188         if (!parse_argument(argc, argv, NULL, NULL, &enable, NULL))
2189                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2190
2191         if (!default_attr) {
2192                 bt_shell_printf("No attribute selected\n");
2193                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2194         }
2195
2196         gatt_notify_attribute(default_attr, enable ? true : false);
2197 }
2198
2199 static void cmd_clone(int argc, char *argv[])
2200 {
2201         GDBusProxy *proxy;
2202
2203         proxy = default_attr ? default_attr : default_dev;
2204         if (!proxy) {
2205                 bt_shell_printf("Not connected\n");
2206                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2207         }
2208
2209         gatt_clone_attribute(proxy, argc, argv);
2210 }
2211
2212 static void cmd_register_app(int argc, char *argv[])
2213 {
2214         if (check_default_ctrl() == FALSE)
2215                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2216
2217         gatt_register_app(dbus_conn, default_ctrl->proxy, argc, argv);
2218 }
2219
2220 static void cmd_unregister_app(int argc, char *argv[])
2221 {
2222         if (check_default_ctrl() == FALSE)
2223                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2224
2225         gatt_unregister_app(dbus_conn, default_ctrl->proxy);
2226 }
2227
2228 static void cmd_register_service(int argc, char *argv[])
2229 {
2230         if (check_default_ctrl() == FALSE)
2231                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2232
2233         gatt_register_service(dbus_conn, default_ctrl->proxy, argc, argv);
2234 }
2235
2236 static void cmd_register_includes(int argc, char *argv[])
2237 {
2238         if (check_default_ctrl() == FALSE)
2239                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2240
2241         gatt_register_include(dbus_conn, default_ctrl->proxy, argc, argv);
2242 }
2243
2244 static void cmd_unregister_includes(int argc, char *argv[])
2245 {
2246         if (check_default_ctrl() == FALSE)
2247                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2248
2249         gatt_unregister_include(dbus_conn, default_ctrl->proxy, argc, argv);
2250 }
2251
2252 static void cmd_unregister_service(int argc, char *argv[])
2253 {
2254         if (check_default_ctrl() == FALSE)
2255                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2256
2257         gatt_unregister_service(dbus_conn, default_ctrl->proxy, argc, argv);
2258 }
2259
2260 static void cmd_register_characteristic(int argc, char *argv[])
2261 {
2262         if (check_default_ctrl() == FALSE)
2263                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2264
2265         gatt_register_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
2266 }
2267
2268 static void cmd_unregister_characteristic(int argc, char *argv[])
2269 {
2270         if (check_default_ctrl() == FALSE)
2271                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2272
2273         gatt_unregister_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
2274 }
2275
2276 static void cmd_register_descriptor(int argc, char *argv[])
2277 {
2278         if (check_default_ctrl() == FALSE)
2279                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2280
2281         gatt_register_desc(dbus_conn, default_ctrl->proxy, argc, argv);
2282 }
2283
2284 static void cmd_unregister_descriptor(int argc, char *argv[])
2285 {
2286         if (check_default_ctrl() == FALSE)
2287                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2288
2289         gatt_unregister_desc(dbus_conn, default_ctrl->proxy, argc, argv);
2290 }
2291
2292 static char *generic_generator(const char *text, int state,
2293                                         GList *source, const char *property)
2294 {
2295         static int index, len;
2296         GList *list;
2297
2298         if (!state) {
2299                 index = 0;
2300                 len = strlen(text);
2301         }
2302
2303         for (list = g_list_nth(source, index); list;
2304                                                 list = g_list_next(list)) {
2305                 GDBusProxy *proxy = list->data;
2306                 DBusMessageIter iter;
2307                 const char *str;
2308
2309                 index++;
2310
2311                 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
2312                         continue;
2313
2314                 dbus_message_iter_get_basic(&iter, &str);
2315
2316                 if (!strncasecmp(str, text, len))
2317                         return strdup(str);
2318         }
2319
2320         return NULL;
2321 }
2322
2323 static char *ctrl_generator(const char *text, int state)
2324 {
2325         static int index = 0;
2326         static int len = 0;
2327         GList *list;
2328
2329         if (!state) {
2330                 index = 0;
2331                 len = strlen(text);
2332         }
2333
2334         for (list = g_list_nth(ctrl_list, index); list;
2335                                                 list = g_list_next(list)) {
2336                 struct adapter *adapter = list->data;
2337                 DBusMessageIter iter;
2338                 const char *str;
2339
2340                 index++;
2341
2342                 if (g_dbus_proxy_get_property(adapter->proxy,
2343                                         "Address", &iter) == FALSE)
2344                         continue;
2345
2346                 dbus_message_iter_get_basic(&iter, &str);
2347
2348                 if (!strncasecmp(str, text, len))
2349                         return strdup(str);
2350         }
2351
2352         return NULL;
2353 }
2354
2355 static char *dev_generator(const char *text, int state)
2356 {
2357         return generic_generator(text, state,
2358                         default_ctrl ? default_ctrl->devices : NULL, "Address");
2359 }
2360
2361 static char *attribute_generator(const char *text, int state)
2362 {
2363         return gatt_attribute_generator(text, state);
2364 }
2365
2366 static char *argument_generator(const char *text, int state,
2367                                         const char *args_list[])
2368 {
2369         static int index, len;
2370         const char *arg;
2371
2372         if (!state) {
2373                 index = 0;
2374                 len = strlen(text);
2375         }
2376
2377         while ((arg = args_list[index])) {
2378                 index++;
2379
2380                 if (!strncmp(arg, text, len))
2381                         return strdup(arg);
2382         }
2383
2384         return NULL;
2385 }
2386
2387 static char *capability_generator(const char *text, int state)
2388 {
2389         return argument_generator(text, state, agent_arguments);
2390 }
2391
2392 static void cmd_advertise(int argc, char *argv[])
2393 {
2394         dbus_bool_t enable;
2395         const char *type;
2396
2397         if (!parse_argument(argc, argv, ad_arguments, "type",
2398                                         &enable, &type))
2399                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2400
2401         if (!default_ctrl || !default_ctrl->ad_proxy) {
2402                 bt_shell_printf("LEAdvertisingManager not found\n");
2403                 bt_shell_noninteractive_quit(EXIT_FAILURE);
2404         }
2405
2406         if (enable == TRUE)
2407                 ad_register(dbus_conn, default_ctrl->ad_proxy, type);
2408         else
2409                 ad_unregister(dbus_conn, default_ctrl->ad_proxy);
2410 }
2411
2412 static char *ad_generator(const char *text, int state)
2413 {
2414         return argument_generator(text, state, ad_arguments);
2415 }
2416
2417 static void cmd_advertise_uuids(int argc, char *argv[])
2418 {
2419         ad_advertise_uuids(dbus_conn, argc, argv);
2420 }
2421
2422 static void cmd_advertise_service(int argc, char *argv[])
2423 {
2424         ad_advertise_service(dbus_conn, argc, argv);
2425 }
2426
2427 static void cmd_advertise_manufacturer(int argc, char *argv[])
2428 {
2429         ad_advertise_manufacturer(dbus_conn, argc, argv);
2430 }
2431
2432 static void cmd_advertise_data(int argc, char *argv[])
2433 {
2434         ad_advertise_data(dbus_conn, argc, argv);
2435 }
2436
2437 static void cmd_advertise_discoverable(int argc, char *argv[])
2438 {
2439         dbus_bool_t discoverable;
2440
2441         if (argc < 2) {
2442                 ad_advertise_discoverable(dbus_conn, NULL);
2443                 return;
2444         }
2445
2446         if (!parse_argument(argc, argv, NULL, NULL, &discoverable, NULL))
2447                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2448
2449         ad_advertise_discoverable(dbus_conn, &discoverable);
2450 }
2451
2452 static void cmd_advertise_discoverable_timeout(int argc, char *argv[])
2453 {
2454         long int value;
2455         char *endptr = NULL;
2456
2457         if (argc < 2) {
2458                 ad_advertise_discoverable_timeout(dbus_conn, NULL);
2459                 return;
2460         }
2461
2462         value = strtol(argv[1], &endptr, 0);
2463         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2464                 bt_shell_printf("Invalid argument\n");
2465                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2466         }
2467
2468         ad_advertise_discoverable_timeout(dbus_conn, &value);
2469 }
2470
2471 static void cmd_advertise_tx_power(int argc, char *argv[])
2472 {
2473         dbus_bool_t powered;
2474
2475         if (argc < 2) {
2476                 ad_advertise_tx_power(dbus_conn, NULL);
2477                 return;
2478         }
2479
2480         if (!parse_argument(argc, argv, NULL, NULL, &powered, NULL))
2481                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2482
2483         ad_advertise_tx_power(dbus_conn, &powered);
2484 }
2485
2486 static void cmd_advertise_name(int argc, char *argv[])
2487 {
2488         if (argc < 2) {
2489                 ad_advertise_local_name(dbus_conn, NULL);
2490                 return;
2491         }
2492
2493         if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) {
2494                 ad_advertise_name(dbus_conn, true);
2495                 return;
2496         }
2497
2498         if (strcmp(argv[1], "off") == 0 || strcmp(argv[1], "no") == 0) {
2499                 ad_advertise_name(dbus_conn, false);
2500                 return;
2501         }
2502
2503         ad_advertise_local_name(dbus_conn, argv[1]);
2504 }
2505
2506 static void cmd_advertise_appearance(int argc, char *argv[])
2507 {
2508         long int value;
2509         char *endptr = NULL;
2510
2511         if (argc < 2) {
2512                 ad_advertise_local_appearance(dbus_conn, NULL);
2513                 return;
2514         }
2515
2516         if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) {
2517                 ad_advertise_appearance(dbus_conn, true);
2518                 return;
2519         }
2520
2521         if (strcmp(argv[1], "off") == 0 || strcmp(argv[1], "no") == 0) {
2522                 ad_advertise_appearance(dbus_conn, false);
2523                 return;
2524         }
2525
2526         value = strtol(argv[1], &endptr, 0);
2527         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2528                 bt_shell_printf("Invalid argument\n");
2529                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2530         }
2531
2532         ad_advertise_local_appearance(dbus_conn, &value);
2533 }
2534
2535 static void cmd_advertise_duration(int argc, char *argv[])
2536 {
2537         long int value;
2538         char *endptr = NULL;
2539
2540         if (argc < 2) {
2541                 ad_advertise_duration(dbus_conn, NULL);
2542                 return;
2543         }
2544
2545         value = strtol(argv[1], &endptr, 0);
2546         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2547                 bt_shell_printf("Invalid argument\n");
2548                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2549         }
2550
2551         ad_advertise_duration(dbus_conn, &value);
2552 }
2553
2554 static void cmd_advertise_timeout(int argc, char *argv[])
2555 {
2556         long int value;
2557         char *endptr = NULL;
2558
2559         if (argc < 2) {
2560                 ad_advertise_timeout(dbus_conn, NULL);
2561                 return;
2562         }
2563
2564         value = strtol(argv[1], &endptr, 0);
2565         if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
2566                 bt_shell_printf("Invalid argument\n");
2567                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2568         }
2569
2570         ad_advertise_timeout(dbus_conn, &value);
2571 }
2572
2573 static void cmd_advertise_secondary(int argc, char *argv[])
2574 {
2575         if (argc < 2) {
2576                 ad_advertise_secondary(dbus_conn, NULL);
2577                 return;
2578         }
2579
2580         ad_advertise_secondary(dbus_conn, argv[1]);
2581 }
2582
2583 static void ad_clear_uuids(void)
2584 {
2585         ad_disable_uuids(dbus_conn);
2586 }
2587
2588 static void ad_clear_service(void)
2589 {
2590         ad_disable_service(dbus_conn);
2591 }
2592
2593 static void ad_clear_manufacturer(void)
2594 {
2595         ad_disable_manufacturer(dbus_conn);
2596 }
2597
2598 static void ad_clear_data(void)
2599 {
2600         ad_disable_data(dbus_conn);
2601 }
2602
2603 static void ad_clear_tx_power(void)
2604 {
2605         dbus_bool_t powered = false;
2606
2607         ad_advertise_tx_power(dbus_conn, &powered);
2608 }
2609
2610 static void ad_clear_name(void)
2611 {
2612         ad_advertise_name(dbus_conn, false);
2613 }
2614
2615 static void ad_clear_appearance(void)
2616 {
2617         ad_advertise_appearance(dbus_conn, false);
2618 }
2619
2620 static void ad_clear_duration(void)
2621 {
2622         long int value = 0;
2623
2624         ad_advertise_duration(dbus_conn, &value);
2625 }
2626
2627 static void ad_clear_timeout(void)
2628 {
2629         long int value = 0;
2630
2631         ad_advertise_timeout(dbus_conn, &value);
2632 }
2633
2634 static void ad_clear_secondary(void)
2635 {
2636         const char *value = "";
2637
2638         ad_advertise_secondary(dbus_conn, value);
2639 }
2640
2641 static const struct clear_entry ad_clear[] = {
2642         { "uuids",              ad_clear_uuids },
2643         { "service",            ad_clear_service },
2644         { "manufacturer",       ad_clear_manufacturer },
2645         { "data",               ad_clear_data },
2646         { "tx-power",           ad_clear_tx_power },
2647         { "name",               ad_clear_name },
2648         { "appearance",         ad_clear_appearance },
2649         { "duration",           ad_clear_duration },
2650         { "timeout",            ad_clear_timeout },
2651         { "secondary",          ad_clear_secondary },
2652         {}
2653 };
2654
2655 static void cmd_ad_clear(int argc, char *argv[])
2656 {
2657         bool all = false;
2658
2659         if (argc < 2 || !strlen(argv[1]))
2660                 all = true;
2661
2662         if(!data_clear(ad_clear, all ? "all" : argv[1]))
2663                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2664 }
2665
2666 static const struct bt_shell_menu advertise_menu = {
2667         .name = "advertise",
2668         .desc = "Advertise Options Submenu",
2669         .entries = {
2670         { "uuids", "[uuid1 uuid2 ...]", cmd_advertise_uuids,
2671                         "Set/Get advertise uuids" },
2672         { "service", "[uuid] [data=xx xx ...]", cmd_advertise_service,
2673                         "Set/Get advertise service data" },
2674         { "manufacturer", "[id] [data=xx xx ...]",
2675                         cmd_advertise_manufacturer,
2676                         "Set/Get advertise manufacturer data" },
2677         { "data", "[type] [data=xx xx ...]", cmd_advertise_data,
2678                         "Set/Get advertise data" },
2679         { "discoverable", "[on/off]", cmd_advertise_discoverable,
2680                         "Set/Get advertise discoverable" },
2681         { "discoverable-timeout", "[seconds]",
2682                         cmd_advertise_discoverable_timeout,
2683                         "Set/Get advertise discoverable timeout" },
2684         { "tx-power", "[on/off]", cmd_advertise_tx_power,
2685                         "Show/Enable/Disable TX power to be advertised",
2686                                                         NULL },
2687         { "name", "[on/off/name]", cmd_advertise_name,
2688                         "Configure local name to be advertised" },
2689         { "appearance", "[on/off/value]", cmd_advertise_appearance,
2690                         "Configure custom appearance to be advertised" },
2691         { "duration", "[seconds]", cmd_advertise_duration,
2692                         "Set/Get advertise duration" },
2693         { "timeout", "[seconds]", cmd_advertise_timeout,
2694                         "Set/Get advertise timeout" },
2695         { "secondary", "[1M/2M/Coded]", cmd_advertise_secondary,
2696                         "Set/Get advertise secondary channel" },
2697         { "clear", "[uuids/service/manufacturer/config-name...]", cmd_ad_clear,
2698                         "Clear advertise config" },
2699         { } },
2700 };
2701
2702 static const struct bt_shell_menu scan_menu = {
2703         .name = "scan",
2704         .desc = "Scan Options Submenu",
2705         .entries = {
2706         { "uuids", "[all/uuid1 uuid2 ...]", cmd_scan_filter_uuids,
2707                                 "Set/Get UUIDs filter" },
2708         { "rssi", "[rssi]", cmd_scan_filter_rssi,
2709                                 "Set/Get RSSI filter, and clears pathloss" },
2710         { "pathloss", "[pathloss]", cmd_scan_filter_pathloss,
2711                                 "Set/Get Pathloss filter, and clears RSSI" },
2712         { "transport", "[transport]", cmd_scan_filter_transport,
2713                                 "Set/Get transport filter" },
2714         { "duplicate-data", "[on/off]", cmd_scan_filter_duplicate_data,
2715                                 "Set/Get duplicate data filter",
2716                                 NULL },
2717         { "discoverable", "[on/off]", cmd_scan_filter_discoverable,
2718                                 "Set/Get discoverable filter",
2719                                 NULL },
2720         { "pattern", "[value]", cmd_scan_filter_pattern,
2721                                 "Set/Get pattern filter",
2722                                 NULL },
2723         { "clear",
2724         "[uuids/rssi/pathloss/transport/duplicate-data/discoverable/pattern]",
2725                                 cmd_scan_filter_clear,
2726                                 "Clears discovery filter.",
2727                                 filter_clear_generator },
2728         { } },
2729 };
2730
2731 static const struct bt_shell_menu gatt_menu = {
2732         .name = "gatt",
2733         .desc = "Generic Attribute Submenu",
2734         .entries = {
2735         { "list-attributes", "[dev/local]", cmd_list_attributes,
2736                                 "List attributes", dev_generator },
2737         { "select-attribute", "<attribute/UUID>",  cmd_select_attribute,
2738                                 "Select attribute", attribute_generator },
2739         { "attribute-info", "[attribute/UUID]",  cmd_attribute_info,
2740                                 "Select attribute", attribute_generator },
2741         { "read", "[offset]", cmd_read, "Read attribute value" },
2742         { "write", "<data=xx xx ...> [offset] [type]", cmd_write,
2743                                                 "Write attribute value" },
2744         { "acquire-write", NULL, cmd_acquire_write,
2745                                         "Acquire Write file descriptor" },
2746         { "release-write", NULL, cmd_release_write,
2747                                         "Release Write file descriptor" },
2748         { "acquire-notify", NULL, cmd_acquire_notify,
2749                                         "Acquire Notify file descriptor" },
2750         { "release-notify", NULL, cmd_release_notify,
2751                                         "Release Notify file descriptor" },
2752         { "notify",       "<on/off>", cmd_notify, "Notify attribute value",
2753                                                         NULL },
2754         { "clone",        "[dev/attribute/UUID]", cmd_clone,
2755                                                 "Clone a device or attribute" },
2756         { "register-application", "[UUID ...]", cmd_register_app,
2757                                                 "Register profile to connect" },
2758         { "unregister-application", NULL, cmd_unregister_app,
2759                                                 "Unregister profile" },
2760         { "register-service", "<UUID> [handle]", cmd_register_service,
2761                                         "Register application service."  },
2762         { "unregister-service", "<UUID/object>", cmd_unregister_service,
2763                                         "Unregister application service" },
2764         { "register-includes", "<UUID> [handle]", cmd_register_includes,
2765                                         "Register as Included service in." },
2766         { "unregister-includes", "<Service-UUID><Inc-UUID>",
2767                         cmd_unregister_includes,
2768                                  "Unregister Included service." },
2769         { "register-characteristic",
2770                         "<UUID> <Flags=read,write,notify...> [handle]",
2771                         cmd_register_characteristic,
2772                         "Register application characteristic" },
2773         { "unregister-characteristic", "<UUID/object>",
2774                                 cmd_unregister_characteristic,
2775                                 "Unregister application characteristic" },
2776         { "register-descriptor", "<UUID> <Flags=read,write...> [handle]",
2777                                         cmd_register_descriptor,
2778                                         "Register application descriptor" },
2779         { "unregister-descriptor", "<UUID/object>",
2780                                         cmd_unregister_descriptor,
2781                                         "Unregister application descriptor" },
2782         { } },
2783 };
2784
2785 static const struct bt_shell_menu main_menu = {
2786         .name = "main",
2787         .entries = {
2788         { "list",         NULL,       cmd_list, "List available controllers" },
2789         { "show",         "[ctrl]",   cmd_show, "Controller information",
2790                                                         ctrl_generator },
2791         { "select",       "<ctrl>",   cmd_select, "Select default controller",
2792                                                         ctrl_generator },
2793         { "devices",      NULL,       cmd_devices, "List available devices" },
2794         { "paired-devices", NULL,     cmd_paired_devices,
2795                                         "List paired devices"},
2796         { "system-alias", "<name>",   cmd_system_alias,
2797                                         "Set controller alias" },
2798         { "reset-alias",  NULL,       cmd_reset_alias,
2799                                         "Reset controller alias" },
2800         { "power",        "<on/off>", cmd_power, "Set controller power",
2801                                                         NULL },
2802         { "pairable",     "<on/off>", cmd_pairable,
2803                                         "Set controller pairable mode",
2804                                                         NULL },
2805         { "discoverable", "<on/off>", cmd_discoverable,
2806                                         "Set controller discoverable mode",
2807                                                         NULL },
2808         { "discoverable-timeout", "[value]", cmd_discoverable_timeout,
2809                                         "Set discoverable timeout", NULL },
2810         { "agent",        "<on/off/capability>", cmd_agent,
2811                                 "Enable/disable agent with given capability",
2812                                                         capability_generator},
2813         { "default-agent",NULL,       cmd_default_agent,
2814                                 "Set agent as the default one" },
2815         { "advertise",    "<on/off/type>", cmd_advertise,
2816                                 "Enable/disable advertising with given type",
2817                                                         ad_generator},
2818         { "set-alias",    "<alias>",  cmd_set_alias, "Set device alias" },
2819         { "scan",         "<on/off>", cmd_scan, "Scan for devices", NULL },
2820         { "info",         "[dev]",    cmd_info, "Device information",
2821                                                         dev_generator },
2822         { "pair",         "[dev]",    cmd_pair, "Pair with device",
2823                                                         dev_generator },
2824         { "trust",        "[dev]",    cmd_trust, "Trust device",
2825                                                         dev_generator },
2826         { "untrust",      "[dev]",    cmd_untrust, "Untrust device",
2827                                                         dev_generator },
2828         { "block",        "[dev]",    cmd_block, "Block device",
2829                                                                 dev_generator },
2830         { "unblock",      "[dev]",    cmd_unblock, "Unblock device",
2831                                                                 dev_generator },
2832         { "remove",       "<dev>",    cmd_remove, "Remove device",
2833                                                         dev_generator },
2834         { "connect",      "<dev>",    cmd_connect, "Connect device",
2835                                                         dev_generator },
2836         { "disconnect",   "[dev]",    cmd_disconn, "Disconnect device",
2837                                                         dev_generator },
2838         { } },
2839 };
2840
2841 static const struct option options[] = {
2842         { "agent",      required_argument, 0, 'a' },
2843         { 0, 0, 0, 0 }
2844 };
2845
2846 static const char *agent_option;
2847
2848 static const char **optargs[] = {
2849         &agent_option
2850 };
2851
2852 static const char *help[] = {
2853         "Register agent handler: <capability>"
2854 };
2855
2856 static const struct bt_shell_opt opt = {
2857         .options = options,
2858         .optno = sizeof(options) / sizeof(struct option),
2859         .optstr = "a:",
2860         .optarg = optargs,
2861         .help = help,
2862 };
2863
2864 static void client_ready(GDBusClient *client, void *user_data)
2865 {
2866         setup_standard_input();
2867 }
2868
2869 int main(int argc, char *argv[])
2870 {
2871         GDBusClient *client;
2872         int status;
2873
2874         bt_shell_init(argc, argv, &opt);
2875         bt_shell_set_menu(&main_menu);
2876         bt_shell_add_submenu(&advertise_menu);
2877         bt_shell_add_submenu(&scan_menu);
2878         bt_shell_add_submenu(&gatt_menu);
2879         bt_shell_set_prompt(PROMPT_OFF);
2880
2881         if (agent_option)
2882                 auto_register_agent = g_strdup(agent_option);
2883         else
2884                 auto_register_agent = g_strdup("");
2885
2886         dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
2887         g_dbus_attach_object_manager(dbus_conn);
2888
2889         bt_shell_set_env("DBUS_CONNECTION", dbus_conn);
2890
2891         client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
2892
2893         g_dbus_client_set_connect_watch(client, connect_handler, NULL);
2894         g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
2895         g_dbus_client_set_signal_watch(client, message_handler, NULL);
2896
2897         g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
2898                                                         property_changed, NULL);
2899
2900         g_dbus_client_set_ready_watch(client, client_ready, NULL);
2901
2902         status = bt_shell_run();
2903
2904         g_dbus_client_unref(client);
2905
2906         dbus_connection_unref(dbus_conn);
2907
2908         g_list_free_full(ctrl_list, proxy_leak);
2909
2910         g_free(auto_register_agent);
2911
2912         return status;
2913 }