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