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