client: Remove unused functions
[platform/upstream/connman.git] / client / services.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012  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 <stdint.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #include <glib.h>
35
36 #include "services.h"
37 #include "dbus.h"
38
39 int parse_boolean(char *arg)
40 {
41         if (arg == NULL)
42                 return -1;
43
44         if (strcasecmp(arg, "no") == 0 ||
45                         strcasecmp(arg, "false") == 0 ||
46                         strcasecmp(arg, "off" ) == 0 ||
47                         strcasecmp(arg, "disable" ) == 0 ||
48                         strcasecmp(arg, "n") == 0 ||
49                         strcasecmp(arg, "f") == 0 ||
50                         strcasecmp(arg, "0") == 0)
51                 return 0;
52
53         if (strcasecmp(arg, "yes") == 0 ||
54                         strcasecmp(arg, "true") == 0 ||
55                         strcasecmp(arg, "on") == 0 ||
56                         strcasecmp(arg, "enable" ) == 0 ||
57                         strcasecmp(arg, "y") == 0 ||
58                         strcasecmp(arg, "t") == 0 ||
59                         strcasecmp(arg, "1") == 0)
60                 return 1;
61
62         return -1;
63 }
64
65 static int append_property_array(DBusMessageIter *iter, char *property,
66                                                 char **data, int num_args)
67 {
68         DBusMessageIter value, array;
69         int i = 0;
70
71         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
72
73         dbus_array_open(iter, &value);
74         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
75                                          DBUS_TYPE_STRING_AS_STRING, &array);
76
77         while (data[i] != NULL && strncmp(data[i], "--", 2) != 0) {
78                 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
79                                                 &data[i]);
80                 if (num_args > 0 && i == num_args)
81                         break;
82                 i++;
83         }
84
85         dbus_message_iter_close_container(&value, &array);
86         dbus_message_iter_close_container(iter, &value);
87
88         return i;
89 }
90
91 static int append_property_dict(DBusMessageIter *iter, char *property,
92                                         char **keys, char **data, int num_args)
93 {
94         int is_ipv6 = 0;
95         DBusMessageIter value, dict, entry, dict_key;
96         int i = 0;
97         unsigned char prefix;
98         char *property_value;
99
100         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
101
102         /* Top most level is a{sv} */
103         dbus_dict_open_variant(iter, &value);
104
105         dbus_dict_open(&value, &dict);
106
107         if (strcmp(property, "IPv6.Configuration") == 0)
108                 is_ipv6 = 1;
109
110         while (keys[i] != NULL && data[i] != NULL
111                         && strncmp(data[i], "--", 2) != 0) {
112
113                 if (num_args > 0 && i == num_args)
114                         break;
115
116                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
117                                                         NULL, &entry);
118                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
119                                                         &keys[i]);
120
121                 property_value = data[i];
122
123                 if (is_ipv6 == 1 && g_strcmp0(keys[i], "PrefixLength") == 0) {
124                         prefix = atoi(data[i]);
125
126                         dbus_message_iter_open_container(&entry,
127                                                 DBUS_TYPE_VARIANT,
128                                                 DBUS_TYPE_BYTE_AS_STRING,
129                                                 &dict_key);
130                         dbus_message_iter_append_basic(&dict_key,
131                                                        DBUS_TYPE_BYTE, &prefix);
132                 } else {
133                         if (is_ipv6 == 1 && strcmp(keys[i], "Privacy") == 0) {
134                                 switch (parse_boolean(property_value)) {
135                                 case 0:
136                                         property_value = "disabled";
137                                         break;
138                                 case 1:
139                                         property_value = "enabled";
140                                         break;
141                                 case -1:
142                                         if (strcmp(property_value,
143                                                         "prefered") != 0)
144                                                 return -EINVAL;
145                                         break;
146                                 }
147                         }
148
149                         dbus_message_iter_open_container(&entry,
150                                                  DBUS_TYPE_VARIANT,
151                                                  DBUS_TYPE_STRING_AS_STRING,
152                                                  &dict_key);
153                         dbus_message_iter_append_basic(&dict_key,
154                                                         DBUS_TYPE_STRING,
155                                                         &property_value);
156                 }
157
158                 dbus_message_iter_close_container(&entry, &dict_key);
159                 dbus_message_iter_close_container(&dict, &entry);
160
161                 i++;
162         }
163         /* Close {sv}, then close a{sv} */
164         dbus_dict_close(&value, &dict);
165         dbus_dict_close(iter, &value);
166
167         return i;
168 }
169
170 void iterate_array(DBusMessageIter *iter)
171 {
172         DBusMessageIter array_item;
173         dbus_bool_t key_bool;
174         char *key_str;
175
176         dbus_message_iter_recurse(iter, &array_item);
177         /* Make sure the entry is not NULL! */
178         printf("[ ");
179         while (dbus_message_iter_get_arg_type(&array_item) !=
180                                         DBUS_TYPE_INVALID) {
181                 if (dbus_message_iter_get_arg_type(&array_item) ==
182                                         DBUS_TYPE_STRING) {
183                         dbus_message_iter_get_basic(&array_item,
184                                                 &key_str);
185                         printf("%s ", key_str);
186                 } else if (dbus_message_iter_get_arg_type(&array_item) ==
187                                         DBUS_TYPE_BOOLEAN) {
188                         dbus_message_iter_get_basic(&array_item, &key_bool);
189                         printf("%s ", key_bool == TRUE ? "True"
190                                                 : "False");
191                 }
192                 dbus_message_iter_next(&array_item);
193         }
194         if (dbus_message_iter_get_arg_type(&array_item) ==
195                                         DBUS_TYPE_INVALID)
196                 printf("] ");
197 }
198
199 void iterate_dict(DBusMessageIter *dict, char *string, uint16_t key_int)
200 {
201         DBusMessageIter dict_entry, sub_dict_entry;
202
203         printf("{ ");
204         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
205                 dbus_message_iter_recurse(dict, &dict_entry);
206                 dbus_message_iter_get_basic(&dict_entry, &string);
207                 printf("%s=", string);
208                 dbus_message_iter_next(&dict_entry);
209                 while (dbus_message_iter_get_arg_type(&dict_entry)
210                                                         != DBUS_TYPE_INVALID) {
211                         dbus_message_iter_recurse(&dict_entry, &sub_dict_entry);
212                         if (dbus_message_iter_get_arg_type(&sub_dict_entry)
213                                                         == DBUS_TYPE_UINT16) {
214                                 dbus_message_iter_get_basic(&sub_dict_entry,
215                                                                 &key_int);
216                                 printf("%d ", key_int);
217                         } else if (dbus_message_iter_get_arg_type(&sub_dict_entry)
218                                                         == DBUS_TYPE_STRING) {
219                                 dbus_message_iter_get_basic(&sub_dict_entry,
220                                                                 &string);
221                                 printf("%s ", string);
222                         } else if (dbus_message_iter_get_arg_type(&sub_dict_entry)
223                                                         == DBUS_TYPE_ARRAY) {
224                                 iterate_array(&sub_dict_entry);
225                         }
226                         dbus_message_iter_next(&dict_entry);
227                 }
228                 dbus_message_iter_next(dict);
229         }
230         printf("}");
231 }
232
233 /* Get dictionary info about the current service and store it */
234 static void extract_service_properties(DBusMessageIter *dict,
235                                 struct service_data *service)
236 {
237         DBusMessageIter entry, value, array_item;
238         char *key;
239         char *key_str;
240         uint16_t key_uint16;
241         dbus_bool_t key_bool;
242
243         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
244                 dbus_message_iter_recurse(dict, &entry);
245                 dbus_message_iter_get_basic(&entry, &key);
246                 printf("\n  %s = ", key);
247                 if (strcmp(key, "Name") == 0 && strlen(key) < 5)
248                         service->name = key;
249
250                 dbus_message_iter_next(&entry);
251                 dbus_message_iter_recurse(&entry, &value);
252                 /* Check if entry is a dictionary itself */
253                 if (strcmp(key, "Ethernet") == 0 ||
254                         /* if just strcmp, the .Configuration names don't match
255                          * and they are iterated with iterate_array instead*/
256                                 strncmp(key, "IPv4", 4) == 0 ||
257                                 strncmp(key, "IPv6", 4) == 0 ||
258                                 strncmp(key, "Proxy", 5) == 0 ||
259                                 strcmp(key, "Provider") == 0) {
260                         dbus_message_iter_recurse(&value, &array_item);
261                         iterate_dict(&array_item, key_str, key_uint16);
262                 } else
263                 switch (dbus_message_iter_get_arg_type(&value)) {
264                 case DBUS_TYPE_ARRAY:
265                         iterate_array(&value);
266                         break;
267                 case DBUS_TYPE_BOOLEAN:
268                         dbus_message_iter_get_basic(&value, &key_bool);
269                         printf("%s", key_bool == TRUE ? "True" : "False");
270                         break;
271                 case DBUS_TYPE_BYTE:
272                         dbus_message_iter_get_basic(&value, &key_uint16);
273                         printf("%d", key_uint16);
274                         break;
275                 case DBUS_TYPE_STRING:
276                         dbus_message_iter_get_basic(&value, &key_str);
277                         printf("%s", key_str);
278                         break;
279                 }
280                 dbus_message_iter_next(dict);
281         }
282         printf("\n\n");
283 }
284
285 void extract_service_name(DBusMessageIter *dict, struct service_data *service)
286 {
287         DBusMessageIter dict_entry, value;
288         const char *key;
289         const char *state;
290
291         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
292                 dbus_message_iter_recurse(dict, &dict_entry);
293                 dbus_message_iter_get_basic(&dict_entry, &key);
294                 if (strcmp(key, "Name") == 0) {
295                         dbus_message_iter_next(&dict_entry);
296                         dbus_message_iter_recurse(&dict_entry, &value);
297                         dbus_message_iter_get_basic(&value, &service->name);
298                 }
299                 if (strcmp(key, "AutoConnect") == 0) {
300                         dbus_message_iter_next(&dict_entry);
301                         dbus_message_iter_recurse(&dict_entry, &value);
302                         dbus_message_iter_get_basic(&value, &service->autoconn);
303                 }
304                 if (strcmp(key, "State") == 0) {
305                         dbus_message_iter_next(&dict_entry);
306                         dbus_message_iter_recurse(&dict_entry, &value);
307                         dbus_message_iter_get_basic(&value, &state);
308                         if (strcmp(state, "ready") == 0) {
309                                 service->connected = TRUE;
310                                 service->online = FALSE;
311                         } else if (strcmp(state, "online") == 0) {
312                                 service->connected = FALSE;
313                                 service->online = TRUE;
314                         } else {
315                                 service->connected = FALSE;
316                                 service->online = FALSE;
317                         }
318                 }
319                 if (strcmp(key, "Favorite") == 0) {
320                         dbus_message_iter_next(&dict_entry);
321                         dbus_message_iter_recurse(&dict_entry, &value);
322                         dbus_message_iter_get_basic(&value, &service->favorite);
323                 }
324                 dbus_message_iter_next(dict);
325         }
326 }
327
328 /* Show detailed information about a service */
329 void extract_services(DBusMessage *message, char *service_name)
330 {
331         DBusMessageIter iter, array;
332
333         dbus_message_iter_init(message, &iter);
334         dbus_message_iter_recurse(&iter, &array);
335
336         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
337                 DBusMessageIter entry, dict;
338                 struct service_data service;
339                 char *path;
340
341                 dbus_message_iter_recurse(&array, &entry);
342                 dbus_message_iter_get_basic(&entry, &path);
343
344                 service.path = strip_service_path(path);
345                 if (g_strcmp0(service.path, service_name) == 0) {
346                         printf("[ %s ]\n", service.path);
347                         dbus_message_iter_next(&entry);
348                         dbus_message_iter_recurse(&entry, &dict);
349                         extract_service_properties(&dict, &service);
350                 }
351                 dbus_message_iter_next(&array);
352         }
353 }
354
355 /* Support both string names and path names for connecting to services */
356 char *strip_service_path(char *service)
357 {
358         char *service_name;
359         service_name = strrchr(service, '/');
360         if (service_name == NULL)
361                 return service;
362         else
363                 return service_name + 1;
364 }
365
366 /* Show a simple list of service names only */
367 void get_services(DBusMessage *message)
368 {
369         DBusMessageIter iter, array;
370
371         dbus_message_iter_init(message, &iter);
372         dbus_message_iter_recurse(&iter, &array);
373
374         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
375                 DBusMessageIter entry, dict;
376                 struct service_data service;
377                 char *path;
378
379                 dbus_message_iter_recurse(&array, &entry);
380                 dbus_message_iter_get_basic(&entry, &path);
381
382                 service.path = strip_service_path(path);
383                 dbus_message_iter_next(&entry);
384                 dbus_message_iter_recurse(&entry, &dict);
385                 extract_service_name(&dict, &service);
386                 printf("%-1s%-1s%-1s %-20s { %s }\n",
387                         service.favorite ? "*" : "",
388                         service.autoconn ? "A" : "",
389                         service.online ? "O" : (service.connected ? "R" : ""),
390                         service.name, service.path);
391                 dbus_message_iter_next(&array);
392         }
393 }
394
395 int set_proxy_manual(DBusConnection *connection, DBusMessage *message,
396                                 char *name, char **servers, char **excludes,
397                                 int num_servers, int num_excludes)
398 {
399         DBusMessage *message_send;
400         DBusMessageIter iter, value, dict, entry, data;
401         char *path;
402         const char *path_name;
403         char *property = "Proxy.Configuration";
404         char *method = "Method";
405         char *manual = "manual";
406         DBusError dbus_error;
407
408         path_name = strip_service_path(name);
409         if (path_name == NULL)
410                 return -ENXIO;
411
412         path = g_strdup_printf("/net/connman/service/%s", path_name);
413         message_send = dbus_message_new_method_call("net.connman", path,
414                                                         "net.connman.Service",
415                                                         "SetProperty");
416
417         if (message_send == NULL) {
418                 g_free(path);
419                 return -ENOMEM;
420         }
421
422         dbus_message_iter_init_append(message_send, &iter);
423         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
424         dbus_dict_open_variant(&iter, &value);
425         dbus_dict_open(&value, &dict);
426         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL,
427                                                         &entry);
428         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &method);
429         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
430                                                 DBUS_TYPE_STRING_AS_STRING,
431                                                 &data);
432         dbus_message_iter_append_basic(&data, DBUS_TYPE_STRING, &manual);
433         dbus_message_iter_close_container(&entry, &data);
434         dbus_message_iter_close_container(&dict, &entry);
435         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL,
436                                                         &entry);
437         append_property_array(&entry, "Servers", servers, num_servers -1);
438         dbus_message_iter_close_container(&dict, &entry);
439
440         if (num_excludes != 0) {
441                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
442                                                         NULL, &entry);
443                 append_property_array(&entry, "Excludes", excludes,
444                                                         num_excludes -1);
445                 dbus_message_iter_close_container(&dict, &entry);
446         }
447
448         dbus_message_iter_close_container(&value, &dict);
449         dbus_message_iter_close_container(&iter, &value);
450
451         dbus_error_init(&dbus_error);
452         dbus_connection_send_with_reply_and_block(connection, message_send,
453                         -1, &dbus_error);
454
455         if (dbus_error_is_set(&dbus_error) == TRUE) {
456                 printf("Error '%s': %s", path, dbus_error.message);
457                 dbus_error_free(&dbus_error);
458         }
459
460         dbus_message_unref(message_send);
461
462         g_free(path);
463
464         return num_servers + num_excludes;
465 }
466
467 int set_service_property(DBusConnection *connection, DBusMessage *message,
468                                 char *name, char *property, char **keys,
469                                 void *data, int num_args)
470 {
471         int num_props = 1;
472         DBusMessage *message_send;
473         DBusMessageIter iter;
474         char *path;
475         const char *path_name;
476         DBusError dbus_error;
477
478         path_name = strip_service_path(name);
479         if (path_name == NULL)
480                 return -ENXIO;
481
482         path = g_strdup_printf("/net/connman/service/%s", path_name);
483         message_send = dbus_message_new_method_call("net.connman", path,
484                                                         "net.connman.Service",
485                                                         "SetProperty");
486
487         if (message_send == NULL) {
488                 g_free(path);
489                 return -ENOMEM;
490         }
491
492         dbus_message_iter_init_append(message_send, &iter);
493
494         if (strcmp(property, "AutoConnect") == 0)
495                 dbus_property_append_basic(&iter, (const char *) property,
496                                                 DBUS_TYPE_BOOLEAN, data);
497         else if ((strcmp(property, "Domains.Configuration") == 0)
498                         || (strcmp(property, "Timeservers.Configuration") == 0)
499                         || (strcmp(property, "Nameservers.Configuration") == 0))
500                 num_props = append_property_array(&iter, property, data,
501                                 num_args);
502         else if ((strcmp(property, "IPv4.Configuration") == 0)
503                         || (strcmp(property, "IPv6.Configuration") == 0)
504                         || (strcmp(property, "Proxy.Configuration") == 0))
505                 num_props = append_property_dict(&iter, property, keys, data,
506                                 num_args);
507
508         if (num_props >= 0) {
509                 dbus_error_init(&dbus_error);
510                 dbus_connection_send_with_reply_and_block(connection,
511                                 message_send, -1, &dbus_error);
512
513                 if (dbus_error_is_set(&dbus_error) == TRUE) {
514                         printf("Error '%s': %s", path, dbus_error.message);
515                         dbus_error_free(&dbus_error);
516                 }
517         }
518
519         dbus_message_unref(message_send);
520         g_free(path);
521
522         return num_props;
523 }
524
525 int remove_service(DBusConnection *connection, DBusMessage *message,
526                                                                 char *name)
527 {
528         DBusMessage *message_send;
529         const char *path_name;
530         char *path;
531         DBusError err;
532
533         path_name = strip_service_path(name);
534         path = g_strdup_printf("/net/connman/service/%s", path_name);
535         message_send = dbus_message_new_method_call(CONNMAN_SERVICE, path,
536                                                 CONNMAN_SERVICE_INTERFACE,
537                                                 "Remove");
538         if (message_send == NULL) {
539                 g_free(path);
540                 return -ENOMEM;
541         }
542
543         dbus_error_init(&err);
544         dbus_connection_send_with_reply_and_block(connection, message_send,
545                         -1, &err);
546         if (dbus_error_is_set(&err) == TRUE) {
547                 printf("Error '%s' %s\n", path, err.message);
548                 dbus_error_free(&err);
549         }
550
551         dbus_message_unref(message_send);
552         g_free(path);
553
554         return 0;
555 }