client: Fix minor issues in D-Bus path name checking
[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, "/",
254                         "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                         "net.connman.Manager", "GetServices",
329                         services_list, NULL, DBUS_TYPE_INVALID);
330         }
331
332         if (check_dbus_name(service_name) == false)
333                 return -EINVAL;
334
335         path = g_strdup_printf("/net/connman/service/%s", service_name);
336         return __connmanctl_dbus_method_call(connection, path,
337                         "net.connman.Service", "GetProperties",
338                         services_properties, path, DBUS_TYPE_INVALID);
339 }
340
341 static int technology_print(DBusMessageIter *iter, const char *error,
342                 void *user_data)
343 {
344         DBusMessageIter array;
345
346         if (error != NULL) {
347                 fprintf(stderr, "Error: %s\n", error);
348                 return 0;
349         }
350
351         dbus_message_iter_recurse(iter, &array);
352         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
353                 DBusMessageIter entry, dict;
354                 const char *path;
355
356                 dbus_message_iter_recurse(&array, &entry);
357                 dbus_message_iter_get_basic(&entry, &path);
358                 fprintf(stdout, "%s\n", path);
359
360                 dbus_message_iter_next(&entry);
361
362                 dbus_message_iter_recurse(&entry, &dict);
363                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
364                 fprintf(stdout, "\n");
365
366                 dbus_message_iter_next(&array);
367         }
368
369         return 0;
370 }
371
372 static int cmd_technologies(char *args[], int num,
373                 struct connman_option *options)
374 {
375         if (num > 1)
376                 return -E2BIG;
377
378         return __connmanctl_dbus_method_call(connection, "/",
379                         "net.connman.Manager", "GetTechnologies",
380                         technology_print, NULL, DBUS_TYPE_INVALID);
381 }
382
383 struct tether_enable {
384         char *path;
385         dbus_bool_t enable;
386 };
387
388 static int tether_set_return(DBusMessageIter *iter, const char *error,
389                 void *user_data)
390 {
391         struct tether_enable *tether = user_data;
392         char *str;
393
394         str = strrchr(tether->path, '/');
395         if (str != NULL)
396                 str++;
397         else
398                 str = tether->path;
399
400         if (error == NULL) {
401                 fprintf(stdout, "%s tethering for %s\n",
402                                 tether->enable == TRUE ? "Enabled": "Disabled",
403                                 str);
404         } else
405                 fprintf(stderr, "Error %s %s tethering: %s\n",
406                                 tether->enable == TRUE ?
407                                 "enabling": "disabling", str, error);
408
409         g_free(tether->path);
410         g_free(user_data);
411
412         return 0;
413 }
414
415 static int tether_set(char *technology, int set_tethering)
416 {
417         struct tether_enable *tether = g_new(struct tether_enable, 1);
418
419         switch(set_tethering) {
420         case 1:
421                 tether->enable = TRUE;
422                 break;
423         case 0:
424                 tether->enable = FALSE;
425                 break;
426         default:
427                 g_free(tether);
428                 return 0;
429         }
430
431         tether->path = g_strdup_printf("/net/connman/technology/%s",
432                         technology);
433
434         return __connmanctl_dbus_set_property(connection, tether->path,
435                         "net.connman.Technology", tether_set_return,
436                         tether, "Tethering", DBUS_TYPE_BOOLEAN,
437                         &tether->enable);
438 }
439
440 struct tether_properties {
441         int ssid_result;
442         int passphrase_result;
443         int set_tethering;
444 };
445
446 static int tether_update(struct tether_properties *tether)
447 {
448         printf("%d %d %d\n", tether->ssid_result, tether->passphrase_result,
449                 tether->set_tethering);
450
451         if (tether->ssid_result == 0 && tether->passphrase_result == 0)
452                 return tether_set("wifi", tether->set_tethering);
453
454         if (tether->ssid_result != -EINPROGRESS &&
455                         tether->passphrase_result != -EINPROGRESS) {
456                 g_free(tether);
457                 return 0;
458         }
459
460         return -EINPROGRESS;
461 }
462
463 static int tether_set_ssid_return(DBusMessageIter *iter, const char *error,
464                 void *user_data)
465 {
466         struct tether_properties *tether = user_data;
467
468         if (error == NULL) {
469                 fprintf(stdout, "Wifi SSID set\n");
470                 tether->ssid_result = 0;
471         } else {
472                 fprintf(stderr, "Error setting wifi SSID: %s\n", error);
473                 tether->ssid_result = -EINVAL;
474         }
475
476         return tether_update(tether);
477 }
478
479 static int tether_set_passphrase_return(DBusMessageIter *iter,
480                 const char *error, void *user_data)
481 {
482         struct tether_properties *tether = user_data;
483
484         if (error == NULL) {
485                 fprintf(stdout, "Wifi passphrase set\n");
486                 tether->passphrase_result = 0;
487         } else {
488                 fprintf(stderr, "Error setting wifi passphrase: %s\n", error);
489                 tether->passphrase_result = -EINVAL;
490         }
491
492         return tether_update(tether);
493 }
494
495 static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
496 {
497         struct tether_properties *tether = g_new(struct tether_properties, 1);
498
499         tether->set_tethering = set_tethering;
500
501         tether->ssid_result = __connmanctl_dbus_set_property(connection,
502                         "/net/connman/technology/wifi",
503                         "net.connman.Technology",
504                         tether_set_ssid_return, tether,
505                         "TetheringIdentifier", DBUS_TYPE_STRING, &ssid);
506
507         tether->passphrase_result =__connmanctl_dbus_set_property(connection,
508                         "/net/connman/technology/wifi",
509                         "net.connman.Technology",
510                         tether_set_passphrase_return, tether,
511                         "TetheringPassphrase", DBUS_TYPE_STRING, &passphrase);
512
513         if (tether->ssid_result != -EINPROGRESS &&
514                         tether->passphrase_result != -EINPROGRESS) {
515                 g_free(tether);
516                 return -ENXIO;
517         }
518
519         return -EINPROGRESS;
520 }
521
522 static int cmd_tether(char *args[], int num, struct connman_option *options)
523 {
524         char *ssid, *passphrase;
525         int set_tethering;
526
527         if (num < 3)
528                 return -EINVAL;
529
530         passphrase = args[num - 1];
531         ssid = args[num - 2];
532
533         set_tethering = parse_boolean(args[2]);
534
535         if (strcmp(args[1], "wifi") == 0) {
536
537                 if (num > 5)
538                         return -E2BIG;
539
540                 if (num == 5 && set_tethering == -1)
541                         return -EINVAL;
542
543                 if (num == 4)
544                         set_tethering = -1;
545
546                 if (num > 3)
547                         return tether_set_ssid(ssid, passphrase, set_tethering);
548         }
549
550         if (num > 3)
551                 return -E2BIG;
552
553         if (set_tethering == -1)
554                 return -EINVAL;
555
556         if (check_dbus_name(args[1]) == false)
557                 return -EINVAL;
558
559         return tether_set(args[1], set_tethering);
560 }
561
562 static int scan_return(DBusMessageIter *iter, const char *error,
563                 void *user_data)
564 {
565         char *path = user_data;
566
567         if (error == NULL) {
568                 char *str = strrchr(path, '/');
569                 str++;
570                 fprintf(stdout, "Scan completed for %s\n", str);
571         } else
572                 fprintf(stderr, "Error %s: %s\n", path, error);
573
574         g_free(user_data);
575
576         return 0;
577 }
578
579 static int cmd_scan(char *args[], int num, struct connman_option *options)
580 {
581         char *path;
582
583         if (num > 2)
584                 return -E2BIG;
585
586         if (num < 2)
587                 return -EINVAL;
588
589         if (check_dbus_name(args[1]) == false)
590                 return -EINVAL;
591
592         path = g_strdup_printf("/net/connman/technology/%s", args[1]);
593         return __connmanctl_dbus_method_call(connection, path,
594                         "net.connman.Technology", "Scan",
595                         scan_return, path, DBUS_TYPE_INVALID);
596 }
597
598 static int connect_return(DBusMessageIter *iter, const char *error,
599                 void *user_data)
600 {
601         char *path = user_data;
602
603         if (error == NULL) {
604                 char *str = strrchr(path, '/');
605                 str++;
606                 fprintf(stdout, "Connected %s\n", str);
607         } else
608                 fprintf(stderr, "Error %s: %s\n", path, error);
609
610         g_free(user_data);
611
612         return 0;
613 }
614
615 static int cmd_connect(char *args[], int num, struct connman_option *options)
616 {
617         char *path;
618
619         if (num > 2)
620                 return -E2BIG;
621
622         if (num < 2)
623                 return -EINVAL;
624
625         if (check_dbus_name(args[1]) == false)
626                 return -EINVAL;
627
628         path = g_strdup_printf("/net/connman/service/%s", args[1]);
629         return __connmanctl_dbus_method_call(connection, path,
630                         "net.connman.Service", "Connect",
631                         connect_return, path, DBUS_TYPE_INVALID);
632 }
633
634 static int disconnect_return(DBusMessageIter *iter, const char *error,
635                 void *user_data)
636 {
637         char *path = user_data;
638
639         if (error == NULL) {
640                 char *str = strrchr(path, '/');
641                 str++;
642                 fprintf(stdout, "Disconnected %s\n", str);
643         } else
644                 fprintf(stderr, "Error %s: %s\n", path, error);
645
646         g_free(user_data);
647
648         return 0;
649 }
650
651 static int cmd_disconnect(char *args[], int num, struct connman_option *options)
652 {
653         char *path;
654
655         if (num > 2)
656                 return -E2BIG;
657
658         if (num < 2)
659                 return -EINVAL;
660
661         if (check_dbus_name(args[1]) == false)
662                 return -EINVAL;
663
664         path = g_strdup_printf("/net/connman/service/%s", args[1]);
665         return __connmanctl_dbus_method_call(connection, path,
666                         "net.connman.Service", "Disconnect",
667                         disconnect_return, path, DBUS_TYPE_INVALID);
668 }
669
670 static int config_return(DBusMessageIter *iter, const char *error,
671                 void *user_data)
672 {
673         char *service_name = user_data;
674
675         if (error != NULL)
676                 fprintf(stderr, "Error %s: %s\n", service_name, error);
677
678         g_free(user_data);
679
680         return 0;
681 }
682
683 struct config_append {
684         char **opts;
685         int values;
686 };
687
688 static void config_append_ipv4(DBusMessageIter *iter,
689                 void *user_data)
690 {
691         struct config_append *append = user_data;
692         char **opts = append->opts;
693         int i = 0;
694
695         if (opts == NULL)
696                 return;
697
698         while (opts[i] != NULL && ipv4[i] != NULL) {
699                 __connmanctl_dbus_append_dict_entry(iter, ipv4[i],
700                                 DBUS_TYPE_STRING, &opts[i]);
701                 i++;
702         }
703
704         append->values = i;
705 }
706
707 static void config_append_ipv6(DBusMessageIter *iter, void *user_data)
708 {
709         struct config_append *append = user_data;
710         char **opts = append->opts;
711
712         if (opts == NULL)
713                 return;
714
715         append->values = 1;
716
717         if (g_strcmp0(opts[0], "auto") == 0) {
718                 char *str;
719
720                 switch (parse_boolean(opts[1])) {
721                 case 0:
722                         append->values = 2;
723
724                         str = "disabled";
725                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
726                                         DBUS_TYPE_STRING, &str);
727                         break;
728
729                 case 1:
730                         append->values = 2;
731
732                         str = "enabled";
733                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
734                                         DBUS_TYPE_STRING, &str);
735                         break;
736
737                 default:
738                         if (opts[1] != NULL) {
739                                 append->values = 2;
740
741                                 if (g_strcmp0(opts[1], "prefered") != 0) {
742                                         fprintf(stderr, "Error %s: %s\n",
743                                                         opts[1],
744                                                         strerror(-EINVAL));
745                                         return;
746                                 }
747
748                                 str = "prefered";
749                                 __connmanctl_dbus_append_dict_entry(iter,
750                                                 "Privacy", DBUS_TYPE_STRING,
751                                                 &str);
752                         }
753                         break;
754                 }
755         } else if (g_strcmp0(opts[0], "manual") == 0) {
756                 int i = 1;
757
758                 while (opts[i] != NULL && ipv6[i] != NULL) {
759                         if (i == 2) {
760                                 int value = atoi(opts[i]);
761                                 __connmanctl_dbus_append_dict_entry(iter,
762                                                 ipv6[i], DBUS_TYPE_BYTE,
763                                                 &value);
764                         } else {
765                                 __connmanctl_dbus_append_dict_entry(iter,
766                                                 ipv6[i], DBUS_TYPE_STRING,
767                                                 &opts[i]);
768                         }
769                         i++;
770                 }
771
772                 append->values = i;
773
774         } else if (g_strcmp0(opts[0], "off") != 0) {
775                 fprintf(stderr, "Error %s: %s\n", opts[0], strerror(-EINVAL));
776
777                 return;
778         }
779
780         __connmanctl_dbus_append_dict_entry(iter, "Method", DBUS_TYPE_STRING,
781                                 &opts[0]);
782 }
783
784 static void config_append_str(DBusMessageIter *iter, void *user_data)
785 {
786         struct config_append *append = user_data;
787         char **opts = append->opts;
788         int i = 0;
789
790         if (opts == NULL)
791                 return;
792
793         while (opts[i] != NULL) {
794                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
795                                 &opts[i]);
796                 i++;
797         }
798
799         append->values = i;
800 }
801
802 static void append_servers(DBusMessageIter *iter, void *user_data)
803 {
804         struct config_append *append = user_data;
805         char **opts = append->opts;
806         int i = 1;
807
808         if (opts == NULL)
809                 return;
810
811         while (opts[i] != NULL && g_strcmp0(opts[i], "--excludes") != 0) {
812                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
813                                 &opts[i]);
814                 i++;
815         }
816
817         append->values = i;
818 }
819
820 static void append_excludes(DBusMessageIter *iter, void *user_data)
821 {
822         struct config_append *append = user_data;
823         char **opts = append->opts;
824         int i = append->values;
825
826         if (opts == NULL || opts[i] == NULL ||
827                         g_strcmp0(opts[i], "--excludes") != 0)
828                 return;
829
830         i++;
831         while (opts[i] != NULL) {
832                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
833                                 &opts[i]);
834                 i++;
835         }
836
837         append->values = i;
838 }
839
840 static void config_append_proxy(DBusMessageIter *iter, void *user_data)
841 {
842         struct config_append *append = user_data;
843         char **opts = append->opts;
844
845         if (opts == NULL)
846                 return;
847
848         if (g_strcmp0(opts[0], "manual") == 0) {
849                 __connmanctl_dbus_append_dict_string_array(iter, "Servers",
850                                 append_servers, append);
851
852                 __connmanctl_dbus_append_dict_string_array(iter, "Excludes",
853                                 append_excludes, append);
854
855         } else if (g_strcmp0(opts[0], "auto") == 0) {
856                 if (opts[1] != NULL) {
857                         __connmanctl_dbus_append_dict_entry(iter, "URL",
858                                         DBUS_TYPE_STRING, &opts[1]);
859                         append->values++;
860                 }
861
862         } else if (g_strcmp0(opts[0], "direct") != 0)
863                 return;
864
865         __connmanctl_dbus_append_dict_entry(iter, "Method",DBUS_TYPE_STRING,
866                         &opts[0]);
867
868         append->values++;
869 }
870
871 static int cmd_config(char *args[], int num, struct connman_option *options)
872 {
873         int result = 0, res = 0, index = 2, oldindex = 0;
874         int c;
875         char *service_name, *path;
876         char **opt_start;
877         dbus_bool_t val;
878         struct config_append append;
879
880         service_name = args[1];
881         if (service_name == NULL)
882                 return -EINVAL;
883
884         if (check_dbus_name(service_name) == false)
885                 return -EINVAL;
886
887         while (index < num && args[index] != NULL) {
888                 c = parse_args(args[index], options);
889                 opt_start = &args[index + 1];
890                 append.opts = opt_start;
891                 append.values = 0;
892
893                 res = 0;
894
895                 oldindex = index;
896                 path = g_strdup_printf("/net/connman/service/%s", service_name);
897
898                 switch (c) {
899                 case 'a':
900                         switch (parse_boolean(*opt_start)) {
901                         case 1:
902                                 val = TRUE;
903                                 break;
904                         case 0:
905                                 val = FALSE;
906                                 break;
907                         default:
908                                 res = -EINVAL;
909                                 break;
910                         }
911
912                         index++;
913
914                         if (res == 0) {
915                                 res = __connmanctl_dbus_set_property(connection,
916                                                 path, "net.connman.Service",
917                                                 config_return,
918                                                 g_strdup(service_name),
919                                                 "AutoConnect",
920                                                 DBUS_TYPE_BOOLEAN, &val);
921                         }
922                         break;
923                 case 'i':
924                         res = __connmanctl_dbus_set_property_dict(connection,
925                                         path, "net.connman.Service",
926                                         config_return, g_strdup(service_name),
927                                         "IPv4.Configuration", DBUS_TYPE_STRING,
928                                         config_append_ipv4, &append);
929                         index += append.values;
930                         break;
931
932                 case 'v':
933                         res = __connmanctl_dbus_set_property_dict(connection,
934                                         path, "net.connman.Service",
935                                         config_return, g_strdup(service_name),
936                                         "IPv6.Configuration", DBUS_TYPE_STRING,
937                                         config_append_ipv6, &append);
938                         index += append.values;
939                         break;
940
941                 case 'n':
942                         res = __connmanctl_dbus_set_property_array(connection,
943                                         path, "net.connman.Service",
944                                         config_return, g_strdup(service_name),
945                                         "Nameservers.Configuration",
946                                         DBUS_TYPE_STRING, config_append_str,
947                                         &append);
948                         index += append.values;
949                         break;
950
951                 case 't':
952                         res = __connmanctl_dbus_set_property_array(connection,
953                                         path, "net.connman.Service",
954                                         config_return, g_strdup(service_name),
955                                         "Timeservers.Configuration",
956                                         DBUS_TYPE_STRING, config_append_str,
957                                         &append);
958                         index += append.values;
959                         break;
960
961                 case 'd':
962                         res = __connmanctl_dbus_set_property_array(connection,
963                                         path, "net.connman.Service",
964                                         config_return, g_strdup(service_name),
965                                         "Domains.Configuration",
966                                         DBUS_TYPE_STRING, config_append_str,
967                                         &append);
968                         index += append.values;
969                         break;
970
971                 case 'x':
972                         res = __connmanctl_dbus_set_property_dict(connection,
973                                         path, "net.connman.Service",
974                                         config_return, g_strdup(service_name),
975                                         "Proxy.Configuration",
976                                         DBUS_TYPE_STRING, config_append_proxy,
977                                         &append);
978                         index += append.values;
979                         break;
980                 case 'r':
981                         res = __connmanctl_dbus_method_call(connection,
982                                         path, "net.connman.Service", "Remove",
983                                         config_return, g_strdup(service_name),
984                                         DBUS_TYPE_INVALID);
985                         break;
986                 default:
987                         res = -EINVAL;
988                         break;
989                 }
990
991                 g_free(path);
992
993                 if (res < 0) {
994                         if (res == -EINPROGRESS)
995                                 result = -EINPROGRESS;
996                         else
997                                 printf("Error '%s': %s\n", args[oldindex],
998                                                 strerror(-res));
999                 } else
1000                         index += res;
1001
1002                 index++;
1003         }
1004
1005         return result;
1006 }
1007
1008 static DBusHandlerResult monitor_changed(DBusConnection *connection,
1009                 DBusMessage *message, void *user_data)
1010 {
1011         DBusMessageIter iter;
1012         const char *interface, *path;
1013
1014         interface = dbus_message_get_interface(message);
1015         if (strncmp(interface, "net.connman.", 12) != 0)
1016                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1017
1018         interface = strrchr(interface, '.');
1019         if (interface != NULL && *interface != '\0')
1020                 interface++;
1021
1022         path = strrchr(dbus_message_get_path(message), '/');
1023         if (path != NULL && *path != '\0')
1024                 path++;
1025
1026         __connmanctl_save_rl();
1027
1028         if (dbus_message_is_signal(message, "net.connman.Manager",
1029                                         "ServicesChanged") == TRUE) {
1030
1031                 fprintf(stdout, "%-12s %-20s = {\n", interface,
1032                                 "ServicesChanged");
1033                 dbus_message_iter_init(message, &iter);
1034                 __connmanctl_services_list(&iter);
1035                 fprintf(stdout, "\n}\n");
1036
1037                 __connmanctl_redraw_rl();
1038
1039                 return DBUS_HANDLER_RESULT_HANDLED;
1040         }
1041
1042         if (dbus_message_is_signal(message, "net.connman.Manager",
1043                                         "TechnologyAdded") == TRUE)
1044                 path = "TechnologyAdded";
1045
1046         if (dbus_message_is_signal(message, "net.connman.Manager",
1047                                         "TechnologyRemoved") == TRUE)
1048                 path = "TechnologyRemoved";
1049
1050         fprintf(stdout, "%-12s %-20s ", interface, path);
1051         dbus_message_iter_init(message, &iter);
1052
1053         __connmanctl_dbus_print(&iter, "", " = ", " = ");
1054         fprintf(stdout, "\n");
1055
1056         __connmanctl_redraw_rl();
1057
1058         return DBUS_HANDLER_RESULT_HANDLED;
1059 }
1060
1061 static bool monitor_s = false;
1062 static bool monitor_t = false;
1063 static bool monitor_m = false;
1064
1065 static void monitor_add(char *interface)
1066 {
1067         char *rule;
1068         DBusError err;
1069
1070         if (monitor_s == false && monitor_t == false && monitor_m == false)
1071                 dbus_connection_add_filter(connection, monitor_changed,
1072                                 NULL, NULL);
1073
1074         if (g_strcmp0(interface, "Service") == 0) {
1075                 if (monitor_s == true)
1076                         return;
1077                 monitor_s = true;
1078         } else if (g_strcmp0(interface, "Technology") == 0) {
1079                 if (monitor_t == true)
1080                         return;
1081                 monitor_t = true;
1082         } else if (g_strcmp0(interface, "Manager") == 0) {
1083                 if (monitor_m == true)
1084                         return;
1085                 monitor_m = true;
1086         } else
1087                 return;
1088
1089         dbus_error_init(&err);
1090         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1091                         interface);
1092         dbus_bus_add_match(connection, rule, &err);
1093         g_free(rule);
1094
1095         if (dbus_error_is_set(&err))
1096                 fprintf(stderr, "Error: %s\n", err.message);
1097 }
1098
1099 static void monitor_del(char *interface)
1100 {
1101         char *rule;
1102
1103         if (g_strcmp0(interface, "Service") == 0) {
1104                 if (monitor_s == false)
1105                         return;
1106                 monitor_s = false;
1107         } else if (g_strcmp0(interface, "Technology") == 0) {
1108                 if (monitor_t == false)
1109                         return;
1110                 monitor_t = false;
1111         } else if (g_strcmp0(interface, "Manager") == 0) {
1112                 if (monitor_m == false)
1113                         return;
1114                 monitor_m = false;
1115         } else
1116                 return;
1117
1118         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1119                         interface);
1120         dbus_bus_remove_match(connection, rule, NULL);
1121         g_free(rule);
1122
1123         if (monitor_s == false && monitor_t == false && monitor_m == false)
1124                 dbus_connection_remove_filter(connection, monitor_changed,
1125                                 NULL);
1126 }
1127
1128 static int cmd_monitor(char *args[], int num, struct connman_option *options)
1129 {
1130         bool add = true;
1131         int c;
1132
1133         if (num > 3)
1134                 return -E2BIG;
1135
1136         if (num == 3) {
1137                 switch (parse_boolean(args[2])) {
1138                 case 0:
1139                         add = false;
1140                         break;
1141
1142                 default:
1143                         break;
1144                 }
1145         }
1146
1147         c = parse_args(args[1], options);
1148         switch (c) {
1149         case -1:
1150                 monitor_add("Service");
1151                 monitor_add("Technology");
1152                 monitor_add("Manager");
1153                 break;
1154
1155         case 's':
1156                 if (add == true)
1157                         monitor_add("Service");
1158                 else
1159                         monitor_del("Service");
1160                 break;
1161
1162         case 'c':
1163                 if (add == true)
1164                         monitor_add("Technology");
1165                 else
1166                         monitor_del("Technology");
1167                 break;
1168
1169         case 'm':
1170                 if (add == true)
1171                         monitor_add("Manager");
1172                 else
1173                         monitor_del("Manager");
1174                 break;
1175
1176         default:
1177                 switch(parse_boolean(args[1])) {
1178                 case 0:
1179                         monitor_del("Service");
1180                         monitor_del("Technology");
1181                         monitor_del("Manager");
1182                         break;
1183
1184                 case 1:
1185                         monitor_add("Service");
1186                         monitor_add("Technology");
1187                         monitor_add("Manager");
1188                         break;
1189
1190                 default:
1191                         return -EINVAL;
1192                 }
1193         }
1194
1195         if (add == true)
1196                 return -EINPROGRESS;
1197
1198         return 0;
1199 }
1200
1201 static int cmd_agent(char *args[], int num, struct connman_option *options)
1202 {
1203         if (num > 2)
1204                 return -E2BIG;
1205
1206         if (num < 2)
1207                 return -EINVAL;
1208
1209         switch(parse_boolean(args[1])) {
1210         case 0:
1211                 __connmanctl_agent_unregister(connection);
1212                 break;
1213
1214         case 1:
1215                 if (__connmanctl_agent_register(connection) == -EINPROGRESS)
1216                         return -EINPROGRESS;
1217
1218                 break;
1219
1220         default:
1221                 return -EINVAL;
1222                 break;
1223         }
1224
1225         return 0;
1226 }
1227
1228 static int cmd_exit(char *args[], int num, struct connman_option *options)
1229 {
1230         return 1;
1231 }
1232
1233 static struct connman_option service_options[] = {
1234         {"properties", 'p', "[<service>]      (obsolete)"},
1235         { NULL, }
1236 };
1237
1238 static struct connman_option config_options[] = {
1239         {"nameservers", 'n', "<dns1> [<dns2>] [<dns3>]"},
1240         {"timeservers", 't', "<ntp1> [<ntp2>] [...]"},
1241         {"domains", 'd', "<domain1> [<domain2>] [...]"},
1242         {"ipv6", 'v', "off|auto [enable|disable|prefered]|\n"
1243                       "\t\t\tmanual <address> <prefixlength> <gateway>"},
1244         {"proxy", 'x', "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
1245                        "\t\t\t[exclude <exclude1> [<exclude2>] [...]]"},
1246         {"autoconnect", 'a', "yes|no"},
1247         {"ipv4", 'i', "off|dhcp|manual <address> <netmask> <gateway>"},
1248         {"remove", 'r', "                 Remove service"},
1249         { NULL, }
1250 };
1251
1252 static struct connman_option monitor_options[] = {
1253         {"services", 's', "[off]            Monitor only services"},
1254         {"tech", 'c', "[off]            Monitor only technologies"},
1255         {"manager", 'm', "[off]            Monitor only manager interface"},
1256         { NULL, }
1257 };
1258
1259 static const struct {
1260         const char *cmd;
1261         const char *argument;
1262         struct connman_option *options;
1263         int (*func) (char *args[], int num, struct connman_option *options);
1264         const char *desc;
1265 } cmd_table[] = {
1266         { "state",        NULL,           NULL,            cmd_state,
1267           "Shows if the system is online or offline" },
1268         { "technologies", NULL,           NULL,            cmd_technologies,
1269           "Display technologies" },
1270         { "enable",       "<technology>|offline", NULL,    cmd_enable,
1271           "Enables given technology or offline mode" },
1272         { "disable",      "<technology>|offline", NULL,    cmd_disable,
1273           "Disables given technology or offline mode"},
1274         { "tether", "<technology> on|off\n"
1275                     "            wifi [on|off] <ssid> <passphrase> ",
1276                                           NULL,            cmd_tether,
1277           "Enable, disable tethering, set SSID and passphrase for wifi" },
1278         { "services",     "[<service>]",  service_options, cmd_services,
1279           "Display services" },
1280         { "scan",         "<technology>", NULL,            cmd_scan,
1281           "Scans for new services for given technology" },
1282         { "connect",      "<service>",    NULL,            cmd_connect,
1283           "Connect a given service" },
1284         { "disconnect",   "<service>",    NULL,            cmd_disconnect,
1285           "Disconnect a given service" },
1286         { "config",       "<service>",    config_options,  cmd_config,
1287           "Set service configuration options" },
1288         { "monitor",      "[off]",        monitor_options, cmd_monitor,
1289           "Monitor signals from interfaces" },
1290         { "agent", "on|off",              NULL,            cmd_agent,
1291           "Agent mode" },
1292         { "help",         NULL,           NULL,            cmd_help,
1293           "Show help" },
1294         { "exit",         NULL,           NULL,            cmd_exit,
1295           "Exit" },
1296         { "quit",         NULL,           NULL,            cmd_exit,
1297           "Quit" },
1298         {  NULL, },
1299 };
1300
1301 static int cmd_help(char *args[], int num, struct connman_option *options)
1302 {
1303         bool interactive = __connmanctl_is_interactive();
1304         int i, j;
1305
1306         if (interactive == false)
1307                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
1308
1309         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1310                 const char *cmd = cmd_table[i].cmd;
1311                 const char *argument = cmd_table[i].argument;
1312                 const char *desc = cmd_table[i].desc;
1313
1314                 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
1315                                 argument != NULL? argument: "",
1316                                 desc != NULL? desc: "");
1317
1318                 if (cmd_table[i].options != NULL) {
1319                         for (j = 0; cmd_table[i].options[j].name != NULL;
1320                              j++) {
1321                                 const char *options_desc =
1322                                         cmd_table[i].options[j].desc != NULL ?
1323                                         cmd_table[i].options[j].desc: "";
1324
1325                                 printf("   --%-12s%s\n",
1326                                                 cmd_table[i].options[j].name,
1327                                                 options_desc);
1328                         }
1329                 }
1330         }
1331
1332         if (interactive == false)
1333                 fprintf(stdout, "\nNote: arguments and output are considered "
1334                                 "EXPERIMENTAL for now.\n");
1335
1336         return 0;
1337 }
1338
1339 int __connmanctl_commands(DBusConnection *dbus_conn, char *argv[], int argc)
1340 {
1341         int i, result;
1342
1343         connection = dbus_conn;
1344
1345         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1346                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
1347                                 cmd_table[i].func != NULL) {
1348                         result = cmd_table[i].func(argv, argc,
1349                                         cmd_table[i].options);
1350                         if (result < 0 && result != -EINPROGRESS)
1351                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
1352                                                 strerror(-result));
1353                         return result;
1354                 }
1355         }
1356
1357         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
1358         return -EINVAL;
1359 }
1360
1361 char *__connmanctl_lookup_command(const char *text, int state)
1362 {
1363         static int i = 0;
1364         static int len = 0;
1365
1366         if (state == 0) {
1367                 i = 0;
1368                 len = strlen(text);
1369         }
1370
1371         while (cmd_table[i].cmd != NULL) {
1372                 const char *command = cmd_table[i].cmd;
1373
1374                 i++;
1375
1376                 if (strncmp(text, command, len) == 0)
1377                         return strdup(command);
1378         }
1379
1380         return NULL;
1381 }