Imported Upstream 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         default:
257                 return -EOPNOTSUPP;
258         }
259
260         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
261         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type_str,
262                         &variant);
263         dbus_message_iter_append_basic(&variant, type, value);
264         dbus_message_iter_close_container(iter, &variant);
265
266         return 0;
267 }
268
269 int __connmanctl_dbus_method_call(DBusConnection *connection,
270                 const char *service, const char *path, const char *interface,
271                 const char *method, connmanctl_dbus_method_return_func_t cb,
272                 void *user_data, connmanctl_dbus_append_func_t append_func,
273                 void *append_data)
274 {
275         DBusMessage *message;
276         DBusMessageIter iter;
277
278         message = dbus_message_new_method_call(service, path, interface,
279                         method);
280
281         if (!message)
282                 return -ENOMEM;
283
284         if (append_func) {
285                 dbus_message_iter_init_append(message, &iter);
286                 append_func(&iter, append_data);
287         }
288
289         return send_method_call(connection, message, cb, user_data);
290 }
291
292 int __connmanctl_dbus_set_property(DBusConnection *connection,
293                 const char *path, const char *interface,
294                 connmanctl_dbus_method_return_func_t cb, void * user_data,
295                 const char *property, int type, void *value)
296 {
297         DBusMessage *message;
298         DBusMessageIter iter;
299
300         message = dbus_message_new_method_call("net.connman", path,
301                         interface, "SetProperty");
302
303         if (!message)
304                 return -ENOMEM;
305
306         dbus_message_iter_init_append(message, &iter);
307
308         if (append_variant(&iter, property, type, value) < 0) {
309                 dbus_message_unref(message);
310                 return -EINVAL;
311         }
312
313         return send_method_call(connection, message, cb, user_data);
314 }
315
316 void __connmanctl_dbus_append_dict(DBusMessageIter *iter,
317                 connmanctl_dbus_append_func_t append_fn, void *append_data)
318 {
319         DBusMessageIter dict;
320
321         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
322                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
323                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
324                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
325
326         if (append_fn)
327                 append_fn(&dict, append_data);
328
329         dbus_message_iter_close_container(iter, &dict);
330 }
331
332 void __connmanctl_dbus_append_dict_entry(DBusMessageIter *iter,
333                 const char *property, int type, void *value)
334 {
335         DBusMessageIter dict_entry;
336
337         dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
338                         &dict_entry);
339
340         append_variant(&dict_entry, property, type, value);
341
342         dbus_message_iter_close_container(iter, &dict_entry);
343 }
344
345 int __connmanctl_dbus_set_property_dict(DBusConnection *connection,
346                 const char *path, const char *interface,
347                 connmanctl_dbus_method_return_func_t cb, void *user_data,
348                 const char *property, int type,
349                 connmanctl_dbus_append_func_t append_fn,
350                 void *append_user_data)
351 {
352         DBusMessage *message;
353         DBusMessageIter iter, variant, dict;
354
355         message = dbus_message_new_method_call("net.connman", path,
356                         interface, "SetProperty");
357
358         if (!message)
359                 return -ENOMEM;
360
361         dbus_message_iter_init_append(message, &iter);
362         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
363         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
364                         DBUS_TYPE_ARRAY_AS_STRING
365                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
366                                         DBUS_TYPE_STRING_AS_STRING
367                                         DBUS_TYPE_VARIANT_AS_STRING
368                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
369                         &variant);
370
371         dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
372                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
373                                 DBUS_TYPE_STRING_AS_STRING
374                                 DBUS_TYPE_VARIANT_AS_STRING
375                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
376                         &dict);
377
378         append_fn(&dict, append_user_data);
379
380         dbus_message_iter_close_container(&variant, &dict);
381         dbus_message_iter_close_container(&iter, &variant);
382
383         return send_method_call(connection, message, cb, user_data);
384 }
385
386 static void append_variant_array(DBusMessageIter *iter, const char *property,
387                 connmanctl_dbus_append_func_t append_fn,
388                 void *append_user_data)
389 {
390         DBusMessageIter variant, array;
391
392         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
393         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
394                         DBUS_TYPE_ARRAY_AS_STRING
395                                 DBUS_TYPE_STRING_AS_STRING,
396                         &variant);
397
398         dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
399                         DBUS_TYPE_STRING_AS_STRING, &array);
400
401         append_fn(&array, append_user_data);
402
403         dbus_message_iter_close_container(&variant, &array);
404         dbus_message_iter_close_container(iter, &variant);
405 }
406
407 void __connmanctl_dbus_append_dict_string_array(DBusMessageIter *iter,
408                 const char *property, connmanctl_dbus_append_func_t append_fn,
409                 void *append_user_data)
410 {
411         DBusMessageIter dict_entry;
412
413         dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
414                         &dict_entry);
415
416         append_variant_array(&dict_entry, property, append_fn,
417                         append_user_data);
418
419         dbus_message_iter_close_container(iter, &dict_entry);
420 }
421
422 int __connmanctl_dbus_set_property_array(DBusConnection *connection,
423                 const char *path, const char *interface,
424                 connmanctl_dbus_method_return_func_t cb, void *user_data,
425                 const char *property, int type,
426                 connmanctl_dbus_append_func_t append_fn,
427                 void *append_user_data)
428 {
429         DBusMessage *message;
430         DBusMessageIter iter;
431
432         if (type != DBUS_TYPE_STRING)
433                 return -EOPNOTSUPP;
434
435         message = dbus_message_new_method_call("net.connman", path,
436                         interface, "SetProperty");
437
438         if (!message)
439                 return -ENOMEM;
440
441         dbus_message_iter_init_append(message, &iter);
442
443         append_variant_array(&iter, property, append_fn, append_user_data);
444
445         return send_method_call(connection, message, cb, user_data);
446 }
447
448 int __connmanctl_dbus_session_change(DBusConnection *connection,
449                 const char *session_path,
450                 connmanctl_dbus_method_return_func_t cb, void * user_data,
451                 const char *property, int type, void *value)
452 {
453         DBusMessage *message;
454         DBusMessageIter iter;
455
456         message = dbus_message_new_method_call("net.connman", session_path,
457                         "net.connman.Session", "Change");
458
459         if (!message)
460                 return -ENOMEM;
461
462         dbus_message_iter_init_append(message, &iter);
463
464         if (append_variant(&iter, property, type, value) < 0) {
465                 dbus_message_unref(message);
466                 return -EINVAL;
467         }
468
469         return send_method_call(connection, message, cb, user_data);
470 }
471
472 int __connmanctl_dbus_session_change_array(DBusConnection *connection,
473                 const char *session_path,
474                 connmanctl_dbus_method_return_func_t cb, void *user_data,
475                 const char *property,
476                 connmanctl_dbus_append_func_t append_fn,
477                 void *append_user_data)
478 {
479         DBusMessage *message;
480         DBusMessageIter iter;
481
482         message = dbus_message_new_method_call("net.connman", session_path,
483                         "net.connman.Session", "Change");
484
485         if (!message)
486                 return -ENOMEM;
487
488         dbus_message_iter_init_append(message, &iter);
489
490         append_variant_array(&iter, property, append_fn, append_user_data);
491
492         return send_method_call(connection, message, cb, user_data);
493 }