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