client: Move boolean parsing helper function to commands file
[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 <getopt.h>
32 #include <stdbool.h>
33
34 #include <glib.h>
35 #include <gdbus.h>
36
37 #include "dbus_helpers.h"
38 #include "input.h"
39 #include "services.h"
40 #include "commands.h"
41
42 static DBusConnection *connection;
43
44 static char *ipv4[] = {
45         "Method",
46         "Address",
47         "Netmask",
48         "Gateway",
49         NULL
50 };
51
52 static char *ipv6[] = {
53         "Method",
54         "Address",
55         "PrefixLength",
56         "Gateway",
57         NULL
58 };
59
60 static int cmd_help(char *args[], int num, struct option *options);
61
62 static int parse_boolean(char *arg)
63 {
64         if (arg == NULL)
65                 return -1;
66
67         if (strcasecmp(arg, "no") == 0 ||
68                         strcasecmp(arg, "false") == 0 ||
69                         strcasecmp(arg, "off" ) == 0 ||
70                         strcasecmp(arg, "disable" ) == 0 ||
71                         strcasecmp(arg, "n") == 0 ||
72                         strcasecmp(arg, "f") == 0 ||
73                         strcasecmp(arg, "0") == 0)
74                 return 0;
75
76         if (strcasecmp(arg, "yes") == 0 ||
77                         strcasecmp(arg, "true") == 0 ||
78                         strcasecmp(arg, "on") == 0 ||
79                         strcasecmp(arg, "enable" ) == 0 ||
80                         strcasecmp(arg, "y") == 0 ||
81                         strcasecmp(arg, "t") == 0 ||
82                         strcasecmp(arg, "1") == 0)
83                 return 1;
84
85         return -1;
86 }
87
88 static int parse_args(char *arg, struct option *options)
89 {
90         int i;
91
92         if (arg == NULL)
93                 return -1;
94
95         for (i = 0; options[i].name != NULL; i++) {
96                 if (strcmp(options[i].name, arg) == 0 ||
97                                 (strncmp(arg, "--", 2) == 0 &&
98                                         strcmp(&arg[2], options[i].name) == 0))
99                         return options[i].val;
100         }
101
102         return '?';
103 }
104
105 static void enable_return(DBusMessageIter *iter, const char *error,
106                 void *user_data)
107 {
108         char *tech = user_data;
109         char *str;
110
111         str = strrchr(tech, '/');
112         if (str != NULL)
113                 str++;
114         else
115                 str = tech;
116
117         if (error == NULL) {
118                 fprintf(stdout, "Enabled %s\n", str);
119         } else
120                 fprintf(stderr, "Error %s: %s\n", str, error);
121
122         g_free(user_data);
123 }
124
125 static int cmd_enable(char *args[], int num, struct option *options)
126 {
127         char *tech;
128         dbus_bool_t b = TRUE;
129
130         if (num > 2)
131                 return -E2BIG;
132
133         if (num < 2)
134                 return -EINVAL;
135
136         if (strcmp(args[1], "offlinemode") == 0) {
137                 tech = g_strdup(args[1]);
138                 return __connmanctl_dbus_set_property(connection, "/",
139                                 "net.connman.Manager", enable_return, tech,
140                                 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
141         }
142
143         tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
144         return __connmanctl_dbus_set_property(connection, tech,
145                                 "net.connman.Technology", enable_return, tech,
146                                 "Powered", DBUS_TYPE_BOOLEAN, &b);
147 }
148
149 static void disable_return(DBusMessageIter *iter, const char *error,
150                 void *user_data)
151 {
152         char *tech = user_data;
153         char *str;
154
155         str = strrchr(tech, '/');
156         if (str != NULL)
157                 str++;
158         else
159                 str = tech;
160
161         if (error == NULL) {
162                 fprintf(stdout, "Disabled %s\n", str);
163         } else
164                 fprintf(stderr, "Error %s: %s\n", str, error);
165
166         g_free(user_data);
167 }
168
169 static int cmd_disable(char *args[], int num, struct option *options)
170 {
171         char *tech;
172         dbus_bool_t b = FALSE;
173
174         if (num > 2)
175                 return -E2BIG;
176
177         if (num < 2)
178                 return -EINVAL;
179
180         if (strcmp(args[1], "offlinemode") == 0) {
181                 tech = g_strdup(args[1]);
182                 return __connmanctl_dbus_set_property(connection, "/",
183                                 "net.connman.Manager", disable_return, tech,
184                                 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
185         }
186
187         tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
188         return __connmanctl_dbus_set_property(connection, tech,
189                                 "net.connman.Technology", disable_return, tech,
190                                 "Powered", DBUS_TYPE_BOOLEAN, &b);
191 }
192
193 static void state_print(DBusMessageIter *iter, const char *error,
194                 void *user_data)
195 {
196         DBusMessageIter entry;
197
198         if (error != NULL) {
199                 fprintf(stderr, "Error: %s", error);
200                 return;
201         }
202
203         dbus_message_iter_recurse(iter, &entry);
204         __connmanctl_dbus_print(&entry, "  ", " = ", "\n");
205         fprintf(stdout, "\n");
206 }
207
208 static int cmd_state(char *args[], int num, struct option *options)
209 {
210         if (num > 1)
211                 return -E2BIG;
212
213         return __connmanctl_dbus_method_call(connection, "/",
214                         "net.connman.Manager", "GetProperties",
215                         state_print, NULL, DBUS_TYPE_INVALID);
216 }
217
218 static void services_list(DBusMessageIter *iter, const char *error,
219                 void *user_data)
220 {
221         if (error == NULL) {
222                 __connmanctl_services_list(iter);
223                 fprintf(stdout, "\n");
224         } else {
225                 fprintf(stderr, "Error: %s\n", error);
226         }
227 }
228
229 static void services_properties(DBusMessageIter *iter, const char *error,
230                 void *user_data)
231 {
232         char *path = user_data;
233         char *str;
234         DBusMessageIter dict;
235
236         if (error == NULL) {
237                 fprintf(stdout, "%s\n", path);
238
239                 dbus_message_iter_recurse(iter, &dict);
240                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
241
242                 fprintf(stdout, "\n");
243
244         } else {
245                 str = strrchr(path, '/');
246                 if (str != NULL)
247                         str++;
248                 else
249                         str = path;
250
251                 fprintf(stderr, "Error %s: %s\n", str, error);
252         }
253
254         g_free(user_data);
255 }
256
257 static int cmd_services(char *args[], int num, struct option *options)
258 {
259         char *service_name = NULL;
260         char *path;
261         int c;
262
263         if (num > 3)
264                 return -E2BIG;
265
266         c = parse_args(args[1], options);
267         switch (c) {
268         case -1:
269                 break;
270         case 'p':
271                 if (num < 3)
272                         return -EINVAL;
273                 service_name = args[2];
274                 break;
275         default:
276                 if (num > 2)
277                         return -E2BIG;
278                 service_name = args[1];
279                 break;
280         }
281
282         if (service_name == NULL) {
283                 return __connmanctl_dbus_method_call(connection, "/",
284                         "net.connman.Manager", "GetServices",
285                         services_list, NULL, DBUS_TYPE_INVALID);
286         }
287
288         path = g_strdup_printf("/net/connman/service/%s", service_name);
289         return __connmanctl_dbus_method_call(connection, path,
290                         "net.connman.Service", "GetProperties",
291                         services_properties, path, DBUS_TYPE_INVALID);
292 }
293
294 static void technology_print(DBusMessageIter *iter, const char *error,
295                 void *user_data)
296 {
297         DBusMessageIter array;
298
299         if (error != NULL) {
300                 fprintf(stderr, "Error: %s\n", error);
301                 return;
302         }
303
304         dbus_message_iter_recurse(iter, &array);
305         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
306                 DBusMessageIter entry, dict;
307                 const char *path;
308
309                 dbus_message_iter_recurse(&array, &entry);
310                 dbus_message_iter_get_basic(&entry, &path);
311                 fprintf(stdout, "%s\n", path);
312
313                 dbus_message_iter_next(&entry);
314
315                 dbus_message_iter_recurse(&entry, &dict);
316                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
317                 fprintf(stdout, "\n");
318
319                 dbus_message_iter_next(&array);
320         }
321 }
322
323 static int cmd_technologies(char *args[], int num, struct option *options)
324 {
325         if (num > 1)
326                 return -E2BIG;
327
328         return __connmanctl_dbus_method_call(connection, "/",
329                         "net.connman.Manager", "GetTechnologies",
330                         technology_print, NULL, DBUS_TYPE_INVALID);
331 }
332
333 static void scan_return(DBusMessageIter *iter, const char *error,
334                 void *user_data)
335 {
336         char *path = user_data;
337
338         if (error == NULL) {
339                 char *str = strrchr(path, '/');
340                 str++;
341                 fprintf(stdout, "Scan completed for %s\n", str);
342         } else
343                 fprintf(stderr, "Error %s: %s", path, error);
344
345         g_free(user_data);
346 }
347
348 static int cmd_scan(char *args[], int num, struct option *options)
349 {
350         char *path;
351
352         if (num > 2)
353                 return -E2BIG;
354
355         if (num < 2)
356                 return -EINVAL;
357
358         path = g_strdup_printf("/net/connman/technology/%s", args[1]);
359         return __connmanctl_dbus_method_call(connection, path,
360                         "net.connman.Technology", "Scan",
361                         scan_return, path, DBUS_TYPE_INVALID);
362 }
363
364 static void connect_return(DBusMessageIter *iter, const char *error,
365                 void *user_data)
366 {
367         char *path = user_data;
368
369         if (error == NULL) {
370                 char *str = strrchr(path, '/');
371                 str++;
372                 fprintf(stdout, "Connected %s\n", str);
373         } else
374                 fprintf(stderr, "Error %s: %s\n", path, error);
375
376         g_free(user_data);
377 }
378
379 static int cmd_connect(char *args[], int num, struct option *options)
380 {
381         char *path;
382
383         if (num > 2)
384                 return -E2BIG;
385
386         if (num < 2)
387                 return -EINVAL;
388
389         path = g_strdup_printf("/net/connman/service/%s", args[1]);
390         return __connmanctl_dbus_method_call(connection, path,
391                         "net.connman.Service", "Connect",
392                         connect_return, path, DBUS_TYPE_INVALID);
393 }
394
395 static void disconnect_return(DBusMessageIter *iter, const char *error,
396                 void *user_data)
397 {
398         char *path = user_data;
399
400         if (error == NULL) {
401                 char *str = strrchr(path, '/');
402                 str++;
403                 fprintf(stdout, "Disconnected %s\n", str);
404         } else
405                 fprintf(stderr, "Error %s: %s\n", path, error);
406
407         g_free(user_data);
408 }
409
410 static int cmd_disconnect(char *args[], int num, struct option *options)
411 {
412         char *path;
413
414         if (num > 2)
415                 return -E2BIG;
416
417         if (num < 2)
418                 return -EINVAL;
419
420         path = g_strdup_printf("/net/connman/service/%s", args[1]);
421         return __connmanctl_dbus_method_call(connection, path,
422                         "net.connman.Service", "Disconnect",
423                         disconnect_return, path, DBUS_TYPE_INVALID);
424
425         return 0;
426 }
427
428 static void config_return(DBusMessageIter *iter, const char *error,
429                 void *user_data)
430 {
431         char *service_name = user_data;
432
433         if (error != NULL)
434                 fprintf(stderr, "Error %s: %s\n", service_name, error);
435
436         g_free(user_data);
437 }
438
439 struct config_append {
440         char **opts;
441         int values;
442 };
443
444 static void config_append_ipv4(DBusMessageIter *iter,
445                 void *user_data)
446 {
447         struct config_append *append = user_data;
448         char **opts = append->opts;
449         int i = 0;
450
451         if (opts == NULL)
452                 return;
453
454         while (opts[i] != NULL && ipv4[i] != NULL) {
455                 __connmanctl_dbus_append_dict_entry(iter, ipv4[i],
456                                 DBUS_TYPE_STRING, &opts[i]);
457                 i++;
458         }
459
460         append->values = i;
461 }
462
463 static void config_append_ipv6(DBusMessageIter *iter, void *user_data)
464 {
465         struct config_append *append = user_data;
466         char **opts = append->opts;
467
468         if (opts == NULL)
469                 return;
470
471         append->values = 1;
472
473         if (g_strcmp0(opts[0], "auto") == 0) {
474                 char *str;
475
476                 switch (parse_boolean(opts[1])) {
477                 case 0:
478                         append->values = 2;
479
480                         str = "disabled";
481                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
482                                         DBUS_TYPE_STRING, &str);
483                         break;
484
485                 case 1:
486                         append->values = 2;
487
488                         str = "enabled";
489                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
490                                         DBUS_TYPE_STRING, &str);
491                         break;
492
493                 default:
494                         if (opts[1] != NULL) {
495                                 append->values = 2;
496
497                                 if (g_strcmp0(opts[0], "prefered") != 0) {
498                                         fprintf(stderr, "Error %s: %s\n",
499                                                         opts[1],
500                                                         strerror(-EINVAL));
501                                         return;
502                                 }
503
504                                 str = "prefered";
505                                 __connmanctl_dbus_append_dict_entry(iter,
506                                                 "Privacy", DBUS_TYPE_STRING,
507                                                 &str);
508                         }
509                         break;
510                 }
511         } else if (g_strcmp0(opts[0], "manual") == 0) {
512                 int i = 1;
513
514                 while (opts[i] != NULL && ipv6[i] != NULL) {
515                         if (i == 2) {
516                                 int value = atoi(opts[i]);
517                                 __connmanctl_dbus_append_dict_entry(iter,
518                                                 ipv6[i], DBUS_TYPE_BYTE,
519                                                 &value);
520                         } else {
521                                 __connmanctl_dbus_append_dict_entry(iter,
522                                                 ipv6[i], DBUS_TYPE_STRING,
523                                                 &opts[i]);
524                         }
525                         i++;
526                 }
527
528                 append->values = i;
529
530         } else if (g_strcmp0(opts[0], "off") != 0) {
531                 fprintf(stderr, "Error %s: %s\n", opts[0], strerror(-EINVAL));
532
533                 return;
534         }
535
536         __connmanctl_dbus_append_dict_entry(iter, "Method", DBUS_TYPE_STRING,
537                                 &opts[0]);
538 }
539
540 static void config_append_str(DBusMessageIter *iter, void *user_data)
541 {
542         struct config_append *append = user_data;
543         char **opts = append->opts;
544         int i = 0;
545
546         if (opts == NULL)
547                 return;
548
549         while (opts[i] != NULL) {
550                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
551                                 &opts[i]);
552                 i++;
553         }
554
555         append->values = i;
556 }
557
558 static void append_servers(DBusMessageIter *iter, void *user_data)
559 {
560         struct config_append *append = user_data;
561         char **opts = append->opts;
562         int i = 1;
563
564         if (opts == NULL)
565                 return;
566
567         while (opts[i] != NULL && g_strcmp0(opts[i], "--excludes") != 0) {
568                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
569                                 &opts[i]);
570                 i++;
571         }
572
573         append->values = i;
574 }
575
576 static void append_excludes(DBusMessageIter *iter, void *user_data)
577 {
578         struct config_append *append = user_data;
579         char **opts = append->opts;
580         int i = append->values;
581
582         if (opts == NULL || opts[i] == NULL ||
583                         g_strcmp0(opts[i], "--excludes") != 0)
584                 return;
585
586         i++;
587         while (opts[i] != NULL) {
588                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
589                                 &opts[i]);
590                 i++;
591         }
592
593         append->values = i;
594 }
595
596 static void config_append_proxy(DBusMessageIter *iter, void *user_data)
597 {
598         struct config_append *append = user_data;
599         char **opts = append->opts;
600
601         if (opts == NULL)
602                 return;
603
604         if (g_strcmp0(opts[0], "manual") == 0) {
605                 __connmanctl_dbus_append_dict_string_array(iter, "Servers",
606                                 append_servers, append);
607
608                 __connmanctl_dbus_append_dict_string_array(iter, "Excludes",
609                                 append_excludes, append);
610
611         } else if (g_strcmp0(opts[0], "auto") == 0) {
612                 if (opts[1] != NULL) {
613                         __connmanctl_dbus_append_dict_entry(iter, "URL",
614                                         DBUS_TYPE_STRING, &opts[1]);
615                         append->values++;
616                 }
617
618         } else if (g_strcmp0(opts[0], "direct") != 0)
619                 return;
620
621         __connmanctl_dbus_append_dict_entry(iter, "Method",DBUS_TYPE_STRING,
622                         &opts[0]);
623
624         append->values++;
625 }
626
627 static int cmd_config(char *args[], int num, struct option *options)
628 {
629         int result = 0, res = 0, index = 2, oldindex = 0;
630         int c;
631         char *service_name, *path;
632         char **opt_start;
633         dbus_bool_t val;
634         struct config_append append;
635
636         service_name = args[1];
637         if (service_name == NULL)
638                 return -EINVAL;
639
640         while (index < num && args[index] != NULL) {
641                 c = parse_args(args[index], options);
642                 opt_start = &args[index + 1];
643                 append.opts = opt_start;
644                 append.values = 0;
645
646                 res = 0;
647
648                 oldindex = index;
649                 path = g_strdup_printf("/net/connman/service/%s", service_name);
650
651                 switch (c) {
652                 case 'a':
653                         switch (parse_boolean(*opt_start)) {
654                         case 1:
655                                 val = TRUE;
656                                 break;
657                         case 0:
658                                 val = FALSE;
659                                 break;
660                         default:
661                                 res = -EINVAL;
662                                 break;
663                         }
664
665                         index++;
666
667                         if (res == 0) {
668                                 res = __connmanctl_dbus_set_property(connection,
669                                                 path, "net.connman.Service",
670                                                 config_return,
671                                                 g_strdup(service_name),
672                                                 "AutoConnect",
673                                                 DBUS_TYPE_BOOLEAN, &val);
674                         }
675                         break;
676                 case 'i':
677                         res = __connmanctl_dbus_set_property_dict(connection,
678                                         path, "net.connman.Service",
679                                         config_return, g_strdup(service_name),
680                                         "IPv4.Configuration", DBUS_TYPE_STRING,
681                                         config_append_ipv4, &append);
682                         index += append.values;
683                         break;
684
685                 case 'v':
686                         res = __connmanctl_dbus_set_property_dict(connection,
687                                         path, "net.connman.Service",
688                                         config_return, g_strdup(service_name),
689                                         "IPv6.Configuration", DBUS_TYPE_STRING,
690                                         config_append_ipv6, &append);
691                         index += append.values;
692                         break;
693
694                 case 'n':
695                         res = __connmanctl_dbus_set_property_array(connection,
696                                         path, "net.connman.Service",
697                                         config_return, g_strdup(service_name),
698                                         "Nameservers.Configuration",
699                                         DBUS_TYPE_STRING, config_append_str,
700                                         &append);
701                         index += append.values;
702                         break;
703
704                 case 't':
705                         res = __connmanctl_dbus_set_property_array(connection,
706                                         path, "net.connman.Service",
707                                         config_return, g_strdup(service_name),
708                                         "Timeservers.Configuration",
709                                         DBUS_TYPE_STRING, config_append_str,
710                                         &append);
711                         index += append.values;
712                         break;
713
714                 case 'd':
715                         res = __connmanctl_dbus_set_property_array(connection,
716                                         path, "net.connman.Service",
717                                         config_return, g_strdup(service_name),
718                                         "Domains.Configuration",
719                                         DBUS_TYPE_STRING, config_append_str,
720                                         &append);
721                         index += append.values;
722                         break;
723
724                 case 'x':
725                         res = __connmanctl_dbus_set_property_dict(connection,
726                                         path, "net.connman.Service",
727                                         config_return, g_strdup(service_name),
728                                         "Proxy.Configuration",
729                                         DBUS_TYPE_STRING, config_append_proxy,
730                                         &append);
731                         index += append.values;
732                         break;
733                 case 'r':
734                         res = __connmanctl_dbus_method_call(connection,
735                                         path, "net.connman.Service", "Remove",
736                                         config_return, g_strdup(service_name),
737                                         DBUS_TYPE_INVALID);
738                         break;
739                 default:
740                         res = -EINVAL;
741                         break;
742                 }
743
744                 g_free(path);
745
746                 if (res < 0) {
747                         if (res == -EINPROGRESS)
748                                 result = -EINPROGRESS;
749                         else
750                                 printf("Error '%s': %s\n", args[oldindex],
751                                                 strerror(-res));
752                 } else
753                         index += res;
754
755                 index++;
756         }
757
758         return result;
759 }
760
761 static DBusHandlerResult monitor_changed(DBusConnection *connection,
762                 DBusMessage *message, void *user_data)
763 {
764         DBusMessageIter iter;
765         const char *interface, *path;
766
767         interface = dbus_message_get_interface(message);
768         if (strncmp(interface, "net.connman.", 12) != 0)
769                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
770
771         interface = strrchr(interface, '.');
772         if (interface != NULL && *interface != '\0')
773                 interface++;
774
775         path = strrchr(dbus_message_get_path(message), '/');
776         if (path != NULL && *path != '\0')
777                 path++;
778
779         __connmanctl_save_rl();
780
781         if (dbus_message_is_signal(message, "net.connman.Manager",
782                                         "ServicesChanged") == TRUE) {
783
784                 fprintf(stdout, "%-12s %-20s = {\n", interface,
785                                 "ServicesChanged");
786                 dbus_message_iter_init(message, &iter);
787                 __connmanctl_services_list(&iter);
788                 fprintf(stdout, "\n}\n");
789
790                 __connmanctl_redraw_rl();
791
792                 return DBUS_HANDLER_RESULT_HANDLED;
793         }
794
795         if (dbus_message_is_signal(message, "net.connman.Manager",
796                                         "TechnologyAdded") == TRUE)
797                 path = "TechnologyAdded";
798
799         if (dbus_message_is_signal(message, "net.connman.Manager",
800                                         "TechnologyRemoved") == TRUE)
801                 path = "TechnologyRemoved";
802
803         fprintf(stdout, "%-12s %-20s ", interface, path);
804         dbus_message_iter_init(message, &iter);
805
806         __connmanctl_dbus_print(&iter, "", " = ", " = ");
807         fprintf(stdout, "\n");
808
809         __connmanctl_redraw_rl();
810
811         return DBUS_HANDLER_RESULT_HANDLED;
812 }
813
814 static bool monitor_s = false;
815 static bool monitor_t = false;
816 static bool monitor_m = false;
817
818 static void monitor_add(char *interface)
819 {
820         char *rule;
821         DBusError err;
822
823         if (monitor_s == false && monitor_t == false && monitor_m == false)
824                 dbus_connection_add_filter(connection, monitor_changed,
825                                 NULL, NULL);
826
827         if (g_strcmp0(interface, "Service") == 0) {
828                 if (monitor_s == true)
829                         return;
830                 monitor_s = true;
831         } else if (g_strcmp0(interface, "Technology") == 0) {
832                 if (monitor_t == true)
833                         return;
834                 monitor_t = true;
835         } else if (g_strcmp0(interface, "Manager") == 0) {
836                 if (monitor_m == true)
837                         return;
838                 monitor_m = true;
839         } else
840                 return;
841
842         dbus_error_init(&err);
843         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
844                         interface);
845         dbus_bus_add_match(connection, rule, &err);
846         g_free(rule);
847
848         if (dbus_error_is_set(&err))
849                 fprintf(stderr, "Error: %s\n", err.message);
850 }
851
852 static void monitor_del(char *interface)
853 {
854         char *rule;
855
856         if (g_strcmp0(interface, "Service") == 0) {
857                 if (monitor_s == false)
858                         return;
859                 monitor_s = false;
860         } else if (g_strcmp0(interface, "Technology") == 0) {
861                 if (monitor_t == false)
862                         return;
863                 monitor_t = false;
864         } else if (g_strcmp0(interface, "Manager") == 0) {
865                 if (monitor_m == false)
866                         return;
867                 monitor_m = false;
868         } else
869                 return;
870
871         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
872                         interface);
873         dbus_bus_remove_match(connection, rule, NULL);
874         g_free(rule);
875
876         if (monitor_s == false && monitor_t == false && monitor_m == false)
877                 dbus_connection_remove_filter(connection, monitor_changed,
878                                 NULL);
879 }
880
881 static int cmd_monitor(char *args[], int num, struct option *options)
882 {
883         bool add = true;
884         int c;
885
886         if (num > 3)
887                 return -E2BIG;
888
889         if (num == 3) {
890                 switch (parse_boolean(args[2])) {
891                 case 0:
892                         add = false;
893                         break;
894
895                 default:
896                         break;
897                 }
898         }
899
900         c = parse_args(args[1], options);
901         switch (c) {
902         case -1:
903                 monitor_add("Service");
904                 monitor_add("Technology");
905                 monitor_add("Manager");
906                 break;
907
908         case 's':
909                 if (add == true)
910                         monitor_add("Service");
911                 else
912                         monitor_del("Service");
913                 break;
914
915         case 'c':
916                 if (add == true)
917                         monitor_add("Technology");
918                 else
919                         monitor_del("Technology");
920                 break;
921
922         case 'm':
923                 if (add == true)
924                         monitor_add("Manager");
925                 else
926                         monitor_del("Manager");
927                 break;
928
929         default:
930                 switch(parse_boolean(args[1])) {
931                 case 0:
932                         monitor_del("Service");
933                         monitor_del("Technology");
934                         monitor_del("Manager");
935                         break;
936
937                 case 1:
938                         monitor_add("Service");
939                         monitor_add("Technology");
940                         monitor_add("Manager");
941                         break;
942
943                 default:
944                         return -EINVAL;
945                 }
946         }
947
948         if (add == true)
949                 return -EINPROGRESS;
950
951         return 0;
952 }
953
954 static int cmd_exit(char *args[], int num, struct option *options)
955 {
956         return 1;
957 }
958
959 static struct option service_options[] = {
960         {"properties", required_argument, 0, 'p'},
961         { NULL, }
962 };
963
964 static const char *service_desc[] = {
965         "[<service>]      (obsolete)",
966         NULL
967 };
968
969 static struct option config_options[] = {
970         {"nameservers", required_argument, 0, 'n'},
971         {"timeservers", required_argument, 0, 't'},
972         {"domains", required_argument, 0, 'd'},
973         {"ipv6", required_argument, 0, 'v'},
974         {"proxy", required_argument, 0, 'x'},
975         {"autoconnect", required_argument, 0, 'a'},
976         {"ipv4", required_argument, 0, 'i'},
977         {"remove", 0, 0, 'r'},
978         { NULL, }
979 };
980
981 static const char *config_desc[] = {
982         "<dns1> [<dns2>] [<dns3>]",
983         "<ntp1> [<ntp2>] [...]",
984         "<domain1> [<domain2>] [...]",
985         "off|auto [enable|disable|prefered]|\n"
986         "\t\t\tmanual <address> <prefixlength> <gateway>",
987         "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
988         "\t\t\t[exclude <exclude1> [<exclude2>] [...]]",
989         "yes|no",
990         "off|dhcp|manual <address> <prefixlength> <gateway>",
991         "                 Remove service",
992         NULL
993 };
994
995 static struct option monitor_options[] = {
996         {"services", no_argument, 0, 's'},
997         {"tech", no_argument, 0, 'c'},
998         {"manager", no_argument, 0, 'm'},
999         { NULL, }
1000 };
1001
1002 static const char *monitor_desc[] = {
1003         "[off]            Monitor only services",
1004         "[off]            Monitor only technologies",
1005         "[off]            Monitor only manager interface",
1006         NULL
1007 };
1008
1009 static const struct {
1010         const char *cmd;
1011         const char *argument;
1012         struct option *options;
1013         const char **options_desc;
1014         int (*func) (char *args[], int num, struct option *options);
1015         const char *desc;
1016 } cmd_table[] = {
1017         { "enable",       "<technology>|offline", NULL,    NULL,
1018           cmd_enable, "Enables given technology or offline mode" },
1019         { "disable",      "<technology>|offline", NULL,    NULL,
1020           cmd_disable, "Disables given technology or offline mode"},
1021         { "state",        NULL,           NULL,            NULL,
1022           cmd_state, "Shows if the system is online or offline" },
1023         { "services",     "[<service>]",  service_options, &service_desc[0],
1024           cmd_services, "Display services" },
1025         { "technologies", NULL,           NULL,            NULL,
1026           cmd_technologies, "Display technologies" },
1027         { "scan",         "<technology>", NULL,            NULL,
1028           cmd_scan, "Scans for new services for given technology" },
1029         { "connect",      "<service>",    NULL,            NULL,
1030           cmd_connect, "Connect a given service" },
1031         { "disconnect",   "<service>",    NULL,            NULL,
1032           cmd_disconnect, "Disconnect a given service" },
1033         { "config",       "<service>",    config_options,  &config_desc[0],
1034           cmd_config, "Set service configuration options" },
1035         { "monitor",      "[off]",        monitor_options, &monitor_desc[0],
1036           cmd_monitor, "Monitor signals from interfaces" },
1037         { "help",         NULL,           NULL,            NULL,
1038           cmd_help, "Show help" },
1039         { "exit",         NULL,           NULL,            NULL,
1040           cmd_exit,       "Exit" },
1041         { "quit",         NULL,           NULL,            NULL,
1042           cmd_exit,       "Quit" },
1043         {  NULL, },
1044 };
1045
1046 static int cmd_help(char *args[], int num, struct option *options)
1047 {
1048         bool interactive = __connmanctl_is_interactive();
1049         int i, j;
1050
1051         if (interactive == false)
1052                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
1053
1054         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1055                 const char *cmd = cmd_table[i].cmd;
1056                 const char *argument = cmd_table[i].argument;
1057                 const char *desc = cmd_table[i].desc;
1058
1059                 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
1060                                 argument != NULL? argument: "",
1061                                 desc != NULL? desc: "");
1062
1063                 if (cmd_table[i].options != NULL) {
1064                         for (j = 0; cmd_table[i].options[j].name != NULL;
1065                              j++) {
1066                                 const char *options_desc =
1067                                         cmd_table[i].options_desc != NULL ?
1068                                         cmd_table[i].options_desc[j]: "";
1069
1070                                 printf("   --%-12s%s\n",
1071                                                 cmd_table[i].options[j].name,
1072                                                 options_desc);
1073                         }
1074                 }
1075         }
1076
1077         if (interactive == false)
1078                 fprintf(stdout, "\nNote: arguments and output are considered "
1079                                 "EXPERIMENTAL for now.\n");
1080
1081         return 0;
1082 }
1083
1084 int commands(DBusConnection *dbus_conn, char *argv[], int argc)
1085 {
1086         int i, result;
1087
1088         connection = dbus_conn;
1089
1090         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1091                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
1092                                 cmd_table[i].func != NULL) {
1093                         result = cmd_table[i].func(argv, argc,
1094                                         cmd_table[i].options);
1095                         if (result < 0 && result != -EINPROGRESS)
1096                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
1097                                                 strerror(-result));
1098                         return result;
1099                 }
1100         }
1101
1102         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
1103         return -EINVAL;
1104 }