Add set property result handling for supplicant test program
[framework/connectivity/connman.git] / tools / supplicant-dbus.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <dbus/dbus.h>
30
31 #include "supplicant-dbus.h"
32
33 #define TIMEOUT 5000
34
35 static DBusConnection *connection;
36
37 void supplicant_dbus_setup(DBusConnection *conn)
38 {
39         connection = conn;
40 }
41
42 void supplicant_dbus_array_foreach(DBusMessageIter *iter,
43                                 supplicant_dbus_array_function function,
44                                                         void *user_data)
45 {
46         DBusMessageIter entry;
47
48         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
49                 return;
50
51         dbus_message_iter_recurse(iter, &entry);
52
53         while (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_INVALID) {
54                 if (function != NULL)
55                         function(&entry, user_data);
56
57                 dbus_message_iter_next(&entry);
58         }
59 }
60
61 void supplicant_dbus_property_foreach(DBusMessageIter *iter,
62                                 supplicant_dbus_property_function function,
63                                                         void *user_data)
64 {
65         DBusMessageIter dict;
66
67         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
68                 return;
69
70         dbus_message_iter_recurse(iter, &dict);
71
72         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
73                 DBusMessageIter entry, value;
74                 const char *key;
75
76                 dbus_message_iter_recurse(&dict, &entry);
77
78                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
79                         return;
80
81                 dbus_message_iter_get_basic(&entry, &key);
82                 dbus_message_iter_next(&entry);
83
84                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
85                         return;
86
87                 dbus_message_iter_recurse(&entry, &value);
88
89                 if (key != NULL) {
90                         if (strcmp(key, "Properties") == 0)
91                                 supplicant_dbus_property_foreach(&value,
92                                                         function, user_data);
93                         else if (function != NULL)
94                                 function(key, &value, user_data);
95                 }
96
97                 dbus_message_iter_next(&dict);
98         }
99 }
100
101 struct property_get_data {
102         supplicant_dbus_property_function function;
103         void *user_data;
104 };
105
106 static void property_get_all_reply(DBusPendingCall *call, void *user_data)
107 {
108         struct property_get_data *data = user_data;
109         DBusMessage *reply;
110         DBusMessageIter iter;
111
112         reply = dbus_pending_call_steal_reply(call);
113         if (reply == NULL)
114                 return;
115
116         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
117                 goto done;
118
119         if (dbus_message_iter_init(reply, &iter) == FALSE)
120                 goto done;
121
122         supplicant_dbus_property_foreach(&iter, data->function,
123                                                         data->user_data);
124
125         if (data->function != NULL)
126                 data->function(NULL, NULL, data->user_data);
127
128 done:
129         dbus_message_unref(reply);
130 }
131
132 int supplicant_dbus_property_get_all(const char *path, const char *interface,
133                                 supplicant_dbus_property_function function,
134                                                         void *user_data)
135 {
136         struct property_get_data *data;
137         DBusMessage *message;
138         DBusPendingCall *call;
139
140         if (path == NULL || interface == NULL)
141                 return -EINVAL;
142
143         data = dbus_malloc0(sizeof(*data));
144         if (data == NULL)
145                 return -ENOMEM;
146
147         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
148                                         DBUS_INTERFACE_PROPERTIES, "GetAll");
149         if (message == NULL) {
150                 dbus_free(data);
151                 return -ENOMEM;
152         }
153
154         dbus_message_set_auto_start(message, FALSE);
155
156         dbus_message_append_args(message, DBUS_TYPE_STRING, &interface, NULL);
157
158         if (dbus_connection_send_with_reply(connection, message,
159                                                 &call, TIMEOUT) == FALSE) {
160                 dbus_message_unref(message);
161                 dbus_free(data);
162                 return -EIO;
163         }
164
165         if (call == NULL) {
166                 dbus_message_unref(message);
167                 dbus_free(data);
168                 return -EIO;
169         }
170
171         data->function = function;
172         data->user_data = user_data;
173
174         dbus_pending_call_set_notify(call, property_get_all_reply,
175                                                         data, dbus_free);
176
177         dbus_message_unref(message);
178
179         return 0;
180 }
181
182 struct property_set_data {
183         supplicant_dbus_result_function function;
184         void *user_data;
185 };
186
187 static void property_set_reply(DBusPendingCall *call, void *user_data)
188 {
189         struct property_set_data *data = user_data;
190         DBusMessage *reply;
191         DBusMessageIter iter;
192         const char *error;
193
194         reply = dbus_pending_call_steal_reply(call);
195         if (reply == NULL)
196                 return;
197
198         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
199                 error = dbus_message_get_error_name(reply);
200         else
201                 error = NULL;
202
203         if (dbus_message_iter_init(reply, &iter) == FALSE)
204                 goto done;
205
206         if (data->function != NULL)
207                 data->function(error, &iter, data->user_data);
208
209 done:
210         dbus_message_unref(reply);
211 }
212
213 int supplicant_dbus_property_set(const char *path, const char *interface,
214                                 const char *key, const char *signature,
215                                 supplicant_dbus_setup_function setup,
216                                 supplicant_dbus_result_function function,
217                                                         void *user_data)
218 {
219         struct property_set_data *data;
220         DBusMessage *message;
221         DBusMessageIter iter, value;
222         DBusPendingCall *call;
223
224         if (path == NULL || interface == NULL)
225                 return -EINVAL;
226
227         if (key == NULL || signature == NULL || setup == NULL)
228                 return -EINVAL;
229
230         data = dbus_malloc0(sizeof(*data));
231         if (data == NULL)
232                 return -ENOMEM;
233
234         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
235                                         DBUS_INTERFACE_PROPERTIES, "Set");
236         if (message == NULL) {
237                 dbus_free(data);
238                 return -ENOMEM;
239         }
240
241         dbus_message_set_auto_start(message, FALSE);
242
243         dbus_message_iter_init_append(message, &iter);
244         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface);
245         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
246
247         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
248                                                         signature, &value);
249         setup(&value, user_data);
250         dbus_message_iter_close_container(&iter, &value);
251
252         if (dbus_connection_send_with_reply(connection, message,
253                                                 &call, TIMEOUT) == FALSE) {
254                 dbus_message_unref(message);
255                 dbus_free(data);
256                 return -EIO;
257         }
258
259         if (call == NULL) {
260                 dbus_message_unref(message);
261                 dbus_free(data);
262                 return -EIO;
263         }
264
265         data->function = function;
266         data->user_data = user_data;
267
268         dbus_pending_call_set_notify(call, property_set_reply,
269                                                         data, dbus_free);
270
271         dbus_message_unref(message);
272
273         return 0;
274 }