client: Use D-Bus helper functions for service connect and disconnect
[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         "Privacy",
63         NULL
64 };
65
66 static char *proxy_simple[] = {
67         "Method",
68         "URL",
69         NULL
70 };
71
72 static int cmd_help(char *args[], int num, struct option *options);
73
74 static int parse_args(char *arg, struct option *options)
75 {
76         int i;
77
78         if (arg == NULL)
79                 return -1;
80
81         for (i = 0; options[i].name != NULL; i++) {
82                 if (strcmp(options[i].name, arg) == 0 ||
83                                 (strncmp(arg, "--", 2) == 0 &&
84                                         strcmp(&arg[2], options[i].name) == 0))
85                         return options[i].val;
86         }
87
88         return '?';
89 }
90
91 static int cmd_enable(char *args[], int num, struct option *options)
92 {
93         DBusMessage *message;
94         int err;
95
96         if (num > 2)
97                 return -E2BIG;
98
99         if (num < 2)
100                 return -EINVAL;
101
102         if (strcmp(args[1], "offlinemode") == 0) {
103                 err = set_manager(connection, "OfflineMode", TRUE);
104                 if (err == 0)
105                         printf("OfflineMode enabled\n");
106
107                 return 0;
108         }
109
110         message = get_message(connection, "GetTechnologies");
111         if (message == NULL)
112                 return -ENOMEM;
113
114         set_technology(connection, message, "Powered", args[1], TRUE);
115
116         return 0;
117 }
118
119 static int cmd_disable(char *args[], int num, struct option *options)
120 {
121         DBusMessage *message;
122         int err;
123
124         if (num > 2)
125                 return -E2BIG;
126
127         if (num < 2)
128                 return -EINVAL;
129
130         if (strcmp(args[1], "offlinemode") == 0) {
131                 err = set_manager(connection, "OfflineMode", FALSE);
132                 if (err == 0)
133                         printf("OfflineMode enabled\n");
134
135                 return 0;
136         }
137
138         message = get_message(connection, "GetTechnologies");
139         if (message == NULL)
140                 return -ENOMEM;
141
142         set_technology(connection, message, "Powered", args[1], FALSE);
143
144         return 0;
145 }
146
147 static void state_print(DBusMessageIter *iter, const char *error,
148                 void *user_data)
149 {
150         DBusMessageIter entry;
151
152         if (error != NULL) {
153                 fprintf(stderr, "Error: %s", error);
154                 return;
155         }
156
157         dbus_message_iter_recurse(iter, &entry);
158         __connmanctl_dbus_print(&entry, "  ", " = ", "\n");
159         fprintf(stdout, "\n");
160 }
161
162 static int cmd_state(char *args[], int num, struct option *options)
163 {
164         if (num > 1)
165                 return -E2BIG;
166
167         return __connmanctl_dbus_method_call(connection, "/",
168                         "net.connman.Manager", "GetProperties",
169                         state_print, NULL, DBUS_TYPE_INVALID);
170 }
171
172 static int cmd_services(char *args[], int num, struct option *options)
173 {
174         char *service_name = NULL;
175         int err = 0;
176         int c;
177         DBusMessage *message;
178
179         if (num > 3)
180                 return -E2BIG;
181
182         c = parse_args(args[1], options);
183         switch (c) {
184         case -1:
185                 break;
186         case 'p':
187                 if (num < 3)
188                         return -EINVAL;
189                 service_name = args[2];
190                 break;
191         default:
192                 if (num > 2)
193                         return -E2BIG;
194                 service_name = args[1];
195                 break;
196         }
197
198         message = get_message(connection, "GetServices");
199         if (message == NULL)
200                 return -ENOMEM;
201
202         err = list_properties(connection, "GetServices", service_name);
203         dbus_message_unref(message);
204
205         return err;
206 }
207
208 static int cmd_technologies(char *args[], int num, struct option *options)
209 {
210         if (num > 1)
211                 return -E2BIG;
212
213         return list_properties(connection, "GetTechnologies", NULL);
214 }
215
216 static int cmd_scan(char *args[], int num, struct option *options)
217 {
218         DBusMessage *message;
219         int err;
220
221         if (num > 2)
222                 return -E2BIG;
223
224         if (num < 2)
225                 return -EINVAL;
226
227         message = get_message(connection, "GetTechnologies");
228         if (message == NULL)
229                 err = -ENOMEM;
230         else {
231                 err = scan_technology(connection, message, args[1]);
232                 if (err == 0)
233                         printf("Scan completed\n");
234         }
235
236         return 0;
237 }
238
239 static void connect_return(DBusMessageIter *iter, const char *error,
240                 void *user_data)
241 {
242         char *path = user_data;
243
244         if (error == NULL) {
245                 char *str = strrchr(path, '/');
246                 str++;
247                 fprintf(stdout, "Connected %s\n", str);
248         } else
249                 fprintf(stderr, "Error %s: %s\n", path, error);
250
251         g_free(user_data);
252 }
253
254 static int cmd_connect(char *args[], int num, struct option *options)
255 {
256         char *path;
257
258         if (num > 2)
259                 return -E2BIG;
260
261         if (num < 2)
262                 return -EINVAL;
263
264         path = g_strdup_printf("/net/connman/service/%s", args[1]);
265         return __connmanctl_dbus_method_call(connection, path,
266                         "net.connman.Service", "Connect",
267                         connect_return, path, DBUS_TYPE_INVALID);
268 }
269
270 static void disconnect_return(DBusMessageIter *iter, const char *error,
271                 void *user_data)
272 {
273         char *path = user_data;
274
275         if (error == NULL) {
276                 char *str = strrchr(path, '/');
277                 str++;
278                 fprintf(stdout, "Disconnected %s\n", str);
279         } else
280                 fprintf(stderr, "Error %s: %s\n", path, error);
281
282         g_free(user_data);
283 }
284
285 static int cmd_disconnect(char *args[], int num, struct option *options)
286 {
287         char *path;
288
289         if (num > 2)
290                 return -E2BIG;
291
292         if (num < 2)
293                 return -EINVAL;
294
295         path = g_strdup_printf("/net/connman/service/%s", args[1]);
296         return __connmanctl_dbus_method_call(connection, path,
297                         "net.connman.Service", "Disconnect",
298                         disconnect_return, path, DBUS_TYPE_INVALID);
299
300         return 0;
301 }
302
303 static int cmd_config(char *args[], int num, struct option *options)
304 {
305         int res = 0, index = 2, oldindex = 0;
306         int c;
307         char *service_name;
308         DBusMessage *message;
309         char **opt_start;
310         dbus_bool_t val;
311
312         service_name = args[1];
313         if (service_name == NULL)
314                 return -EINVAL;
315
316         while (index < num && args[index] != NULL) {
317                 c = parse_args(args[index], options);
318                 opt_start = &args[index + 1];
319                 res = 0;
320
321                 message = get_message(connection, "GetServices");
322                 if (message == NULL)
323                         return -ENOMEM;
324
325                 oldindex = index;
326
327                 switch (c) {
328                 case 'a':
329                         switch (parse_boolean(*opt_start)) {
330                         case 1:
331                                 val = TRUE;
332                                 break;
333                         case 0:
334                                 val = FALSE;
335                                 break;
336                         default:
337                                 res = -EINVAL;
338                                 break;
339                         }
340                         if (res == 0)
341                                 res = set_service_property(connection, message,
342                                                 service_name, "AutoConnect",
343                                                 NULL, &val, 0);
344                         break;
345                 case 'i':
346                         res = set_service_property(connection, message,
347                                         service_name, "IPv4.Configuration",
348                                         ipv4, opt_start, 0);
349                         if (res < 0)
350                                 index += 4;
351                         break;
352                 case 'v':
353                         res = set_service_property(connection, message,
354                                         service_name, "IPv6.Configuration",
355                                         ipv6, opt_start, 0);
356                         if (res < 0)
357                                 index += 5;
358                         break;
359                 case 'n':
360                         res = set_service_property(connection, message,
361                                         service_name,
362                                         "Nameservers.Configuration",
363                                         NULL, opt_start, 0);
364                         break;
365                 case 't':
366                         res = set_service_property(connection, message,
367                                         service_name,
368                                         "Timeservers.Configuration",
369                                         NULL, opt_start, 0);
370                         break;
371                 case 'd':
372                         res = set_service_property(connection, message,
373                                         service_name,
374                                         "Domains.Configuration",
375                                         NULL, opt_start, 0);
376                         break;
377                 case 'x':
378                         if (*opt_start == NULL) {
379                                 res = -EINVAL;
380                                 break;
381                         }
382
383                         if (strcmp(*opt_start, "direct") == 0) {
384                                 res = set_service_property(connection, message,
385                                                 service_name,
386                                                 "Proxy.Configuration",
387                                                 proxy_simple, opt_start, 1);
388                                 break;
389                         }
390
391                         if (strcmp(*opt_start, "auto") == 0) {
392                                 res = set_service_property(connection, message,
393                                                 service_name,
394                                                 "Proxy.Configuration",
395                                                 proxy_simple, opt_start, 1);
396                                 break;
397                         }
398
399                         if (strcmp(*opt_start, "manual") == 0) {
400                                         char **url_start = &args[index + 2];
401
402                                         if (*url_start != NULL &&
403                                                 strcmp(*url_start,
404                                                         "servers") == 0) {
405                                                 url_start = &args[index + 3];
406                                                 index++;
407                                         }
408                                         res = store_proxy_input(connection,
409                                                         message, service_name,
410                                                         0, url_start);
411                         }
412
413                         break;
414                 case 'r':
415                         res = remove_service(connection, message, service_name);
416                         break;
417                 default:
418                         res = -EINVAL;
419                         break;
420                 }
421
422                 dbus_message_unref(message);
423
424                 if (res < 0) {
425                         printf("Error '%s': %s\n", args[oldindex],
426                                         strerror(-res));
427                 } else
428                         index += res;
429
430                 index++;
431         }
432
433         return 0;
434 }
435
436 static DBusHandlerResult monitor_changed(DBusConnection *connection,
437                 DBusMessage *message, void *user_data)
438 {
439         DBusMessageIter iter;
440         const char *interface, *path;
441
442         interface = dbus_message_get_interface(message);
443         if (strncmp(interface, "net.connman.", 12) != 0)
444                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
445
446         interface = strrchr(interface, '.');
447         if (interface != NULL && *interface != '\0')
448                 interface++;
449
450         path = strrchr(dbus_message_get_path(message), '/');
451         if (path != NULL && *path != '\0')
452                 path++;
453
454         __connmanctl_save_rl();
455
456         if (dbus_message_is_signal(message, "net.connman.Manager",
457                                         "ServicesChanged") == TRUE) {
458
459                 fprintf(stdout, "%-12s %-20s = {\n", interface,
460                                 "ServicesChanged");
461                 dbus_message_iter_init(message, &iter);
462                 __connmanctl_services_list(&iter);
463                 fprintf(stdout, "\n}\n");
464
465                 __connmanctl_redraw_rl();
466
467                 return DBUS_HANDLER_RESULT_HANDLED;
468         }
469
470         if (dbus_message_is_signal(message, "net.connman.Manager",
471                                         "TechnologyAdded") == TRUE)
472                 path = "TechnologyAdded";
473
474         if (dbus_message_is_signal(message, "net.connman.Manager",
475                                         "TechnologyRemoved") == TRUE)
476                 path = "TechnologyRemoved";
477
478         fprintf(stdout, "%-12s %-20s ", interface, path);
479         dbus_message_iter_init(message, &iter);
480
481         __connmanctl_dbus_print(&iter, "", " = ", " = ");
482         fprintf(stdout, "\n");
483
484         __connmanctl_redraw_rl();
485
486         return DBUS_HANDLER_RESULT_HANDLED;
487 }
488
489 static bool monitor_s = false;
490 static bool monitor_t = false;
491 static bool monitor_m = false;
492
493 static void monitor_add(char *interface)
494 {
495         char *rule;
496         DBusError err;
497
498         if (monitor_s == false && monitor_t == false && monitor_m == false)
499                 dbus_connection_add_filter(connection, monitor_changed,
500                                 NULL, NULL);
501
502         if (g_strcmp0(interface, "Service") == 0) {
503                 if (monitor_s == true)
504                         return;
505                 monitor_s = true;
506         } else if (g_strcmp0(interface, "Technology") == 0) {
507                 if (monitor_t == true)
508                         return;
509                 monitor_t = true;
510         } else if (g_strcmp0(interface, "Manager") == 0) {
511                 if (monitor_m == true)
512                         return;
513                 monitor_m = true;
514         } else
515                 return;
516
517         dbus_error_init(&err);
518         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
519                         interface);
520         dbus_bus_add_match(connection, rule, &err);
521         g_free(rule);
522
523         if (dbus_error_is_set(&err))
524                 fprintf(stderr, "Error: %s\n", err.message);
525 }
526
527 static void monitor_del(char *interface)
528 {
529         char *rule;
530
531         if (g_strcmp0(interface, "Service") == 0) {
532                 if (monitor_s == false)
533                         return;
534                 monitor_s = false;
535         } else if (g_strcmp0(interface, "Technology") == 0) {
536                 if (monitor_t == false)
537                         return;
538                 monitor_t = false;
539         } else if (g_strcmp0(interface, "Manager") == 0) {
540                 if (monitor_m == false)
541                         return;
542                 monitor_m = false;
543         } else
544                 return;
545
546         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
547                         interface);
548         dbus_bus_remove_match(connection, rule, NULL);
549         g_free(rule);
550
551         if (monitor_s == false && monitor_t == false && monitor_m == false)
552                 dbus_connection_remove_filter(connection, monitor_changed,
553                                 NULL);
554 }
555
556 static int cmd_monitor(char *args[], int num, struct option *options)
557 {
558         bool add = true;
559         int c;
560
561         if (num > 3)
562                 return -E2BIG;
563
564         if (num == 3) {
565                 switch (parse_boolean(args[2])) {
566                 case 0:
567                         add = false;
568                         break;
569
570                 default:
571                         break;
572                 }
573         }
574
575         c = parse_args(args[1], options);
576         switch (c) {
577         case -1:
578                 monitor_add("Service");
579                 monitor_add("Technology");
580                 monitor_add("Manager");
581                 break;
582
583         case 's':
584                 if (add == true)
585                         monitor_add("Service");
586                 else
587                         monitor_del("Service");
588                 break;
589
590         case 'c':
591                 if (add == true)
592                         monitor_add("Technology");
593                 else
594                         monitor_del("Technology");
595                 break;
596
597         case 'm':
598                 if (add == true)
599                         monitor_add("Manager");
600                 else
601                         monitor_del("Manager");
602                 break;
603
604         default:
605                 switch(parse_boolean(args[1])) {
606                 case 0:
607                         monitor_del("Service");
608                         monitor_del("Technology");
609                         monitor_del("Manager");
610                         break;
611
612                 case 1:
613                         monitor_add("Service");
614                         monitor_add("Technology");
615                         monitor_add("Manager");
616                         break;
617
618                 default:
619                         return -EINVAL;
620                 }
621         }
622
623         if (add == true)
624                 return -EINPROGRESS;
625
626         return 0;
627 }
628
629 static int cmd_exit(char *args[], int num, struct option *options)
630 {
631         return 1;
632 }
633
634 static struct option service_options[] = {
635         {"properties", required_argument, 0, 'p'},
636         { NULL, }
637 };
638
639 static const char *service_desc[] = {
640         "[<service>]      (obsolete)",
641         NULL
642 };
643
644 static struct option config_options[] = {
645         {"nameservers", required_argument, 0, 'n'},
646         {"timeservers", required_argument, 0, 't'},
647         {"domains", required_argument, 0, 'd'},
648         {"ipv6", required_argument, 0, 'v'},
649         {"proxy", required_argument, 0, 'x'},
650         {"autoconnect", required_argument, 0, 'a'},
651         {"ipv4", required_argument, 0, 'i'},
652         {"remove", 0, 0, 'r'},
653         { NULL, }
654 };
655
656 static const char *config_desc[] = {
657         "<dns1> [<dns2>] [<dns3>]",
658         "<ntp1> [<ntp2>] [...]",
659         "<domain1> [<domain2>] [...]",
660         "off|auto|manual <address> <prefixlength> <gateway> <privacy>",
661         "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
662         "                   [exclude <exclude1> [<exclude2>] [...]]",
663         "yes|no",
664         "off|dhcp|manual <address> <prefixlength> <gateway>",
665         "                 Remove service",
666         NULL
667 };
668
669 static struct option monitor_options[] = {
670         {"services", no_argument, 0, 's'},
671         {"tech", no_argument, 0, 'c'},
672         {"manager", no_argument, 0, 'm'},
673         { NULL, }
674 };
675
676 static const char *monitor_desc[] = {
677         "[off]            Monitor only services",
678         "[off]            Monitor only technologies",
679         "[off]            Monitor only manager interface",
680         NULL
681 };
682
683 static const struct {
684         const char *cmd;
685         const char *argument;
686         struct option *options;
687         const char **options_desc;
688         int (*func) (char *args[], int num, struct option *options);
689         const char *desc;
690 } cmd_table[] = {
691         { "enable",       "<technology>|offline", NULL,    NULL,
692           cmd_enable, "Enables given technology or offline mode" },
693         { "disable",      "<technology>|offline", NULL,    NULL,
694           cmd_disable, "Disables given technology or offline mode"},
695         { "state",        NULL,           NULL,            NULL,
696           cmd_state, "Shows if the system is online or offline" },
697         { "services",     "[<service>]",  service_options, &service_desc[0],
698           cmd_services, "Display services" },
699         { "technologies", NULL,           NULL,            NULL,
700           cmd_technologies, "Display technologies" },
701         { "scan",         "<technology>", NULL,            NULL,
702           cmd_scan, "Scans for new services for given technology" },
703         { "connect",      "<service>",    NULL,            NULL,
704           cmd_connect, "Connect a given service" },
705         { "disconnect",   "<service>",    NULL,            NULL,
706           cmd_disconnect, "Disconnect a given service" },
707         { "config",       "<service>",    config_options,  &config_desc[0],
708           cmd_config, "Set service configuration options" },
709         { "monitor",      "[off]",        monitor_options, &monitor_desc[0],
710           cmd_monitor, "Monitor signals from interfaces" },
711         { "help",         NULL,           NULL,            NULL,
712           cmd_help, "Show help" },
713         { "exit",         NULL,           NULL,            NULL,
714           cmd_exit,       "Exit" },
715         { "quit",         NULL,           NULL,            NULL,
716           cmd_exit,       "Quit" },
717         {  NULL, },
718 };
719
720 static int cmd_help(char *args[], int num, struct option *options)
721 {
722         bool interactive = __connmanctl_is_interactive();
723         int i, j;
724
725         if (interactive == false)
726                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
727
728         for (i = 0; cmd_table[i].cmd != NULL; i++) {
729                 const char *cmd = cmd_table[i].cmd;
730                 const char *argument = cmd_table[i].argument;
731                 const char *desc = cmd_table[i].desc;
732
733                 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
734                                 argument != NULL? argument: "",
735                                 desc != NULL? desc: "");
736
737                 if (cmd_table[i].options != NULL) {
738                         for (j = 0; cmd_table[i].options[j].name != NULL;
739                              j++) {
740                                 const char *options_desc =
741                                         cmd_table[i].options_desc != NULL ?
742                                         cmd_table[i].options_desc[j]: "";
743
744                                 printf("   --%-12s%s\n",
745                                                 cmd_table[i].options[j].name,
746                                                 options_desc);
747                         }
748                 }
749         }
750
751         if (interactive == false)
752                 fprintf(stdout, "\nNote: arguments and output are considered "
753                                 "EXPERIMENTAL for now.\n");
754
755         return 0;
756 }
757
758 int commands(DBusConnection *dbus_conn, char *argv[], int argc)
759 {
760         int i, result;
761
762         connection = dbus_conn;
763
764         for (i = 0; cmd_table[i].cmd != NULL; i++) {
765                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
766                                 cmd_table[i].func != NULL) {
767                         result = cmd_table[i].func(argv, argc,
768                                         cmd_table[i].options);
769                         if (result < 0 && result != -EINPROGRESS)
770                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
771                                                 strerror(-result));
772                         return result;
773                 }
774         }
775
776         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
777         return -EINVAL;
778 }