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