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