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