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