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