client: Add support for tethering
[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 struct tether_enable {
334         char *path;
335         dbus_bool_t enable;
336 };
337
338 static void tether_set_return(DBusMessageIter *iter, const char *error,
339                 void *user_data)
340 {
341         struct tether_enable *tether = user_data;
342         char *str;
343
344         str = strrchr(tether->path, '/');
345         if (str != NULL)
346                 str++;
347         else
348                 str = tether->path;
349
350         if (error == NULL) {
351                 fprintf(stdout, "%s tethering for %s\n",
352                                 tether->enable == TRUE ? "Enabled": "Disabled",
353                                 str);
354         } else
355                 fprintf(stderr, "Error %s %s tethering: %s\n",
356                                 tether->enable == TRUE ?
357                                 "enabling": "disabling", str, error);
358
359         g_free(tether->path);
360         g_free(user_data);
361 }
362
363 static int tether_set(char *technology, int set_tethering)
364 {
365         struct tether_enable *tether = g_new(struct tether_enable, 1);
366
367         switch(set_tethering) {
368         case 1:
369                 tether->enable = TRUE;
370                 break;
371         case 0:
372                 tether->enable = FALSE;
373                 break;
374         default:
375                 g_free(tether);
376                 return 0;
377         }
378
379         tether->path = g_strdup_printf("/net/connman/technology/%s",
380                         technology);
381
382         return __connmanctl_dbus_set_property(connection, tether->path,
383                         "net.connman.Technology", tether_set_return,
384                         tether, "Tethering", DBUS_TYPE_BOOLEAN,
385                         &tether->enable);
386 }
387
388 struct tether_properties {
389         int ssid_result;
390         int passphrase_result;
391         int set_tethering;
392 };
393
394 static void tether_update(struct tether_properties *tether)
395 {
396         printf("%d %d %d\n", tether->ssid_result, tether->passphrase_result,
397                 tether->set_tethering);
398
399         if (tether->ssid_result == 0 && tether->passphrase_result == 0)
400                 tether_set("wifi", tether->set_tethering);
401
402         if (tether->ssid_result != -EINPROGRESS &&
403                         tether->passphrase_result != -EINPROGRESS)
404                 g_free(tether);
405 }
406
407 static void tether_set_ssid_return(DBusMessageIter *iter, const char *error,
408                 void *user_data)
409 {
410         struct tether_properties *tether = user_data;
411
412         if (error == NULL) {
413                 fprintf(stdout, "Wifi SSID set\n");
414                 tether->ssid_result = 0;
415         } else {
416                 fprintf(stderr, "Error setting wifi SSID: %s\n", error);
417                 tether->ssid_result = -EINVAL;
418         }
419
420         tether_update(tether);
421 }
422
423 static void tether_set_passphrase_return(DBusMessageIter *iter,
424                 const char *error, void *user_data)
425 {
426         struct tether_properties *tether = user_data;
427
428         if (error == NULL) {
429                 fprintf(stdout, "Wifi passphrase set\n");
430                 tether->passphrase_result = 0;
431         } else {
432                 fprintf(stderr, "Error setting wifi passphrase: %s\n", error);
433                 tether->passphrase_result = -EINVAL;
434         }
435
436         tether_update(tether);
437 }
438
439 static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
440 {
441         struct tether_properties *tether = g_new(struct tether_properties, 1);
442
443         tether->set_tethering = set_tethering;
444
445         tether->ssid_result = __connmanctl_dbus_set_property(connection,
446                         "/net/connman/technology/wifi",
447                         "net.connman.Technology",
448                         tether_set_ssid_return, tether,
449                         "TetheringIdentifier", DBUS_TYPE_STRING, &ssid);
450
451         tether->passphrase_result =__connmanctl_dbus_set_property(connection,
452                         "/net/connman/technology/wifi",
453                         "net.connman.Technology",
454                         tether_set_passphrase_return, tether,
455                         "TetheringPassphrase", DBUS_TYPE_STRING, &passphrase);
456
457         if (tether->ssid_result != -EINPROGRESS &&
458                         tether->passphrase_result != -EINPROGRESS) {
459                 g_free(tether);
460                 return -ENXIO;
461         }
462
463         return -EINPROGRESS;
464 }
465
466 static int cmd_tether(char *args[], int num, struct option *options)
467 {
468         char *ssid, *passphrase;
469         int set_tethering;
470
471         if (num < 3)
472                 return -EINVAL;
473
474         passphrase = args[num - 1];
475         ssid = args[num - 2];
476
477         set_tethering = parse_boolean(args[2]);
478
479         if (strcmp(args[1], "wifi") == 0) {
480
481                 if (num > 5)
482                         return -E2BIG;
483
484                 if (num == 5 && set_tethering == -1)
485                         return -EINVAL;
486
487                 if (num == 4)
488                         set_tethering = -1;
489
490                 if (num > 3)
491                         return tether_set_ssid(ssid, passphrase, set_tethering);
492         }
493
494         if (num > 3)
495                 return -E2BIG;
496
497         if (set_tethering == -1)
498                 return -EINVAL;
499
500         return tether_set(args[1], set_tethering);
501 }
502
503 static void scan_return(DBusMessageIter *iter, const char *error,
504                 void *user_data)
505 {
506         char *path = user_data;
507
508         if (error == NULL) {
509                 char *str = strrchr(path, '/');
510                 str++;
511                 fprintf(stdout, "Scan completed for %s\n", str);
512         } else
513                 fprintf(stderr, "Error %s: %s", path, error);
514
515         g_free(user_data);
516 }
517
518 static int cmd_scan(char *args[], int num, struct option *options)
519 {
520         char *path;
521
522         if (num > 2)
523                 return -E2BIG;
524
525         if (num < 2)
526                 return -EINVAL;
527
528         path = g_strdup_printf("/net/connman/technology/%s", args[1]);
529         return __connmanctl_dbus_method_call(connection, path,
530                         "net.connman.Technology", "Scan",
531                         scan_return, path, DBUS_TYPE_INVALID);
532 }
533
534 static void connect_return(DBusMessageIter *iter, const char *error,
535                 void *user_data)
536 {
537         char *path = user_data;
538
539         if (error == NULL) {
540                 char *str = strrchr(path, '/');
541                 str++;
542                 fprintf(stdout, "Connected %s\n", str);
543         } else
544                 fprintf(stderr, "Error %s: %s\n", path, error);
545
546         g_free(user_data);
547 }
548
549 static int cmd_connect(char *args[], int num, struct option *options)
550 {
551         char *path;
552
553         if (num > 2)
554                 return -E2BIG;
555
556         if (num < 2)
557                 return -EINVAL;
558
559         path = g_strdup_printf("/net/connman/service/%s", args[1]);
560         return __connmanctl_dbus_method_call(connection, path,
561                         "net.connman.Service", "Connect",
562                         connect_return, path, DBUS_TYPE_INVALID);
563 }
564
565 static void disconnect_return(DBusMessageIter *iter, const char *error,
566                 void *user_data)
567 {
568         char *path = user_data;
569
570         if (error == NULL) {
571                 char *str = strrchr(path, '/');
572                 str++;
573                 fprintf(stdout, "Disconnected %s\n", str);
574         } else
575                 fprintf(stderr, "Error %s: %s\n", path, error);
576
577         g_free(user_data);
578 }
579
580 static int cmd_disconnect(char *args[], int num, struct option *options)
581 {
582         char *path;
583
584         if (num > 2)
585                 return -E2BIG;
586
587         if (num < 2)
588                 return -EINVAL;
589
590         path = g_strdup_printf("/net/connman/service/%s", args[1]);
591         return __connmanctl_dbus_method_call(connection, path,
592                         "net.connman.Service", "Disconnect",
593                         disconnect_return, path, DBUS_TYPE_INVALID);
594
595         return 0;
596 }
597
598 static void config_return(DBusMessageIter *iter, const char *error,
599                 void *user_data)
600 {
601         char *service_name = user_data;
602
603         if (error != NULL)
604                 fprintf(stderr, "Error %s: %s\n", service_name, error);
605
606         g_free(user_data);
607 }
608
609 struct config_append {
610         char **opts;
611         int values;
612 };
613
614 static void config_append_ipv4(DBusMessageIter *iter,
615                 void *user_data)
616 {
617         struct config_append *append = user_data;
618         char **opts = append->opts;
619         int i = 0;
620
621         if (opts == NULL)
622                 return;
623
624         while (opts[i] != NULL && ipv4[i] != NULL) {
625                 __connmanctl_dbus_append_dict_entry(iter, ipv4[i],
626                                 DBUS_TYPE_STRING, &opts[i]);
627                 i++;
628         }
629
630         append->values = i;
631 }
632
633 static void config_append_ipv6(DBusMessageIter *iter, void *user_data)
634 {
635         struct config_append *append = user_data;
636         char **opts = append->opts;
637
638         if (opts == NULL)
639                 return;
640
641         append->values = 1;
642
643         if (g_strcmp0(opts[0], "auto") == 0) {
644                 char *str;
645
646                 switch (parse_boolean(opts[1])) {
647                 case 0:
648                         append->values = 2;
649
650                         str = "disabled";
651                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
652                                         DBUS_TYPE_STRING, &str);
653                         break;
654
655                 case 1:
656                         append->values = 2;
657
658                         str = "enabled";
659                         __connmanctl_dbus_append_dict_entry(iter, "Privacy",
660                                         DBUS_TYPE_STRING, &str);
661                         break;
662
663                 default:
664                         if (opts[1] != NULL) {
665                                 append->values = 2;
666
667                                 if (g_strcmp0(opts[0], "prefered") != 0) {
668                                         fprintf(stderr, "Error %s: %s\n",
669                                                         opts[1],
670                                                         strerror(-EINVAL));
671                                         return;
672                                 }
673
674                                 str = "prefered";
675                                 __connmanctl_dbus_append_dict_entry(iter,
676                                                 "Privacy", DBUS_TYPE_STRING,
677                                                 &str);
678                         }
679                         break;
680                 }
681         } else if (g_strcmp0(opts[0], "manual") == 0) {
682                 int i = 1;
683
684                 while (opts[i] != NULL && ipv6[i] != NULL) {
685                         if (i == 2) {
686                                 int value = atoi(opts[i]);
687                                 __connmanctl_dbus_append_dict_entry(iter,
688                                                 ipv6[i], DBUS_TYPE_BYTE,
689                                                 &value);
690                         } else {
691                                 __connmanctl_dbus_append_dict_entry(iter,
692                                                 ipv6[i], DBUS_TYPE_STRING,
693                                                 &opts[i]);
694                         }
695                         i++;
696                 }
697
698                 append->values = i;
699
700         } else if (g_strcmp0(opts[0], "off") != 0) {
701                 fprintf(stderr, "Error %s: %s\n", opts[0], strerror(-EINVAL));
702
703                 return;
704         }
705
706         __connmanctl_dbus_append_dict_entry(iter, "Method", DBUS_TYPE_STRING,
707                                 &opts[0]);
708 }
709
710 static void config_append_str(DBusMessageIter *iter, void *user_data)
711 {
712         struct config_append *append = user_data;
713         char **opts = append->opts;
714         int i = 0;
715
716         if (opts == NULL)
717                 return;
718
719         while (opts[i] != NULL) {
720                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
721                                 &opts[i]);
722                 i++;
723         }
724
725         append->values = i;
726 }
727
728 static void append_servers(DBusMessageIter *iter, void *user_data)
729 {
730         struct config_append *append = user_data;
731         char **opts = append->opts;
732         int i = 1;
733
734         if (opts == NULL)
735                 return;
736
737         while (opts[i] != NULL && g_strcmp0(opts[i], "--excludes") != 0) {
738                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
739                                 &opts[i]);
740                 i++;
741         }
742
743         append->values = i;
744 }
745
746 static void append_excludes(DBusMessageIter *iter, void *user_data)
747 {
748         struct config_append *append = user_data;
749         char **opts = append->opts;
750         int i = append->values;
751
752         if (opts == NULL || opts[i] == NULL ||
753                         g_strcmp0(opts[i], "--excludes") != 0)
754                 return;
755
756         i++;
757         while (opts[i] != NULL) {
758                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
759                                 &opts[i]);
760                 i++;
761         }
762
763         append->values = i;
764 }
765
766 static void config_append_proxy(DBusMessageIter *iter, void *user_data)
767 {
768         struct config_append *append = user_data;
769         char **opts = append->opts;
770
771         if (opts == NULL)
772                 return;
773
774         if (g_strcmp0(opts[0], "manual") == 0) {
775                 __connmanctl_dbus_append_dict_string_array(iter, "Servers",
776                                 append_servers, append);
777
778                 __connmanctl_dbus_append_dict_string_array(iter, "Excludes",
779                                 append_excludes, append);
780
781         } else if (g_strcmp0(opts[0], "auto") == 0) {
782                 if (opts[1] != NULL) {
783                         __connmanctl_dbus_append_dict_entry(iter, "URL",
784                                         DBUS_TYPE_STRING, &opts[1]);
785                         append->values++;
786                 }
787
788         } else if (g_strcmp0(opts[0], "direct") != 0)
789                 return;
790
791         __connmanctl_dbus_append_dict_entry(iter, "Method",DBUS_TYPE_STRING,
792                         &opts[0]);
793
794         append->values++;
795 }
796
797 static int cmd_config(char *args[], int num, struct option *options)
798 {
799         int result = 0, res = 0, index = 2, oldindex = 0;
800         int c;
801         char *service_name, *path;
802         char **opt_start;
803         dbus_bool_t val;
804         struct config_append append;
805
806         service_name = args[1];
807         if (service_name == NULL)
808                 return -EINVAL;
809
810         while (index < num && args[index] != NULL) {
811                 c = parse_args(args[index], options);
812                 opt_start = &args[index + 1];
813                 append.opts = opt_start;
814                 append.values = 0;
815
816                 res = 0;
817
818                 oldindex = index;
819                 path = g_strdup_printf("/net/connman/service/%s", service_name);
820
821                 switch (c) {
822                 case 'a':
823                         switch (parse_boolean(*opt_start)) {
824                         case 1:
825                                 val = TRUE;
826                                 break;
827                         case 0:
828                                 val = FALSE;
829                                 break;
830                         default:
831                                 res = -EINVAL;
832                                 break;
833                         }
834
835                         index++;
836
837                         if (res == 0) {
838                                 res = __connmanctl_dbus_set_property(connection,
839                                                 path, "net.connman.Service",
840                                                 config_return,
841                                                 g_strdup(service_name),
842                                                 "AutoConnect",
843                                                 DBUS_TYPE_BOOLEAN, &val);
844                         }
845                         break;
846                 case 'i':
847                         res = __connmanctl_dbus_set_property_dict(connection,
848                                         path, "net.connman.Service",
849                                         config_return, g_strdup(service_name),
850                                         "IPv4.Configuration", DBUS_TYPE_STRING,
851                                         config_append_ipv4, &append);
852                         index += append.values;
853                         break;
854
855                 case 'v':
856                         res = __connmanctl_dbus_set_property_dict(connection,
857                                         path, "net.connman.Service",
858                                         config_return, g_strdup(service_name),
859                                         "IPv6.Configuration", DBUS_TYPE_STRING,
860                                         config_append_ipv6, &append);
861                         index += append.values;
862                         break;
863
864                 case 'n':
865                         res = __connmanctl_dbus_set_property_array(connection,
866                                         path, "net.connman.Service",
867                                         config_return, g_strdup(service_name),
868                                         "Nameservers.Configuration",
869                                         DBUS_TYPE_STRING, config_append_str,
870                                         &append);
871                         index += append.values;
872                         break;
873
874                 case 't':
875                         res = __connmanctl_dbus_set_property_array(connection,
876                                         path, "net.connman.Service",
877                                         config_return, g_strdup(service_name),
878                                         "Timeservers.Configuration",
879                                         DBUS_TYPE_STRING, config_append_str,
880                                         &append);
881                         index += append.values;
882                         break;
883
884                 case 'd':
885                         res = __connmanctl_dbus_set_property_array(connection,
886                                         path, "net.connman.Service",
887                                         config_return, g_strdup(service_name),
888                                         "Domains.Configuration",
889                                         DBUS_TYPE_STRING, config_append_str,
890                                         &append);
891                         index += append.values;
892                         break;
893
894                 case 'x':
895                         res = __connmanctl_dbus_set_property_dict(connection,
896                                         path, "net.connman.Service",
897                                         config_return, g_strdup(service_name),
898                                         "Proxy.Configuration",
899                                         DBUS_TYPE_STRING, config_append_proxy,
900                                         &append);
901                         index += append.values;
902                         break;
903                 case 'r':
904                         res = __connmanctl_dbus_method_call(connection,
905                                         path, "net.connman.Service", "Remove",
906                                         config_return, g_strdup(service_name),
907                                         DBUS_TYPE_INVALID);
908                         break;
909                 default:
910                         res = -EINVAL;
911                         break;
912                 }
913
914                 g_free(path);
915
916                 if (res < 0) {
917                         if (res == -EINPROGRESS)
918                                 result = -EINPROGRESS;
919                         else
920                                 printf("Error '%s': %s\n", args[oldindex],
921                                                 strerror(-res));
922                 } else
923                         index += res;
924
925                 index++;
926         }
927
928         return result;
929 }
930
931 static DBusHandlerResult monitor_changed(DBusConnection *connection,
932                 DBusMessage *message, void *user_data)
933 {
934         DBusMessageIter iter;
935         const char *interface, *path;
936
937         interface = dbus_message_get_interface(message);
938         if (strncmp(interface, "net.connman.", 12) != 0)
939                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
940
941         interface = strrchr(interface, '.');
942         if (interface != NULL && *interface != '\0')
943                 interface++;
944
945         path = strrchr(dbus_message_get_path(message), '/');
946         if (path != NULL && *path != '\0')
947                 path++;
948
949         __connmanctl_save_rl();
950
951         if (dbus_message_is_signal(message, "net.connman.Manager",
952                                         "ServicesChanged") == TRUE) {
953
954                 fprintf(stdout, "%-12s %-20s = {\n", interface,
955                                 "ServicesChanged");
956                 dbus_message_iter_init(message, &iter);
957                 __connmanctl_services_list(&iter);
958                 fprintf(stdout, "\n}\n");
959
960                 __connmanctl_redraw_rl();
961
962                 return DBUS_HANDLER_RESULT_HANDLED;
963         }
964
965         if (dbus_message_is_signal(message, "net.connman.Manager",
966                                         "TechnologyAdded") == TRUE)
967                 path = "TechnologyAdded";
968
969         if (dbus_message_is_signal(message, "net.connman.Manager",
970                                         "TechnologyRemoved") == TRUE)
971                 path = "TechnologyRemoved";
972
973         fprintf(stdout, "%-12s %-20s ", interface, path);
974         dbus_message_iter_init(message, &iter);
975
976         __connmanctl_dbus_print(&iter, "", " = ", " = ");
977         fprintf(stdout, "\n");
978
979         __connmanctl_redraw_rl();
980
981         return DBUS_HANDLER_RESULT_HANDLED;
982 }
983
984 static bool monitor_s = false;
985 static bool monitor_t = false;
986 static bool monitor_m = false;
987
988 static void monitor_add(char *interface)
989 {
990         char *rule;
991         DBusError err;
992
993         if (monitor_s == false && monitor_t == false && monitor_m == false)
994                 dbus_connection_add_filter(connection, monitor_changed,
995                                 NULL, NULL);
996
997         if (g_strcmp0(interface, "Service") == 0) {
998                 if (monitor_s == true)
999                         return;
1000                 monitor_s = true;
1001         } else if (g_strcmp0(interface, "Technology") == 0) {
1002                 if (monitor_t == true)
1003                         return;
1004                 monitor_t = true;
1005         } else if (g_strcmp0(interface, "Manager") == 0) {
1006                 if (monitor_m == true)
1007                         return;
1008                 monitor_m = true;
1009         } else
1010                 return;
1011
1012         dbus_error_init(&err);
1013         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1014                         interface);
1015         dbus_bus_add_match(connection, rule, &err);
1016         g_free(rule);
1017
1018         if (dbus_error_is_set(&err))
1019                 fprintf(stderr, "Error: %s\n", err.message);
1020 }
1021
1022 static void monitor_del(char *interface)
1023 {
1024         char *rule;
1025
1026         if (g_strcmp0(interface, "Service") == 0) {
1027                 if (monitor_s == false)
1028                         return;
1029                 monitor_s = false;
1030         } else if (g_strcmp0(interface, "Technology") == 0) {
1031                 if (monitor_t == false)
1032                         return;
1033                 monitor_t = false;
1034         } else if (g_strcmp0(interface, "Manager") == 0) {
1035                 if (monitor_m == false)
1036                         return;
1037                 monitor_m = false;
1038         } else
1039                 return;
1040
1041         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
1042                         interface);
1043         dbus_bus_remove_match(connection, rule, NULL);
1044         g_free(rule);
1045
1046         if (monitor_s == false && monitor_t == false && monitor_m == false)
1047                 dbus_connection_remove_filter(connection, monitor_changed,
1048                                 NULL);
1049 }
1050
1051 static int cmd_monitor(char *args[], int num, struct option *options)
1052 {
1053         bool add = true;
1054         int c;
1055
1056         if (num > 3)
1057                 return -E2BIG;
1058
1059         if (num == 3) {
1060                 switch (parse_boolean(args[2])) {
1061                 case 0:
1062                         add = false;
1063                         break;
1064
1065                 default:
1066                         break;
1067                 }
1068         }
1069
1070         c = parse_args(args[1], options);
1071         switch (c) {
1072         case -1:
1073                 monitor_add("Service");
1074                 monitor_add("Technology");
1075                 monitor_add("Manager");
1076                 break;
1077
1078         case 's':
1079                 if (add == true)
1080                         monitor_add("Service");
1081                 else
1082                         monitor_del("Service");
1083                 break;
1084
1085         case 'c':
1086                 if (add == true)
1087                         monitor_add("Technology");
1088                 else
1089                         monitor_del("Technology");
1090                 break;
1091
1092         case 'm':
1093                 if (add == true)
1094                         monitor_add("Manager");
1095                 else
1096                         monitor_del("Manager");
1097                 break;
1098
1099         default:
1100                 switch(parse_boolean(args[1])) {
1101                 case 0:
1102                         monitor_del("Service");
1103                         monitor_del("Technology");
1104                         monitor_del("Manager");
1105                         break;
1106
1107                 case 1:
1108                         monitor_add("Service");
1109                         monitor_add("Technology");
1110                         monitor_add("Manager");
1111                         break;
1112
1113                 default:
1114                         return -EINVAL;
1115                 }
1116         }
1117
1118         if (add == true)
1119                 return -EINPROGRESS;
1120
1121         return 0;
1122 }
1123
1124 static int cmd_exit(char *args[], int num, struct option *options)
1125 {
1126         return 1;
1127 }
1128
1129 static struct option service_options[] = {
1130         {"properties", required_argument, 0, 'p'},
1131         { NULL, }
1132 };
1133
1134 static const char *service_desc[] = {
1135         "[<service>]      (obsolete)",
1136         NULL
1137 };
1138
1139 static struct option config_options[] = {
1140         {"nameservers", required_argument, 0, 'n'},
1141         {"timeservers", required_argument, 0, 't'},
1142         {"domains", required_argument, 0, 'd'},
1143         {"ipv6", required_argument, 0, 'v'},
1144         {"proxy", required_argument, 0, 'x'},
1145         {"autoconnect", required_argument, 0, 'a'},
1146         {"ipv4", required_argument, 0, 'i'},
1147         {"remove", 0, 0, 'r'},
1148         { NULL, }
1149 };
1150
1151 static const char *config_desc[] = {
1152         "<dns1> [<dns2>] [<dns3>]",
1153         "<ntp1> [<ntp2>] [...]",
1154         "<domain1> [<domain2>] [...]",
1155         "off|auto [enable|disable|prefered]|\n"
1156         "\t\t\tmanual <address> <prefixlength> <gateway>",
1157         "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
1158         "\t\t\t[exclude <exclude1> [<exclude2>] [...]]",
1159         "yes|no",
1160         "off|dhcp|manual <address> <netmask> <gateway>",
1161         "                 Remove service",
1162         NULL
1163 };
1164
1165 static struct option monitor_options[] = {
1166         {"services", no_argument, 0, 's'},
1167         {"tech", no_argument, 0, 'c'},
1168         {"manager", no_argument, 0, 'm'},
1169         { NULL, }
1170 };
1171
1172 static const char *monitor_desc[] = {
1173         "[off]            Monitor only services",
1174         "[off]            Monitor only technologies",
1175         "[off]            Monitor only manager interface",
1176         NULL
1177 };
1178
1179 static const struct {
1180         const char *cmd;
1181         const char *argument;
1182         struct option *options;
1183         const char **options_desc;
1184         int (*func) (char *args[], int num, struct option *options);
1185         const char *desc;
1186 } cmd_table[] = {
1187         { "enable",       "<technology>|offline", NULL,    NULL,
1188           cmd_enable, "Enables given technology or offline mode" },
1189         { "disable",      "<technology>|offline", NULL,    NULL,
1190           cmd_disable, "Disables given technology or offline mode"},
1191         { "state",        NULL,           NULL,            NULL,
1192           cmd_state, "Shows if the system is online or offline" },
1193         { "tether", "<technology> on|off\n"
1194                     "            wifi [on|off] <ssid> <passphrase> ",
1195                                           NULL,            NULL,
1196           cmd_tether,
1197           "Enable, disable tethering, set SSID and passphrase for wifi" },
1198         { "services",     "[<service>]",  service_options, &service_desc[0],
1199           cmd_services, "Display services" },
1200         { "technologies", NULL,           NULL,            NULL,
1201           cmd_technologies, "Display technologies" },
1202         { "scan",         "<technology>", NULL,            NULL,
1203           cmd_scan, "Scans for new services for given technology" },
1204         { "connect",      "<service>",    NULL,            NULL,
1205           cmd_connect, "Connect a given service" },
1206         { "disconnect",   "<service>",    NULL,            NULL,
1207           cmd_disconnect, "Disconnect a given service" },
1208         { "config",       "<service>",    config_options,  &config_desc[0],
1209           cmd_config, "Set service configuration options" },
1210         { "monitor",      "[off]",        monitor_options, &monitor_desc[0],
1211           cmd_monitor, "Monitor signals from interfaces" },
1212         { "help",         NULL,           NULL,            NULL,
1213           cmd_help, "Show help" },
1214         { "exit",         NULL,           NULL,            NULL,
1215           cmd_exit,       "Exit" },
1216         { "quit",         NULL,           NULL,            NULL,
1217           cmd_exit,       "Quit" },
1218         {  NULL, },
1219 };
1220
1221 static int cmd_help(char *args[], int num, struct option *options)
1222 {
1223         bool interactive = __connmanctl_is_interactive();
1224         int i, j;
1225
1226         if (interactive == false)
1227                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
1228
1229         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1230                 const char *cmd = cmd_table[i].cmd;
1231                 const char *argument = cmd_table[i].argument;
1232                 const char *desc = cmd_table[i].desc;
1233
1234                 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
1235                                 argument != NULL? argument: "",
1236                                 desc != NULL? desc: "");
1237
1238                 if (cmd_table[i].options != NULL) {
1239                         for (j = 0; cmd_table[i].options[j].name != NULL;
1240                              j++) {
1241                                 const char *options_desc =
1242                                         cmd_table[i].options_desc != NULL ?
1243                                         cmd_table[i].options_desc[j]: "";
1244
1245                                 printf("   --%-12s%s\n",
1246                                                 cmd_table[i].options[j].name,
1247                                                 options_desc);
1248                         }
1249                 }
1250         }
1251
1252         if (interactive == false)
1253                 fprintf(stdout, "\nNote: arguments and output are considered "
1254                                 "EXPERIMENTAL for now.\n");
1255
1256         return 0;
1257 }
1258
1259 int commands(DBusConnection *dbus_conn, char *argv[], int argc)
1260 {
1261         int i, result;
1262
1263         connection = dbus_conn;
1264
1265         for (i = 0; cmd_table[i].cmd != NULL; i++) {
1266                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
1267                                 cmd_table[i].func != NULL) {
1268                         result = cmd_table[i].func(argv, argc,
1269                                         cmd_table[i].options);
1270                         if (result < 0 && result != -EINPROGRESS)
1271                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
1272                                                 strerror(-result));
1273                         return result;
1274                 }
1275         }
1276
1277         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
1278         return -EINVAL;
1279 }