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