557a8ffd93a862b7bcb5f0e12a402b482f82a965
[platform/upstream/connman.git] / client / commands.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012-2013  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
33 #include <glib.h>
34 #include <gdbus.h>
35
36 #include "dbus_helpers.h"
37 #include "input.h"
38 #include "services.h"
39 #include "commands.h"
40 #include "agent.h"
41 #include "vpnconnections.h"
42
43 static DBusConnection *connection;
44
45 struct connman_option {
46         const char *name;
47         const char val;
48         const char *desc;
49 };
50
51 static char *ipv4[] = {
52         "Method",
53         "Address",
54         "Netmask",
55         "Gateway",
56         NULL
57 };
58
59 static char *ipv6[] = {
60         "Method",
61         "Address",
62         "PrefixLength",
63         "Gateway",
64         NULL
65 };
66
67 static int cmd_help(char *args[], int num, struct connman_option *options);
68
69 static bool check_dbus_name(const char *name)
70 {
71         /*
72          * Valid dbus chars should be [A-Z][a-z][0-9]_
73          * and should not start with number.
74          */
75         unsigned int i;
76
77         if (name == NULL || name[0] == '\0')
78                 return false;
79
80         for (i = 0; name[i] != '\0'; i++)
81                 if (!((name[i] >= 'A' && name[i] <= 'Z') ||
82                                 (name[i] >= 'a' && name[i] <= 'z') ||
83                                 (name[i] >= '0' && name[i] <= '9') ||
84                                 name[i] == '_'))
85                         return false;
86
87         return true;
88 }
89
90 static int parse_boolean(char *arg)
91 {
92         if (arg == NULL)
93                 return -1;
94
95         if (strcasecmp(arg, "no") == 0 ||
96                         strcasecmp(arg, "false") == 0 ||
97                         strcasecmp(arg, "off" ) == 0 ||
98                         strcasecmp(arg, "disable" ) == 0 ||
99                         strcasecmp(arg, "n") == 0 ||
100                         strcasecmp(arg, "f") == 0 ||
101                         strcasecmp(arg, "0") == 0)
102                 return 0;
103
104         if (strcasecmp(arg, "yes") == 0 ||
105                         strcasecmp(arg, "true") == 0 ||
106                         strcasecmp(arg, "on") == 0 ||
107                         strcasecmp(arg, "enable" ) == 0 ||
108                         strcasecmp(arg, "y") == 0 ||
109                         strcasecmp(arg, "t") == 0 ||
110                         strcasecmp(arg, "1") == 0)
111                 return 1;
112
113         return -1;
114 }
115
116 static int parse_args(char *arg, struct connman_option *options)
117 {
118         int i;
119
120         if (arg == NULL)
121                 return -1;
122
123         for (i = 0; options[i].name != NULL; i++) {
124                 if (strcmp(options[i].name, arg) == 0 ||
125                                 (strncmp(arg, "--", 2) == 0 &&
126                                         strcmp(&arg[2], options[i].name) == 0))
127                         return options[i].val;
128         }
129
130         return '?';
131 }
132
133 static int enable_return(DBusMessageIter *iter, const char *error,
134                 void *user_data)
135 {
136         char *tech = user_data;
137         char *str;
138
139         str = strrchr(tech, '/');
140         if (str != NULL)
141                 str++;
142         else
143                 str = tech;
144
145         if (error == NULL) {
146                 fprintf(stdout, "Enabled %s\n", str);
147         } else
148                 fprintf(stderr, "Error %s: %s\n", str, error);
149
150         g_free(user_data);
151
152         return 0;
153 }
154
155 static int cmd_enable(char *args[], int num, struct connman_option *options)
156 {
157         char *tech;
158         dbus_bool_t b = TRUE;
159
160         if (num > 2)
161                 return -E2BIG;
162
163         if (num < 2)
164                 return -EINVAL;
165
166         if (check_dbus_name(args[1]) == false)
167                 return -EINVAL;
168
169         if (strcmp(args[1], "offlinemode") == 0) {
170                 tech = g_strdup(args[1]);
171                 return __connmanctl_dbus_set_property(connection, "/",
172                                 "net.connman.Manager", enable_return, tech,
173                                 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
174         }
175
176         tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
177         return __connmanctl_dbus_set_property(connection, tech,
178                                 "net.connman.Technology", enable_return, tech,
179                                 "Powered", DBUS_TYPE_BOOLEAN, &b);
180 }
181
182 static int disable_return(DBusMessageIter *iter, const char *error,
183                 void *user_data)
184 {
185         char *tech = user_data;
186         char *str;
187
188         str = strrchr(tech, '/');
189         if (str != NULL)
190                 str++;
191         else
192                 str = tech;
193
194         if (error == NULL) {
195                 fprintf(stdout, "Disabled %s\n", str);
196         } else
197                 fprintf(stderr, "Error %s: %s\n", str, error);
198
199         g_free(user_data);
200
201         return 0;
202 }
203
204 static int cmd_disable(char *args[], int num, struct connman_option *options)
205 {
206         char *tech;
207         dbus_bool_t b = FALSE;
208
209         if (num > 2)
210                 return -E2BIG;
211
212         if (num < 2)
213                 return -EINVAL;
214
215         if (check_dbus_name(args[1]) == false)
216                 return -EINVAL;
217
218         if (strcmp(args[1], "offlinemode") == 0) {
219                 tech = g_strdup(args[1]);
220                 return __connmanctl_dbus_set_property(connection, "/",
221                                 "net.connman.Manager", disable_return, tech,
222                                 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
223         }
224
225         tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
226         return __connmanctl_dbus_set_property(connection, tech,
227                                 "net.connman.Technology", disable_return, tech,
228                                 "Powered", DBUS_TYPE_BOOLEAN, &b);
229 }
230
231 static int state_print(DBusMessageIter *iter, const char *error,
232                 void *user_data)
233 {
234         DBusMessageIter entry;
235
236         if (error != NULL) {
237                 fprintf(stderr, "Error: %s", error);
238                 return 0;
239         }
240
241         dbus_message_iter_recurse(iter, &entry);
242         __connmanctl_dbus_print(&entry, "  ", " = ", "\n");
243         fprintf(stdout, "\n");
244
245         return 0;
246 }
247
248 static int cmd_state(char *args[], int num, struct connman_option *options)
249 {
250         if (num > 1)
251                 return -E2BIG;
252
253         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
254                         CONNMAN_PATH, "net.connman.Manager", "GetProperties",
255                         state_print, NULL, DBUS_TYPE_INVALID);
256 }
257
258 static int services_list(DBusMessageIter *iter, const char *error,
259                 void *user_data)
260 {
261         if (error == NULL) {
262                 __connmanctl_services_list(iter);
263                 fprintf(stdout, "\n");
264         } else {
265                 fprintf(stderr, "Error: %s\n", error);
266         }
267
268         return 0;
269 }
270
271 static int services_properties(DBusMessageIter *iter, const char *error,
272                 void *user_data)
273 {
274         char *path = user_data;
275         char *str;
276         DBusMessageIter dict;
277
278         if (error == NULL) {
279                 fprintf(stdout, "%s\n", path);
280
281                 dbus_message_iter_recurse(iter, &dict);
282                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
283
284                 fprintf(stdout, "\n");
285
286         } else {
287                 str = strrchr(path, '/');
288                 if (str != NULL)
289                         str++;
290                 else
291                         str = path;
292
293                 fprintf(stderr, "Error %s: %s\n", str, error);
294         }
295
296         g_free(user_data);
297
298         return 0;
299 }
300
301 static int cmd_services(char *args[], int num, struct connman_option *options)
302 {
303         char *service_name = NULL;
304         char *path;
305         int c;
306
307         if (num > 3)
308                 return -E2BIG;
309
310         c = parse_args(args[1], options);
311         switch (c) {
312         case -1:
313                 break;
314         case 'p':
315                 if (num < 3)
316                         return -EINVAL;
317                 service_name = args[2];
318                 break;
319         default:
320                 if (num > 2)
321                         return -E2BIG;
322                 service_name = args[1];
323                 break;
324         }
325
326         if (service_name == NULL) {
327                 return __connmanctl_dbus_method_call(connection,
328                                 CONNMAN_SERVICE, CONNMAN_PATH,
329                                 "net.connman.Manager", "GetServices",
330                                 services_list, NULL, DBUS_TYPE_INVALID);
331         }
332
333         if (check_dbus_name(service_name) == false)
334                 return -EINVAL;
335
336         path = g_strdup_printf("/net/connman/service/%s", service_name);
337         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
338                         "net.connman.Service", "GetProperties",
339                         services_properties, path, DBUS_TYPE_INVALID);
340 }
341
342 static int technology_print(DBusMessageIter *iter, const char *error,
343                 void *user_data)
344 {
345         DBusMessageIter array;
346
347         if (error != NULL) {
348                 fprintf(stderr, "Error: %s\n", error);
349                 return 0;
350         }
351
352         dbus_message_iter_recurse(iter, &array);
353         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
354                 DBusMessageIter entry, dict;
355                 const char *path;
356
357                 dbus_message_iter_recurse(&array, &entry);
358                 dbus_message_iter_get_basic(&entry, &path);
359                 fprintf(stdout, "%s\n", path);
360
361                 dbus_message_iter_next(&entry);
362
363                 dbus_message_iter_recurse(&entry, &dict);
364                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
365                 fprintf(stdout, "\n");
366
367                 dbus_message_iter_next(&array);
368         }
369
370         return 0;
371 }
372
373 static int cmd_technologies(char *args[], int num,
374                 struct connman_option *options)
375 {
376         if (num > 1)
377                 return -E2BIG;
378
379         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
380                         CONNMAN_PATH, "net.connman.Manager", "GetTechnologies",
381                         technology_print, NULL, DBUS_TYPE_INVALID);
382 }
383
384 struct tether_enable {
385         char *path;
386         dbus_bool_t enable;
387 };
388
389 static int tether_set_return(DBusMessageIter *iter, const char *error,
390                 void *user_data)
391 {
392         struct tether_enable *tether = user_data;
393         char *str;
394
395         str = strrchr(tether->path, '/');
396         if (str != NULL)
397                 str++;
398         else
399                 str = tether->path;
400
401         if (error == NULL) {
402                 fprintf(stdout, "%s tethering for %s\n",
403                                 tether->enable == TRUE ? "Enabled": "Disabled",
404                                 str);
405         } else
406                 fprintf(stderr, "Error %s %s tethering: %s\n",
407                                 tether->enable == TRUE ?
408                                 "enabling": "disabling", str, error);
409
410         g_free(tether->path);
411         g_free(user_data);
412
413         return 0;
414 }
415
416 static int tether_set(char *technology, int set_tethering)
417 {
418         struct tether_enable *tether = g_new(struct tether_enable, 1);
419
420         switch(set_tethering) {
421         case 1:
422                 tether->enable = TRUE;
423                 break;
424         case 0:
425                 tether->enable = FALSE;
426                 break;
427         default:
428                 g_free(tether);
429                 return 0;
430         }
431
432         tether->path = g_strdup_printf("/net/connman/technology/%s",
433                         technology);
434
435         return __connmanctl_dbus_set_property(connection, tether->path,
436                         "net.connman.Technology", tether_set_return,
437                         tether, "Tethering", DBUS_TYPE_BOOLEAN,
438                         &tether->enable);
439 }
440
441 struct tether_properties {
442         int ssid_result;
443         int passphrase_result;
444         int set_tethering;
445 };
446
447 static int tether_update(struct tether_properties *tether)
448 {
449         printf("%d %d %d\n", tether->ssid_result, tether->passphrase_result,
450                 tether->set_tethering);
451
452         if (tether->ssid_result == 0 && tether->passphrase_result == 0)
453                 return tether_set("wifi", tether->set_tethering);
454
455         if (tether->ssid_result != -EINPROGRESS &&
456                         tether->passphrase_result != -EINPROGRESS) {
457                 g_free(tether);
458                 return 0;
459         }
460
461         return -EINPROGRESS;
462 }
463
464 static int tether_set_ssid_return(DBusMessageIter *iter, const char *error,
465                 void *user_data)
466 {
467         struct tether_properties *tether = user_data;
468
469         if (error == NULL) {
470                 fprintf(stdout, "Wifi SSID set\n");
471                 tether->ssid_result = 0;
472         } else {
473                 fprintf(stderr, "Error setting wifi SSID: %s\n", error);
474                 tether->ssid_result = -EINVAL;
475         }
476
477         return tether_update(tether);
478 }
479
480 static int tether_set_passphrase_return(DBusMessageIter *iter,
481                 const char *error, void *user_data)
482 {
483         struct tether_properties *tether = user_data;
484
485         if (error == NULL) {
486                 fprintf(stdout, "Wifi passphrase set\n");
487                 tether->passphrase_result = 0;
488         } else {
489                 fprintf(stderr, "Error setting wifi passphrase: %s\n", error);
490                 tether->passphrase_result = -EINVAL;
491         }
492
493         return tether_update(tether);
494 }
495
496 static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
497 {
498         struct tether_properties *tether = g_new(struct tether_properties, 1);
499
500         tether->set_tethering = set_tethering;
501
502         tether->ssid_result = __connmanctl_dbus_set_property(connection,
503                         "/net/connman/technology/wifi",
504                         "net.connman.Technology",
505                         tether_set_ssid_return, tether,
506                         "TetheringIdentifier", DBUS_TYPE_STRING, &ssid);
507
508         tether->passphrase_result =__connmanctl_dbus_set_property(connection,
509                         "/net/connman/technology/wifi",
510                         "net.connman.Technology",
511                         tether_set_passphrase_return, tether,
512                         "TetheringPassphrase", DBUS_TYPE_STRING, &passphrase);
513
514         if (tether->ssid_result != -EINPROGRESS &&
515                         tether->passphrase_result != -EINPROGRESS) {
516                 g_free(tether);
517                 return -ENXIO;
518         }
519
520         return -EINPROGRESS;
521 }
522
523 static int cmd_tether(char *args[], int num, struct connman_option *options)
524 {
525         char *ssid, *passphrase;
526         int set_tethering;
527
528         if (num < 3)
529                 return -EINVAL;
530
531         passphrase = args[num - 1];
532         ssid = args[num - 2];
533
534         set_tethering = parse_boolean(args[2]);
535
536         if (strcmp(args[1], "wifi") == 0) {
537
538                 if (num > 5)
539                         return -E2BIG;
540
541                 if (num == 5 && set_tethering == -1)
542                         return -EINVAL;
543
544                 if (num == 4)
545                         set_tethering = -1;
546
547                 if (num > 3)
548                         return tether_set_ssid(ssid, passphrase, set_tethering);
549         }
550
551         if (num > 3)
552                 return -E2BIG;
553
554         if (set_tethering == -1)
555                 return -EINVAL;
556
557         if (check_dbus_name(args[1]) == false)
558                 return -EINVAL;
559
560         return tether_set(args[1], set_tethering);
561 }
562
563 static int scan_return(DBusMessageIter *iter, const char *error,
564                 void *user_data)
565 {
566         char *path = user_data;
567
568         if (error == NULL) {
569                 char *str = strrchr(path, '/');
570                 str++;
571                 fprintf(stdout, "Scan completed for %s\n", str);
572         } else
573                 fprintf(stderr, "Error %s: %s\n", path, error);
574
575         g_free(user_data);
576
577         return 0;
578 }
579
580 static int cmd_scan(char *args[], int num, struct connman_option *options)
581 {
582         char *path;
583
584         if (num > 2)
585                 return -E2BIG;
586
587         if (num < 2)
588                 return -EINVAL;
589
590         if (check_dbus_name(args[1]) == false)
591                 return -EINVAL;
592
593         path = g_strdup_printf("/net/connman/technology/%s", args[1]);
594         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
595                         "net.connman.Technology", "Scan",
596                         scan_return, path, DBUS_TYPE_INVALID);
597 }
598
599 static int connect_return(DBusMessageIter *iter, const char *error,
600                 void *user_data)
601 {
602         char *path = user_data;
603
604         if (error == NULL) {
605                 char *str = strrchr(path, '/');
606                 str++;
607                 fprintf(stdout, "Connected %s\n", str);
608         } else
609                 fprintf(stderr, "Error %s: %s\n", path, error);
610
611         g_free(user_data);
612
613         return 0;
614 }
615
616 static int cmd_connect(char *args[], int num, struct connman_option *options)
617 {
618         char *path;
619
620         if (num > 2)
621                 return -E2BIG;
622
623         if (num < 2)
624                 return -EINVAL;
625
626         if (check_dbus_name(args[1]) == false)
627                 return -EINVAL;
628
629         path = g_strdup_printf("/net/connman/service/%s", args[1]);
630         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
631                         "net.connman.Service", "Connect",
632                         connect_return, path, DBUS_TYPE_INVALID);
633 }
634
635 static int disconnect_return(DBusMessageIter *iter, const char *error,
636                 void *user_data)
637 {
638         char *path = user_data;
639
640         if (error == NULL) {
641                 char *str = strrchr(path, '/');
642                 str++;
643                 fprintf(stdout, "Disconnected %s\n", str);
644         } else
645                 fprintf(stderr, "Error %s: %s\n", path, error);
646
647         g_free(user_data);
648
649         return 0;
650 }
651
652 static int cmd_disconnect(char *args[], int num, struct connman_option *options)
653 {
654         char *path;
655
656         if (num > 2)
657                 return -E2BIG;
658
659         if (num < 2)
660                 return -EINVAL;
661
662         if (check_dbus_name(args[1]) == false)
663                 return -EINVAL;
664
665         path = g_strdup_printf("/net/connman/service/%s", args[1]);
666         return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
667                         "net.connman.Service", "Disconnect",
668                         disconnect_return, path, DBUS_TYPE_INVALID);
669 }
670
671 static int config_return(DBusMessageIter *iter, const char *error,
672                 void *user_data)
673 {
674         char *service_name = user_data;
675
676         if (error != NULL)
677                 fprintf(stderr, "Error %s: %s\n", service_name, error);
678
679         g_free(user_data);
680
681         return 0;
682 }
683
684 struct config_append {
685         char **opts;
686         int values;
687 };
688
689 static void config_append_ipv4(DBusMessageIter *iter,
690                 void *user_data)
691 {
692         struct config_append *append = user_data;
693         char **opts = append->opts;
694         int i = 0;
695
696         if (opts == NULL)
697                 return;
698
699         while (opts[i] != NULL && ipv4[i] != NULL) {
700                 __connmanctl_dbus_append_dict_entry(iter, ipv4[i],
701                                 DBUS_TYPE_STRING, &opts[i]);
702                 i++;
703         }
704
705         append->values = i;
706 }
707
708 static void config_append_ipv6(DBusMessageIter *iter, void *user_data)
709 {
710         struct config_append *append = user_data;
711         char **opts = append->opts;
712
713         if (opts == NULL)
714                 return;
715
716         append->values = 1;
717
718         if (g_strcmp0(opts[0], "auto") == 0) {
719                 char *str;
720
721                 switch (parse_boolean(opts[1])) {
722                 case 0:
723                         append->values = 2;
724
725                         str = "disabled";
726                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
727                                         DBUS_TYPE_STRING, &str);
728                         break;
729
730                 case 1:
731                         append->values = 2;
732
733                         str = "enabled";
734                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
735                                         DBUS_TYPE_STRING, &str);
736                         break;
737
738                 default:
739                         if (opts[1] != NULL) {
740                                 append->values = 2;
741
742                                 if (g_strcmp0(opts[1], "prefered") != 0 &&
743                                                 g_strcmp0(opts[1],
744                                                         "preferred") != 0) {
745                                         fprintf(stderr, "Error %s: %s\n",
746                                                         opts[1],
747                                                         strerror(EINVAL));
748                                         return;
749                                 }
750
751                                 str = "prefered";
752                                 __connmanctl_dbus_append_dict_entry(iter,
753                                                 "Privacy", DBUS_TYPE_STRING,
754                                                 &str);
755                         }
756                         break;
757                 }
758         } else if (g_strcmp0(opts[0], "manual") == 0) {
759                 int i = 1;
760
761                 while (opts[i] != NULL && ipv6[i] != NULL) {
762                         if (i == 2) {
763                                 int value = atoi(opts[i]);
764                                 __connmanctl_dbus_append_dict_entry(iter,
765                                                 ipv6[i], DBUS_TYPE_BYTE,
766                                                 &value);
767                         } else {
768                                 __connmanctl_dbus_append_dict_entry(iter,
769                                                 ipv6[i], DBUS_TYPE_STRING,
770                                                 &opts[i]);
771                         }
772                         i++;
773                 }
774
775                 append->values = i;
776
777         } else if (g_strcmp0(opts[0], "off") != 0) {
778                 fprintf(stderr, "Error %s: %s\n", opts[0], strerror(-EINVAL));
779
780                 return;
781         }
782
783         __connmanctl_dbus_append_dict_entry(iter, "Method", DBUS_TYPE_STRING,
784                                 &opts[0]);
785 }
786
787 static void config_append_str(DBusMessageIter *iter, void *user_data)
788 {
789         struct config_append *append = user_data;
790         char **opts = append->opts;
791         int i = 0;
792
793         if (opts == NULL)
794                 return;
795
796         while (opts[i] != NULL) {
797                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
798                                 &opts[i]);
799                 i++;
800         }
801
802         append->values = i;
803 }
804
805 static void append_servers(DBusMessageIter *iter, void *user_data)
806 {
807         struct config_append *append = user_data;
808         char **opts = append->opts;
809         int i = 1;
810
811         if (opts == NULL)
812                 return;
813
814         while (opts[i] != NULL && g_strcmp0(opts[i], "--excludes") != 0) {
815                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
816                                 &opts[i]);
817                 i++;
818         }
819
820         append->values = i;
821 }
822
823 static void append_excludes(DBusMessageIter *iter, void *user_data)
824 {
825         struct config_append *append = user_data;
826         char **opts = append->opts;
827         int i = append->values;
828
829         if (opts == NULL || opts[i] == NULL ||
830                         g_strcmp0(opts[i], "--excludes") != 0)
831                 return;
832
833         i++;
834         while (opts[i] != NULL) {
835                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
836                                 &opts[i]);
837                 i++;
838         }
839
840         append->values = i;
841 }
842
843 static void config_append_proxy(DBusMessageIter *iter, void *user_data)
844 {
845         struct config_append *append = user_data;
846         char **opts = append->opts;
847
848         if (opts == NULL)
849                 return;
850
851         if (g_strcmp0(opts[0], "manual") == 0) {
852                 __connmanctl_dbus_append_dict_string_array(iter, "Servers",
853                                 append_servers, append);
854
855                 __connmanctl_dbus_append_dict_string_array(iter, "Excludes",
856                                 append_excludes, append);
857
858         } else if (g_strcmp0(opts[0], "auto") == 0) {
859                 if (opts[1] != NULL) {
860                         __connmanctl_dbus_append_dict_entry(iter, "URL",
861                                         DBUS_TYPE_STRING, &opts[1]);
862                         append->values++;
863                 }
864
865         } else if (g_strcmp0(opts[0], "direct") != 0)
866                 return;
867
868         __connmanctl_dbus_append_dict_entry(iter, "Method",DBUS_TYPE_STRING,
869                         &opts[0]);
870
871         append->values++;
872 }
873
874 static int cmd_config(char *args[], int num, struct connman_option *options)
875 {
876         int result = 0, res = 0, index = 2, oldindex = 0;
877         int c;
878         char *service_name, *path;
879         char **opt_start;
880         dbus_bool_t val;
881         struct config_append append;
882
883         service_name = args[1];
884         if (service_name == NULL)
885                 return -EINVAL;
886
887         if (check_dbus_name(service_name) == false)
888                 return -EINVAL;
889
890         while (index < num && args[index] != NULL) {
891                 c = parse_args(args[index], options);
892                 opt_start = &args[index + 1];
893                 append.opts = opt_start;
894                 append.values = 0;
895
896                 res = 0;
897
898                 oldindex = index;
899                 path = g_strdup_printf("/net/connman/service/%s", service_name);
900
901                 switch (c) {
902                 case 'a':
903                         switch (parse_boolean(*opt_start)) {
904                         case 1:
905                                 val = TRUE;
906                                 break;
907                         case 0:
908                                 val = FALSE;
909                                 break;
910                         default:
911                                 res = -EINVAL;
912                                 break;
913                         }
914
915                         index++;
916
917                         if (res == 0) {
918                                 res = __connmanctl_dbus_set_property(connection,
919                                                 path, "net.connman.Service",
920                                                 config_return,
921                                                 g_strdup(service_name),
922                                                 "AutoConnect",
923                                                 DBUS_TYPE_BOOLEAN, &val);
924                         }
925                         break;
926                 case 'i':
927                         res = __connmanctl_dbus_set_property_dict(connection,
928                                         path, "net.connman.Service",
929                                         config_return, g_strdup(service_name),
930                                         "IPv4.Configuration", DBUS_TYPE_STRING,
931                                         config_append_ipv4, &append);
932                         index += append.values;
933                         break;
934
935                 case 'v':
936                         res = __connmanctl_dbus_set_property_dict(connection,
937                                         path, "net.connman.Service",
938                                         config_return, g_strdup(service_name),
939                                         "IPv6.Configuration", DBUS_TYPE_STRING,
940                                         config_append_ipv6, &append);
941                         index += append.values;
942                         break;
943
944                 case 'n':
945                         res = __connmanctl_dbus_set_property_array(connection,
946                                         path, "net.connman.Service",
947                                         config_return, g_strdup(service_name),
948                                         "Nameservers.Configuration",
949                                         DBUS_TYPE_STRING, config_append_str,
950                                         &append);
951                         index += append.values;
952                         break;
953
954                 case 't':
955                         res = __connmanctl_dbus_set_property_array(connection,
956                                         path, "net.connman.Service",
957                                         config_return, g_strdup(service_name),
958                                         "Timeservers.Configuration",
959                                         DBUS_TYPE_STRING, config_append_str,
960                                         &append);
961                         index += append.values;
962                         break;
963
964                 case 'd':
965                         res = __connmanctl_dbus_set_property_array(connection,
966                                         path, "net.connman.Service",
967                                         config_return, g_strdup(service_name),
968                                         "Domains.Configuration",
969                                         DBUS_TYPE_STRING, config_append_str,
970                                         &append);
971                         index += append.values;
972                         break;
973
974                 case 'x':
975                         res = __connmanctl_dbus_set_property_dict(connection,
976                                         path, "net.connman.Service",
977                                         config_return, g_strdup(service_name),
978                                         "Proxy.Configuration",
979                                         DBUS_TYPE_STRING, config_append_proxy,
980                                         &append);
981                         index += append.values;
982                         break;
983                 case 'r':
984                         res = __connmanctl_dbus_method_call(connection,
985                                         CONNMAN_SERVICE, path,
986                                         "net.connman.Service", "Remove",
987                                         config_return, g_strdup(service_name),
988                                         DBUS_TYPE_INVALID);
989                         break;
990                 default:
991                         res = -EINVAL;
992                         break;
993                 }
994
995                 g_free(path);
996
997                 if (res < 0) {
998                         if (res == -EINPROGRESS)
999                                 result = -EINPROGRESS;
1000                         else
1001                                 printf("Error '%s': %s\n", args[oldindex],
1002                                                 strerror(-res));
1003                 } else
1004                         index += res;
1005
1006                 index++;
1007         }
1008
1009         return result;
1010 }
1011
1012 static DBusHandlerResult monitor_changed(DBusConnection *connection,
1013                 DBusMessage *message, void *user_data)
1014 {
1015         DBusMessageIter iter;
1016         const char *interface, *path;
1017
1018         interface = dbus_message_get_interface(message);
1019         if (strncmp(interface, "net.connman.", 12) != 0)
1020                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1021
1022         if (strncmp(interface, "net.connman.Agent", 17) == 0 ||
1023                         strncmp(interface, "net.connman.vpn.Agent", 21) == 0)
1024                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1025
1026         interface = strrchr(interface, '.');
1027         if (interface != NULL && *interface != '\0')
1028                 interface++;
1029
1030         path = strrchr(dbus_message_get_path(message), '/');
1031         if (path != NULL && *path != '\0')
1032                 path++;
1033
1034         __connmanctl_save_rl();
1035
1036         if (dbus_message_is_signal(message, "net.connman.Manager",
1037                                         "ServicesChanged") == TRUE) {
1038
1039                 fprintf(stdout, "%-12s %-20s = {\n", interface,
1040                                 "ServicesChanged");
1041                 dbus_message_iter_init(message, &iter);
1042                 __connmanctl_services_list(&iter);
1043                 fprintf(stdout, "\n}\n");
1044
1045                 __connmanctl_redraw_rl();
1046
1047                 return DBUS_HANDLER_RESULT_HANDLED;
1048         }
1049
1050
1051         if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
1052                                         "ConnectionAdded") == TRUE ||
1053                         dbus_message_is_signal(message,
1054                                         "net.connman.vpn.Manager",
1055                                         "ConnectionRemoved") == TRUE) {
1056                 interface = "vpn.Manager";
1057                 path = dbus_message_get_member(message);
1058
1059         } else if (dbus_message_is_signal(message, "net.connman.Manager",
1060                                         "TechnologyAdded") == TRUE ||
1061                         dbus_message_is_signal(message, "net.connman.Manager",
1062                                         "TechnologyRemoved") == TRUE)
1063                 path = dbus_message_get_member(message);
1064
1065         fprintf(stdout, "%-12s %-20s ", interface, path);
1066         dbus_message_iter_init(message, &iter);
1067
1068         __connmanctl_dbus_print(&iter, "", " = ", " = ");
1069         fprintf(stdout, "\n");
1070
1071         __connmanctl_redraw_rl();
1072
1073         return DBUS_HANDLER_RESULT_HANDLED;
1074 }
1075
1076 static struct {
1077         char *interface;
1078         bool enabled;
1079 } monitor[] = {
1080         { "Service", false },
1081         { "Technology", false },
1082         { "Manager", false },
1083         { "vpn.Manager", false },
1084         { "vpn.Connection", false },
1085         { NULL, },
1086 };
1087
1088 static void monitor_add(char *interface)
1089 {
1090         bool add_filter = true, found = false;
1091         int i;
1092         char *rule;
1093         DBusError err;
1094
1095         for (i = 0; monitor[i].interface != NULL; i++) {
1096                 if (monitor[i].enabled == true)
1097                         add_filter = false;
1098
1099                 if (g_strcmp0(interface, monitor[i].interface) == 0) {
1100                         if (monitor[i].enabled == true)
1101                                 return;
1102
1103                         monitor[i].enabled = true;
1104                         found = true;
1105                 }
1106         }
1107
1108         if (found == false)
1109                 return;
1110
1111         if (add_filter == true)
1112                 dbus_connection_add_filter(connection, monitor_changed,
1113                                 NULL, NULL);
1114
1115         dbus_error_init(&err);
1116         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1117                         interface);
1118         dbus_bus_add_match(connection, rule, &err);
1119         g_free(rule);
1120
1121         if (dbus_error_is_set(&err))
1122                 fprintf(stderr, "Error: %s\n", err.message);
1123 }
1124
1125 static void monitor_del(char *interface)
1126 {
1127         bool del_filter = true, found = false;
1128         int i;
1129         char *rule;
1130
1131
1132         for (i = 0; monitor[i].interface != NULL; i++) {
1133                 if (g_strcmp0(interface, monitor[i].interface) == 0) {
1134                         if (monitor[i].enabled == false)
1135                                 return;
1136
1137                         monitor[i].enabled = false;
1138                         found = true;
1139                 }
1140
1141                 if (monitor[i].enabled == true)
1142                         del_filter = false;
1143         }
1144
1145         if (found == false)
1146                 return;
1147
1148         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1149                         interface);
1150         dbus_bus_remove_match(connection, rule, NULL);
1151         g_free(rule);
1152
1153         if (del_filter == true)
1154                 dbus_connection_remove_filter(connection, monitor_changed,
1155                                 NULL);
1156 }
1157
1158 static int cmd_monitor(char *args[], int num, struct connman_option *options)
1159 {
1160         bool add = true;
1161         int c;
1162
1163         if (num > 3)
1164                 return -E2BIG;
1165
1166         if (num == 3) {
1167                 switch (parse_boolean(args[2])) {
1168                 case 0:
1169                         add = false;
1170                         break;
1171
1172                 default:
1173                         break;
1174                 }
1175         }
1176
1177         c = parse_args(args[1], options);
1178         switch (c) {
1179         case -1:
1180                 monitor_add("Service");
1181                 monitor_add("Technology");
1182                 monitor_add("Manager");
1183                 monitor_add("vpn.Manager");
1184                 monitor_add("vpn.Connection");
1185                 break;
1186
1187         case 's':
1188                 if (add == true)
1189                         monitor_add("Service");
1190                 else
1191                         monitor_del("Service");
1192                 break;
1193
1194         case 'c':
1195                 if (add == true)
1196                         monitor_add("Technology");
1197                 else
1198                         monitor_del("Technology");
1199                 break;
1200
1201         case 'm':
1202                 if (add == true)
1203                         monitor_add("Manager");
1204                 else
1205                         monitor_del("Manager");
1206                 break;
1207
1208         case 'M':
1209                 if (add == true)
1210                         monitor_add("vpn.Manager");
1211                 else
1212                         monitor_del("vpn.Manager");
1213                 break;
1214
1215         case 'C':
1216                 if (add == true)
1217                         monitor_add("vpn.Connection");
1218                 else
1219                         monitor_del("vpn.Connection");
1220                 break;
1221
1222         default:
1223                 switch(parse_boolean(args[1])) {
1224                 case 0:
1225                         monitor_del("Service");
1226                         monitor_del("Technology");
1227                         monitor_del("Manager");
1228                         monitor_del("vpn.Manager");
1229                         monitor_del("vpn.Connection");
1230                         break;
1231
1232                 case 1:
1233                         monitor_add("Service");
1234                         monitor_add("Technology");
1235                         monitor_add("Manager");
1236                         monitor_add("vpn.Manager");
1237                         monitor_add("vpn.Connection");
1238                         break;
1239
1240                 default:
1241                         return -EINVAL;
1242                 }
1243         }
1244
1245         if (add == true)
1246                 return -EINPROGRESS;
1247
1248         return 0;
1249 }
1250
1251 static int cmd_agent(char *args[], int num, struct connman_option *options)
1252 {
1253         if (num > 2)
1254                 return -E2BIG;
1255
1256         if (num < 2)
1257                 return -EINVAL;
1258
1259         switch(parse_boolean(args[1])) {
1260         case 0:
1261                 __connmanctl_agent_unregister(connection);
1262                 break;
1263
1264         case 1:
1265                 if (__connmanctl_agent_register(connection) == -EINPROGRESS)
1266                         return -EINPROGRESS;
1267
1268                 break;
1269
1270         default:
1271                 return -EINVAL;
1272                 break;
1273         }
1274
1275         return 0;
1276 }
1277
1278 static int vpnconnections_properties(DBusMessageIter *iter, const char *error,
1279                 void *user_data)
1280 {
1281         char *path = user_data;
1282         char *str;
1283         DBusMessageIter dict;
1284
1285         if (error == NULL) {
1286                 fprintf(stdout, "%s\n", path);
1287
1288                 dbus_message_iter_recurse(iter, &dict);
1289                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
1290
1291                 fprintf(stdout, "\n");
1292
1293         } else {
1294                 str = strrchr(path, '/');
1295                 if (str != NULL)
1296                         str++;
1297                 else
1298                         str = path;
1299
1300                 fprintf(stderr, "Error %s: %s\n", str, error);
1301         }
1302
1303         g_free(user_data);
1304
1305         return 0;
1306 }
1307
1308 static int vpnconnections_list(DBusMessageIter *iter, const char *error,
1309                 void *user_data)
1310 {
1311         if (error == NULL)
1312                 __connmanctl_vpnconnections_list(iter);
1313         else
1314                 fprintf(stderr, "Error: %s\n", error);
1315
1316         return 0;
1317 }
1318
1319 static int cmd_vpnconnections(char *args[], int num,
1320                 struct connman_option *options)
1321 {
1322         char *vpnconnection_name, *path;
1323
1324         if (num > 2)
1325                 return -E2BIG;
1326
1327         vpnconnection_name = args[1];
1328
1329         if (vpnconnection_name == NULL)
1330                 return __connmanctl_dbus_method_call(connection,
1331                                 VPN_SERVICE, VPN_PATH,
1332                                 "net.connman.vpn.Manager", "GetConnections",
1333                                 vpnconnections_list, NULL,
1334                                 DBUS_TYPE_INVALID);
1335
1336         if (check_dbus_name(vpnconnection_name) == false)
1337                 return -EINVAL;
1338
1339         path = g_strdup_printf("/net/connman/vpn/connection/%s",
1340                         vpnconnection_name);
1341         return __connmanctl_dbus_method_call(connection, VPN_SERVICE, path,
1342                         "net.connman.vpn.Connection", "GetProperties",
1343                         vpnconnections_properties, path, DBUS_TYPE_INVALID);
1344
1345 }
1346
1347 static int cmd_vpnagent(char *args[], int num, struct connman_option *options)
1348 {
1349         if (num > 2)
1350                 return -E2BIG;
1351
1352         if (num < 2)
1353                 return -EINVAL;
1354
1355         switch(parse_boolean(args[1])) {
1356         case 0:
1357                 __connmanctl_vpn_agent_unregister(connection);
1358                 break;
1359
1360         case 1:
1361                 if (__connmanctl_vpn_agent_register(connection) ==
1362                                 -EINPROGRESS)
1363                         return -EINPROGRESS;
1364
1365                 break;
1366
1367         default:
1368                 return -EINVAL;
1369                 break;
1370         }
1371
1372         return 0;
1373 }
1374
1375 static int cmd_exit(char *args[], int num, struct connman_option *options)
1376 {
1377         return 1;
1378 }
1379
1380 static struct connman_option service_options[] = {
1381         {"properties", 'p', "[<service>]      (obsolete)"},
1382         { NULL, }
1383 };
1384
1385 static struct connman_option config_options[] = {
1386         {"nameservers", 'n', "<dns1> [<dns2>] [<dns3>]"},
1387         {"timeservers", 't', "<ntp1> [<ntp2>] [...]"},
1388         {"domains", 'd', "<domain1> [<domain2>] [...]"},
1389         {"ipv6", 'v', "off|auto [enable|disable|prefered]|\n"
1390                       "\t\t\tmanual <address> <prefixlength> <gateway>"},
1391         {"proxy", 'x', "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
1392                        "\t\t\t[exclude <exclude1> [<exclude2>] [...]]"},
1393         {"autoconnect", 'a', "yes|no"},
1394         {"ipv4", 'i', "off|dhcp|manual <address> <netmask> <gateway>"},
1395         {"remove", 'r', "                 Remove service"},
1396         { NULL, }
1397 };
1398
1399 static struct connman_option monitor_options[] = {
1400         {"services", 's', "[off]            Monitor only services"},
1401         {"tech", 'c', "[off]            Monitor only technologies"},
1402         {"manager", 'm', "[off]            Monitor only manager interface"},
1403         {"vpnmanager", 'M', "[off]            Monitor only VPN manager "
1404          "interface"},
1405         {"vpnconnection", 'C', "[off]            Monitor only VPN "
1406          "connections" },
1407         { NULL, }
1408 };
1409
1410 static const struct {
1411         const char *cmd;
1412         const char *argument;
1413         struct connman_option *options;
1414         int (*func) (char *args[], int num, struct connman_option *options);
1415         const char *desc;
1416 } cmd_table[] = {
1417         { "state",        NULL,           NULL,            cmd_state,
1418           "Shows if the system is online or offline" },
1419         { "technologies", NULL,           NULL,            cmd_technologies,
1420           "Display technologies" },
1421         { "enable",       "<technology>|offline", NULL,    cmd_enable,
1422           "Enables given technology or offline mode" },
1423         { "disable",      "<technology>|offline", NULL,    cmd_disable,
1424           "Disables given technology or offline mode"},
1425         { "tether", "<technology> on|off\n"
1426                     "            wifi [on|off] <ssid> <passphrase> ",
1427                                           NULL,            cmd_tether,
1428           "Enable, disable tethering, set SSID and passphrase for wifi" },
1429         { "services",     "[<service>]",  service_options, cmd_services,
1430           "Display services" },
1431         { "scan",         "<technology>", NULL,            cmd_scan,
1432           "Scans for new services for given technology" },
1433         { "connect",      "<service>",    NULL,            cmd_connect,
1434           "Connect a given service" },
1435         { "disconnect",   "<service>",    NULL,            cmd_disconnect,
1436           "Disconnect a given service" },
1437         { "config",       "<service>",    config_options,  cmd_config,
1438           "Set service configuration options" },
1439         { "monitor",      "[off]",        monitor_options, cmd_monitor,
1440           "Monitor signals from interfaces" },
1441         { "agent", "on|off",              NULL,            cmd_agent,
1442           "Agent mode" },
1443         {"vpnconnections", "[<connection>]", NULL,         cmd_vpnconnections,
1444          "Display VPN connections" },
1445         { "vpnagent",     "on|off",     NULL,            cmd_vpnagent,
1446           "VPN Agent mode" },
1447         { "help",         NULL,           NULL,            cmd_help,
1448           "Show help" },
1449         { "exit",         NULL,           NULL,            cmd_exit,
1450           "Exit" },
1451         { "quit",         NULL,           NULL,            cmd_exit,
1452           "Quit" },
1453         {  NULL, },
1454 };
1455
1456 static int cmd_help(char *args[], int num, struct connman_option *options)
1457 {
1458         bool interactive = __connmanctl_is_interactive();
1459         int i, j;
1460
1461         if (interactive == false)
1462                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
1463
1464         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1465                 const char *cmd = cmd_table[i].cmd;
1466                 const char *argument = cmd_table[i].argument;
1467                 const char *desc = cmd_table[i].desc;
1468
1469                 printf("%-16s%-22s%s\n", cmd != NULL? cmd: "",
1470                                 argument != NULL? argument: "",
1471                                 desc != NULL? desc: "");
1472
1473                 if (cmd_table[i].options != NULL) {
1474                         for (j = 0; cmd_table[i].options[j].name != NULL;
1475                              j++) {
1476                                 const char *options_desc =
1477                                         cmd_table[i].options[j].desc != NULL ?
1478                                         cmd_table[i].options[j].desc: "";
1479
1480                                 printf("   --%-16s%s\n",
1481                                                 cmd_table[i].options[j].name,
1482                                                 options_desc);
1483                         }
1484                 }
1485         }
1486
1487         if (interactive == false)
1488                 fprintf(stdout, "\nNote: arguments and output are considered "
1489                                 "EXPERIMENTAL for now.\n");
1490
1491         return 0;
1492 }
1493
1494 int __connmanctl_commands(DBusConnection *dbus_conn, char *argv[], int argc)
1495 {
1496         int i, result;
1497
1498         connection = dbus_conn;
1499
1500         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1501                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
1502                                 cmd_table[i].func != NULL) {
1503                         result = cmd_table[i].func(argv, argc,
1504                                         cmd_table[i].options);
1505                         if (result < 0 && result != -EINPROGRESS)
1506                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
1507                                                 strerror(-result));
1508                         return result;
1509                 }
1510         }
1511
1512         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
1513         return -EINVAL;
1514 }
1515
1516 char *__connmanctl_lookup_command(const char *text, int state)
1517 {
1518         static int i = 0;
1519         static int len = 0;
1520
1521         if (state == 0) {
1522                 i = 0;
1523                 len = strlen(text);
1524         }
1525
1526         while (cmd_table[i].cmd != NULL) {
1527                 const char *command = cmd_table[i].cmd;
1528
1529                 i++;
1530
1531                 if (strncmp(text, command, len) == 0)
1532                         return strdup(command);
1533         }
1534
1535         return NULL;
1536 }