agent: Agent API ReportError method call
[framework/connectivity/connman.git] / src / agent.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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
30 #include <gdbus.h>
31
32 #include "connman.h"
33
34 static DBusConnection *connection = NULL;
35 static guint agent_watch = 0;
36 static gchar *agent_path = NULL;
37 static gchar *agent_sender = NULL;
38
39 static void agent_free(void)
40 {
41         agent_watch = 0;
42
43         g_free(agent_sender);
44         agent_sender = NULL;
45
46         g_free(agent_path);
47         agent_path = NULL;
48 }
49
50 static void agent_disconnect(DBusConnection *connection, void *data)
51 {
52         DBG("data %p", data);
53
54         agent_free();
55 }
56
57 int __connman_agent_register(const char *sender, const char *path)
58 {
59         DBG("sender %s path %s", sender, path);
60
61         if (agent_path != NULL)
62                 return -EEXIST;
63
64         agent_sender = g_strdup(sender);
65         agent_path = g_strdup(path);
66
67         agent_watch = g_dbus_add_disconnect_watch(connection, sender,
68                                                 agent_disconnect, NULL, NULL);
69
70         return 0;
71 }
72
73 int __connman_agent_unregister(const char *sender, const char *path)
74 {
75         DBG("sender %s path %s", sender, path);
76
77         if (agent_path == NULL)
78                 return -ESRCH;
79
80         if (agent_watch > 0)
81                 g_dbus_remove_watch(connection, agent_watch);
82
83         agent_free();
84
85         return 0;
86 }
87
88 struct request_input_reply {
89         struct connman_service *service;
90         passphrase_cb_t callback;
91         void *user_data;
92 };
93
94 static void request_input_passphrase_reply(DBusPendingCall *call, void *user_data)
95 {
96         struct request_input_reply *passphrase_reply = user_data;
97         char *passphrase = NULL;
98         char *key;
99         DBusMessageIter iter, dict;
100         DBusMessage *reply = dbus_pending_call_steal_reply(call);
101
102         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
103                 goto done;
104
105         dbus_message_iter_init(reply, &iter);
106         dbus_message_iter_recurse(&iter, &dict);
107         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
108                 DBusMessageIter entry, value;
109
110                 dbus_message_iter_recurse(&dict, &entry);
111                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
112                         break;
113
114                 dbus_message_iter_get_basic(&entry, &key);
115                 if (g_str_equal(key, "Passphrase")) {
116                         dbus_message_iter_next(&entry);
117                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
118                                 break;
119                         dbus_message_iter_recurse(&entry, &value);
120                         dbus_message_iter_get_basic(&value, &passphrase);
121                         break;
122                 }
123                 dbus_message_iter_next(&dict);
124         }
125
126 done:
127         passphrase_reply->callback(passphrase_reply->service,
128                                 passphrase, passphrase_reply->user_data);
129         connman_service_unref(passphrase_reply->service);
130         dbus_message_unref(reply);
131         g_free(passphrase_reply);
132 }
133
134 static void request_input_append_passphrase(DBusMessageIter *iter, void *user_data)
135 {
136         struct connman_service *service = user_data;
137         char *value;
138
139         switch (__connman_service_get_security(service)) {
140         case CONNMAN_SERVICE_SECURITY_WEP:
141                 value = "wep";
142                 break;
143         case CONNMAN_SERVICE_SECURITY_PSK:
144                 value = "psk";
145                 break;
146         default:
147                 value = "string";
148                 break;
149         }
150         connman_dbus_dict_append_basic(iter, "Type",
151                                 DBUS_TYPE_STRING, &value);
152         value = "Mandatory";
153         connman_dbus_dict_append_basic(iter, "Requirement",
154                                 DBUS_TYPE_STRING, &value);
155 }
156
157 int __connman_agent_request_input(struct connman_service *service,
158                                 passphrase_cb_t callback, void *user_data)
159 {
160         DBusMessage *message;
161         const char *path;
162         DBusMessageIter iter;
163         DBusMessageIter dict;
164         DBusPendingCall *call;
165         struct request_input_reply *passphrase_reply;
166
167         if (service == NULL || agent_path == NULL || callback == NULL)
168                 return -ESRCH;
169
170         message = dbus_message_new_method_call(agent_sender, agent_path,
171                                         CONNMAN_AGENT_INTERFACE,
172                                         "RequestInput");
173         if (message == NULL)
174                 return -ENOMEM;
175
176         dbus_message_iter_init_append(message, &iter);
177
178         path = __connman_service_get_path(service);
179         dbus_message_iter_append_basic(&iter,
180                                 DBUS_TYPE_OBJECT_PATH, &path);
181
182         connman_dbus_dict_open(&iter, &dict);
183         connman_dbus_dict_append_dict(&dict, "Passphrase",
184                                 request_input_append_passphrase, service);
185         connman_dbus_dict_close(&iter, &dict);
186
187         passphrase_reply = g_try_new0(struct request_input_reply, 1);
188         if (passphrase_reply == NULL) {
189                 dbus_message_unref(message);
190                 return -ENOMEM;
191         }
192
193         if (dbus_connection_send_with_reply(connection, message,
194                                                 &call, -1) == FALSE) {
195                 dbus_message_unref(message);
196                 g_free(passphrase_reply);
197                 return -ESRCH;
198         }
199
200         if (call == NULL) {
201                 dbus_message_unref(message);
202                 g_free(passphrase_reply);
203                 return -ESRCH;
204         }
205
206         passphrase_reply->service = connman_service_ref(service);
207         passphrase_reply->callback = callback;
208         passphrase_reply->user_data = user_data;
209
210         dbus_pending_call_set_notify(call, request_input_passphrase_reply,
211                                 passphrase_reply, NULL);
212
213         dbus_message_unref(message);
214
215         return -EIO;
216 }
217
218 struct report_error_data {
219         struct connman_service *service;
220         report_error_cb_t callback;
221         void *user_data;
222 };
223
224 static void report_error_reply(DBusPendingCall *call, void *user_data)
225 {
226         struct report_error_data *report_error = user_data;
227         DBusMessage *reply = dbus_pending_call_steal_reply(call);
228         gboolean retry = FALSE;
229         const char *dbus_err;
230
231         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
232                 dbus_err = dbus_message_get_error_name(reply);
233                 if (dbus_err != NULL &&
234                         strcmp(dbus_err,
235                                 CONNMAN_AGENT_INTERFACE ".Error.Retry") == 0)
236                         retry = TRUE;
237         }
238
239         report_error->callback(report_error->service, retry,
240                         report_error->user_data);
241         connman_service_unref(report_error->service);
242         g_free(report_error);
243         dbus_message_unref(reply);
244 }
245
246 int __connman_agent_report_error(struct connman_service *service,
247                                 const char *error,
248                                 report_error_cb_t callback, void *user_data)
249 {
250         DBusMessage *message;
251         DBusMessageIter iter;
252         const char *path;
253         struct report_error_data *report_error;
254         DBusPendingCall *call;
255
256         if (service == NULL || agent_path == NULL || error == NULL ||
257                 callback == NULL)
258                 return -ESRCH;
259
260         message = dbus_message_new_method_call(agent_sender, agent_path,
261                                         CONNMAN_AGENT_INTERFACE,
262                                         "ReportError");
263         if (message == NULL)
264                 return -ENOMEM;
265
266         dbus_message_iter_init_append(message, &iter);
267
268         path = __connman_service_get_path(service);
269         dbus_message_iter_append_basic(&iter,
270                                 DBUS_TYPE_OBJECT_PATH, &path);
271         dbus_message_iter_append_basic(&iter,
272                                 DBUS_TYPE_STRING, &error);
273
274         report_error = g_try_new0(struct report_error_data, 1);
275         if (report_error == NULL) {
276                 dbus_message_unref(message);
277                 return -ENOMEM;
278         }
279
280         if (dbus_connection_send_with_reply(connection, message,
281                                                 &call, -1) == FALSE) {
282                 dbus_message_unref(message);
283                 g_free(report_error);
284                 return -ESRCH;
285         }
286
287         if (call == NULL) {
288                 dbus_message_unref(message);
289                 g_free(report_error);
290                 return -ESRCH;
291         }
292
293         report_error->service = connman_service_ref(service);
294         report_error->callback = callback;
295         report_error->user_data = user_data;
296         dbus_pending_call_set_notify(call, report_error_reply,
297                                 report_error, NULL);
298         dbus_message_unref(message);
299
300         return -EIO;
301 }
302
303 int __connman_agent_init(void)
304 {
305         DBG("");
306
307         connection = connman_dbus_get_connection();
308         if (connection == NULL)
309                 return -1;
310
311         return 0;
312 }
313
314 void __connman_agent_cleanup(void)
315 {
316         DBusMessage *message;
317
318         DBG("");
319
320         if (connection == NULL)
321                 return;
322
323         if (agent_watch > 0)
324                 g_dbus_remove_watch(connection, agent_watch);
325
326         if (agent_path == NULL)
327                 return;
328
329         message = dbus_message_new_method_call(agent_sender, agent_path,
330                                         CONNMAN_AGENT_INTERFACE, "Release");
331         if (message == NULL)
332                 return;
333
334         dbus_message_set_no_reply(message, TRUE);
335
336         g_dbus_send_message(connection, message);
337
338         agent_free();
339
340         dbus_connection_unref(connection);
341 }