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