14f5e512634c91d776a6dcdf1351d9c0e3115a5c
[platform/upstream/connman.git] / client / commands.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012-2014  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <stdbool.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <ctype.h>
35
36 #include <glib.h>
37 #include <gdbus.h>
38
39 #include "dbus_helpers.h"
40 #include "input.h"
41 #include "services.h"
42 #if defined TIZEN_EXT_INS
43 #include "ins.h"
44 #endif
45 #include "tethering.h"
46 #include "peers.h"
47 #include "commands.h"
48 #include "agent.h"
49 #include "vpnconnections.h"
50 #if defined TIZEN_EXT_WIFI_MESH
51 #include "mesh.h"
52 #endif
53
54 static DBusConnection *connection;
55 static GHashTable *service_hash;
56 static GHashTable *vpnconnection_hash;
57 static GHashTable *peer_hash;
58 static GHashTable *technology_hash;
59 static char *session_notify_path;
60 static char *session_path;
61 static bool session_connected;
62
63 struct connman_option {
64         const char *name;
65         const char val;
66         const char *desc;
67 };
68
69 static char *ipv4[] = {
70         "Method",
71         "Address",
72         "Netmask",
73         "Gateway",
74         NULL
75 };
76
77 static char *ipv6[] = {
78         "Method",
79         "Address",
80         "PrefixLength",
81         "Gateway",
82         NULL
83 };
84
85 static int cmd_help(char *args[], int num, struct connman_option *options);
86
87 static bool check_dbus_name(const char *name)
88 {
89         /*
90          * Valid dbus chars should be [A-Z][a-z][0-9]_
91          * and should not start with number.
92          */
93         unsigned int i;
94
95         if (!name || name[0] == '\0')
96                 return false;
97
98         for (i = 0; name[i] != '\0'; i++)
99                 if (!((name[i] >= 'A' && name[i] <= 'Z') ||
100                                 (name[i] >= 'a' && name[i] <= 'z') ||
101                                 (name[i] >= '0' && name[i] <= '9') ||
102                                 name[i] == '_'))
103                         return false;
104
105         return true;
106 }
107
108 static int parse_boolean(char *arg)
109 {
110         if (!arg)
111                 return -1;
112
113         if (strcasecmp(arg, "no") == 0 ||
114                         strcasecmp(arg, "false") == 0 ||
115                         strcasecmp(arg, "off" ) == 0 ||
116                         strcasecmp(arg, "disable" ) == 0 ||
117                         strcasecmp(arg, "n") == 0 ||
118                         strcasecmp(arg, "f") == 0 ||
119                         strcasecmp(arg, "0") == 0)
120                 return 0;
121
122         if (strcasecmp(arg, "yes") == 0 ||
123                         strcasecmp(arg, "true") == 0 ||
124                         strcasecmp(arg, "on") == 0 ||
125                         strcasecmp(arg, "enable" ) == 0 ||
126                         strcasecmp(arg, "y") == 0 ||
127                         strcasecmp(arg, "t") == 0 ||
128                         strcasecmp(arg, "1") == 0)
129                 return 1;
130
131         return -1;
132 }
133
134 static int parse_args(char *arg, struct connman_option *options)
135 {
136         int i;
137
138         if (!arg)
139                 return -1;
140
141         for (i = 0; options[i].name; i++) {
142                 if (strcmp(options[i].name, arg) == 0 ||
143                                 (strncmp(arg, "--", 2) == 0 &&
144                                         strcmp(&arg[2], options[i].name) == 0))
145                         return options[i].val;
146         }
147
148         return '?';
149 }
150
151 static int enable_return(DBusMessageIter *iter, int errnum, const char *error,
152                 void *user_data)
153 {
154         char *tech = user_data;
155         char *str;
156
157         str = strrchr(tech, '/');
158         if (str)
159                 str++;
160         else
161                 str = tech;
162
163         switch (errnum) {
164         case 0:
165                 fprintf(stdout, "Enabled %s\n", str);
166                 break;
167         case -ENODEV:
168                 fprintf(stderr, "%s is not available\n", str);
169                 break;
170         case -EALREADY:
171                 fprintf(stderr, "%s is already enabled\n", str);
172                 break;
173         default:
174                 fprintf(stderr, "Error %s: %s\n", str, error);
175         }
176
177         g_free(user_data);
178
179         return 0;
180 }
181
182 static int cmd_enable(char *args[], int num, struct connman_option *options)
183 {
184         char *tech;
185         dbus_bool_t b = TRUE;
186
187         if (num > 2)
188                 return -E2BIG;
189
190         if (num < 2)
191                 return -EINVAL;
192
193         if (check_dbus_name(args[1]) == false)
194                 return -EINVAL;
195
196         if (strcmp(args[1], "offline") == 0) {
197                 tech = g_strdup(args[1]);
198                 return __connmanctl_dbus_set_property(connection, "/",
199                                 "net.connman.Manager", enable_return, tech,
200                                 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
201         }
202
203         tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
204         return __connmanctl_dbus_set_property(connection, tech,
205                                 "net.connman.Technology", enable_return, tech,
206                                 "Powered", DBUS_TYPE_BOOLEAN, &b);
207 }
208
209 static int disable_return(DBusMessageIter *iter, int errnum, const char *error,
210                 void *user_data)
211 {
212         char *tech = user_data;
213         char *str;
214
215         str = strrchr(tech, '/');
216         if (str)
217                 str++;
218         else
219                 str = tech;
220
221         switch (errnum) {
222         case 0:
223                 fprintf(stdout, "Disable %s\n", str);
224                 break;
225         case -ENODEV:
226                 fprintf(stderr, "%s is not available\n", str);
227                 break;
228         case -EALREADY:
229                 fprintf(stderr, "%s is already disabled\n", str);
230                 break;
231         default:
232                 fprintf(stderr, "Error %s: %s\n", str, error);
233         }
234
235         g_free(user_data);
236
237         return 0;
238 }
239
240 static int cmd_disable(char *args[], int num, struct connman_option *options)
241 {
242         char *tech;
243         dbus_bool_t b = FALSE;
244
245         if (num > 2)
246                 return -E2BIG;
247
248         if (num < 2)
249                 return -EINVAL;
250
251         if (check_dbus_name(args[1]) == false)
252                 return -EINVAL;
253
254         if (strcmp(args[1], "offline") == 0) {
255                 tech = g_strdup(args[1]);
256                 return __connmanctl_dbus_set_property(connection, "/",
257                                 "net.connman.Manager", disable_return, tech,
258                                 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
259         }
260
261         tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
262         return __connmanctl_dbus_set_property(connection, tech,
263                                 "net.connman.Technology", disable_return, tech,
264                                 "Powered", DBUS_TYPE_BOOLEAN, &b);
265 }
266
267 static int state_print(DBusMessageIter *iter, int errnum, const char *error,
268                 void *user_data)
269 {
270         DBusMessageIter entry;
271
272         if (error) {
273                 fprintf(stderr, "Error: %s\n", error);
274                 return 0;
275         }
276
277         dbus_message_iter_recurse(iter, &entry);
278         __connmanctl_dbus_print(&entry, "  ", " = ", "\n");
279         fprintf(stdout, "\n");
280
281         return 0;
282 }
283
284 static int cmd_state(char *args[], int num, struct connman_option *options)
285 {
286         if (num > 1)
287                 return -E2BIG;
288
289         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
290                         CONNMAN_PATH, "net.connman.Manager", "GetProperties",
291                         state_print, NULL, NULL, NULL);
292 }
293
294 static int clock_print(DBusMessageIter *iter, int errnum, const char *error,
295                 void *user_data)
296 {
297         DBusMessageIter entry;
298
299         if (error) {
300                 fprintf(stderr, "Error: %s\n", error);
301                 return 0;
302         }
303
304         dbus_message_iter_recurse(iter, &entry);
305         __connmanctl_dbus_print(&entry, "  ", " = ", "\n");
306         fprintf(stdout, "\n");
307
308         return 0;
309 }
310
311 static int cmd_clock(char *args[], int num, struct connman_option *options)
312 {
313         if (num > 1)
314                 return -E2BIG;
315
316         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
317                         CONNMAN_PATH, "net.connman.Clock", "GetProperties",
318                         clock_print, NULL, NULL, NULL);
319 }
320
321 static int services_list(DBusMessageIter *iter, int errnum, const char *error,
322                 void *user_data)
323 {
324         if (!error) {
325                 __connmanctl_services_list(iter);
326                 fprintf(stdout, "\n");
327         } else {
328                 fprintf(stderr, "Error: %s\n", error);
329         }
330
331         return 0;
332 }
333
334 #if defined TIZEN_EXT_INS
335 static int ins_list(DBusMessageIter *iter, int errnum,
336                         const char *error, void *user_data)
337 {
338         char *filter = user_data;
339
340         if (!error) {
341                 __connmanctl_ins_list(iter, filter);
342                 fprintf(stdout, "\n");
343         } else {
344                 fprintf(stderr, "Error: %s\n", error);
345         }
346
347         g_free(filter);
348
349         return 0;
350 }
351 #endif
352
353 static int peers_list(DBusMessageIter *iter, int errnum,
354                                         const char *error, void *user_data)
355 {
356         if (!error) {
357                 __connmanctl_peers_list(iter);
358                 fprintf(stdout, "\n");
359         } else
360                 fprintf(stderr, "Error: %s\n", error);
361
362         return 0;
363 }
364
365 static int tethering_clients_list(DBusMessageIter *iter, int errnum,
366                                         const char *error, void *user_data)
367 {
368         if (!error) {
369                 __connmanctl_tethering_clients_list(iter);
370                 fprintf(stdout, "\n");
371         } else
372                 fprintf(stderr, "Error: %s\n", error);
373
374         return 0;
375 }
376
377 static int object_properties(DBusMessageIter *iter, int errnum,
378                                         const char *error, void *user_data)
379 {
380         char *path = user_data;
381         char *str;
382         DBusMessageIter dict;
383
384         if (!error) {
385                 fprintf(stdout, "%s\n", path);
386
387                 dbus_message_iter_recurse(iter, &dict);
388                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
389
390                 fprintf(stdout, "\n");
391
392         } else {
393                 str = strrchr(path, '/');
394                 if (str)
395                         str++;
396                 else
397                         str = path;
398
399                 fprintf(stderr, "Error %s: %s\n", str, error);
400         }
401
402         g_free(user_data);
403
404         return 0;
405 }
406
407 static int cmd_services(char *args[], int num, struct connman_option *options)
408 {
409         char *service_name = NULL;
410         char *path;
411         int c;
412
413         if (num > 3)
414                 return -E2BIG;
415
416         c = parse_args(args[1], options);
417         switch (c) {
418         case -1:
419                 break;
420         case 'p':
421                 if (num < 3)
422                         return -EINVAL;
423                 service_name = args[2];
424                 break;
425         default:
426                 if (num > 2)
427                         return -E2BIG;
428                 service_name = args[1];
429                 break;
430         }
431
432         if (!service_name) {
433                 return __connmanctl_dbus_method_call(connection,
434                                 CONNMAN_SERVICE, CONNMAN_PATH,
435                                 "net.connman.Manager", "GetServices",
436                                 services_list, NULL, NULL, NULL);
437         }
438
439         if (check_dbus_name(service_name) == false)
440                 return -EINVAL;
441
442         path = g_strdup_printf("/net/connman/service/%s", service_name);
443         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
444                         "net.connman.Service", "GetProperties",
445                         object_properties, path, NULL, NULL);
446 }
447
448 #if defined TIZEN_EXT_INS
449 static int cmd_ins(char *args[], int num, struct connman_option *options)
450 {
451         char *filter = NULL;
452
453         if (num > 2)
454                 return -E2BIG;
455
456         if (num == 2)
457                 filter = g_strdup(args[1]);
458
459         return __connmanctl_dbus_method_call(connection,
460                                 CONNMAN_SERVICE, CONNMAN_PATH,
461                                 "net.connman.Manager", "GetINS",
462                                 ins_list, filter, NULL, NULL);
463 }
464 #endif
465
466 static int cmd_peers(char *args[], int num, struct connman_option *options)
467 {
468         char *peer_name = NULL;
469         char *path;
470
471         if (num > 2)
472                 return -E2BIG;
473
474         if (num == 2)
475                 peer_name = args[1];
476
477         if (!peer_name) {
478                 return __connmanctl_dbus_method_call(connection,
479                                         CONNMAN_SERVICE, CONNMAN_PATH,
480                                         "net.connman.Manager", "GetPeers",
481                                         peers_list, NULL, NULL, NULL);
482         }
483
484         if (check_dbus_name(peer_name) == false)
485                 return -EINVAL;
486
487         path = g_strdup_printf("/net/connman/peer/%s", peer_name);
488         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
489                                 path, "net.connman.Peer", "GetProperties",
490                                 object_properties, path, NULL, NULL);
491 }
492
493 static int technology_print(DBusMessageIter *iter, int errnum, const char *error,
494                 void *user_data)
495 {
496         DBusMessageIter array;
497
498         if (error) {
499                 fprintf(stderr, "Error: %s\n", error);
500                 return 0;
501         }
502
503         dbus_message_iter_recurse(iter, &array);
504         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
505                 DBusMessageIter entry, dict;
506                 const char *path;
507
508                 dbus_message_iter_recurse(&array, &entry);
509                 dbus_message_iter_get_basic(&entry, &path);
510                 fprintf(stdout, "%s\n", path);
511
512                 dbus_message_iter_next(&entry);
513
514                 dbus_message_iter_recurse(&entry, &dict);
515                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
516                 fprintf(stdout, "\n");
517
518                 dbus_message_iter_next(&array);
519         }
520
521         return 0;
522 }
523
524 static int cmd_technologies(char *args[], int num,
525                 struct connman_option *options)
526 {
527         if (num > 1)
528                 return -E2BIG;
529
530         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
531                         CONNMAN_PATH, "net.connman.Manager", "GetTechnologies",
532                         technology_print, NULL, NULL, NULL);
533 }
534
535 struct tether_enable {
536         char *path;
537         dbus_bool_t enable;
538 };
539
540 static int tether_set_return(DBusMessageIter *iter, int errnum,
541                         const char *error, void *user_data)
542 {
543         struct tether_enable *tether = user_data;
544         char *str;
545
546         str = strrchr(tether->path, '/');
547         if (str)
548                 str++;
549         else
550                 str = tether->path;
551
552         if (!error) {
553                 fprintf(stdout, "%s tethering for %s\n",
554                                 tether->enable ? "Enabled" : "Disabled",
555                                 str);
556         } else
557                 fprintf(stderr, "Error %s %s tethering: %s\n",
558                                 tether->enable ?
559                                 "enabling" : "disabling", str, error);
560
561         g_free(tether->path);
562         g_free(user_data);
563
564         return 0;
565 }
566
567 static int tether_set(char *technology, int set_tethering)
568 {
569         struct tether_enable *tether = g_new(struct tether_enable, 1);
570
571         switch(set_tethering) {
572         case 1:
573                 tether->enable = TRUE;
574                 break;
575         case 0:
576                 tether->enable = FALSE;
577                 break;
578         default:
579                 g_free(tether);
580                 return 0;
581         }
582
583         tether->path = g_strdup_printf("/net/connman/technology/%s",
584                         technology);
585
586         return __connmanctl_dbus_set_property(connection, tether->path,
587                         "net.connman.Technology", tether_set_return,
588                         tether, "Tethering", DBUS_TYPE_BOOLEAN,
589                         &tether->enable);
590 }
591
592 struct tether_properties {
593         int ssid_result;
594         int passphrase_result;
595         int set_tethering;
596 };
597
598 static int tether_update(struct tether_properties *tether)
599 {
600         int ret;
601
602         if (tether->ssid_result == 0 && tether->passphrase_result == 0) {
603                 ret = tether_set("wifi", tether->set_tethering);
604                 g_free(tether);
605                 return ret;
606         }
607
608         if (tether->ssid_result != -EINPROGRESS &&
609                         tether->passphrase_result != -EINPROGRESS) {
610                 g_free(tether);
611                 return 0;
612         }
613
614         return -EINPROGRESS;
615 }
616
617 static int tether_set_ssid_return(DBusMessageIter *iter, int errnum,
618                                 const char *error, void *user_data)
619 {
620         struct tether_properties *tether = user_data;
621
622         if (!error) {
623                 fprintf(stdout, "Wifi SSID set\n");
624                 tether->ssid_result = 0;
625         } else {
626                 fprintf(stderr, "Error setting wifi SSID: %s\n", error);
627                 tether->ssid_result = -EINVAL;
628         }
629
630         return tether_update(tether);
631 }
632
633 static int tether_set_passphrase_return(DBusMessageIter *iter, int errnum,
634                                         const char *error, void *user_data)
635 {
636         struct tether_properties *tether = user_data;
637
638         if (!error) {
639                 fprintf(stdout, "Wifi passphrase set\n");
640                 tether->passphrase_result = 0;
641         } else {
642                 fprintf(stderr, "Error setting wifi passphrase: %s\n", error);
643                 tether->passphrase_result = -EINVAL;
644         }
645
646         return tether_update(tether);
647 }
648
649 static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
650 {
651         struct tether_properties *tether = g_new(struct tether_properties, 1);
652
653         tether->set_tethering = set_tethering;
654
655         tether->ssid_result = __connmanctl_dbus_set_property(connection,
656                         "/net/connman/technology/wifi",
657                         "net.connman.Technology",
658                         tether_set_ssid_return, tether,
659                         "TetheringIdentifier", DBUS_TYPE_STRING, &ssid);
660
661         tether->passphrase_result =__connmanctl_dbus_set_property(connection,
662                         "/net/connman/technology/wifi",
663                         "net.connman.Technology",
664                         tether_set_passphrase_return, tether,
665                         "TetheringPassphrase", DBUS_TYPE_STRING, &passphrase);
666
667         if (tether->ssid_result != -EINPROGRESS &&
668                         tether->passphrase_result != -EINPROGRESS) {
669                 g_free(tether);
670                 return -ENXIO;
671         }
672
673         return -EINPROGRESS;
674 }
675
676 #if defined TIZEN_EXT_WIFI_MESH
677 struct mesh_if_prop {
678         char *ifname;
679         char *parent_ifname;
680         char *bridge_ifname;
681 };
682
683 struct mesh_create_network {
684         char *name;
685         unsigned int freq;
686         char *sec_type;
687 };
688
689 struct mesh_specific_scan_params {
690         char *name;
691         unsigned int freq;
692 };
693
694 struct mesh_gate_params {
695         bool gate_announce;
696         int hwmp_rootmode;
697         int stp;
698 };
699
700 static int mesh_return(DBusMessageIter *iter, const char *error,
701                 void *user_data)
702 {
703         char *method = user_data;
704
705         if (error)
706                 fprintf(stderr, "Error %s: %s\n", method, error);
707         else
708                 fprintf(stderr, "Success %s\n", method);
709
710         g_free(method);
711
712         return 0;
713 }
714
715 static void mesh_interface_add_append(DBusMessageIter *iter, void *user_data)
716 {
717         struct mesh_if_prop *append = user_data;
718
719         /* Append Virtual Interface Name */
720                 __connmanctl_dbus_append_dict_entry(iter, "Ifname",
721                                 DBUS_TYPE_STRING, &append->ifname);
722
723         /* Append Parent WiFi Interface Name */
724                 __connmanctl_dbus_append_dict_entry(iter, "ParentIfname",
725                                 DBUS_TYPE_STRING, &append->parent_ifname);
726
727         /* Append Bridge Interface Name */
728                 if (append->bridge_ifname)
729                         __connmanctl_dbus_append_dict_entry(iter, "BridgeIfname",
730                                                 DBUS_TYPE_STRING, &append->bridge_ifname);
731 }
732
733 static void mesh_interface_remove_append(DBusMessageIter *iter, void *user_data)
734 {
735         struct mesh_if_prop *append = user_data;
736
737         /* Append Virtual Interface Name */
738                 __connmanctl_dbus_append_dict_entry(iter, "Ifname",
739                                 DBUS_TYPE_STRING, &append->ifname);
740 }
741
742 static void mesh_create_network_append(DBusMessageIter *iter, void *user_data)
743 {
744         struct mesh_create_network *append = user_data;
745
746         /* Append Mesh Network Name */
747                 __connmanctl_dbus_append_dict_entry(iter, "Name",
748                                 DBUS_TYPE_STRING, &append->name);
749
750         /* Append Mesh Network Frequency */
751                 __connmanctl_dbus_append_dict_entry(iter, "Frequency",
752                                 DBUS_TYPE_UINT16, &append->freq);
753
754         /* Append Mesh Network Security Type */
755                 __connmanctl_dbus_append_dict_entry(iter, "Security",
756                                 DBUS_TYPE_STRING, &append->sec_type);
757 }
758
759 static void mesh_specific_scan_append(DBusMessageIter *iter, void *user_data)
760 {
761         struct mesh_specific_scan_params *append = user_data;
762
763         /* Append Mesh Network Name */
764                 __connmanctl_dbus_append_dict_entry(iter, "Name",
765                                 DBUS_TYPE_STRING, &append->name);
766
767         /* Append Mesh Network Frequency */
768                 __connmanctl_dbus_append_dict_entry(iter, "Frequency",
769                                 DBUS_TYPE_UINT16, &append->freq);
770 }
771
772 static void mesh_set_gate_append(DBusMessageIter *iter, void *user_data)
773 {
774         struct mesh_gate_params *append = user_data;
775
776         /* Append Gate Announce Protocol */
777                 __connmanctl_dbus_append_dict_entry(iter, "GateAnnounce",
778                                 DBUS_TYPE_BOOLEAN, &append->gate_announce);
779
780         /* Append HWMP Root Mode */
781                 __connmanctl_dbus_append_dict_entry(iter, "HWMPRootMode",
782                                 DBUS_TYPE_UINT16, &append->hwmp_rootmode);
783
784         /* Append STP */
785                 __connmanctl_dbus_append_dict_entry(iter, "STP", DBUS_TYPE_UINT16,
786                                 &append->stp);
787 }
788
789 static void mesh_peer_append(DBusMessageIter *iter, void *user_data)
790 {
791         char *peer_addr = user_data;
792
793         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &peer_addr);
794
795         g_free(peer_addr);
796 }
797
798 static int mesh_peers_list(DBusMessageIter *iter,
799                                         const char *error, void *user_data)
800 {
801         if (!error) {
802                 __connmanctl_mesh_peers_list(iter);
803                 fprintf(stdout, "\n");
804         } else
805                 fprintf(stderr, "Error: %s\n", error);
806
807         return 0;
808 }
809
810 static int connected_mesh_peers_list(DBusMessageIter *iter,
811                                         const char *error, void *user_data)
812 {
813         if (!error) {
814                 __connmanctl_mesh_connected_peers_list(iter);
815                 fprintf(stdout, "\n");
816         } else
817                 fprintf(stderr, "Error: %s\n", error);
818
819         return 0;
820 }
821
822 static int disconnected_mesh_peers_list(DBusMessageIter *iter,
823                                         const char *error, void *user_data)
824 {
825         if (!error) {
826                 __connmanctl_mesh_disconnected_peers_list(iter);
827                 fprintf(stdout, "\n");
828         } else
829                 fprintf(stderr, "Error: %s\n", error);
830
831         return 0;
832 }
833
834 static int mesh_connect_return(DBusMessageIter *iter, const char *error,
835                 void *user_data)
836 {
837         char *path = user_data;
838
839         if (!error) {
840                 char *str = strrchr(path, '/');
841                 str++;
842                 fprintf(stdout, "Connected %s\n", str);
843         } else
844                 fprintf(stderr, "Error %s: %s\n", path, error);
845
846         g_free(user_data);
847
848         return 0;
849 }
850
851 static int mesh_disconnect_return(DBusMessageIter *iter, const char *error,
852                 void *user_data)
853 {
854         char *path = user_data;
855
856         if (!error) {
857                 char *str = strrchr(path, '/');
858                 str++;
859                 fprintf(stdout, "Disconnected %s\n", str);
860         } else
861                 fprintf(stderr, "Error %s: %s\n", path, error);
862
863         g_free(user_data);
864
865         return 0;
866 }
867
868 static int mesh_remove_return(DBusMessageIter *iter, const char *error,
869                 void *user_data)
870 {
871         char *path = user_data;
872
873         if (!error) {
874                 char *str = strrchr(path, '/');
875                 str++;
876                 fprintf(stdout, "Removed %s\n", str);
877         } else
878                 fprintf(stderr, "Error %s: %s\n", path, error);
879
880         g_free(user_data);
881
882         return 0;
883 }
884
885 static int mesh_config_return(DBusMessageIter *iter, const char *error,
886                 void *user_data)
887 {
888         char *path = user_data;
889         char *str = strrchr(path, '/');
890         str++;
891
892         if (error)
893                 fprintf(stderr, "Error %s: %s\n", path, error);
894         else
895                 fprintf(stdout, "Success SetProperty %s\n", str);
896
897         g_free(user_data);
898
899         return 0;
900 }
901
902 static int cmd_mesh(char *args[], int num, struct connman_option *options)
903 {
904         int result = 0;
905         int c;
906         char *path = NULL;
907         char *method = NULL;
908         char *mesh_peer_name = NULL;
909         char *mesh_peer_path = NULL;
910         char *property = NULL;
911         char *value = NULL;
912         struct mesh_if_prop *append;
913         struct mesh_create_network *network;
914         struct mesh_specific_scan_params *scan_params;
915         struct mesh_gate_params *gate_params;
916         char *mesh_peer_addr = NULL;
917
918         c = parse_args(args[1], options);
919
920         switch (c) {
921         case 'a':
922                 if (num < 4 || num > 5) {
923                         result = -EINVAL;
924                         break;
925                 }
926                 path = g_strdup_printf("/net/connman/technology/mesh");
927
928                 append = dbus_malloc0(sizeof(struct mesh_if_prop));
929                 append->ifname = g_strdup(args[2]);
930                 append->parent_ifname = g_strdup(args[3]);
931                 if (num == 5)
932                         append->bridge_ifname = g_strdup(args[4]);
933                 method = g_strdup("MeshInterfaceAdd");
934                 result = __connmanctl_dbus_mesh_dict(connection, path,
935                                                         "net.connman.Technology", mesh_return, method,
936                                                         "MeshInterfaceAdd", DBUS_TYPE_STRING,
937                                                         mesh_interface_add_append, append);
938                 g_free(append->ifname);
939                 g_free(append->parent_ifname);
940                 g_free(append->bridge_ifname);
941                 g_free(append);
942                 break;
943
944         case 'r':
945                 if (num != 3) {
946                         result = -EINVAL;
947                         break;
948                 }
949                 path = g_strdup_printf("/net/connman/technology/mesh");
950
951                 append = dbus_malloc0(sizeof(struct mesh_if_prop));
952                 append->ifname = g_strdup(args[2]);
953                 method = g_strdup("MeshInterfaceRemove");
954                 result = __connmanctl_dbus_mesh_dict(connection, path,
955                                                         "net.connman.Technology", mesh_return, method,
956                                                         "MeshInterfaceRemove", DBUS_TYPE_STRING,
957                                                         mesh_interface_remove_append, append);
958                 g_free(append->ifname);
959                 g_free(append);
960                 break;
961
962         case 'p':
963                 if (num > 3) {
964                         result = -E2BIG;
965                         break;
966                 }
967
968                 if (num == 3)
969                         mesh_peer_name = args[2];
970
971                 if (!mesh_peer_name) {
972                         result = __connmanctl_dbus_method_call(connection,
973                                         CONNMAN_SERVICE, CONNMAN_PATH,
974                                         "net.connman.Manager", "GetMeshPeers",
975                                         mesh_peers_list, NULL, NULL, NULL);
976                         break;
977                 }
978
979                 if (check_dbus_name(mesh_peer_name) == false) {
980                         result = -EINVAL;
981                         break;
982                 }
983
984                 mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
985                                                                         mesh_peer_name);
986                 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
987                                                 mesh_peer_path, "net.connman.Mesh", "GetProperties",
988                                                 object_properties, mesh_peer_path, NULL, NULL);
989                 break;
990
991         case 'c':
992                 if (num < 3) {
993                         result = -EINVAL;
994                         break;
995                 }
996
997                 if (num > 3) {
998                         result = -E2BIG;
999                         break;
1000                 }
1001
1002                 mesh_peer_name = args[2];
1003
1004                 if (check_dbus_name(mesh_peer_name) == false) {
1005                         result = -EINVAL;
1006                         break;
1007                 }
1008
1009                 mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
1010                                                                         mesh_peer_name);
1011                 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
1012                                                 mesh_peer_path, "net.connman.Mesh", "Connect",
1013                                                 mesh_connect_return, mesh_peer_path, NULL, NULL);
1014                 break;
1015
1016         case 'd':
1017                 if (num < 3) {
1018                         result = -EINVAL;
1019                         break;
1020                 }
1021
1022                 if (num > 3) {
1023                         result = -E2BIG;
1024                         break;
1025                 }
1026
1027                 mesh_peer_name = args[2];
1028
1029                 if (check_dbus_name(mesh_peer_name) == false) {
1030                         result = -EINVAL;
1031                         break;
1032                 }
1033
1034                 mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
1035                                                                         mesh_peer_name);
1036                 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
1037                                                 mesh_peer_path, "net.connman.Mesh", "Disconnect",
1038                                                 mesh_disconnect_return, mesh_peer_path, NULL, NULL);
1039                 break;
1040
1041         case 'f':
1042                 if (num < 3) {
1043                         result = -EINVAL;
1044                         break;
1045                 }
1046
1047                 if (num > 3) {
1048                         result = -E2BIG;
1049                         break;
1050                 }
1051
1052                 mesh_peer_name = args[2];
1053
1054                 if (check_dbus_name(mesh_peer_name) == false) {
1055                         result = -EINVAL;
1056                         break;
1057                 }
1058
1059                 mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
1060                                                                         mesh_peer_name);
1061                 result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
1062                                                 mesh_peer_path, "net.connman.Mesh", "Remove",
1063                                                 mesh_remove_return, mesh_peer_path, NULL, NULL);
1064                 break;
1065
1066         case 'C':
1067                 if (num > 2) {
1068                         result = -E2BIG;
1069                         break;
1070                 }
1071
1072                 result = __connmanctl_dbus_method_call(connection,
1073                                                                 CONNMAN_SERVICE, CONNMAN_PATH,
1074                                                                 "net.connman.Manager", "GetConnectedMeshPeers",
1075                                                                 connected_mesh_peers_list, NULL, NULL, NULL);
1076                 break;
1077
1078         case 'D':
1079                 if (num > 2) {
1080                         result = -E2BIG;
1081                         break;
1082                 }
1083
1084                 result = __connmanctl_dbus_method_call(connection,
1085                                                                 CONNMAN_SERVICE, CONNMAN_PATH,
1086                                                                 "net.connman.Manager",
1087                                                                 "GetDisconnectedMeshPeers",
1088                                                                 disconnected_mesh_peers_list, NULL, NULL, NULL);
1089                 break;
1090
1091         case 'n':
1092                 if (num != 5) {
1093                         result = -EINVAL;
1094                         break;
1095                 }
1096                 path = g_strdup_printf("/net/connman/technology/mesh");
1097
1098                 network = dbus_malloc0(sizeof(struct mesh_create_network));
1099                 network->name = g_strdup(args[2]);
1100                 network->freq = atoi(args[3]);
1101                 network->sec_type = g_strdup(args[4]);
1102                 method = g_strdup("MeshCreateNetwork");
1103                 result = __connmanctl_dbus_mesh_dict(connection, path,
1104                                                         "net.connman.Technology", mesh_return, method,
1105                                                         "MeshCreateNetwork", DBUS_TYPE_STRING,
1106                                                         mesh_create_network_append, network);
1107                 g_free(network->name);
1108                 g_free(network->sec_type);
1109                 g_free(network);
1110                 break;
1111
1112         case 'A':
1113                 if (num != 2) {
1114                         result = -EINVAL;
1115                         break;
1116                 }
1117                 path = g_strdup_printf("/net/connman/technology/mesh");
1118
1119                 method = g_strdup("AbortScan");
1120                 result = __connmanctl_dbus_mesh_dict(connection, path,
1121                                                         "net.connman.Technology", mesh_return, method,
1122                                                         "AbortScan", DBUS_TYPE_STRING,
1123                                                         NULL, NULL);
1124                 break;
1125
1126         case 'S':
1127                 if (num != 4) {
1128                         result = -EINVAL;
1129                         break;
1130                 }
1131                 path = g_strdup_printf("/net/connman/technology/mesh");
1132
1133                 scan_params = dbus_malloc0(sizeof(struct mesh_specific_scan_params));
1134                 scan_params->name = g_strdup(args[2]);
1135                 scan_params->freq = atoi(args[3]);
1136                 method = g_strdup("MeshSpecificScan");
1137                 result = __connmanctl_dbus_mesh_dict(connection, path,
1138                                                         "net.connman.Technology", mesh_return, method,
1139                                                         "MeshSpecificScan", DBUS_TYPE_STRING,
1140                                                         mesh_specific_scan_append, scan_params);
1141                 g_free(scan_params->name);
1142                 g_free(scan_params);
1143                 break;
1144
1145         case 'P':
1146                 if (num != 5) {
1147                         result = -EINVAL;
1148                         break;
1149                 }
1150
1151                 mesh_peer_name = args[2];
1152                 property = args[3];
1153                 value = args[4];
1154
1155                 if (check_dbus_name(mesh_peer_name) == false) {
1156                         result = -EINVAL;
1157                         break;
1158                 }
1159
1160                 mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
1161                                                                         mesh_peer_name);
1162
1163                 if (g_strcmp0(property, "Passphrase") == 0) {
1164                         result = __connmanctl_dbus_set_property(connection,
1165                                                                 mesh_peer_path, "net.connman.Mesh",
1166                                                                 mesh_config_return, mesh_peer_path, property,
1167                                                                 DBUS_TYPE_STRING, &value);
1168                 } else {
1169                         printf("Invalid property %s\n", property);
1170                         result = -EINVAL;
1171                 }
1172
1173                 break;
1174
1175         case 'G':
1176                 if (num != 5) {
1177                         result = -EINVAL;
1178                         break;
1179                 }
1180
1181                 path = g_strdup_printf("/net/connman/technology/mesh");
1182
1183                 gate_params = dbus_malloc0(sizeof(struct mesh_gate_params));
1184                 gate_params->gate_announce = atoi(args[2]);
1185                 gate_params->hwmp_rootmode = atoi(args[3]);
1186                 gate_params->stp = atoi(args[4]);
1187
1188                 method = g_strdup("SetMeshGate");
1189
1190                 result = __connmanctl_dbus_mesh_dict(connection, path,
1191                                                         "net.connman.Technology", mesh_return, method,
1192                                                         "SetMeshGate", DBUS_TYPE_STRING,
1193                                                         mesh_set_gate_append, gate_params);
1194
1195                 break;
1196
1197         case 'z':
1198                 if (num != 3) {
1199                         result = -EINVAL;
1200                         break;
1201                 }
1202
1203                 mesh_peer_addr = g_strdup(args[2]);
1204                 method = g_strdup("MeshAddPeer");
1205
1206                 result = __connmanctl_dbus_method_call(connection,
1207                                                                 CONNMAN_SERVICE, CONNMAN_PATH,
1208                                                                 "net.connman.Manager", "MeshAddPeer",
1209                                                                 mesh_return, method, mesh_peer_append,
1210                                                                 mesh_peer_addr);
1211
1212                 break;
1213
1214         case 'y':
1215                 if (num != 3) {
1216                         result = -EINVAL;
1217                         break;
1218                 }
1219
1220                 mesh_peer_addr = g_strdup(args[2]);
1221                 method = g_strdup("MeshRemovePeer");
1222
1223                 result = __connmanctl_dbus_method_call(connection,
1224                                                                 CONNMAN_SERVICE, CONNMAN_PATH,
1225                                                                 "net.connman.Manager", "MeshRemovePeer",
1226                                                                 mesh_return, method, mesh_peer_append,
1227                                                                 mesh_peer_addr);
1228
1229                 break;
1230
1231         default:
1232                 result = -EINVAL;
1233                 break;
1234         }
1235
1236         g_free(path);
1237
1238         if (result < 0) {
1239                 if (result != -EINPROGRESS)
1240                         printf("Error '%s': %s\n", args[1], strerror(-result));
1241         }
1242
1243
1244         return result;
1245 }
1246 #endif
1247
1248 static int cmd_tether(char *args[], int num, struct connman_option *options)
1249 {
1250         char *ssid, *passphrase;
1251         int set_tethering;
1252
1253         if (num < 3)
1254                 return -EINVAL;
1255
1256         passphrase = args[num - 1];
1257         ssid = args[num - 2];
1258
1259         set_tethering = parse_boolean(args[2]);
1260
1261         if (strcmp(args[1], "wifi") == 0) {
1262
1263                 if (num > 5)
1264                         return -E2BIG;
1265
1266                 if (num == 5 && set_tethering == -1)
1267                         return -EINVAL;
1268
1269                 if (num == 4)
1270                         set_tethering = -1;
1271
1272                 if (num > 3)
1273                         return tether_set_ssid(ssid, passphrase, set_tethering);
1274         }
1275
1276         if (num > 3)
1277                 return -E2BIG;
1278
1279         if (set_tethering == -1)
1280                 return -EINVAL;
1281
1282         if (check_dbus_name(args[1]) == false)
1283                 return -EINVAL;
1284
1285         return tether_set(args[1], set_tethering);
1286 }
1287
1288 static int cmd_tethering_clients(char *args[], int num, struct connman_option *options)
1289 {
1290         if (num > 1)
1291                 return -E2BIG;
1292
1293         return __connmanctl_dbus_method_call(connection,
1294                                 CONNMAN_SERVICE, CONNMAN_PATH,
1295                                 "net.connman.Manager", "GetTetheringClients",
1296                                 tethering_clients_list, NULL, NULL, NULL);
1297 }
1298
1299 static int scan_return(DBusMessageIter *iter, int ernnum, const char *error,
1300                 void *user_data)
1301 {
1302         char *path = user_data;
1303
1304         if (!error) {
1305                 char *str = strrchr(path, '/');
1306                 str++;
1307                 fprintf(stdout, "Scan completed for %s\n", str);
1308         } else
1309                 fprintf(stderr, "Error %s: %s\n", path, error);
1310
1311         g_free(user_data);
1312
1313         return 0;
1314 }
1315
1316 static int cmd_scan(char *args[], int num, struct connman_option *options)
1317 {
1318         char *path;
1319
1320         if (num > 2)
1321                 return -E2BIG;
1322
1323         if (num < 2)
1324                 return -EINVAL;
1325
1326         if (check_dbus_name(args[1]) == false)
1327                 return -EINVAL;
1328
1329         path = g_strdup_printf("/net/connman/technology/%s", args[1]);
1330         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
1331                         "net.connman.Technology", "Scan",
1332                         scan_return, path, NULL, NULL);
1333 }
1334
1335 static int connect_return(DBusMessageIter *iter, int errnum,
1336                         const char *error, void *user_data)
1337 {
1338         char *path = user_data;
1339
1340         if (!error) {
1341                 char *str = strrchr(path, '/');
1342                 str++;
1343                 fprintf(stdout, "Connected %s\n", str);
1344         } else
1345                 fprintf(stderr, "Error %s: %s\n", path, error);
1346
1347         g_free(user_data);
1348
1349         return 0;
1350 }
1351
1352 static int cmd_connect(char *args[], int num, struct connman_option *options)
1353 {
1354         const char *iface = "net.connman.Service";
1355         char *path;
1356
1357         if (num > 2)
1358                 return -E2BIG;
1359
1360         if (num < 2)
1361                 return -EINVAL;
1362
1363         if (check_dbus_name(args[1]) == false)
1364                 return -EINVAL;
1365
1366         if (g_strstr_len(args[1], 5, "peer_") == args[1]) {
1367                 iface = "net.connman.Peer";
1368                 path = g_strdup_printf("/net/connman/peer/%s", args[1]);
1369         } else
1370                 path = g_strdup_printf("/net/connman/service/%s", args[1]);
1371
1372         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
1373                         iface, "Connect", connect_return, path, NULL, NULL);
1374 }
1375
1376 static int disconnect_return(DBusMessageIter *iter, int errnum,
1377                         const char *error, void *user_data)
1378 {
1379         char *path = user_data;
1380
1381         if (!error) {
1382                 char *str = strrchr(path, '/');
1383                 str++;
1384                 fprintf(stdout, "Disconnected %s\n", str);
1385         } else
1386                 fprintf(stderr, "Error %s: %s\n", path, error);
1387
1388         g_free(user_data);
1389
1390         return 0;
1391 }
1392
1393 static int cmd_disconnect(char *args[], int num, struct connman_option *options)
1394 {
1395         const char *iface = "net.connman.Service";
1396         char *path;
1397
1398         if (num > 2)
1399                 return -E2BIG;
1400
1401         if (num < 2)
1402                 return -EINVAL;
1403
1404         if (check_dbus_name(args[1]) == false)
1405                 return -EINVAL;
1406
1407         if (g_strstr_len(args[1], 5, "peer_") == args[1]) {
1408                 iface = "net.connman.Peer";
1409                 path = g_strdup_printf("/net/connman/peer/%s", args[1]);
1410         } else
1411                 path = g_strdup_printf("/net/connman/service/%s", args[1]);
1412
1413         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
1414                                         path, iface, "Disconnect",
1415                                         disconnect_return, path, NULL, NULL);
1416 }
1417
1418 struct move_service {
1419         char *service;
1420         char *target;
1421 };
1422
1423 static int move_before_return(DBusMessageIter *iter, int errnum,
1424                         const char *error, void *user_data)
1425 {
1426         struct move_service *services = user_data;
1427         char *service;
1428         char *target;
1429
1430         if (!error) {
1431                 service = strrchr(services->service, '/');
1432                 service++;
1433                 target = strrchr(services->target, '/');
1434                 target++;
1435                 fprintf(stdout, "Moved %s before %s\n", service, target);
1436         } else
1437                 fprintf(stderr, "Error %s: %s\n", services->service, error);
1438
1439         g_free(services->service);
1440         g_free(services->target);
1441         g_free(user_data);
1442
1443         return 0;
1444 }
1445
1446 static void move_before_append_args(DBusMessageIter *iter, void *user_data)
1447 {
1448         char *path = user_data;
1449
1450         dbus_message_iter_append_basic(iter,
1451                                 DBUS_TYPE_OBJECT_PATH, &path);
1452 }
1453
1454 static int cmd_service_move_before(char *args[], int num,
1455                 struct connman_option *options)
1456 {
1457         const char *iface = "net.connman.Service";
1458         struct move_service *services;
1459
1460         if (num > 3)
1461                 return -E2BIG;
1462
1463         if (num < 3)
1464                 return -EINVAL;
1465
1466         if (check_dbus_name(args[1]) == false)
1467                 return -EINVAL;
1468
1469         services = g_new(struct move_service, 1);
1470
1471         services->service = g_strdup_printf("/net/connman/service/%s", args[1]);
1472         services->target = g_strdup_printf("/net/connman/service/%s", args[2]);
1473
1474         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
1475                                         services->service, iface, "MoveBefore",
1476                                         move_before_return, services,
1477                                         move_before_append_args,
1478                                         services->target);
1479 }
1480
1481 static int move_after_return(DBusMessageIter *iter, int errnum,
1482                         const char *error, void *user_data)
1483 {
1484         struct move_service *services = user_data;
1485         char *service;
1486         char *target;
1487
1488         if (!error) {
1489                 service = strrchr(services->service, '/');
1490                 service++;
1491                 target = strrchr(services->target, '/');
1492                 target++;
1493                 fprintf(stdout, "Moved %s after %s\n", service, target);
1494         } else
1495                 fprintf(stderr, "Error %s: %s\n", services->service, error);
1496
1497         g_free(services->service);
1498         g_free(services->target);
1499         g_free(user_data);
1500
1501         return 0;
1502 }
1503
1504 static void move_after_append_args(DBusMessageIter *iter, void *user_data)
1505 {
1506         char *path = user_data;
1507
1508         dbus_message_iter_append_basic(iter,
1509                                 DBUS_TYPE_OBJECT_PATH, &path);
1510 }
1511
1512 static int cmd_service_move_after(char *args[], int num,
1513                 struct connman_option *options)
1514 {
1515         const char *iface = "net.connman.Service";
1516         struct move_service *services;
1517
1518         if (num > 3)
1519                 return -E2BIG;
1520
1521         if (num < 3)
1522                 return -EINVAL;
1523
1524         if (check_dbus_name(args[1]) == false)
1525                 return -EINVAL;
1526
1527         services = g_new(struct move_service, 1);
1528
1529         services->service = g_strdup_printf("/net/connman/service/%s", args[1]);
1530         services->target = g_strdup_printf("/net/connman/service/%s", args[2]);
1531
1532         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
1533                                         services->service, iface, "MoveAfter",
1534                                         move_after_return, services,
1535                                         move_after_append_args,
1536                                         services->target);
1537 }
1538
1539 static int config_return(DBusMessageIter *iter, int errnum,
1540                         const char *error, void *user_data)
1541 {
1542         char *service_name = user_data;
1543
1544         if (error)
1545                 fprintf(stderr, "Error %s: %s\n", service_name, error);
1546
1547         g_free(user_data);
1548
1549         return 0;
1550 }
1551
1552 struct config_append {
1553         char **opts;
1554         int values;
1555 };
1556
1557 struct session_options {
1558         char **args;
1559         int num;
1560         char *notify_path;
1561         struct connman_option *options;
1562 };
1563
1564 static void config_append_ipv4(DBusMessageIter *iter,
1565                 void *user_data)
1566 {
1567         struct config_append *append = user_data;
1568         char **opts = append->opts;
1569         int i = 0;
1570
1571         if (!opts)
1572                 return;
1573
1574         while (opts[i] && ipv4[i]) {
1575                 __connmanctl_dbus_append_dict_entry(iter, ipv4[i],
1576                                 DBUS_TYPE_STRING, &opts[i]);
1577                 i++;
1578         }
1579
1580         append->values = i;
1581 }
1582
1583 static void config_append_ipv6(DBusMessageIter *iter, void *user_data)
1584 {
1585         struct config_append *append = user_data;
1586         char **opts = append->opts;
1587
1588         if (!opts)
1589                 return;
1590
1591         append->values = 1;
1592
1593         if (g_strcmp0(opts[0], "auto") == 0) {
1594                 char *str;
1595
1596                 switch (parse_boolean(opts[1])) {
1597                 case 0:
1598                         append->values = 2;
1599
1600                         str = "disabled";
1601                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
1602                                         DBUS_TYPE_STRING, &str);
1603                         break;
1604
1605                 case 1:
1606                         append->values = 2;
1607
1608                         str = "enabled";
1609                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
1610                                         DBUS_TYPE_STRING, &str);
1611                         break;
1612
1613                 default:
1614                         if (opts[1]) {
1615                                 append->values = 2;
1616
1617                                 if (g_strcmp0(opts[1], "prefered") != 0 &&
1618                                                 g_strcmp0(opts[1],
1619                                                         "preferred") != 0) {
1620                                         fprintf(stderr, "Error %s: %s\n",
1621                                                         opts[1],
1622                                                         strerror(EINVAL));
1623                                         return;
1624                                 }
1625
1626                                 str = "prefered";
1627                                 __connmanctl_dbus_append_dict_entry(iter,
1628                                                 "Privacy", DBUS_TYPE_STRING,
1629                                                 &str);
1630                         }
1631                         break;
1632                 }
1633         } else if (g_strcmp0(opts[0], "manual") == 0) {
1634                 int i = 1;
1635
1636                 while (opts[i] && ipv6[i]) {
1637                         if (i == 2) {
1638                                 int value = atoi(opts[i]);
1639                                 __connmanctl_dbus_append_dict_entry(iter,
1640                                                 ipv6[i], DBUS_TYPE_BYTE,
1641                                                 &value);
1642                         } else {
1643                                 __connmanctl_dbus_append_dict_entry(iter,
1644                                                 ipv6[i], DBUS_TYPE_STRING,
1645                                                 &opts[i]);
1646                         }
1647                         i++;
1648                 }
1649
1650                 append->values = i;
1651
1652         } else if (g_strcmp0(opts[0], "off") != 0) {
1653                 fprintf(stderr, "Error %s: %s\n", opts[0], strerror(EINVAL));
1654
1655                 return;
1656         }
1657
1658         __connmanctl_dbus_append_dict_entry(iter, "Method", DBUS_TYPE_STRING,
1659                                 &opts[0]);
1660 }
1661
1662 static void config_append_str(DBusMessageIter *iter, void *user_data)
1663 {
1664         struct config_append *append = user_data;
1665         char **opts = append->opts;
1666         int i = 0;
1667
1668         if (!opts)
1669                 return;
1670
1671         while (opts[i]) {
1672                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1673                                 &opts[i]);
1674                 i++;
1675         }
1676
1677         append->values = i;
1678 }
1679
1680 static void append_servers(DBusMessageIter *iter, void *user_data)
1681 {
1682         struct config_append *append = user_data;
1683         char **opts = append->opts;
1684         int i = 1;
1685
1686         if (!opts)
1687                 return;
1688
1689         while (opts[i] && g_strcmp0(opts[i], "--excludes") != 0) {
1690                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1691                                 &opts[i]);
1692                 i++;
1693         }
1694
1695         append->values = i;
1696 }
1697
1698 static void append_excludes(DBusMessageIter *iter, void *user_data)
1699 {
1700         struct config_append *append = user_data;
1701         char **opts = append->opts;
1702         int i = append->values;
1703
1704         if (!opts || !opts[i] ||
1705                         g_strcmp0(opts[i], "--excludes") != 0)
1706                 return;
1707
1708         i++;
1709         while (opts[i]) {
1710                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1711                                 &opts[i]);
1712                 i++;
1713         }
1714
1715         append->values = i;
1716 }
1717
1718 static void config_append_proxy(DBusMessageIter *iter, void *user_data)
1719 {
1720         struct config_append *append = user_data;
1721         char **opts = append->opts;
1722
1723         if (!opts)
1724                 return;
1725
1726         if (g_strcmp0(opts[0], "manual") == 0) {
1727                 __connmanctl_dbus_append_dict_string_array(iter, "Servers",
1728                                 append_servers, append);
1729
1730                 __connmanctl_dbus_append_dict_string_array(iter, "Excludes",
1731                                 append_excludes, append);
1732
1733         } else if (g_strcmp0(opts[0], "auto") == 0) {
1734                 if (opts[1]) {
1735                         __connmanctl_dbus_append_dict_entry(iter, "URL",
1736                                         DBUS_TYPE_STRING, &opts[1]);
1737                         append->values++;
1738                 }
1739
1740         } else if (g_strcmp0(opts[0], "direct") != 0)
1741                 return;
1742
1743         __connmanctl_dbus_append_dict_entry(iter, "Method",DBUS_TYPE_STRING,
1744                         &opts[0]);
1745
1746         append->values++;
1747 }
1748
1749 static int cmd_config(char *args[], int num, struct connman_option *options)
1750 {
1751         int result = 0, res = 0, index = 2, oldindex = 0;
1752         int c;
1753         char *service_name, *path;
1754         char **opt_start;
1755         dbus_bool_t val;
1756         struct config_append append;
1757
1758         service_name = args[1];
1759         if (!service_name)
1760                 return -EINVAL;
1761
1762         if (check_dbus_name(service_name) == false)
1763                 return -EINVAL;
1764
1765         while (index < num && args[index]) {
1766                 c = parse_args(args[index], options);
1767                 opt_start = &args[index + 1];
1768                 append.opts = opt_start;
1769                 append.values = 0;
1770
1771                 res = 0;
1772
1773                 oldindex = index;
1774                 path = g_strdup_printf("/net/connman/service/%s", service_name);
1775
1776                 switch (c) {
1777                 case 'a':
1778                         switch (parse_boolean(*opt_start)) {
1779                         case 1:
1780                                 val = TRUE;
1781                                 break;
1782                         case 0:
1783                                 val = FALSE;
1784                                 break;
1785                         default:
1786                                 res = -EINVAL;
1787                                 break;
1788                         }
1789
1790                         index++;
1791
1792                         if (res == 0) {
1793                                 res = __connmanctl_dbus_set_property(connection,
1794                                                 path, "net.connman.Service",
1795                                                 config_return,
1796                                                 g_strdup(service_name),
1797                                                 "AutoConnect",
1798                                                 DBUS_TYPE_BOOLEAN, &val);
1799                         }
1800                         break;
1801                 case 'i':
1802                         res = __connmanctl_dbus_set_property_dict(connection,
1803                                         path, "net.connman.Service",
1804                                         config_return, g_strdup(service_name),
1805                                         "IPv4.Configuration", DBUS_TYPE_STRING,
1806                                         config_append_ipv4, &append);
1807                         index += append.values;
1808                         break;
1809
1810                 case 'v':
1811                         res = __connmanctl_dbus_set_property_dict(connection,
1812                                         path, "net.connman.Service",
1813                                         config_return, g_strdup(service_name),
1814                                         "IPv6.Configuration", DBUS_TYPE_STRING,
1815                                         config_append_ipv6, &append);
1816                         index += append.values;
1817                         break;
1818
1819                 case 'n':
1820                         res = __connmanctl_dbus_set_property_array(connection,
1821                                         path, "net.connman.Service",
1822                                         config_return, g_strdup(service_name),
1823                                         "Nameservers.Configuration",
1824                                         DBUS_TYPE_STRING, config_append_str,
1825                                         &append);
1826                         index += append.values;
1827                         break;
1828
1829                 case 't':
1830                         res = __connmanctl_dbus_set_property_array(connection,
1831                                         path, "net.connman.Service",
1832                                         config_return, g_strdup(service_name),
1833                                         "Timeservers.Configuration",
1834                                         DBUS_TYPE_STRING, config_append_str,
1835                                         &append);
1836                         index += append.values;
1837                         break;
1838
1839                 case 'd':
1840                         res = __connmanctl_dbus_set_property_array(connection,
1841                                         path, "net.connman.Service",
1842                                         config_return, g_strdup(service_name),
1843                                         "Domains.Configuration",
1844                                         DBUS_TYPE_STRING, config_append_str,
1845                                         &append);
1846                         index += append.values;
1847                         break;
1848
1849                 case 'x':
1850                         res = __connmanctl_dbus_set_property_dict(connection,
1851                                         path, "net.connman.Service",
1852                                         config_return, g_strdup(service_name),
1853                                         "Proxy.Configuration",
1854                                         DBUS_TYPE_STRING, config_append_proxy,
1855                                         &append);
1856                         index += append.values;
1857                         break;
1858                 case 'r':
1859                         res = __connmanctl_dbus_method_call(connection,
1860                                         CONNMAN_SERVICE, path,
1861                                         "net.connman.Service", "Remove",
1862                                         config_return, g_strdup(service_name),
1863                                         NULL, NULL);
1864                         break;
1865
1866                 case 'm':
1867                         switch (parse_boolean(*opt_start)) {
1868                         case 1:
1869                                 val = TRUE;
1870                                 break;
1871                         case 0:
1872                                 val = FALSE;
1873                                 break;
1874                         default:
1875                                 res = -EINVAL;
1876                                 break;
1877                         }
1878                         if (res == 0) {
1879                                 res = __connmanctl_dbus_set_property(connection,
1880                                                 path, "net.connman.Service",
1881                                                 config_return,
1882                                                 g_strdup(service_name),
1883                                                 "mDNS.Configuration",
1884                                                 DBUS_TYPE_BOOLEAN, &val);
1885                         }
1886                         index++;
1887                         break;
1888
1889                 default:
1890                         res = -EINVAL;
1891                         break;
1892                 }
1893
1894                 g_free(path);
1895
1896                 if (res < 0) {
1897                         if (res == -EINPROGRESS)
1898                                 result = -EINPROGRESS;
1899                         else
1900                                 printf("Error '%s': %s\n", args[oldindex],
1901                                                 strerror(-res));
1902                 } else
1903                         index += res;
1904
1905                 index++;
1906         }
1907
1908         return result;
1909 }
1910
1911 static DBusHandlerResult monitor_changed(DBusConnection *connection,
1912                 DBusMessage *message, void *user_data)
1913 {
1914         DBusMessageIter iter;
1915         const char *interface, *path;
1916
1917         interface = dbus_message_get_interface(message);
1918         if (!interface)
1919                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1920
1921         if (strncmp(interface, "net.connman.", 12) != 0)
1922                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1923
1924         if (!strcmp(interface, "net.connman.Agent") ||
1925                         !strcmp(interface, "net.connman.vpn.Agent") ||
1926                         !strcmp(interface, "net.connman.Session") ||
1927                         !strcmp(interface, "net.connman.Notification"))
1928                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1929
1930         interface = strrchr(interface, '.');
1931         if (interface && *interface != '\0')
1932                 interface++;
1933
1934         path = strrchr(dbus_message_get_path(message), '/');
1935         if (path && *path != '\0')
1936                 path++;
1937
1938         __connmanctl_save_rl();
1939
1940         if (dbus_message_is_signal(message, "net.connman.Manager",
1941                                         "ServicesChanged")) {
1942
1943                 fprintf(stdout, "%-12s %-20s = {\n", interface,
1944                                 "ServicesChanged");
1945                 dbus_message_iter_init(message, &iter);
1946                 __connmanctl_services_list(&iter);
1947                 fprintf(stdout, "\n}\n");
1948
1949                 __connmanctl_redraw_rl();
1950
1951                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1952         } else if (dbus_message_is_signal(message, "net.connman.Manager",
1953                                                         "PeersChanged")) {
1954                 fprintf(stdout, "%-12s %-20s = {\n", interface,
1955                                                         "PeersChanged");
1956                 dbus_message_iter_init(message, &iter);
1957                 __connmanctl_peers_list(&iter);
1958                 fprintf(stdout, "\n}\n");
1959
1960                 __connmanctl_redraw_rl();
1961
1962                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1963         } else if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
1964                                         "ConnectionAdded") ||
1965                         dbus_message_is_signal(message,
1966                                         "net.connman.vpn.Manager",
1967                                         "ConnectionRemoved")) {
1968                 interface = "vpn.Manager";
1969                 path = dbus_message_get_member(message);
1970
1971         } else if (dbus_message_is_signal(message, "net.connman.Manager",
1972                                         "TechnologyAdded") ||
1973                         dbus_message_is_signal(message, "net.connman.Manager",
1974                                         "TechnologyRemoved"))
1975                 path = dbus_message_get_member(message);
1976
1977         fprintf(stdout, "%-12s %-20s ", interface, path);
1978         dbus_message_iter_init(message, &iter);
1979
1980         __connmanctl_dbus_print(&iter, "", " = ", " = ");
1981         fprintf(stdout, "\n");
1982
1983         __connmanctl_redraw_rl();
1984
1985         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1986 }
1987
1988 static struct {
1989         char *interface;
1990         bool enabled;
1991 } monitor[] = {
1992         { "Service", false },
1993         { "Technology", false },
1994         { "Manager", false },
1995         { "vpn.Manager", false },
1996         { "vpn.Connection", false },
1997         { NULL, },
1998 };
1999
2000 static void monitor_add(char *interface)
2001 {
2002         bool add_filter = true, found = false;
2003         int i;
2004         char *rule;
2005         DBusError err;
2006
2007         for (i = 0; monitor[i].interface; i++) {
2008                 if (monitor[i].enabled == true)
2009                         add_filter = false;
2010
2011                 if (g_strcmp0(interface, monitor[i].interface) == 0) {
2012                         if (monitor[i].enabled == true)
2013                                 return;
2014
2015                         monitor[i].enabled = true;
2016                         found = true;
2017                 }
2018         }
2019
2020         if (found == false)
2021                 return;
2022
2023         if (add_filter == true)
2024                 dbus_connection_add_filter(connection, monitor_changed,
2025                                 NULL, NULL);
2026
2027         dbus_error_init(&err);
2028         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
2029                         interface);
2030         dbus_bus_add_match(connection, rule, &err);
2031         g_free(rule);
2032
2033         if (dbus_error_is_set(&err))
2034                 fprintf(stderr, "Error: %s\n", err.message);
2035 }
2036
2037 static void monitor_del(char *interface)
2038 {
2039         bool del_filter = true, found = false;
2040         int i;
2041         char *rule;
2042
2043
2044         for (i = 0; monitor[i].interface; i++) {
2045                 if (g_strcmp0(interface, monitor[i].interface) == 0) {
2046                         if (monitor[i].enabled == false)
2047                                 return;
2048
2049                         monitor[i].enabled = false;
2050                         found = true;
2051                 }
2052
2053                 if (monitor[i].enabled == true)
2054                         del_filter = false;
2055         }
2056
2057         if (found == false)
2058                 return;
2059
2060         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
2061                         interface);
2062         dbus_bus_remove_match(connection, rule, NULL);
2063         g_free(rule);
2064
2065         if (del_filter == true)
2066                 dbus_connection_remove_filter(connection, monitor_changed,
2067                                 NULL);
2068 }
2069
2070 static int cmd_monitor(char *args[], int num, struct connman_option *options)
2071 {
2072         bool add = true;
2073         int c;
2074
2075         if (num > 3)
2076                 return -E2BIG;
2077
2078         if (num == 3) {
2079                 switch (parse_boolean(args[2])) {
2080                 case 0:
2081                         add = false;
2082                         break;
2083
2084                 default:
2085                         break;
2086                 }
2087         }
2088
2089         c = parse_args(args[1], options);
2090         switch (c) {
2091         case -1:
2092                 monitor_add("Service");
2093                 monitor_add("Technology");
2094                 monitor_add("Manager");
2095                 monitor_add("vpn.Manager");
2096                 monitor_add("vpn.Connection");
2097                 break;
2098
2099         case 's':
2100                 if (add == true)
2101                         monitor_add("Service");
2102                 else
2103                         monitor_del("Service");
2104                 break;
2105
2106         case 'c':
2107                 if (add == true)
2108                         monitor_add("Technology");
2109                 else
2110                         monitor_del("Technology");
2111                 break;
2112
2113         case 'm':
2114                 if (add == true)
2115                         monitor_add("Manager");
2116                 else
2117                         monitor_del("Manager");
2118                 break;
2119
2120         case 'M':
2121                 if (add == true)
2122                         monitor_add("vpn.Manager");
2123                 else
2124                         monitor_del("vpn.Manager");
2125                 break;
2126
2127         case 'C':
2128                 if (add == true)
2129                         monitor_add("vpn.Connection");
2130                 else
2131                         monitor_del("vpn.Connection");
2132                 break;
2133
2134         default:
2135                 switch(parse_boolean(args[1])) {
2136                 case 0:
2137                         monitor_del("Service");
2138                         monitor_del("Technology");
2139                         monitor_del("Manager");
2140                         monitor_del("vpn.Manager");
2141                         monitor_del("vpn.Connection");
2142                         break;
2143
2144                 case 1:
2145                         monitor_add("Service");
2146                         monitor_add("Technology");
2147                         monitor_add("Manager");
2148                         monitor_add("vpn.Manager");
2149                         monitor_add("vpn.Connection");
2150                         break;
2151
2152                 default:
2153                         return -EINVAL;
2154                 }
2155         }
2156
2157         if (add == true)
2158                 return -EINPROGRESS;
2159
2160         return 0;
2161 }
2162
2163 static int cmd_agent(char *args[], int num, struct connman_option *options)
2164 {
2165         if (!__connmanctl_is_interactive()) {
2166                 fprintf(stderr, "Error: Not supported in non-interactive "
2167                                 "mode\n");
2168                 return 0;
2169         }
2170
2171         if (num > 2)
2172                 return -E2BIG;
2173
2174         if (num < 2)
2175                 return -EINVAL;
2176
2177         switch(parse_boolean(args[1])) {
2178         case 0:
2179                 __connmanctl_agent_unregister(connection);
2180                 break;
2181
2182         case 1:
2183                 if (__connmanctl_agent_register(connection) == -EINPROGRESS)
2184                         return -EINPROGRESS;
2185
2186                 break;
2187
2188         default:
2189                 return -EINVAL;
2190                 break;
2191         }
2192
2193         return 0;
2194 }
2195
2196 static int vpnconnections_properties(DBusMessageIter *iter, int errnum,
2197                                 const char *error, void *user_data)
2198 {
2199         char *path = user_data;
2200         char *str;
2201         DBusMessageIter dict;
2202
2203         if (!error) {
2204                 fprintf(stdout, "%s\n", path);
2205
2206                 dbus_message_iter_recurse(iter, &dict);
2207                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
2208
2209                 fprintf(stdout, "\n");
2210
2211         } else {
2212                 str = strrchr(path, '/');
2213                 if (str)
2214                         str++;
2215                 else
2216                         str = path;
2217
2218                 fprintf(stderr, "Error %s: %s\n", str, error);
2219         }
2220
2221         g_free(user_data);
2222
2223         return 0;
2224 }
2225
2226 static int vpnconnections_list(DBusMessageIter *iter, int errnum,
2227                         const char *error, void *user_data)
2228 {
2229         if (!error)
2230                 __connmanctl_vpnconnections_list(iter);
2231         else
2232                 fprintf(stderr, "Error: %s\n", error);
2233
2234         return 0;
2235 }
2236
2237 static int cmd_vpnconnections(char *args[], int num,
2238                 struct connman_option *options)
2239 {
2240         char *vpnconnection_name, *path;
2241
2242         if (num > 2)
2243                 return -E2BIG;
2244
2245         vpnconnection_name = args[1];
2246
2247         if (!vpnconnection_name)
2248                 return __connmanctl_dbus_method_call(connection,
2249                                 VPN_SERVICE, VPN_PATH,
2250                                 "net.connman.vpn.Manager", "GetConnections",
2251                                 vpnconnections_list, NULL,
2252                                 NULL, NULL);
2253
2254         if (check_dbus_name(vpnconnection_name) == false)
2255                 return -EINVAL;
2256
2257         path = g_strdup_printf("/net/connman/vpn/connection/%s",
2258                         vpnconnection_name);
2259         return __connmanctl_dbus_method_call(connection, VPN_SERVICE, path,
2260                         "net.connman.vpn.Connection", "GetProperties",
2261                         vpnconnections_properties, path, NULL, NULL);
2262
2263 }
2264
2265 static int cmd_vpnagent(char *args[], int num, struct connman_option *options)
2266 {
2267         if (!__connmanctl_is_interactive()) {
2268                 fprintf(stderr, "Error: Not supported in non-interactive "
2269                                 "mode\n");
2270                 return 0;
2271         }
2272
2273         if (num > 2)
2274                 return -E2BIG;
2275
2276         if (num < 2)
2277                 return -EINVAL;
2278
2279         switch(parse_boolean(args[1])) {
2280         case 0:
2281                 __connmanctl_vpn_agent_unregister(connection);
2282                 break;
2283
2284         case 1:
2285                 if (__connmanctl_vpn_agent_register(connection) ==
2286                                 -EINPROGRESS)
2287                         return -EINPROGRESS;
2288
2289                 break;
2290
2291         default:
2292                 return -EINVAL;
2293                 break;
2294         }
2295
2296         return 0;
2297 }
2298
2299 static DBusMessage *session_release(DBusConnection *connection,
2300                 DBusMessage *message, void *user_data)
2301 {
2302         __connmanctl_save_rl();
2303
2304         fprintf(stdout, "Session %s released\n", session_path);
2305
2306         __connmanctl_redraw_rl();
2307
2308         g_free(session_path);
2309         session_path = NULL;
2310         session_connected = false;
2311
2312         return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
2313 }
2314
2315 static DBusMessage *session_update(DBusConnection *connection,
2316                 DBusMessage *message, void *user_data)
2317 {
2318         DBusMessageIter iter, dict;
2319
2320         __connmanctl_save_rl();
2321
2322         fprintf(stdout, "Session      Update               = {\n");
2323
2324         dbus_message_iter_init(message, &iter);
2325         dbus_message_iter_recurse(&iter, &dict);
2326
2327         __connmanctl_dbus_print(&dict, "", " = ", "\n");
2328         fprintf(stdout, "\n}\n");
2329
2330         dbus_message_iter_recurse(&iter, &dict);
2331
2332         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2333                 DBusMessageIter entry, variant;
2334                 char *field, *state;
2335
2336                 dbus_message_iter_recurse(&dict, &entry);
2337
2338                 dbus_message_iter_get_basic(&entry, &field);
2339
2340                 if (dbus_message_iter_get_arg_type(&entry)
2341                                 == DBUS_TYPE_STRING
2342                                 && !strcmp(field, "State")) {
2343
2344                         dbus_message_iter_next(&entry);
2345                         dbus_message_iter_recurse(&entry, &variant);
2346                         if (dbus_message_iter_get_arg_type(&variant)
2347                                         != DBUS_TYPE_STRING)
2348                                 break;
2349
2350                         dbus_message_iter_get_basic(&variant, &state);
2351
2352                         if (!session_connected && (!strcmp(state, "connected")
2353                                         || !strcmp(state, "online"))) {
2354
2355                                 fprintf(stdout, "Session %s connected\n",
2356                                         session_path);
2357                                 session_connected = true;
2358
2359                                 break;
2360                         }
2361
2362                         if (!strcmp(state, "disconnected") &&
2363                                         session_connected) {
2364
2365                                 fprintf(stdout, "Session %s disconnected\n",
2366                                         session_path);
2367                                 session_connected = false;
2368                         }
2369                         break;
2370                 }
2371
2372                 dbus_message_iter_next(&dict);
2373         }
2374
2375         __connmanctl_redraw_rl();
2376
2377         return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
2378 }
2379
2380 static const GDBusMethodTable notification_methods[] = {
2381         { GDBUS_METHOD("Release", NULL, NULL, session_release) },
2382         { GDBUS_METHOD("Update", GDBUS_ARGS({"settings", "a{sv}"}),
2383                                 NULL, session_update) },
2384         { },
2385 };
2386
2387 static int session_notify_add(const char *path)
2388 {
2389         if (session_notify_path)
2390                 return 0;
2391
2392         if (!g_dbus_register_interface(connection, path,
2393                                         "net.connman.Notification",
2394                                         notification_methods, NULL, NULL,
2395                                         NULL, NULL)) {
2396                 fprintf(stderr, "Error: Failed to register VPN Agent "
2397                                 "callbacks\n");
2398                 return -EIO;
2399         }
2400
2401         session_notify_path = g_strdup(path);
2402
2403         return 0;
2404 }
2405
2406 static void session_notify_remove(void)
2407 {
2408         if (!session_notify_path)
2409                 return;
2410
2411         g_dbus_unregister_interface(connection, session_notify_path,
2412                         "net.connman.Notification");
2413
2414         g_free(session_notify_path);
2415         session_notify_path = NULL;
2416 }
2417
2418 static int session_connect_cb(DBusMessageIter *iter, int errnum,
2419                         const char *error, void *user_data)
2420 {
2421         if (error) {
2422                 fprintf(stderr, "Error: %s\n", error);
2423                 return 0;
2424         }
2425
2426         return -EINPROGRESS;
2427 }
2428
2429
2430 static int session_connect(void)
2431 {
2432         return __connmanctl_dbus_method_call(connection, "net.connman",
2433                         session_path, "net.connman.Session", "Connect",
2434                         session_connect_cb, NULL, NULL, NULL);
2435 }
2436
2437 static int session_disconnect_cb(DBusMessageIter *iter, int errnum,
2438                                 const char *error, void *user_data)
2439 {
2440         if (error)
2441                 fprintf(stderr, "Error: %s\n", error);
2442
2443         return 0;
2444 }
2445
2446 static int session_disconnect(void)
2447 {
2448         return __connmanctl_dbus_method_call(connection, "net.connman",
2449                         session_path, "net.connman.Session", "Disconnect",
2450                         session_disconnect_cb, NULL, NULL, NULL);
2451 }
2452
2453 static int session_create_cb(DBusMessageIter *iter, int errnum,
2454                         const char *error, void *user_data)
2455 {
2456         gboolean connect = GPOINTER_TO_INT(user_data);
2457         char *str;
2458
2459         if (error) {
2460                 fprintf(stderr, "Error creating session: %s", error);
2461                 session_notify_remove();
2462                 return 0;
2463         }
2464
2465         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH) {
2466                 fprintf(stderr, "Error creating session: No session path\n");
2467                 return -EINVAL;
2468         }
2469
2470         g_free(session_path);
2471
2472         dbus_message_iter_get_basic(iter, &str);
2473         session_path = g_strdup(str);
2474
2475         fprintf(stdout, "Session %s created\n", session_path);
2476
2477         if (connect)
2478                 return session_connect();
2479
2480         return -EINPROGRESS;
2481 }
2482
2483 static void session_config_append_array(DBusMessageIter *iter,
2484                 void *user_data)
2485 {
2486         struct config_append *append = user_data;
2487         char **opts = append->opts;
2488         int i = 1;
2489
2490         if (!opts)
2491                 return;
2492
2493         while (opts[i] && strncmp(opts[i], "--", 2) != 0) {
2494                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
2495                                                &opts[i]);
2496                 i++;
2497         }
2498
2499         append->values = i;
2500 }
2501
2502 static void session_create_append_dict(DBusMessageIter *iter, void *user_data)
2503 {
2504         struct session_options *args_struct = user_data;
2505         int index = 0, res = 0;
2506         struct config_append append;
2507         char c;
2508         char *ifname;
2509         dbus_bool_t source_ip_rule;
2510
2511         while (index < args_struct->num && args_struct->args[index]) {
2512                 append.opts = &args_struct->args[index];
2513                 append.values = 0;
2514
2515                 c = parse_args(args_struct->args[index], args_struct->options);
2516
2517                 switch (c) {
2518                 case 'b':
2519                         __connmanctl_dbus_append_dict_string_array(iter, "AllowedBearers",
2520                                                                    session_config_append_array,
2521                                                                    &append);
2522                         break;
2523                 case 't':
2524                         if (! args_struct->args[index + 1]) {
2525                                 res = -EINVAL;
2526                                 break;
2527                         }
2528                         __connmanctl_dbus_append_dict_entry(iter, "ConnectionType",
2529                                                             DBUS_TYPE_STRING,
2530                                                             &args_struct->args[index + 1]);
2531                         append.values = 2;
2532                         break;
2533                 case 'i':
2534                         if (index + 1 <  args_struct->num)
2535                                 ifname =  args_struct->args[index + 1];
2536                         else
2537                                 ifname = "";
2538                          __connmanctl_dbus_append_dict_entry(iter, "AllowedInterface",
2539                                                              DBUS_TYPE_STRING,
2540                                                              &ifname);
2541                         append.values = 2;
2542                         break;
2543                 case 's':
2544                         if (! args_struct->args[index + 1]) {
2545                                 res = -EINVAL;
2546                                 break;
2547                         }
2548                         switch (parse_boolean( args_struct->args[index + 1])) {
2549                         case 1:
2550                                 source_ip_rule = TRUE;
2551                                 break;
2552                         case 0:
2553                                 source_ip_rule = FALSE;
2554                                 break;
2555                         default:
2556                                 res = -EINVAL;
2557                                 break;
2558                         }
2559                         __connmanctl_dbus_append_dict_entry(iter, "SourceIPRule",
2560                                                             DBUS_TYPE_BOOLEAN,
2561                                                             &source_ip_rule);
2562                         append.values = 2;
2563                         break;
2564                 case 'c':
2565                         if (!args_struct->args[index + 1]) {
2566                                 res = -EINVAL;
2567                                 break;
2568                         }
2569                         __connmanctl_dbus_append_dict_entry(iter, "ContextIdentifier",
2570                                                             DBUS_TYPE_STRING,
2571                                                             &args_struct->args[index + 1]);
2572                         append.values = 2;
2573                         break;
2574                 default:
2575                         res = -EINVAL;
2576                 }
2577
2578                 if (res < 0 && res != -EINPROGRESS) {
2579                         printf("Error '%s': %s\n",  args_struct->args[index],
2580                                         strerror(-res));
2581                         return;
2582                 }
2583
2584                 index += append.values;
2585         }
2586 }
2587
2588 static void session_create_append(DBusMessageIter *iter, void *user_data)
2589 {
2590         struct session_options *args_struct = user_data;
2591
2592         __connmanctl_dbus_append_dict(iter, session_create_append_dict,
2593                                       args_struct);
2594
2595         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2596                                        &args_struct->notify_path);
2597 }
2598
2599 static int session_create(gboolean connect, char *args[], int num,
2600                           struct connman_option *options)
2601 {
2602         int res;
2603         char *notify_path;
2604         struct session_options args_struct;
2605         args_struct.args = args;
2606         args_struct.num = num;
2607         args_struct.options = options;
2608
2609         notify_path = g_strdup_printf("/net/connman/connmanctl%d", getpid());
2610         session_notify_add(notify_path);
2611         args_struct.notify_path = notify_path;
2612
2613         res = __connmanctl_dbus_method_call(connection, "net.connman", "/",
2614                         "net.connman.Manager", "CreateSession",
2615                         session_create_cb, GINT_TO_POINTER(connect),
2616                         session_create_append, &args_struct);
2617
2618         g_free(notify_path);
2619
2620         if (res < 0 && res != -EINPROGRESS)
2621                 session_notify_remove();
2622
2623         return res;
2624 }
2625
2626 static int session_destroy_cb(DBusMessageIter *iter, int errnum,
2627                         const char *error, void *user_data)
2628 {
2629         if (error) {
2630                 fprintf(stderr, "Error destroying session: %s", error);
2631                 return 0;
2632         }
2633
2634         fprintf(stdout, "Session %s ended\n", session_path);
2635
2636         g_free(session_path);
2637         session_path = NULL;
2638         session_connected = false;
2639
2640         return 0;
2641 }
2642
2643 static void session_destroy_append(DBusMessageIter *iter, void *user_data)
2644 {
2645         const char *path = user_data;
2646
2647         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
2648 }
2649
2650 static int session_destroy(void)
2651 {
2652         return __connmanctl_dbus_method_call(connection, "net.connman", "/",
2653                         "net.connman.Manager", "DestroySession",
2654                         session_destroy_cb, NULL,
2655                         session_destroy_append, session_path);
2656 }
2657
2658 static int session_config_return(DBusMessageIter *iter, int errnum,
2659                                 const char *error, void *user_data)
2660 {
2661         char *property_name = user_data;
2662
2663         if (error)
2664                 fprintf(stderr, "Error setting session %s: %s\n",
2665                                 property_name, error);
2666
2667         return 0;
2668 }
2669
2670 static int session_config(char *args[], int num,
2671                 struct connman_option *options)
2672 {
2673         int index = 0, res = 0;
2674         struct config_append append;
2675         char c;
2676         char *ifname;
2677         dbus_bool_t source_ip_rule;
2678
2679         while (index < num && args[index]) {
2680                 append.opts = &args[index];
2681                 append.values = 0;
2682
2683                 c = parse_args(args[index], options);
2684
2685                 switch (c) {
2686                 case 'b':
2687                         res = __connmanctl_dbus_session_change_array(connection,
2688                                         session_path, session_config_return,
2689                                         "AllowedBearers", "AllowedBearers",
2690                                         session_config_append_array, &append);
2691                         break;
2692                 case 't':
2693                         if (!args[index + 1]) {
2694                                 res = -EINVAL;
2695                                 break;
2696                         }
2697
2698                         res = __connmanctl_dbus_session_change(connection,
2699                                         session_path, session_config_return,
2700                                         "ConnectionType", "ConnectionType",
2701                                         DBUS_TYPE_STRING, &args[index + 1]);
2702                         append.values = 2;
2703                         break;
2704                 case 'i':
2705                         if (index + 1 < num)
2706                                 ifname = args[index + 1];
2707                         else
2708                                 ifname = "";
2709
2710                         res = __connmanctl_dbus_session_change(connection,
2711                                         session_path, session_config_return,
2712                                         "AllowedInterface", "AllowedInterface",
2713                                         DBUS_TYPE_STRING, &ifname);
2714                         append.values = 2;
2715                         break;
2716                 case 's':
2717                         if (!args[index + 1]) {
2718                                 res = -EINVAL;
2719                                 break;
2720                         }
2721                         switch (parse_boolean(args[index + 1])) {
2722                         case 1:
2723                                 source_ip_rule = TRUE;
2724                                 break;
2725                         case 0:
2726                                 source_ip_rule = FALSE;
2727                                 break;
2728                         default:
2729                                 res = -EINVAL;
2730                                 break;
2731                         }
2732
2733                         res = __connmanctl_dbus_session_change(connection,
2734                                         session_path, session_config_return,
2735                                         "SourceIPRule", "SourceIPRule",
2736                                         DBUS_TYPE_BOOLEAN, &source_ip_rule);
2737                         append.values = 2;
2738                         break;
2739                 case 'c':
2740                                 if (!args[index + 1]) {
2741                                         res = -EINVAL;
2742                                         break;
2743                                 }
2744
2745                                 res = __connmanctl_dbus_session_change(connection,
2746                                                 session_path, session_config_return,
2747                                                 "ctxid", "ctxid", DBUS_TYPE_STRING,
2748                                                 &args[index + 1]);
2749                                 append.values = 2;
2750                                 break;
2751
2752                 default:
2753                         res = -EINVAL;
2754                 }
2755
2756                 if (res < 0 && res != -EINPROGRESS) {
2757                         printf("Error '%s': %s\n", args[index],
2758                                         strerror(-res));
2759                         return 0;
2760                 }
2761
2762                 index += append.values;
2763         }
2764
2765         return 0;
2766 }
2767
2768 static int cmd_session(char *args[], int num, struct connman_option *options)
2769 {
2770         char *command;
2771
2772         if (num < 2)
2773                 return -EINVAL;
2774
2775         command = args[1];
2776
2777         switch(parse_boolean(command)) {
2778         case 0:
2779                 if (!session_path)
2780                         return -EALREADY;
2781                 return session_destroy();
2782
2783         case 1:
2784                 if (session_path)
2785                         return -EALREADY;
2786                 return session_create(FALSE, &args[2], num - 2, options);
2787
2788         default:
2789                 if (!strcmp(command, "connect")) {
2790                         if (!session_path)
2791                                 return session_create(TRUE, &args[2], num - 2,
2792                                                       options);
2793
2794                         return session_connect();
2795
2796                 } else if (!strcmp(command, "disconnect")) {
2797
2798                         if (!session_path) {
2799                                 fprintf(stdout, "Session does not exist\n");
2800                                 return 0;
2801                         }
2802
2803                         return session_disconnect();
2804                 } else if (!strcmp(command, "config")) {
2805                         if (!session_path) {
2806                                 fprintf(stdout, "Session does not exist\n");
2807                                 return 0;
2808                         }
2809
2810                         if (num == 2)
2811                                 return -EINVAL;
2812
2813                         return session_config(&args[2], num - 2, options);
2814                 }
2815
2816         }
2817
2818         return -EINVAL;
2819 }
2820
2821 static int cmd_exit(char *args[], int num, struct connman_option *options)
2822 {
2823         return 1;
2824 }
2825
2826 static char *lookup_key_from_table(GHashTable *hash, const char *text,
2827                                         int state)
2828 {
2829         static int len = 0;
2830         static GHashTableIter iter;
2831         gpointer key, value;
2832
2833         if (state == 0) {
2834                 g_hash_table_iter_init(&iter, hash);
2835                 len = strlen(text);
2836         }
2837
2838         while (g_hash_table_iter_next(&iter, &key, &value))
2839                 if (strncmp(text, key, len) == 0)
2840                         return strdup(key);
2841
2842         return NULL;
2843 }
2844
2845 static char *lookup_service_arg(const char *text, int state)
2846 {
2847         if (__connmanctl_input_calc_level() > 1) {
2848                 __connmanctl_input_lookup_end();
2849                 return NULL;
2850         }
2851
2852         return lookup_key_from_table(service_hash, text, state);
2853 }
2854
2855 static char *lookup_peer(const char *text, int state)
2856 {
2857         static GHashTableIter iter;
2858         gpointer key, value;
2859         static int len = 0;
2860
2861         if (state == 0) {
2862                 g_hash_table_iter_init(&iter, peer_hash);
2863                 len = strlen(text);
2864         }
2865
2866         while (g_hash_table_iter_next(&iter, &key, &value)) {
2867                 const char *peer = key;
2868                 if (strncmp(text, peer, len) == 0)
2869                         return strdup(peer);
2870         }
2871
2872         return NULL;
2873 }
2874
2875 static char *lookup_peer_arg(const char *text, int state)
2876 {
2877         if (__connmanctl_input_calc_level() > 1) {
2878                 __connmanctl_input_lookup_end();
2879                 return NULL;
2880         }
2881
2882         return lookup_peer(text, state);
2883 }
2884
2885 static char *lookup_technology(const char *text, int state)
2886 {
2887         static int len = 0;
2888         static GHashTableIter iter;
2889         gpointer key, value;
2890
2891         if (state == 0) {
2892                 g_hash_table_iter_init(&iter, technology_hash);
2893                 len = strlen(text);
2894         }
2895
2896         while (g_hash_table_iter_next(&iter, &key, &value)) {
2897                 const char *technology = key;
2898                 if (strncmp(text, technology, len) == 0)
2899                         return strdup(technology);
2900         }
2901
2902         return NULL;
2903 }
2904
2905 static char *lookup_technology_arg(const char *text, int state)
2906 {
2907         if (__connmanctl_input_calc_level() > 1) {
2908                 __connmanctl_input_lookup_end();
2909                 return NULL;
2910         }
2911
2912         return lookup_technology(text, state);
2913 }
2914
2915 static char *lookup_technology_offline(const char *text, int state)
2916 {
2917         static int len = 0;
2918         static bool end = false;
2919         char *str;
2920
2921         if (__connmanctl_input_calc_level() > 1) {
2922                 __connmanctl_input_lookup_end();
2923                 return NULL;
2924         }
2925
2926         if (state == 0) {
2927                 len = strlen(text);
2928                 end = false;
2929         }
2930
2931         if (end)
2932                 return NULL;
2933
2934         str = lookup_technology(text, state);
2935         if (str)
2936                 return str;
2937
2938         end = true;
2939
2940         if (strncmp(text, "offline", len) == 0)
2941                 return strdup("offline");
2942
2943         return NULL;
2944 }
2945
2946 static char *lookup_on_off(const char *text, int state)
2947 {
2948         char *onoff[] = { "on", "off", NULL };
2949         static int idx = 0;
2950         static int len = 0;
2951
2952         char *str;
2953
2954         if (!state) {
2955                 idx = 0;
2956                 len = strlen(text);
2957         }
2958
2959         while (onoff[idx]) {
2960                 str = onoff[idx];
2961                 idx++;
2962
2963                 if (!strncmp(text, str, len))
2964                         return strdup(str);
2965         }
2966
2967         return NULL;
2968 }
2969
2970 static char *lookup_tether(const char *text, int state)
2971 {
2972         int level;
2973
2974         level = __connmanctl_input_calc_level();
2975         if (level < 2)
2976                 return lookup_technology(text, state);
2977
2978         if (level == 2)
2979                 return lookup_on_off(text, state);
2980
2981         __connmanctl_input_lookup_end();
2982
2983         return NULL;
2984 }
2985
2986 static char *lookup_agent(const char *text, int state)
2987 {
2988         if (__connmanctl_input_calc_level() > 1) {
2989                 __connmanctl_input_lookup_end();
2990                 return NULL;
2991         }
2992
2993         return lookup_on_off(text, state);
2994 }
2995
2996 static char *lookup_vpnconnection_arg(const char *text, int state)
2997 {
2998         if (__connmanctl_input_calc_level() > 1) {
2999                 __connmanctl_input_lookup_end();
3000                 return NULL;
3001         }
3002
3003         return lookup_key_from_table(vpnconnection_hash, text, state);
3004 }
3005
3006 static struct connman_option service_options[] = {
3007         {"properties", 'p', "[<service>]      (obsolete)"},
3008         { NULL, }
3009 };
3010
3011 #if defined TIZEN_EXT_INS
3012 static struct connman_option ins_options[] = {
3013         {"all",         'a', ""},
3014         {"filter-ssid", 's', "ssid"},
3015         {"filter-name", 'n', "[<service_name>]"},
3016         { NULL, }
3017 };
3018 #endif
3019
3020 static struct connman_option config_options[] = {
3021         {"nameservers", 'n', "<dns1> [<dns2>] [<dns3>]"},
3022         {"timeservers", 't', "<ntp1> [<ntp2>] [...]"},
3023         {"domains", 'd', "<domain1> [<domain2>] [...]"},
3024         {"mdns", 'm', "yes|no"},
3025         {"ipv6", 'v', "off|auto [enable|disable|preferred]|\n"
3026                       "\t\t\tmanual <address> <prefixlength> <gateway>"},
3027         {"proxy", 'x', "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
3028                        "\t\t\t[exclude <exclude1> [<exclude2>] [...]]"},
3029         {"autoconnect", 'a', "yes|no"},
3030         {"ipv4", 'i', "off|dhcp|manual <address> <netmask> <gateway>"},
3031         {"remove", 'r', "                 Remove service"},
3032         { NULL, }
3033 };
3034
3035 static struct connman_option monitor_options[] = {
3036         {"services", 's', "[off]            Monitor only services"},
3037         {"tech", 'c', "[off]            Monitor only technologies"},
3038         {"manager", 'm', "[off]            Monitor only manager interface"},
3039         {"vpnmanager", 'M', "[off]            Monitor only VPN manager "
3040          "interface"},
3041         {"vpnconnection", 'C', "[off]            Monitor only VPN "
3042          "connections" },
3043         { NULL, }
3044 };
3045
3046 static struct connman_option session_options[] = {
3047         {"bearers", 'b', "<technology1> [<technology2> [...]]"},
3048         {"type", 't', "local|internet|any"},
3049         {"ifname", 'i', "[<interface_name>]"},
3050         {"srciprule", 's', "yes|no"},
3051         {"ctxid", 'c', "<context_identifier>"},
3052         { NULL, }
3053 };
3054
3055 #if defined TIZEN_EXT_WIFI_MESH
3056 static struct connman_option mesh_options[] = {
3057         {"ifadd", 'a', "<ifname> <wifi_ifname>\n"
3058                 "                     [bridge_ifname]                Add Virtual Mesh "
3059                         "interface"},
3060         {"ifrmv", 'r', "<ifname>                       Remove Virtual Mesh "
3061                 "interface"},
3062         {"peers", 'p', "[peer]                         Display Mesh peer "
3063                 "informations"},
3064         {"connect", 'c', "<peer>                         Connect Mesh Peer"},
3065         {"disconnect", 'd', "<peer>                         Disconnect Mesh Peer"},
3066         {"remove", 'f', "<peer>                         Forget Mesh Peer"},
3067         {"connected_peers", 'C', "[]                             Displays connected"
3068                 " Peer informations"},
3069         {"disconnected_peers", 'D', "[]                           Displays "
3070                 "Disconnected Peer informations"},
3071         {"create_network", 'n', "<name> <frequency> <sec_type>  Create New Mesh "
3072                 "Network"},
3073         {"abort_scan", 'A', "                               Abort ongoing mesh "
3074                 "scan"},
3075         {"specific_scan", 'S', "<name> <frequency>             Create New Mesh "
3076                 "Network"},
3077         {"config", 'P', "<peer>                         Set Mesh Network "
3078                 "Configurations\n          Passphrase    <passphrase>"},
3079         {"set_gate", 'G', "<gate_ann> <rootmode> <stp>    Set Mesh Gate "
3080                 "Option"},
3081         {"add_peer", 'z', "<addr>                         Add Mesh Peer"},
3082         {"remove_peer", 'y', "<addr>                         Remove Mesh Peer"},
3083         { NULL, }
3084 };
3085 #endif
3086
3087 static char *lookup_options(struct connman_option *options, const char *text,
3088                 int state)
3089 {
3090         static int idx = 0;
3091         static int len = 0;
3092         const char *str;
3093
3094         if (state == 0) {
3095                 idx = 0;
3096                 len = strlen(text);
3097         }
3098
3099         while (options[idx].name) {
3100                 str = options[idx].name;
3101                 idx++;
3102
3103                 if (str && strncmp(text, str, len) == 0)
3104                         return strdup(str);
3105         }
3106
3107         return NULL;
3108 }
3109
3110 static char *lookup_monitor(const char *text, int state)
3111 {
3112         int level;
3113
3114         level = __connmanctl_input_calc_level();
3115
3116         if (level < 2)
3117                 return lookup_options(monitor_options, text, state);
3118
3119         if (level == 2)
3120                 return lookup_on_off(text, state);
3121
3122         __connmanctl_input_lookup_end();
3123         return NULL;
3124 }
3125
3126 static char *lookup_config(const char *text, int state)
3127 {
3128         if (__connmanctl_input_calc_level() < 2)
3129                 return lookup_key_from_table(service_hash, text, state);
3130
3131         return lookup_options(config_options, text, state);
3132 }
3133
3134 static char *lookup_session(const char *text, int state)
3135 {
3136         return lookup_options(session_options, text, state);
3137 }
3138
3139 #if defined TIZEN_EXT_WIFI_MESH
3140 static char *lookup_mesh(const char *text, int state)
3141 {
3142         return lookup_options(mesh_options, text, state);
3143 }
3144 #endif
3145
3146 static int peer_service_cb(DBusMessageIter *iter, int errnum,
3147                         const char *error, void *user_data)
3148 {
3149         bool registration = GPOINTER_TO_INT(user_data);
3150
3151         if (error)
3152                 fprintf(stderr, "Error %s peer service: %s\n",
3153                         registration ? "registering" : "unregistering", error);
3154         else
3155                 fprintf(stdout, "Peer service %s\n",
3156                         registration ? "registered" : "unregistered");
3157
3158         return 0;
3159 }
3160
3161 struct _peer_service {
3162         unsigned char *bjr_query;
3163         int bjr_query_len;
3164         unsigned char *bjr_response;
3165         int bjr_response_len;
3166         unsigned char *wfd_ies;
3167         int wfd_ies_len;
3168         char *upnp_service;
3169         int version;
3170         int master;
3171 };
3172
3173 static void append_dict_entry_fixed_array(DBusMessageIter *iter,
3174                         const char *property, void *value, int length)
3175 {
3176         DBusMessageIter dict_entry, variant, array;
3177
3178         dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
3179                                                         NULL, &dict_entry);
3180         dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING,
3181                                                                 &property);
3182         dbus_message_iter_open_container(&dict_entry, DBUS_TYPE_VARIANT,
3183                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
3184                         &variant);
3185         dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
3186                                         DBUS_TYPE_BYTE_AS_STRING, &array);
3187         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
3188                                                         value, length);
3189         dbus_message_iter_close_container(&variant, &array);
3190         dbus_message_iter_close_container(&dict_entry, &variant);
3191         dbus_message_iter_close_container(iter, &dict_entry);
3192 }
3193
3194 static void append_peer_service_dict(DBusMessageIter *iter, void *user_data)
3195 {
3196         struct _peer_service *service = user_data;
3197
3198         if (service->bjr_query && service->bjr_response) {
3199                 append_dict_entry_fixed_array(iter, "BonjourQuery",
3200                         &service->bjr_query, service->bjr_query_len);
3201                 append_dict_entry_fixed_array(iter, "BonjourResponse",
3202                         &service->bjr_response, service->bjr_response_len);
3203         } else if (service->upnp_service && service->version) {
3204                 __connmanctl_dbus_append_dict_entry(iter, "UpnpVersion",
3205                                         DBUS_TYPE_INT32, &service->version);
3206                 __connmanctl_dbus_append_dict_entry(iter, "UpnpService",
3207                                 DBUS_TYPE_STRING, &service->upnp_service);
3208         } else if (service->wfd_ies) {
3209                 append_dict_entry_fixed_array(iter, "WiFiDisplayIEs",
3210                                 &service->wfd_ies, service->wfd_ies_len);
3211         }
3212 }
3213
3214 static void peer_service_append(DBusMessageIter *iter, void *user_data)
3215 {
3216         struct _peer_service *service = user_data;
3217         dbus_bool_t master;
3218
3219         __connmanctl_dbus_append_dict(iter, append_peer_service_dict, service);
3220
3221         if (service->master < 0)
3222                 return;
3223
3224         master = service->master == 1 ? TRUE : FALSE;
3225         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &master);
3226 }
3227
3228 static struct _peer_service *fill_in_peer_service(unsigned char *bjr_query,
3229                                 int bjr_query_len, unsigned char *bjr_response,
3230                                 int bjr_response_len, char *upnp_service,
3231                                 int version, unsigned char *wfd_ies,
3232                                 int wfd_ies_len)
3233 {
3234         struct _peer_service *service;
3235
3236         service = dbus_malloc0(sizeof(*service));
3237
3238 #if defined TIZEN_EXT
3239         if (!service)
3240                 return NULL;
3241 #endif
3242
3243         if (bjr_query_len && bjr_response_len) {
3244                 service->bjr_query = dbus_malloc0(bjr_query_len);
3245 #if defined TIZEN_EXT
3246                 if(!service->bjr_query) {
3247                         dbus_free(service);
3248                         return NULL;
3249                 }
3250 #endif
3251                 memcpy(service->bjr_query, bjr_query, bjr_query_len);
3252                 service->bjr_query_len = bjr_query_len;
3253
3254                 service->bjr_response = dbus_malloc0(bjr_response_len);
3255 #if defined TIZEN_EXT
3256                 if(!service->bjr_response) {
3257                         dbus_free(service->bjr_query);
3258                         dbus_free(service);
3259                         return NULL;
3260                 }
3261 #endif
3262                 memcpy(service->bjr_response, bjr_response, bjr_response_len);
3263                 service->bjr_response_len = bjr_response_len;
3264         } else if (upnp_service && version) {
3265                 service->upnp_service = strdup(upnp_service);
3266                 service->version = version;
3267         } else if (wfd_ies && wfd_ies_len) {
3268                 service->wfd_ies = dbus_malloc0(wfd_ies_len);
3269 #if defined TIZEN_EXT
3270                 if (!service->wfd_ies) {
3271                         dbus_free(service);
3272                         return NULL;
3273                 }
3274 #endif
3275                 memcpy(service->wfd_ies, wfd_ies, wfd_ies_len);
3276                 service->wfd_ies_len = wfd_ies_len;
3277         } else {
3278                 dbus_free(service);
3279                 service = NULL;
3280         }
3281
3282         return service;
3283 }
3284
3285 static void free_peer_service(struct _peer_service *service)
3286 {
3287         dbus_free(service->bjr_query);
3288         dbus_free(service->bjr_response);
3289         dbus_free(service->wfd_ies);
3290         free(service->upnp_service);
3291         dbus_free(service);
3292 }
3293
3294 static int peer_service_register(unsigned char *bjr_query, int bjr_query_len,
3295                         unsigned char *bjr_response, int bjr_response_len,
3296                         char *upnp_service, int version,
3297                         unsigned char *wfd_ies, int wfd_ies_len, int master)
3298 {
3299         struct _peer_service *service;
3300         bool registration = true;
3301         int ret;
3302
3303         service = fill_in_peer_service(bjr_query, bjr_query_len, bjr_response,
3304                                 bjr_response_len, upnp_service, version,
3305                                 wfd_ies, wfd_ies_len);
3306         if (!service)
3307                 return -EINVAL;
3308
3309         service->master = master;
3310
3311         ret = __connmanctl_dbus_method_call(connection, "net.connman", "/",
3312                         "net.connman.Manager", "RegisterPeerService",
3313                         peer_service_cb, GINT_TO_POINTER(registration),
3314                         peer_service_append, service);
3315
3316         free_peer_service(service);
3317
3318         return ret;
3319 }
3320
3321 static int peer_service_unregister(unsigned char *bjr_query, int bjr_query_len,
3322                         unsigned char *bjr_response, int bjr_response_len,
3323                         char *upnp_service, int version,
3324                         unsigned char *wfd_ies, int wfd_ies_len)
3325 {
3326         struct _peer_service *service;
3327         bool registration = false;
3328         int ret;
3329
3330         service = fill_in_peer_service(bjr_query, bjr_query_len, bjr_response,
3331                                 bjr_response_len, upnp_service, version,
3332                                 wfd_ies, wfd_ies_len);
3333         if (!service)
3334                 return -EINVAL;
3335
3336         service->master = -1;
3337
3338         ret = __connmanctl_dbus_method_call(connection, "net.connman", "/",
3339                         "net.connman.Manager", "UnregisterPeerService",
3340                         peer_service_cb, GINT_TO_POINTER(registration),
3341                         peer_service_append, service);
3342
3343         free_peer_service(service);
3344
3345         return ret;
3346 }
3347
3348 static int parse_spec_array(char *command, unsigned char spec[1024])
3349 {
3350         int length, pos, end;
3351         char b[3] = {};
3352         char *e;
3353
3354         end = strlen(command);
3355         for (e = NULL, length = pos = 0; command[pos] != '\0'; length++) {
3356                 if (pos+2 > end)
3357                         return -EINVAL;
3358
3359                 b[0] = command[pos];
3360                 b[1] = command[pos+1];
3361
3362                 spec[length] = strtol(b, &e, 16);
3363                 if (e && *e != '\0')
3364                         return -EINVAL;
3365
3366                 pos += 2;
3367         }
3368
3369         return length;
3370 }
3371
3372 static int cmd_peer_service(char *args[], int num,
3373                                 struct connman_option *options)
3374 {
3375         unsigned char bjr_query[1024] = {};
3376         unsigned char bjr_response[1024] = {};
3377         unsigned char wfd_ies[1024] = {};
3378         char *upnp_service = NULL;
3379         int bjr_query_len = 0, bjr_response_len = 0;
3380         int version = 0, master = 0, wfd_ies_len = 0;
3381         int limit;
3382
3383         if (num < 4)
3384                 return -EINVAL;
3385
3386         if (!strcmp(args[2], "wfd_ies")) {
3387                 wfd_ies_len = parse_spec_array(args[3], wfd_ies);
3388                 if (wfd_ies_len == -EINVAL)
3389                         return -EINVAL;
3390                 limit = 5;
3391                 goto master;
3392         }
3393
3394         if (num < 6)
3395                 return -EINVAL;
3396
3397         limit = 7;
3398         if (!strcmp(args[2], "bjr_query")) {
3399                 if (strcmp(args[4], "bjr_response"))
3400                         return -EINVAL;
3401                 bjr_query_len = parse_spec_array(args[3], bjr_query);
3402                 bjr_response_len = parse_spec_array(args[5], bjr_response);
3403
3404                 if (bjr_query_len == -EINVAL || bjr_response_len == -EINVAL)
3405                         return -EINVAL;
3406         } else if (!strcmp(args[2], "upnp_service")) {
3407                 char *e = NULL;
3408
3409                 if (strcmp(args[4], "upnp_version"))
3410                         return -EINVAL;
3411                 upnp_service = args[3];
3412                 version = strtol(args[5], &e, 10);
3413                 if (*e != '\0')
3414                         return -EINVAL;
3415         }
3416
3417 master:
3418         if (num == limit) {
3419                 master = parse_boolean(args[6]);
3420                 if (master < 0)
3421                         return -EINVAL;
3422         }
3423
3424         if (!strcmp(args[1], "register")) {
3425                 return peer_service_register(bjr_query, bjr_query_len,
3426                                 bjr_response, bjr_response_len, upnp_service,
3427                                 version, wfd_ies, wfd_ies_len, master);
3428         } else if (!strcmp(args[1], "unregister")) {
3429                 return peer_service_unregister(bjr_query, bjr_query_len,
3430                                 bjr_response, bjr_response_len, upnp_service,
3431                                 version, wfd_ies, wfd_ies_len);
3432         }
3433
3434         return -EINVAL;
3435 }
3436
3437 static const struct {
3438         const char *cmd;
3439         const char *argument;
3440         struct connman_option *options;
3441         int (*func) (char *args[], int num, struct connman_option *options);
3442         const char *desc;
3443         __connmanctl_lookup_cb cb;
3444 } cmd_table[] = {
3445         { "state",        NULL,           NULL,            cmd_state,
3446           "Shows if the system is online or offline", NULL },
3447         { "technologies", NULL,           NULL,            cmd_technologies,
3448           "Display technologies", NULL },
3449         { "clock",        NULL,           NULL,            cmd_clock,
3450           "Get System Clock Properties", NULL },
3451         { "enable",       "<technology>|offline", NULL,    cmd_enable,
3452           "Enables given technology or offline mode",
3453           lookup_technology_offline },
3454         { "disable",      "<technology>|offline", NULL,    cmd_disable,
3455           "Disables given technology or offline mode",
3456           lookup_technology_offline },
3457 #if defined TIZEN_EXT_WIFI_MESH
3458         { "mesh",      "", mesh_options, cmd_mesh, "Mesh specific commands",
3459                 lookup_mesh },
3460 #endif
3461         { "tether", "<technology> on|off\n"
3462                     "            wifi [on|off] <ssid> <passphrase> ",
3463                                           NULL,            cmd_tether,
3464           "Enable, disable tethering, set SSID and passphrase for wifi",
3465           lookup_tether },
3466         { "tethering_clients", NULL,      NULL,            cmd_tethering_clients,
3467           "Display tethering clients", NULL },
3468         { "services",     "[<service>]",  service_options, cmd_services,
3469           "Display services", lookup_service_arg },
3470 #if defined TIZEN_EXT_INS
3471         { "ins",                  NULL,      ins_options, cmd_ins,
3472           "Display intelligent network selection", NULL },
3473 #endif
3474         { "peers",        "[peer]",       NULL,            cmd_peers,
3475           "Display peers", lookup_peer_arg },
3476         { "scan",         "<technology>", NULL,            cmd_scan,
3477           "Scans for new services for given technology",
3478           lookup_technology_arg },
3479         { "connect",      "<service/peer>", NULL,          cmd_connect,
3480           "Connect a given service or peer", lookup_service_arg },
3481         { "disconnect",   "<service/peer>", NULL,          cmd_disconnect,
3482           "Disconnect a given service or peer", lookup_service_arg },
3483         { "move-before",   "<service> <target service>  ", NULL,
3484           cmd_service_move_before, "Move <service> before <target service>",
3485           lookup_service_arg },
3486         { "move-after",   "<service> <target service>   ", NULL,
3487           cmd_service_move_after, "Move <service> after <target service>",
3488           lookup_service_arg },
3489         { "config",       "<service>",    config_options,  cmd_config,
3490           "Set service configuration options", lookup_config },
3491         { "monitor",      "[off]",        monitor_options, cmd_monitor,
3492           "Monitor signals from interfaces", lookup_monitor },
3493         { "agent", "on|off",              NULL,            cmd_agent,
3494           "Agent mode", lookup_agent },
3495         { "vpnconnections", "[<connection>]", NULL,        cmd_vpnconnections,
3496           "Display VPN connections", lookup_vpnconnection_arg },
3497         { "vpnagent",     "on|off",     NULL,            cmd_vpnagent,
3498           "VPN Agent mode", lookup_agent },
3499         { "session",      "on|off|connect|disconnect|config", session_options,
3500           cmd_session, "Enable or disable a session", lookup_session },
3501         { "peer_service", "register|unregister <specs> <master>\n"
3502                           "Where specs are:\n"
3503                           "\tbjr_query <query> bjr_response <response>\n"
3504                           "\tupnp_service <service> upnp_version <version>\n"
3505                           "\twfd_ies <ies>\n", NULL,
3506           cmd_peer_service, "(Un)Register a Peer Service", NULL },
3507         { "help",         NULL,           NULL,            cmd_help,
3508           "Show help", NULL },
3509         { "exit",         NULL,           NULL,            cmd_exit,
3510           "Exit", NULL },
3511         { "quit",         NULL,           NULL,            cmd_exit,
3512           "Quit", NULL },
3513         {  NULL, },
3514 };
3515
3516 static int cmd_help(char *args[], int num, struct connman_option *options)
3517 {
3518         bool interactive = __connmanctl_is_interactive();
3519         int i, j;
3520
3521         if (interactive == false)
3522                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
3523
3524         for (i = 0; cmd_table[i].cmd; i++) {
3525                 const char *cmd = cmd_table[i].cmd;
3526                 const char *argument = cmd_table[i].argument;
3527                 const char *desc = cmd_table[i].desc;
3528
3529                 printf("%-16s%-22s%s\n", cmd? cmd: "",
3530                                 argument? argument: "",
3531                                 desc? desc: "");
3532
3533                 if (cmd_table[i].options) {
3534                         for (j = 0; cmd_table[i].options[j].name;
3535                              j++) {
3536                                 const char *options_desc =
3537                                         cmd_table[i].options[j].desc ?
3538                                         cmd_table[i].options[j].desc: "";
3539
3540                                 printf("   --%-16s%s\n",
3541                                                 cmd_table[i].options[j].name,
3542                                                 options_desc);
3543                         }
3544                 }
3545         }
3546
3547         if (interactive == false)
3548                 fprintf(stdout, "\nNote: arguments and output are considered "
3549                                 "EXPERIMENTAL for now.\n");
3550
3551         return 0;
3552 }
3553
3554 __connmanctl_lookup_cb __connmanctl_get_lookup_func(const char *text)
3555 {
3556         int i, cmdlen, textlen;
3557
3558         if (!text)
3559                 return NULL;
3560
3561         textlen = strlen(text);
3562
3563         for (i = 0; cmd_table[i].cmd; i++) {
3564                 cmdlen = strlen(cmd_table[i].cmd);
3565
3566                 if (textlen > cmdlen && text[cmdlen] != ' ')
3567                         continue;
3568
3569                 if (strncmp(cmd_table[i].cmd, text, cmdlen) == 0)
3570                         return cmd_table[i].cb;
3571         }
3572
3573         return NULL;
3574 }
3575
3576 int __connmanctl_commands(DBusConnection *dbus_conn, char *argv[], int argc)
3577 {
3578         int i, result;
3579
3580         connection = dbus_conn;
3581
3582         for (i = 0; cmd_table[i].cmd; i++) {
3583                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
3584                                 cmd_table[i].func) {
3585                         result = cmd_table[i].func(argv, argc,
3586                                         cmd_table[i].options);
3587                         if (result < 0 && result != -EINPROGRESS)
3588                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
3589                                                 strerror(-result));
3590                         return result;
3591                 }
3592         }
3593
3594         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
3595         return -EINVAL;
3596 }
3597
3598 char *__connmanctl_lookup_command(const char *text, int state)
3599 {
3600         static int i = 0;
3601         static int len = 0;
3602
3603         if (state == 0) {
3604                 i = 0;
3605                 len = strlen(text);
3606         }
3607
3608         while (cmd_table[i].cmd) {
3609                 const char *command = cmd_table[i].cmd;
3610
3611                 i++;
3612
3613                 if (strncmp(text, command, len) == 0)
3614                         return strdup(command);
3615         }
3616
3617         return NULL;
3618 }
3619
3620 static char *get_path(char *full_path)
3621 {
3622         char *path;
3623
3624         path = strrchr(full_path, '/');
3625         if (path && *path != '\0')
3626                 path++;
3627         else
3628                 path = full_path;
3629
3630         return path;
3631 }
3632
3633 static void add_service_id(const char *path)
3634 {
3635         g_hash_table_replace(service_hash, g_strdup(path),
3636                         GINT_TO_POINTER(TRUE));
3637 }
3638
3639 static void remove_service_id(const char *path)
3640 {
3641         g_hash_table_remove(service_hash, path);
3642 }
3643
3644 static void services_added(DBusMessageIter *iter)
3645 {
3646         DBusMessageIter array;
3647         char *path = NULL;
3648
3649         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) {
3650
3651                 dbus_message_iter_recurse(iter, &array);
3652                 if (dbus_message_iter_get_arg_type(&array) !=
3653                                                 DBUS_TYPE_OBJECT_PATH)
3654                         return;
3655
3656                 dbus_message_iter_get_basic(&array, &path);
3657                 add_service_id(get_path(path));
3658
3659                 dbus_message_iter_next(iter);
3660         }
3661 }
3662
3663 static void update_services(DBusMessageIter *iter)
3664 {
3665         DBusMessageIter array;
3666         char *path;
3667
3668         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3669                 return;
3670
3671         dbus_message_iter_recurse(iter, &array);
3672         services_added(&array);
3673
3674         dbus_message_iter_next(iter);
3675         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3676                 return;
3677
3678         dbus_message_iter_recurse(iter, &array);
3679         while (dbus_message_iter_get_arg_type(&array) ==
3680                                                 DBUS_TYPE_OBJECT_PATH) {
3681                 dbus_message_iter_get_basic(&array, &path);
3682                 remove_service_id(get_path(path));
3683
3684                 dbus_message_iter_next(&array);
3685         }
3686 }
3687
3688 static int populate_service_hash(DBusMessageIter *iter, int errnum,
3689                                 const char *error, void *user_data)
3690 {
3691         if (error) {
3692                 fprintf(stderr, "Error getting services: %s", error);
3693                 return 0;
3694         }
3695
3696         update_services(iter);
3697         return 0;
3698 }
3699
3700 static void add_vpnconnection_id(const char *path)
3701 {
3702         g_hash_table_replace(vpnconnection_hash, g_strdup(path),
3703                         GINT_TO_POINTER(TRUE));
3704 }
3705
3706 static void remove_vpnconnection_id(const char *path)
3707 {
3708         g_hash_table_remove(vpnconnection_hash, path);
3709 }
3710
3711 static void vpnconnection_added(DBusMessageIter *iter)
3712 {
3713         char *path = NULL;
3714
3715         dbus_message_iter_get_basic(iter, &path);
3716         add_vpnconnection_id(get_path(path));
3717 }
3718
3719 static void vpnconnection_removed(DBusMessageIter *iter)
3720 {
3721         char *path = NULL;
3722
3723         dbus_message_iter_get_basic(iter, &path);
3724         remove_vpnconnection_id(get_path(path));
3725 }
3726
3727 static void add_vpnconnections(DBusMessageIter *iter)
3728 {
3729         DBusMessageIter array;
3730         char *path = NULL;
3731
3732         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) {
3733
3734                 dbus_message_iter_recurse(iter, &array);
3735                 if (dbus_message_iter_get_arg_type(&array) !=
3736                                                 DBUS_TYPE_OBJECT_PATH)
3737                         return;
3738
3739                 dbus_message_iter_get_basic(&array, &path);
3740                 add_vpnconnection_id(get_path(path));
3741
3742                 dbus_message_iter_next(iter);
3743         }
3744 }
3745
3746 static int populate_vpnconnection_hash(DBusMessageIter *iter, int errnum,
3747                                 const char *error, void *user_data)
3748 {
3749         DBusMessageIter array;
3750
3751         if (error) {
3752                 fprintf(stderr, "Error getting VPN connections: %s", error);
3753                 return 0;
3754         }
3755
3756         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3757                 return 0;
3758
3759         dbus_message_iter_recurse(iter, &array);
3760
3761         add_vpnconnections(&array);
3762
3763         return 0;
3764 }
3765
3766 static void add_peer_id(const char *path)
3767 {
3768         g_hash_table_replace(peer_hash, g_strdup(path), GINT_TO_POINTER(TRUE));
3769 }
3770
3771 static void remove_peer_id(const char *path)
3772 {
3773         g_hash_table_remove(peer_hash, path);
3774 }
3775
3776 static void peers_added(DBusMessageIter *iter)
3777 {
3778         DBusMessageIter array;
3779         char *path = NULL;
3780
3781         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) {
3782
3783                 dbus_message_iter_recurse(iter, &array);
3784                 if (dbus_message_iter_get_arg_type(&array) !=
3785                                                 DBUS_TYPE_OBJECT_PATH)
3786                         return;
3787
3788                 dbus_message_iter_get_basic(&array, &path);
3789                 add_peer_id(get_path(path));
3790
3791                 dbus_message_iter_next(iter);
3792         }
3793 }
3794
3795 static void update_peers(DBusMessageIter *iter)
3796 {
3797         DBusMessageIter array;
3798         char *path;
3799
3800         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3801                 return;
3802
3803         dbus_message_iter_recurse(iter, &array);
3804         peers_added(&array);
3805
3806         dbus_message_iter_next(iter);
3807         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3808                 return;
3809
3810         dbus_message_iter_recurse(iter, &array);
3811         while (dbus_message_iter_get_arg_type(&array) ==
3812                                                 DBUS_TYPE_OBJECT_PATH) {
3813                 dbus_message_iter_get_basic(&array, &path);
3814                 remove_peer_id(get_path(path));
3815
3816                 dbus_message_iter_next(&array);
3817         }
3818 }
3819
3820 static int populate_peer_hash(DBusMessageIter *iter, int errnum,
3821                         const char *error, void *user_data)
3822 {
3823         if (error) {
3824                 fprintf(stderr, "Error getting peers: %s", error);
3825                 return 0;
3826         }
3827
3828         update_peers(iter);
3829         return 0;
3830 }
3831
3832 static void add_technology_id(const char *path)
3833 {
3834         g_hash_table_replace(technology_hash, g_strdup(path),
3835                         GINT_TO_POINTER(TRUE));
3836 }
3837
3838 static void remove_technology_id(const char *path)
3839 {
3840         g_hash_table_remove(technology_hash, path);
3841 }
3842
3843 static void remove_technology(DBusMessageIter *iter)
3844 {
3845         char *path = NULL;
3846
3847         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH)
3848                 return;
3849
3850         dbus_message_iter_get_basic(iter, &path);
3851         remove_technology_id(get_path(path));
3852 }
3853
3854 static void add_technology(DBusMessageIter *iter)
3855 {
3856         char *path = NULL;
3857
3858         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH)
3859                 return;
3860
3861         dbus_message_iter_get_basic(iter, &path);
3862         add_technology_id(get_path(path));
3863 }
3864
3865 static void update_technologies(DBusMessageIter *iter)
3866 {
3867         DBusMessageIter array;
3868
3869         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3870                 return;
3871
3872         dbus_message_iter_recurse(iter, &array);
3873
3874         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
3875                 DBusMessageIter object_path;
3876
3877                 dbus_message_iter_recurse(&array, &object_path);
3878
3879                 add_technology(&object_path);
3880
3881                 dbus_message_iter_next(&array);
3882         }
3883 }
3884
3885 static int populate_technology_hash(DBusMessageIter *iter, int errnum,
3886                                 const char *error, void *user_data)
3887 {
3888         if (error) {
3889                 fprintf(stderr, "Error getting technologies: %s\n", error);
3890                 return 0;
3891         }
3892
3893         update_technologies(iter);
3894
3895         return 0;
3896 }
3897
3898 static DBusHandlerResult monitor_completions_changed(
3899                 DBusConnection *connection,
3900                 DBusMessage *message, void *user_data)
3901 {
3902         bool *enabled = user_data;
3903         DBusMessageIter iter;
3904         DBusHandlerResult handled;
3905
3906         if (*enabled)
3907                 handled = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3908         else
3909                 handled = DBUS_HANDLER_RESULT_HANDLED;
3910
3911         if (dbus_message_is_signal(message, "net.connman.Manager",
3912                                         "ServicesChanged")) {
3913                 dbus_message_iter_init(message, &iter);
3914                 update_services(&iter);
3915                 return handled;
3916         }
3917
3918         if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
3919                                         "ConnectionAdded")) {
3920                 dbus_message_iter_init(message, &iter);
3921                 vpnconnection_added(&iter);
3922                 return handled;
3923         }
3924
3925         if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
3926                                         "ConnectionRemoved")) {
3927                 dbus_message_iter_init(message, &iter);
3928                 vpnconnection_removed(&iter);
3929                 return handled;
3930         }
3931
3932         if (dbus_message_is_signal(message, "net.connman.Manager",
3933                                                 "PeersChanged")) {
3934                 dbus_message_iter_init(message, &iter);
3935                 update_peers(&iter);
3936                 return handled;
3937         }
3938
3939         if (dbus_message_is_signal(message, "net.connman.Manager",
3940                                         "TechnologyAdded")) {
3941                 dbus_message_iter_init(message, &iter);
3942                 add_technology(&iter);
3943                 return handled;
3944         }
3945
3946         if (dbus_message_is_signal(message, "net.connman.Manager",
3947                                         "TechnologyRemoved")) {
3948                 dbus_message_iter_init(message, &iter);
3949                 remove_technology(&iter);
3950                 return handled;
3951         }
3952
3953         if (!g_strcmp0(dbus_message_get_interface(message),
3954                                         "net.connman.Manager"))
3955                 return handled;
3956
3957         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3958 }
3959
3960 void __connmanctl_monitor_completions(DBusConnection *dbus_conn)
3961 {
3962         bool *manager_enabled = NULL;
3963         DBusError err;
3964         int i;
3965
3966         for (i = 0; monitor[i].interface; i++) {
3967                 if (!strcmp(monitor[i].interface, "Manager")) {
3968                         manager_enabled = &monitor[i].enabled;
3969                         break;
3970                 }
3971         }
3972
3973         if (!dbus_conn) {
3974                 g_hash_table_destroy(service_hash);
3975                 g_hash_table_destroy(vpnconnection_hash);
3976                 g_hash_table_destroy(technology_hash);
3977
3978                 dbus_bus_remove_match(connection,
3979                         "type='signal',interface='net.connman.Manager'", NULL);
3980                 dbus_bus_remove_match(connection,
3981                         "type='signal',interface='net.connman.vpn.Manager'",
3982                         NULL);
3983                 dbus_connection_remove_filter(connection,
3984                                         monitor_completions_changed,
3985                                         manager_enabled);
3986                 return;
3987         }
3988
3989         connection = dbus_conn;
3990
3991         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
3992                                                                 g_free, NULL);
3993
3994         vpnconnection_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
3995                                                                 g_free, NULL);
3996
3997         peer_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
3998                                                                 g_free, NULL);
3999
4000         technology_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
4001                                                                 g_free, NULL);
4002
4003         __connmanctl_dbus_method_call(connection,
4004                                 CONNMAN_SERVICE, CONNMAN_PATH,
4005                                 "net.connman.Manager", "GetServices",
4006                                 populate_service_hash, NULL, NULL, NULL);
4007
4008         __connmanctl_dbus_method_call(connection,
4009                                 VPN_SERVICE, CONNMAN_PATH,
4010                                 "net.connman.vpn.Manager", "GetConnections",
4011                                 populate_vpnconnection_hash, NULL, NULL, NULL);
4012
4013         __connmanctl_dbus_method_call(connection,
4014                                 CONNMAN_SERVICE, CONNMAN_PATH,
4015                                 "net.connman.Manager", "GetPeers",
4016                                 populate_peer_hash, NULL, NULL, NULL);
4017
4018         __connmanctl_dbus_method_call(connection,
4019                                 CONNMAN_SERVICE, CONNMAN_PATH,
4020                                 "net.connman.Manager", "GetTechnologies",
4021                                 populate_technology_hash, NULL, NULL, NULL);
4022
4023         dbus_connection_add_filter(connection,
4024                                 monitor_completions_changed, manager_enabled,
4025                         NULL);
4026
4027         dbus_error_init(&err);
4028         dbus_bus_add_match(connection,
4029                         "type='signal',interface='net.connman.Manager'", &err);
4030
4031         if (dbus_error_is_set(&err)) {
4032                 fprintf(stderr, "Error: %s\n", err.message);
4033                 return;
4034         }
4035
4036         dbus_bus_add_match(connection,
4037                         "type='signal',interface='net.connman.vpn.Manager'",
4038                         &err);
4039
4040         if (dbus_error_is_set(&err))
4041                 fprintf(stderr, "Error: %s\n", err.message);
4042 }