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