agent: Use the Agent queueing functions when sending requests
[platform/upstream/connman.git] / src / agent.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  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 typedef void (*agent_queue_cb)(DBusMessage *reply, void *user_data);
40
41 struct agent_data {
42         struct connman_service *service;
43         DBusMessage *msg;
44         DBusPendingCall *call;
45         int timeout;
46         agent_queue_cb callback;
47         void *user_data;
48 };
49
50 static GList *agent_queue = NULL;
51 static struct agent_data *agent_request = NULL;
52
53 static void agent_free(void)
54 {
55         agent_watch = 0;
56
57         g_free(agent_sender);
58         agent_sender = NULL;
59
60         g_free(agent_path);
61         agent_path = NULL;
62 }
63
64 static void agent_disconnect(DBusConnection *conn, void *data)
65 {
66         DBG("data %p", data);
67
68         agent_free();
69 }
70
71 int __connman_agent_register(const char *sender, const char *path)
72 {
73         DBG("sender %s path %s", sender, path);
74
75         if (agent_path != NULL)
76                 return -EEXIST;
77
78         agent_sender = g_strdup(sender);
79         agent_path = g_strdup(path);
80
81         agent_watch = g_dbus_add_disconnect_watch(connection, sender,
82                                                 agent_disconnect, NULL, NULL);
83
84         return 0;
85 }
86
87 int __connman_agent_unregister(const char *sender, const char *path)
88 {
89         DBG("sender %s path %s", sender, path);
90
91         if (agent_path == NULL)
92                 return -ESRCH;
93
94         if (agent_watch > 0)
95                 g_dbus_remove_watch(connection, agent_watch);
96
97         agent_free();
98
99         return 0;
100 }
101
102 static void agent_data_free(struct agent_data *data)
103 {
104         if (data == NULL)
105                 return;
106         if (data->service != NULL)
107                 connman_service_unref(data->service);
108         if (data->msg != NULL)
109                 dbus_message_unref(data->msg);
110         if (data->call != NULL)
111                 dbus_pending_call_cancel(data->call);
112
113         g_free(data);
114 }
115
116 static void agent_receive_message(DBusPendingCall *call, void *user_data);
117
118 static int agent_send_next_request(void)
119 {
120         if (agent_request != NULL)
121                 return -EBUSY;
122
123         if (agent_queue == NULL)
124                 return 0;
125
126         agent_request = agent_queue->data;
127         agent_queue = g_list_remove(agent_queue, agent_request);
128
129         if (dbus_connection_send_with_reply(connection, agent_request->msg,
130                                         &agent_request->call,
131                                         agent_request->timeout)
132                         == FALSE)
133                 goto fail;
134
135         if (agent_request->call == NULL)
136                 goto fail;
137
138         if (dbus_pending_call_set_notify(agent_request->call,
139                                         agent_receive_message, agent_request,
140                                         NULL) == FALSE)
141                 goto fail;
142
143         dbus_message_unref(agent_request->msg);
144         agent_request->msg = NULL;
145         return 0;
146
147 fail:
148         agent_data_free(agent_request);
149         agent_request = NULL;
150         return -ESRCH;
151 }
152
153 static void agent_receive_message(DBusPendingCall *call, void *user_data)
154 {
155         struct agent_data *queue_data = user_data;
156         DBusMessage *reply;
157
158         DBG("waiting for %p received %p", agent_request, queue_data);
159
160         if (agent_request != queue_data) {
161                 connman_error("Agent callback expected %p got %p",
162                                 agent_request, queue_data);
163                 return;
164         }
165
166         reply = dbus_pending_call_steal_reply(call);
167         dbus_pending_call_unref(call);
168         queue_data->call = NULL;
169
170         queue_data->callback(reply, queue_data->user_data);
171         dbus_message_unref(reply);
172
173         agent_data_free(queue_data);
174         agent_request = NULL;
175
176         agent_send_next_request();
177 }
178
179 static int agent_queue_message(struct connman_service *service,
180                 DBusMessage *msg, int timeout,
181                 agent_queue_cb callback, void *user_data)
182 {
183         struct agent_data *queue_data;
184
185         if (service == NULL || callback == NULL)
186                 return -EBADMSG;
187
188         queue_data = g_new0(struct agent_data, 1);
189         if (queue_data == NULL)
190                 return -ENOMEM;
191
192         queue_data->service = connman_service_ref(service);
193         queue_data->msg = dbus_message_ref(msg);
194         queue_data->timeout = timeout;
195         queue_data->callback = callback;
196         queue_data->user_data = user_data;
197         agent_queue = g_list_append(agent_queue, queue_data);
198
199         return agent_send_next_request();
200 }
201
202 static connman_bool_t check_reply_has_dict(DBusMessage *reply)
203 {
204         const char *signature = DBUS_TYPE_ARRAY_AS_STRING
205                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
206                 DBUS_TYPE_STRING_AS_STRING
207                 DBUS_TYPE_VARIANT_AS_STRING
208                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
209
210         if (dbus_message_has_signature(reply, signature) == TRUE)
211                 return TRUE;
212
213         connman_warn("Reply %s to %s from %s has wrong signature %s",
214                         signature,
215                         dbus_message_get_interface(reply),
216                         dbus_message_get_sender(reply),
217                         dbus_message_get_signature(reply));
218
219         return FALSE;
220 }
221
222 struct request_input_reply {
223         struct connman_service *service;
224         authentication_cb_t callback;
225         void *user_data;
226 };
227
228 static void request_input_passphrase_reply(DBusMessage *reply, void *user_data)
229 {
230         struct request_input_reply *passphrase_reply = user_data;
231         connman_bool_t values_received = FALSE;
232         connman_bool_t wps = FALSE;
233         const char *error = NULL;
234         char *identity = NULL;
235         char *passphrase = NULL;
236         char *wpspin = NULL;
237         char *key;
238         char *name = NULL;
239         int name_len = 0;
240         DBusMessageIter iter, dict;
241
242         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
243                 error = dbus_message_get_error_name(reply);
244                 goto done;
245         }
246
247         if (check_reply_has_dict(reply) == FALSE)
248                 goto done;
249
250         values_received = TRUE;
251
252         dbus_message_iter_init(reply, &iter);
253         dbus_message_iter_recurse(&iter, &dict);
254         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
255                 DBusMessageIter entry, value;
256
257                 dbus_message_iter_recurse(&dict, &entry);
258                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
259                         break;
260
261                 dbus_message_iter_get_basic(&entry, &key);
262
263                 if (g_str_equal(key, "Identity")) {
264                         dbus_message_iter_next(&entry);
265                         if (dbus_message_iter_get_arg_type(&entry)
266                                                         != DBUS_TYPE_VARIANT)
267                                 break;
268                         dbus_message_iter_recurse(&entry, &value);
269                         dbus_message_iter_get_basic(&value, &identity);
270
271                 } else if (g_str_equal(key, "Passphrase")) {
272                         dbus_message_iter_next(&entry);
273                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
274                                 break;
275                         dbus_message_iter_recurse(&entry, &value);
276                         dbus_message_iter_get_basic(&value, &passphrase);
277
278                 } else if (g_str_equal(key, "WPS")) {
279                         wps = TRUE;
280
281                         dbus_message_iter_next(&entry);
282                         if (dbus_message_iter_get_arg_type(&entry)
283                                                         != DBUS_TYPE_VARIANT)
284                                 break;
285                         dbus_message_iter_recurse(&entry, &value);
286                         dbus_message_iter_get_basic(&value, &wpspin);
287                         break;
288                 } else if (g_str_equal(key, "Name")) {
289                         dbus_message_iter_next(&entry);
290                         if (dbus_message_iter_get_arg_type(&entry)
291                                                         != DBUS_TYPE_VARIANT)
292                                 break;
293                         dbus_message_iter_recurse(&entry, &value);
294                         dbus_message_iter_get_basic(&value, &name);
295                         name_len = strlen(name);
296                 } else if (g_str_equal(key, "SSID")) {
297                         dbus_message_iter_next(&entry);
298                         if (dbus_message_iter_get_arg_type(&entry)
299                                                         != DBUS_TYPE_VARIANT)
300                                 break;
301                         dbus_message_iter_recurse(&entry, &value);
302                         if (dbus_message_iter_get_arg_type(&value)
303                                                         != DBUS_TYPE_VARIANT)
304                                 break;
305                         if (dbus_message_iter_get_element_type(&value)
306                                                         != DBUS_TYPE_VARIANT)
307                                 break;
308                         dbus_message_iter_get_fixed_array(&value, &name,
309                                                         &name_len);
310                 }
311                 dbus_message_iter_next(&dict);
312         }
313
314 done:
315         passphrase_reply->callback(passphrase_reply->service, values_received,
316                                 name, name_len,
317                                 identity, passphrase,
318                                 wps, wpspin, error,
319                                 passphrase_reply->user_data);
320         connman_service_unref(passphrase_reply->service);
321         g_free(passphrase_reply);
322 }
323
324 static void request_input_append_alternates(DBusMessageIter *iter,
325                                                         void *user_data)
326 {
327         const char *str = user_data;
328         char **alternates, **alternative;
329
330         if (str == NULL)
331                 return;
332
333         alternates = g_strsplit(str, ",", 0);
334         if (alternates == NULL)
335                 return;
336
337         for (alternative = alternates; *alternative != NULL; alternative++)
338                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
339                                                                 alternative);
340
341         g_strfreev(alternates);
342 }
343
344 static void request_input_append_identity(DBusMessageIter *iter,
345                                                         void *user_data)
346 {
347         char *str = "string";
348
349         connman_dbus_dict_append_basic(iter, "Type",
350                                 DBUS_TYPE_STRING, &str);
351         str = "mandatory";
352         connman_dbus_dict_append_basic(iter, "Requirement",
353                                 DBUS_TYPE_STRING, &str);
354 }
355
356 static void request_input_append_passphrase(DBusMessageIter *iter,
357                                                         void *user_data)
358 {
359         struct connman_service *service = user_data;
360         char *value;
361         const char *phase2;
362
363         switch (__connman_service_get_security(service)) {
364         case CONNMAN_SERVICE_SECURITY_WEP:
365                 value = "wep";
366                 break;
367         case CONNMAN_SERVICE_SECURITY_PSK:
368                 value = "psk";
369                 break;
370         case CONNMAN_SERVICE_SECURITY_8021X:
371                 phase2 = __connman_service_get_phase2(service);
372
373                 if (phase2 != NULL && (
374                                 g_str_has_suffix(phase2, "GTC") == TRUE ||
375                                 g_str_has_suffix(phase2, "OTP") == TRUE))
376                         value = "response";
377                 else
378                         value = "passphrase";
379
380                 break;
381         default:
382                 value = "string";
383                 break;
384         }
385         connman_dbus_dict_append_basic(iter, "Type",
386                                 DBUS_TYPE_STRING, &value);
387         value = "mandatory";
388         connman_dbus_dict_append_basic(iter, "Requirement",
389                                 DBUS_TYPE_STRING, &value);
390
391         if (__connman_service_wps_enabled(service) == TRUE) {
392                 connman_dbus_dict_append_array(iter, "Alternates",
393                                         DBUS_TYPE_STRING,
394                                         request_input_append_alternates,
395                                         "WPS");
396         }
397 }
398
399 static void request_input_append_wps(DBusMessageIter *iter, void *user_data)
400 {
401         const char *str = "wpspin";
402
403         connman_dbus_dict_append_basic(iter, "Type",
404                                 DBUS_TYPE_STRING, &str);
405         str = "alternate";
406         connman_dbus_dict_append_basic(iter, "Requirement",
407                                 DBUS_TYPE_STRING, &str);
408 }
409
410 static void request_input_append_name(DBusMessageIter *iter, void *user_data)
411 {
412         const char *str = "string";
413
414         connman_dbus_dict_append_basic(iter, "Type",
415                                 DBUS_TYPE_STRING, &str);
416         str = "mandatory";
417         connman_dbus_dict_append_basic(iter, "Requirement",
418                                 DBUS_TYPE_STRING, &str);
419         connman_dbus_dict_append_array(iter, "Alternates",
420                                 DBUS_TYPE_STRING,
421                                 request_input_append_alternates,
422                                 "SSID");
423 }
424
425 static void request_input_append_ssid(DBusMessageIter *iter, void *user_data)
426 {
427         const char *str = "ssid";
428
429         connman_dbus_dict_append_basic(iter, "Type",
430                                 DBUS_TYPE_STRING, &str);
431         str = "alternate";
432         connman_dbus_dict_append_basic(iter, "Requirement",
433                                 DBUS_TYPE_STRING, &str);
434 }
435
436 static void request_input_append_password(DBusMessageIter *iter,
437                                                         void *user_data)
438 {
439         char *str = "passphrase";
440
441         connman_dbus_dict_append_basic(iter, "Type",
442                                 DBUS_TYPE_STRING, &str);
443         str = "mandatory";
444         connman_dbus_dict_append_basic(iter, "Requirement",
445                                 DBUS_TYPE_STRING, &str);
446 }
447
448 struct previous_passphrase_data {
449         const char *passphrase;
450         const char *type;
451 };
452
453 static void request_input_append_previouspassphrase(DBusMessageIter *iter,
454                                                         void *user_data)
455 {
456         struct previous_passphrase_data *data = user_data;
457         const char *requirement = "informational";
458
459         connman_dbus_dict_append_basic(iter, "Type",
460                                 DBUS_TYPE_STRING, &data->type);
461
462         connman_dbus_dict_append_basic(iter, "Requirement",
463                                 DBUS_TYPE_STRING, &requirement);
464
465         connman_dbus_dict_append_basic(iter, "Value",
466                                 DBUS_TYPE_STRING, &data->passphrase);
467 }
468
469 static void previous_passphrase_handler(DBusMessageIter *iter,
470                                         struct connman_service *service)
471 {
472         enum connman_service_security security;
473         struct previous_passphrase_data data;
474         struct connman_network *network;
475
476         network = __connman_service_get_network(service);
477         data.passphrase = connman_network_get_string(network, "WiFi.PinWPS");
478
479         if (connman_network_get_bool(network, "WiFi.UseWPS") == TRUE &&
480                                                 data.passphrase != NULL) {
481                 data.type = "wpspin";
482         } else {
483                 data.passphrase = __connman_service_get_passphrase(service);
484                 if (data.passphrase == NULL)
485                         return;
486
487                 security = __connman_service_get_security(service);
488                 switch (security) {
489                 case CONNMAN_SERVICE_SECURITY_WEP:
490                         data.type = "wep";
491                         break;
492                 case CONNMAN_SERVICE_SECURITY_PSK:
493                         data.type  = "psk";
494                         break;
495                 /*
496                  * This should never happen: no passphrase is set if security
497                  * is not one of the above. */
498                 default:
499                         break;
500                 }
501         }
502
503         connman_dbus_dict_append_dict(iter, "PreviousPassphrase",
504                         request_input_append_previouspassphrase, &data);
505 }
506
507 static void request_input_login_reply(DBusMessage *reply, void *user_data)
508 {
509         struct request_input_reply *username_password_reply = user_data;
510         const char *error = NULL;
511         connman_bool_t values_received = FALSE;
512         char *username = NULL;
513         char *password = NULL;
514         char *key;
515         DBusMessageIter iter, dict;
516
517         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
518                 error = dbus_message_get_error_name(reply);
519                 goto done;
520         }
521
522         if (check_reply_has_dict(reply) == FALSE)
523                 goto done;
524
525         values_received = TRUE;
526
527         dbus_message_iter_init(reply, &iter);
528         dbus_message_iter_recurse(&iter, &dict);
529         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
530                 DBusMessageIter entry, value;
531
532                 dbus_message_iter_recurse(&dict, &entry);
533                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
534                         break;
535
536                 dbus_message_iter_get_basic(&entry, &key);
537
538                 if (g_str_equal(key, "Username")) {
539                         dbus_message_iter_next(&entry);
540                         if (dbus_message_iter_get_arg_type(&entry)
541                                                         != DBUS_TYPE_VARIANT)
542                                 break;
543                         dbus_message_iter_recurse(&entry, &value);
544                         dbus_message_iter_get_basic(&value, &username);
545
546                 } else if (g_str_equal(key, "Password")) {
547                         dbus_message_iter_next(&entry);
548                         if (dbus_message_iter_get_arg_type(&entry) !=
549                                                         DBUS_TYPE_VARIANT)
550                                 break;
551                         dbus_message_iter_recurse(&entry, &value);
552                         dbus_message_iter_get_basic(&value, &password);
553                 }
554
555                 dbus_message_iter_next(&dict);
556         }
557
558 done:
559         username_password_reply->callback(username_password_reply->service,
560                                         values_received, NULL, 0,
561                                         username, password,
562                                         FALSE, NULL, error,
563                                         username_password_reply->user_data);
564         connman_service_unref(username_password_reply->service);
565         g_free(username_password_reply);
566 }
567
568 int __connman_agent_request_passphrase_input(struct connman_service *service,
569                                 authentication_cb_t callback, void *user_data)
570 {
571         DBusMessage *message;
572         const char *path;
573         DBusMessageIter iter;
574         DBusMessageIter dict;
575         struct request_input_reply *passphrase_reply;
576         int err;
577
578         if (service == NULL || agent_path == NULL || callback == NULL)
579                 return -ESRCH;
580
581         message = dbus_message_new_method_call(agent_sender, agent_path,
582                                         CONNMAN_AGENT_INTERFACE,
583                                         "RequestInput");
584         if (message == NULL)
585                 return -ENOMEM;
586
587         dbus_message_iter_init_append(message, &iter);
588
589         path = __connman_service_get_path(service);
590         dbus_message_iter_append_basic(&iter,
591                                 DBUS_TYPE_OBJECT_PATH, &path);
592
593         connman_dbus_dict_open(&iter, &dict);
594
595         if (__connman_service_is_hidden(service)) {
596                 connman_dbus_dict_append_dict(&dict, "Name",
597                                         request_input_append_name, NULL);
598                 connman_dbus_dict_append_dict(&dict, "SSID",
599                                         request_input_append_ssid, NULL);
600         }
601
602         if (__connman_service_get_security(service) ==
603                         CONNMAN_SERVICE_SECURITY_8021X) {
604                 connman_dbus_dict_append_dict(&dict, "Identity",
605                                         request_input_append_identity, service);
606         }
607
608         if (__connman_service_get_security(service) !=
609                         CONNMAN_SERVICE_SECURITY_NONE) {
610                 connman_dbus_dict_append_dict(&dict, "Passphrase",
611                                         request_input_append_passphrase, service);
612
613                 previous_passphrase_handler(&dict, service);
614         }
615
616         if (__connman_service_wps_enabled(service) == TRUE) {
617             connman_dbus_dict_append_dict(&dict, "WPS",
618                                 request_input_append_wps, NULL);
619         }
620
621         connman_dbus_dict_close(&iter, &dict);
622
623         passphrase_reply = g_try_new0(struct request_input_reply, 1);
624         if (passphrase_reply == NULL) {
625                 dbus_message_unref(message);
626                 return -ENOMEM;
627         }
628
629         passphrase_reply->service = connman_service_ref(service);
630         passphrase_reply->callback = callback;
631         passphrase_reply->user_data = user_data;
632
633         err = agent_queue_message(service, message,
634                         connman_timeout_input_request(),
635                         request_input_passphrase_reply,
636                         passphrase_reply);
637
638         if (err < 0 && err != -EBUSY) {
639                 DBG("error %d sending agent message", err);
640                 connman_service_unref(service);
641                 dbus_message_unref(message);
642                 g_free(passphrase_reply);
643                 return err;
644         }
645
646         dbus_message_unref(message);
647
648         return -EINPROGRESS;
649 }
650
651 int __connman_agent_request_login_input(struct connman_service *service,
652                                 authentication_cb_t callback, void *user_data)
653 {
654         DBusMessage *message;
655         const char *path;
656         DBusMessageIter iter;
657         DBusMessageIter dict;
658         struct request_input_reply *username_password_reply;
659         int err;
660
661         if (service == NULL || agent_path == NULL || callback == NULL)
662                 return -ESRCH;
663
664         message = dbus_message_new_method_call(agent_sender, agent_path,
665                                         CONNMAN_AGENT_INTERFACE,
666                                         "RequestInput");
667         if (message == NULL)
668                 return -ENOMEM;
669
670         dbus_message_iter_init_append(message, &iter);
671
672         path = __connman_service_get_path(service);
673         dbus_message_iter_append_basic(&iter,
674                                 DBUS_TYPE_OBJECT_PATH, &path);
675
676         connman_dbus_dict_open(&iter, &dict);
677
678         connman_dbus_dict_append_dict(&dict, "Username",
679                                 request_input_append_identity, service);
680
681         connman_dbus_dict_append_dict(&dict, "Password",
682                                 request_input_append_password, service);
683
684         connman_dbus_dict_close(&iter, &dict);
685
686         username_password_reply = g_try_new0(struct request_input_reply, 1);
687         if (username_password_reply == NULL) {
688                 dbus_message_unref(message);
689                 return -ENOMEM;
690         }
691
692         username_password_reply->service = connman_service_ref(service);
693         username_password_reply->callback = callback;
694         username_password_reply->user_data = user_data;
695
696         err = agent_queue_message(service, message,
697                         connman_timeout_input_request(),
698                         request_input_login_reply, username_password_reply);
699         if (err < 0 && err != -EBUSY) {
700                 DBG("error %d sending agent request", err);
701                 connman_service_unref(service);
702                 dbus_message_unref(message);
703                 g_free(username_password_reply);
704                 return err;
705         }
706
707         dbus_message_unref(message);
708
709         return -EINPROGRESS;
710 }
711
712 struct request_browser_reply_data {
713         struct connman_service *service;
714         browser_authentication_cb_t callback;
715         void *user_data;
716 };
717
718 static void request_browser_reply(DBusMessage *reply, void *user_data)
719 {
720         struct request_browser_reply_data *browser_reply_data = user_data;
721         connman_bool_t result = FALSE;
722         const char *error = NULL;
723
724         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
725                 error = dbus_message_get_error_name(reply);
726                 goto done;
727         }
728
729         result = TRUE;
730
731 done:
732         browser_reply_data->callback(browser_reply_data->service, result,
733                                         error, browser_reply_data->user_data);
734         connman_service_unref(browser_reply_data->service);
735         g_free(browser_reply_data);
736 }
737
738 int __connman_agent_request_browser(struct connman_service *service,
739                                 browser_authentication_cb_t callback,
740                                 const char *url, void *user_data)
741 {
742         struct request_browser_reply_data *browser_reply_data;
743         DBusMessage *message;
744         DBusMessageIter iter;
745         const char *path;
746         int err;
747
748         if (service == NULL || agent_path == NULL || callback == NULL)
749                 return -ESRCH;
750
751         if (url == NULL)
752                 url = "";
753
754         message = dbus_message_new_method_call(agent_sender, agent_path,
755                                         CONNMAN_AGENT_INTERFACE,
756                                         "RequestBrowser");
757         if (message == NULL)
758                 return -ENOMEM;
759
760         dbus_message_iter_init_append(message, &iter);
761
762         path = __connman_service_get_path(service);
763         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
764
765         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &url);
766
767         browser_reply_data = g_try_new0(struct request_browser_reply_data, 1);
768         if (browser_reply_data == NULL) {
769                 dbus_message_unref(message);
770                 return -ENOMEM;
771         }
772
773         browser_reply_data->service = connman_service_ref(service);
774         browser_reply_data->callback = callback;
775         browser_reply_data->user_data = user_data;
776
777         err = agent_queue_message(service, message,
778                         connman_timeout_browser_launch(),
779                         request_browser_reply, browser_reply_data);
780
781         if (err < 0 && err != -EBUSY) {
782                 DBG("error %d sending browser request", err);
783                 connman_service_unref(service);
784                 dbus_message_unref(message);
785                 g_free(browser_reply_data);
786                 return err;
787         }
788
789         dbus_message_unref(message);
790
791         return -EINPROGRESS;
792 }
793
794 struct report_error_data {
795         struct connman_service *service;
796         report_error_cb_t callback;
797         void *user_data;
798 };
799
800 static void report_error_reply(DBusMessage *reply, void *user_data)
801 {
802         struct report_error_data *report_error = user_data;
803         gboolean retry = FALSE;
804         const char *dbus_err;
805
806         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
807                 dbus_err = dbus_message_get_error_name(reply);
808                 if (dbus_err != NULL &&
809                         strcmp(dbus_err,
810                                 CONNMAN_AGENT_INTERFACE ".Error.Retry") == 0)
811                         retry = TRUE;
812         }
813
814         report_error->callback(report_error->service, retry,
815                         report_error->user_data);
816         connman_service_unref(report_error->service);
817         g_free(report_error);
818 }
819
820 int __connman_agent_report_error(struct connman_service *service,
821                                 const char *error,
822                                 report_error_cb_t callback, void *user_data)
823 {
824         DBusMessage *message;
825         DBusMessageIter iter;
826         const char *path;
827         struct report_error_data *report_error;
828         int err;
829
830         if (service == NULL || agent_path == NULL || error == NULL ||
831                 callback == NULL)
832                 return -ESRCH;
833
834         message = dbus_message_new_method_call(agent_sender, agent_path,
835                                         CONNMAN_AGENT_INTERFACE,
836                                         "ReportError");
837         if (message == NULL)
838                 return -ENOMEM;
839
840         dbus_message_iter_init_append(message, &iter);
841
842         path = __connman_service_get_path(service);
843         dbus_message_iter_append_basic(&iter,
844                                 DBUS_TYPE_OBJECT_PATH, &path);
845         dbus_message_iter_append_basic(&iter,
846                                 DBUS_TYPE_STRING, &error);
847
848         report_error = g_try_new0(struct report_error_data, 1);
849         if (report_error == NULL) {
850                 dbus_message_unref(message);
851                 return -ENOMEM;
852         }
853
854         report_error->service = connman_service_ref(service);
855         report_error->callback = callback;
856         report_error->user_data = user_data;
857
858         err = agent_queue_message(service, message,
859                         connman_timeout_input_request(),
860                         report_error_reply, report_error);
861         if (err < 0 && err != -EBUSY) {
862                 DBG("error %d sending error request", err);
863                 connman_service_unref(service);
864                 g_free(report_error);
865                 dbus_message_unref(message);
866                 return -ESRCH;
867         }
868
869         dbus_message_unref(message);
870
871         return -EINPROGRESS;
872 }
873
874 int __connman_agent_init(void)
875 {
876         DBG("");
877
878         connection = connman_dbus_get_connection();
879         if (connection == NULL)
880                 return -1;
881
882         return 0;
883 }
884
885 void __connman_agent_cleanup(void)
886 {
887         DBusMessage *message;
888
889         DBG("");
890
891         if (connection == NULL)
892                 return;
893
894         if (agent_watch > 0)
895                 g_dbus_remove_watch(connection, agent_watch);
896
897         if (agent_path == NULL)
898                 return;
899
900         message = dbus_message_new_method_call(agent_sender, agent_path,
901                                         CONNMAN_AGENT_INTERFACE, "Release");
902         if (message == NULL)
903                 return;
904
905         dbus_message_set_no_reply(message, TRUE);
906
907         g_dbus_send_message(connection, message);
908
909         agent_free();
910
911         dbus_connection_unref(connection);
912 }