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