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