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