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