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