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