client: Add parameter to specify D-Bus service for method call
[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
42 static DBusConnection *connection;
43
44 struct connman_option {
45         const char *name;
46         const char val;
47         const char *desc;
48 };
49
50 static char *ipv4[] = {
51         "Method",
52         "Address",
53         "Netmask",
54         "Gateway",
55         NULL
56 };
57
58 static char *ipv6[] = {
59         "Method",
60         "Address",
61         "PrefixLength",
62         "Gateway",
63         NULL
64 };
65
66 static int cmd_help(char *args[], int num, struct connman_option *options);
67
68 static bool check_dbus_name(const char *name)
69 {
70         /*
71          * Valid dbus chars should be [A-Z][a-z][0-9]_
72          * and should not start with number.
73          */
74         unsigned int i;
75
76         if (name == NULL || name[0] == '\0' || (name[0] >= '0' &&
77                                         name[0] <= '9'))
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         interface = strrchr(interface, '.');
1023         if (interface != NULL && *interface != '\0')
1024                 interface++;
1025
1026         path = strrchr(dbus_message_get_path(message), '/');
1027         if (path != NULL && *path != '\0')
1028                 path++;
1029
1030         __connmanctl_save_rl();
1031
1032         if (dbus_message_is_signal(message, "net.connman.Manager",
1033                                         "ServicesChanged") == TRUE) {
1034
1035                 fprintf(stdout, "%-12s %-20s = {\n", interface,
1036                                 "ServicesChanged");
1037                 dbus_message_iter_init(message, &iter);
1038                 __connmanctl_services_list(&iter);
1039                 fprintf(stdout, "\n}\n");
1040
1041                 __connmanctl_redraw_rl();
1042
1043                 return DBUS_HANDLER_RESULT_HANDLED;
1044         }
1045
1046         if (dbus_message_is_signal(message, "net.connman.Manager",
1047                                         "TechnologyAdded") == TRUE)
1048                 path = "TechnologyAdded";
1049
1050         if (dbus_message_is_signal(message, "net.connman.Manager",
1051                                         "TechnologyRemoved") == TRUE)
1052                 path = "TechnologyRemoved";
1053
1054         fprintf(stdout, "%-12s %-20s ", interface, path);
1055         dbus_message_iter_init(message, &iter);
1056
1057         __connmanctl_dbus_print(&iter, "", " = ", " = ");
1058         fprintf(stdout, "\n");
1059
1060         __connmanctl_redraw_rl();
1061
1062         return DBUS_HANDLER_RESULT_HANDLED;
1063 }
1064
1065 static bool monitor_s = false;
1066 static bool monitor_t = false;
1067 static bool monitor_m = false;
1068
1069 static void monitor_add(char *interface)
1070 {
1071         char *rule;
1072         DBusError err;
1073
1074         if (monitor_s == false && monitor_t == false && monitor_m == false)
1075                 dbus_connection_add_filter(connection, monitor_changed,
1076                                 NULL, NULL);
1077
1078         if (g_strcmp0(interface, "Service") == 0) {
1079                 if (monitor_s == true)
1080                         return;
1081                 monitor_s = true;
1082         } else if (g_strcmp0(interface, "Technology") == 0) {
1083                 if (monitor_t == true)
1084                         return;
1085                 monitor_t = true;
1086         } else if (g_strcmp0(interface, "Manager") == 0) {
1087                 if (monitor_m == true)
1088                         return;
1089                 monitor_m = true;
1090         } else
1091                 return;
1092
1093         dbus_error_init(&err);
1094         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1095                         interface);
1096         dbus_bus_add_match(connection, rule, &err);
1097         g_free(rule);
1098
1099         if (dbus_error_is_set(&err))
1100                 fprintf(stderr, "Error: %s\n", err.message);
1101 }
1102
1103 static void monitor_del(char *interface)
1104 {
1105         char *rule;
1106
1107         if (g_strcmp0(interface, "Service") == 0) {
1108                 if (monitor_s == false)
1109                         return;
1110                 monitor_s = false;
1111         } else if (g_strcmp0(interface, "Technology") == 0) {
1112                 if (monitor_t == false)
1113                         return;
1114                 monitor_t = false;
1115         } else if (g_strcmp0(interface, "Manager") == 0) {
1116                 if (monitor_m == false)
1117                         return;
1118                 monitor_m = false;
1119         } else
1120                 return;
1121
1122         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1123                         interface);
1124         dbus_bus_remove_match(connection, rule, NULL);
1125         g_free(rule);
1126
1127         if (monitor_s == false && monitor_t == false && monitor_m == false)
1128                 dbus_connection_remove_filter(connection, monitor_changed,
1129                                 NULL);
1130 }
1131
1132 static int cmd_monitor(char *args[], int num, struct connman_option *options)
1133 {
1134         bool add = true;
1135         int c;
1136
1137         if (num > 3)
1138                 return -E2BIG;
1139
1140         if (num == 3) {
1141                 switch (parse_boolean(args[2])) {
1142                 case 0:
1143                         add = false;
1144                         break;
1145
1146                 default:
1147                         break;
1148                 }
1149         }
1150
1151         c = parse_args(args[1], options);
1152         switch (c) {
1153         case -1:
1154                 monitor_add("Service");
1155                 monitor_add("Technology");
1156                 monitor_add("Manager");
1157                 break;
1158
1159         case 's':
1160                 if (add == true)
1161                         monitor_add("Service");
1162                 else
1163                         monitor_del("Service");
1164                 break;
1165
1166         case 'c':
1167                 if (add == true)
1168                         monitor_add("Technology");
1169                 else
1170                         monitor_del("Technology");
1171                 break;
1172
1173         case 'm':
1174                 if (add == true)
1175                         monitor_add("Manager");
1176                 else
1177                         monitor_del("Manager");
1178                 break;
1179
1180         default:
1181                 switch(parse_boolean(args[1])) {
1182                 case 0:
1183                         monitor_del("Service");
1184                         monitor_del("Technology");
1185                         monitor_del("Manager");
1186                         break;
1187
1188                 case 1:
1189                         monitor_add("Service");
1190                         monitor_add("Technology");
1191                         monitor_add("Manager");
1192                         break;
1193
1194                 default:
1195                         return -EINVAL;
1196                 }
1197         }
1198
1199         if (add == true)
1200                 return -EINPROGRESS;
1201
1202         return 0;
1203 }
1204
1205 static int cmd_agent(char *args[], int num, struct connman_option *options)
1206 {
1207         if (num > 2)
1208                 return -E2BIG;
1209
1210         if (num < 2)
1211                 return -EINVAL;
1212
1213         switch(parse_boolean(args[1])) {
1214         case 0:
1215                 __connmanctl_agent_unregister(connection);
1216                 break;
1217
1218         case 1:
1219                 if (__connmanctl_agent_register(connection) == -EINPROGRESS)
1220                         return -EINPROGRESS;
1221
1222                 break;
1223
1224         default:
1225                 return -EINVAL;
1226                 break;
1227         }
1228
1229         return 0;
1230 }
1231
1232 static int cmd_exit(char *args[], int num, struct connman_option *options)
1233 {
1234         return 1;
1235 }
1236
1237 static struct connman_option service_options[] = {
1238         {"properties", 'p', "[<service>]      (obsolete)"},
1239         { NULL, }
1240 };
1241
1242 static struct connman_option config_options[] = {
1243         {"nameservers", 'n', "<dns1> [<dns2>] [<dns3>]"},
1244         {"timeservers", 't', "<ntp1> [<ntp2>] [...]"},
1245         {"domains", 'd', "<domain1> [<domain2>] [...]"},
1246         {"ipv6", 'v', "off|auto [enable|disable|prefered]|\n"
1247                       "\t\t\tmanual <address> <prefixlength> <gateway>"},
1248         {"proxy", 'x', "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
1249                        "\t\t\t[exclude <exclude1> [<exclude2>] [...]]"},
1250         {"autoconnect", 'a', "yes|no"},
1251         {"ipv4", 'i', "off|dhcp|manual <address> <netmask> <gateway>"},
1252         {"remove", 'r', "                 Remove service"},
1253         { NULL, }
1254 };
1255
1256 static struct connman_option monitor_options[] = {
1257         {"services", 's', "[off]            Monitor only services"},
1258         {"tech", 'c', "[off]            Monitor only technologies"},
1259         {"manager", 'm', "[off]            Monitor only manager interface"},
1260         { NULL, }
1261 };
1262
1263 static const struct {
1264         const char *cmd;
1265         const char *argument;
1266         struct connman_option *options;
1267         int (*func) (char *args[], int num, struct connman_option *options);
1268         const char *desc;
1269 } cmd_table[] = {
1270         { "state",        NULL,           NULL,            cmd_state,
1271           "Shows if the system is online or offline" },
1272         { "technologies", NULL,           NULL,            cmd_technologies,
1273           "Display technologies" },
1274         { "enable",       "<technology>|offline", NULL,    cmd_enable,
1275           "Enables given technology or offline mode" },
1276         { "disable",      "<technology>|offline", NULL,    cmd_disable,
1277           "Disables given technology or offline mode"},
1278         { "tether", "<technology> on|off\n"
1279                     "            wifi [on|off] <ssid> <passphrase> ",
1280                                           NULL,            cmd_tether,
1281           "Enable, disable tethering, set SSID and passphrase for wifi" },
1282         { "services",     "[<service>]",  service_options, cmd_services,
1283           "Display services" },
1284         { "scan",         "<technology>", NULL,            cmd_scan,
1285           "Scans for new services for given technology" },
1286         { "connect",      "<service>",    NULL,            cmd_connect,
1287           "Connect a given service" },
1288         { "disconnect",   "<service>",    NULL,            cmd_disconnect,
1289           "Disconnect a given service" },
1290         { "config",       "<service>",    config_options,  cmd_config,
1291           "Set service configuration options" },
1292         { "monitor",      "[off]",        monitor_options, cmd_monitor,
1293           "Monitor signals from interfaces" },
1294         { "agent", "on|off",              NULL,            cmd_agent,
1295           "Agent mode" },
1296         { "help",         NULL,           NULL,            cmd_help,
1297           "Show help" },
1298         { "exit",         NULL,           NULL,            cmd_exit,
1299           "Exit" },
1300         { "quit",         NULL,           NULL,            cmd_exit,
1301           "Quit" },
1302         {  NULL, },
1303 };
1304
1305 static int cmd_help(char *args[], int num, struct connman_option *options)
1306 {
1307         bool interactive = __connmanctl_is_interactive();
1308         int i, j;
1309
1310         if (interactive == false)
1311                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
1312
1313         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1314                 const char *cmd = cmd_table[i].cmd;
1315                 const char *argument = cmd_table[i].argument;
1316                 const char *desc = cmd_table[i].desc;
1317
1318                 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
1319                                 argument != NULL? argument: "",
1320                                 desc != NULL? desc: "");
1321
1322                 if (cmd_table[i].options != NULL) {
1323                         for (j = 0; cmd_table[i].options[j].name != NULL;
1324                              j++) {
1325                                 const char *options_desc =
1326                                         cmd_table[i].options[j].desc != NULL ?
1327                                         cmd_table[i].options[j].desc: "";
1328
1329                                 printf("   --%-12s%s\n",
1330                                                 cmd_table[i].options[j].name,
1331                                                 options_desc);
1332                         }
1333                 }
1334         }
1335
1336         if (interactive == false)
1337                 fprintf(stdout, "\nNote: arguments and output are considered "
1338                                 "EXPERIMENTAL for now.\n");
1339
1340         return 0;
1341 }
1342
1343 int __connmanctl_commands(DBusConnection *dbus_conn, char *argv[], int argc)
1344 {
1345         int i, result;
1346
1347         connection = dbus_conn;
1348
1349         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1350                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
1351                                 cmd_table[i].func != NULL) {
1352                         result = cmd_table[i].func(argv, argc,
1353                                         cmd_table[i].options);
1354                         if (result < 0 && result != -EINPROGRESS)
1355                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
1356                                                 strerror(-result));
1357                         return result;
1358                 }
1359         }
1360
1361         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
1362         return -EINVAL;
1363 }
1364
1365 char *__connmanctl_lookup_command(const char *text, int state)
1366 {
1367         static int i = 0;
1368         static int len = 0;
1369
1370         if (state == 0) {
1371                 i = 0;
1372                 len = strlen(text);
1373         }
1374
1375         while (cmd_table[i].cmd != NULL) {
1376                 const char *command = cmd_table[i].cmd;
1377
1378                 i++;
1379
1380                 if (strncmp(text, command, len) == 0)
1381                         return strdup(command);
1382         }
1383
1384         return NULL;
1385 }