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