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