Imported Upstream connman version 1.38
[platform/upstream/connman.git] / client / dbus_helpers.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2013  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 <errno.h>
25 #include <inttypes.h>
26 #include <glib.h>
27
28 #include "input.h"
29 #include "dbus_helpers.h"
30
31 #define TIMEOUT         120000
32
33 #ifndef DBUS_ERROR_UNKNOWN_METHOD
34 #define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod"
35 #endif
36
37 #ifndef DBUS_ERROR_UNKNOWN_PROPERTY
38 #define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
39 #endif
40
41 #ifndef DBUS_ERROR_UNKNOWN_OBJECT
42 #define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject"
43 #endif
44
45 static int string2errno(const char *error)
46 {
47         if (!g_strcmp0(error, DBUS_ERROR_UNKNOWN_METHOD))
48                 return -ENOTSUP;
49         if (!g_strcmp0(error, DBUS_ERROR_UNKNOWN_PROPERTY))
50                 return -ENOENT;
51         if (!g_strcmp0(error, DBUS_ERROR_UNKNOWN_OBJECT))
52                 return -ENODEV;
53         if (!g_strcmp0(error, "net.connman.Error.AlreadyEnabled"))
54                 return -EALREADY;
55         if (!g_strcmp0(error, "net.connman.Error.AlreadyDisabled"))
56                 return -EALREADY;
57
58         return -EINVAL;
59 }
60
61 void __connmanctl_dbus_print(DBusMessageIter *iter, const char *pre,
62                 const char *dict, const char *sep)
63 {
64         int arg_type;
65         dbus_bool_t b;
66         unsigned char c;
67         dbus_uint16_t u16;
68         dbus_uint32_t u;
69         dbus_int32_t i;
70         dbus_uint64_t u64;
71         double d;
72
73         char *str;
74         DBusMessageIter entry;
75
76         if (!pre)
77                 pre = "";
78
79         while ((arg_type = dbus_message_iter_get_arg_type(iter))
80                         != DBUS_TYPE_INVALID) {
81
82                 fprintf(stdout, "%s", pre);
83
84                 switch (arg_type) {
85                 case DBUS_TYPE_STRUCT:
86                         fprintf(stdout, "{ ");
87                         dbus_message_iter_recurse(iter, &entry);
88                         __connmanctl_dbus_print(&entry, "", "=", " ");
89                         fprintf(stdout, " }");
90                         break;
91
92                 case DBUS_TYPE_ARRAY:
93                         fprintf(stdout, "[ ");
94
95                         dbus_message_iter_recurse(iter, &entry);
96                         __connmanctl_dbus_print(&entry, "", "=", ", ");
97
98                         fprintf(stdout, " ]");
99                         break;
100
101                 case DBUS_TYPE_DICT_ENTRY:
102
103                         dbus_message_iter_recurse(iter, &entry);
104                         __connmanctl_dbus_print(&entry, "", dict, dict);
105                         break;
106
107                 case DBUS_TYPE_STRING:
108                 case DBUS_TYPE_OBJECT_PATH:
109                         dbus_message_iter_get_basic(iter, &str);
110                         fprintf(stdout, "%s", str);
111                         break;
112
113                 case DBUS_TYPE_VARIANT:
114                         dbus_message_iter_recurse(iter, &entry);
115                         __connmanctl_dbus_print(&entry, pre, dict, sep);
116                         break;
117
118                 case DBUS_TYPE_BOOLEAN:
119                         dbus_message_iter_get_basic(iter, &b);
120                         if (!b)
121                                 fprintf(stdout, "False");
122                         else
123                                 fprintf(stdout, "True");
124                         break;
125
126                 case DBUS_TYPE_BYTE:
127                         dbus_message_iter_get_basic(iter, &c);
128                         fprintf(stdout, "%d", c);
129                         break;
130
131                 case DBUS_TYPE_UINT16:
132                         dbus_message_iter_get_basic(iter, &u16);
133                         fprintf(stdout, "%u", u16);
134                         break;
135
136                 case DBUS_TYPE_UINT32:
137                         dbus_message_iter_get_basic(iter, &u);
138                         fprintf(stdout, "%d", u);
139                         break;
140
141                 case DBUS_TYPE_INT32:
142                         dbus_message_iter_get_basic(iter, &i);
143                         fprintf(stdout, "%d", i);
144                         break;
145
146                 case DBUS_TYPE_UINT64:
147                         dbus_message_iter_get_basic(iter, &u64);
148                         fprintf(stdout, "%"PRIu64, u64);
149                         break;
150
151                 case DBUS_TYPE_DOUBLE:
152                         dbus_message_iter_get_basic(iter, &d);
153                         fprintf(stdout, "%f", d);
154                         break;
155
156                 default:
157                         fprintf(stdout, "<type %c>", arg_type);
158                         break;
159                 }
160
161                 if (dbus_message_iter_has_next(iter))
162                         fprintf(stdout, "%s", sep);
163
164                 dbus_message_iter_next(iter);
165         }
166 }
167
168 struct dbus_callback {
169         connmanctl_dbus_method_return_func_t cb;
170         void *user_data;
171 };
172
173 static void dbus_method_reply(DBusPendingCall *call, void *user_data)
174 {
175         struct dbus_callback *callback = user_data;
176         int res = 0;
177         DBusMessage *reply;
178         DBusMessageIter iter;
179
180         __connmanctl_save_rl();
181
182         reply = dbus_pending_call_steal_reply(call);
183         dbus_pending_call_unref(call);
184         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
185                 DBusError err;
186
187                 dbus_error_init(&err);
188                 dbus_set_error_from_message(&err, reply);
189
190                 callback->cb(NULL, string2errno(err.name), err.message,
191                         callback->user_data);
192
193                 dbus_error_free(&err);
194                 goto end;
195         }
196
197         dbus_message_iter_init(reply, &iter);
198         res = callback->cb(&iter, 0, NULL, callback->user_data);
199
200 end:
201         __connmanctl_redraw_rl();
202         if (__connmanctl_is_interactive() == false && res != -EINPROGRESS)
203                 __connmanctl_quit();
204
205         g_free(callback);
206         dbus_message_unref(reply);
207 }
208
209 static int send_method_call(DBusConnection *connection,
210                 DBusMessage *message, connmanctl_dbus_method_return_func_t cb,
211                 void *user_data)
212 {
213         int res = -ENXIO;
214         DBusPendingCall *call;
215         struct dbus_callback *callback;
216
217         if (!dbus_connection_send_with_reply(connection, message, &call, TIMEOUT))
218                 goto end;
219
220         if (!call)
221                 goto end;
222
223         if (cb) {
224                 callback = g_new0(struct dbus_callback, 1);
225                 callback->cb = cb;
226                 callback->user_data = user_data;
227                 dbus_pending_call_set_notify(call, dbus_method_reply,
228                                 callback, NULL);
229                 res = -EINPROGRESS;
230         }
231
232 end:
233         dbus_message_unref(message);
234         return res;
235 }
236
237 static int append_variant(DBusMessageIter *iter, const char *property,
238                 int type, void *value)
239 {
240         DBusMessageIter variant;
241         char *type_str;
242
243         switch(type) {
244         case DBUS_TYPE_BOOLEAN:
245                 type_str = DBUS_TYPE_BOOLEAN_AS_STRING;
246                 break;
247         case DBUS_TYPE_BYTE:
248                 type_str = DBUS_TYPE_BYTE_AS_STRING;
249                 break;
250         case DBUS_TYPE_STRING:
251                 type_str = DBUS_TYPE_STRING_AS_STRING;
252                 break;
253         case DBUS_TYPE_INT32:
254                 type_str = DBUS_TYPE_INT32_AS_STRING;
255                 break;
256 #if defined TIZEN_EXT_WIFI_MESH
257         case DBUS_TYPE_UINT16:
258                 type_str = DBUS_TYPE_UINT16_AS_STRING;
259                 break;
260 #endif
261         default:
262                 return -EOPNOTSUPP;
263         }
264
265         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
266         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type_str,
267                         &variant);
268         dbus_message_iter_append_basic(&variant, type, value);
269         dbus_message_iter_close_container(iter, &variant);
270
271         return 0;
272 }
273
274 int __connmanctl_dbus_method_call(DBusConnection *connection,
275                 const char *service, const char *path, const char *interface,
276                 const char *method, connmanctl_dbus_method_return_func_t cb,
277                 void *user_data, connmanctl_dbus_append_func_t append_func,
278                 void *append_data)
279 {
280         DBusMessage *message;
281         DBusMessageIter iter;
282
283         message = dbus_message_new_method_call(service, path, interface,
284                         method);
285
286         if (!message)
287                 return -ENOMEM;
288
289         if (append_func) {
290                 dbus_message_iter_init_append(message, &iter);
291                 append_func(&iter, append_data);
292         }
293
294         return send_method_call(connection, message, cb, user_data);
295 }
296
297 int __connmanctl_dbus_set_property(DBusConnection *connection,
298                 const char *path, const char *interface,
299                 connmanctl_dbus_method_return_func_t cb, void * user_data,
300                 const char *property, int type, void *value)
301 {
302         DBusMessage *message;
303         DBusMessageIter iter;
304
305         message = dbus_message_new_method_call("net.connman", path,
306                         interface, "SetProperty");
307
308         if (!message)
309                 return -ENOMEM;
310
311         dbus_message_iter_init_append(message, &iter);
312
313         if (append_variant(&iter, property, type, value) < 0) {
314                 dbus_message_unref(message);
315                 return -EINVAL;
316         }
317
318         return send_method_call(connection, message, cb, user_data);
319 }
320
321 void __connmanctl_dbus_append_dict(DBusMessageIter *iter,
322                 connmanctl_dbus_append_func_t append_fn, void *append_data)
323 {
324         DBusMessageIter dict;
325
326         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
327                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
328                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
329                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
330
331         if (append_fn)
332                 append_fn(&dict, append_data);
333
334         dbus_message_iter_close_container(iter, &dict);
335 }
336
337 void __connmanctl_dbus_append_dict_entry(DBusMessageIter *iter,
338                 const char *property, int type, void *value)
339 {
340         DBusMessageIter dict_entry;
341
342         dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
343                         &dict_entry);
344
345         append_variant(&dict_entry, property, type, value);
346
347         dbus_message_iter_close_container(iter, &dict_entry);
348 }
349
350 int __connmanctl_dbus_set_property_dict(DBusConnection *connection,
351                 const char *path, const char *interface,
352                 connmanctl_dbus_method_return_func_t cb, void *user_data,
353                 const char *property, int type,
354                 connmanctl_dbus_append_func_t append_fn,
355                 void *append_user_data)
356 {
357         DBusMessage *message;
358         DBusMessageIter iter, variant, dict;
359
360         message = dbus_message_new_method_call("net.connman", path,
361                         interface, "SetProperty");
362
363         if (!message)
364                 return -ENOMEM;
365
366         dbus_message_iter_init_append(message, &iter);
367         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
368         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
369                         DBUS_TYPE_ARRAY_AS_STRING
370                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
371                                         DBUS_TYPE_STRING_AS_STRING
372                                         DBUS_TYPE_VARIANT_AS_STRING
373                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
374                         &variant);
375
376         dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
377                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
378                                 DBUS_TYPE_STRING_AS_STRING
379                                 DBUS_TYPE_VARIANT_AS_STRING
380                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
381                         &dict);
382
383         append_fn(&dict, append_user_data);
384
385         dbus_message_iter_close_container(&variant, &dict);
386         dbus_message_iter_close_container(&iter, &variant);
387
388         return send_method_call(connection, message, cb, user_data);
389 }
390
391 #if defined TIZEN_EXT_WIFI_MESH
392 int __connmanctl_dbus_mesh_dict(DBusConnection *connection,
393                 const char *path, const char *interface,
394                 connmanctl_dbus_method_return_func_t cb, void *user_data,
395                 const char *property, int type,
396                 connmanctl_dbus_append_func_t append_fn,
397                 void *append_user_data)
398 {
399         DBusMessage *message;
400         DBusMessageIter iter, variant, dict;
401
402         message = dbus_message_new_method_call(CONNMAN_SERVICE, path,
403                         interface, "MeshCommands");
404
405         if (!message)
406                 return -ENOMEM;
407
408         dbus_message_iter_init_append(message, &iter);
409         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
410         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
411                         DBUS_TYPE_ARRAY_AS_STRING
412                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
413                                         DBUS_TYPE_STRING_AS_STRING
414                                         DBUS_TYPE_VARIANT_AS_STRING
415                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
416                         &variant);
417
418         dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
419                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
420                                 DBUS_TYPE_STRING_AS_STRING
421                                 DBUS_TYPE_VARIANT_AS_STRING
422                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
423                         &dict);
424
425         if (append_fn)
426                 append_fn(&dict, append_user_data);
427
428         dbus_message_iter_close_container(&variant, &dict);
429         dbus_message_iter_close_container(&iter, &variant);
430
431         return send_method_call(connection, message, cb, user_data);
432 }
433 #endif
434
435 static void append_variant_array(DBusMessageIter *iter, const char *property,
436                 connmanctl_dbus_append_func_t append_fn,
437                 void *append_user_data)
438 {
439         DBusMessageIter variant, array;
440
441         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
442         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
443                         DBUS_TYPE_ARRAY_AS_STRING
444                                 DBUS_TYPE_STRING_AS_STRING,
445                         &variant);
446
447         dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
448                         DBUS_TYPE_STRING_AS_STRING, &array);
449
450         append_fn(&array, append_user_data);
451
452         dbus_message_iter_close_container(&variant, &array);
453         dbus_message_iter_close_container(iter, &variant);
454 }
455
456 void __connmanctl_dbus_append_dict_string_array(DBusMessageIter *iter,
457                 const char *property, connmanctl_dbus_append_func_t append_fn,
458                 void *append_user_data)
459 {
460         DBusMessageIter dict_entry;
461
462         dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
463                         &dict_entry);
464
465         append_variant_array(&dict_entry, property, append_fn,
466                         append_user_data);
467
468         dbus_message_iter_close_container(iter, &dict_entry);
469 }
470
471 int __connmanctl_dbus_set_property_array(DBusConnection *connection,
472                 const char *path, const char *interface,
473                 connmanctl_dbus_method_return_func_t cb, void *user_data,
474                 const char *property, int type,
475                 connmanctl_dbus_append_func_t append_fn,
476                 void *append_user_data)
477 {
478         DBusMessage *message;
479         DBusMessageIter iter;
480
481         if (type != DBUS_TYPE_STRING)
482                 return -EOPNOTSUPP;
483
484         message = dbus_message_new_method_call("net.connman", path,
485                         interface, "SetProperty");
486
487         if (!message)
488                 return -ENOMEM;
489
490         dbus_message_iter_init_append(message, &iter);
491
492         append_variant_array(&iter, property, append_fn, append_user_data);
493
494         return send_method_call(connection, message, cb, user_data);
495 }
496
497 int __connmanctl_dbus_session_change(DBusConnection *connection,
498                 const char *session_path,
499                 connmanctl_dbus_method_return_func_t cb, void * user_data,
500                 const char *property, int type, void *value)
501 {
502         DBusMessage *message;
503         DBusMessageIter iter;
504
505         message = dbus_message_new_method_call("net.connman", session_path,
506                         "net.connman.Session", "Change");
507
508         if (!message)
509                 return -ENOMEM;
510
511         dbus_message_iter_init_append(message, &iter);
512
513         if (append_variant(&iter, property, type, value) < 0) {
514                 dbus_message_unref(message);
515                 return -EINVAL;
516         }
517
518         return send_method_call(connection, message, cb, user_data);
519 }
520
521 int __connmanctl_dbus_session_change_array(DBusConnection *connection,
522                 const char *session_path,
523                 connmanctl_dbus_method_return_func_t cb, void *user_data,
524                 const char *property,
525                 connmanctl_dbus_append_func_t append_fn,
526                 void *append_user_data)
527 {
528         DBusMessage *message;
529         DBusMessageIter iter;
530
531         message = dbus_message_new_method_call("net.connman", session_path,
532                         "net.connman.Session", "Change");
533
534         if (!message)
535                 return -ENOMEM;
536
537         dbus_message_iter_init_append(message, &iter);
538
539         append_variant_array(&iter, property, append_fn, append_user_data);
540
541         return send_method_call(connection, message, cb, user_data);
542 }