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