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