ec79fca3baab7debf484df4f17e208f116a24102
[profile/ivi/gsignond.git] / src / daemon / gsignond-signonui-proxy.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2013 Intel Corporation.
7  *
8  * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include "gsignond-signonui-proxy.h"
27 #include <gsignond/gsignond-log.h>
28 #include <gsignond/gsignond-signonui.h>
29 #include "dbus/gsignond-dbus-signonui-adapter.h"
30
31 static void _process_next_request (GSignondSignonuiProxy *proxy);
32 static void _on_refresh_request (GSignondSignonuiProxy *proxy,
33                                  gchar *request_id, gpointer userdata);
34
35 typedef struct {
36     GObject *caller;
37     GSignondSignonuiData *ui_data;
38     GSignondSignonuiProxyQueryDialogCb cb;
39     GSignondSignonuiProxyRefreshCb refresh_cb;
40     gpointer userdata;
41 } _UIQueryRequest;
42
43 typedef struct {
44     GSignondSignonuiProxyRefreshDialogCb cb;
45     gpointer userdata;
46 } _UIRefreshRequest;
47
48 typedef struct {
49     GSignondSignonuiProxyCancelRequestCb cb;
50     gpointer userdata;
51 } _UICancelRequest;
52
53 struct _GSignondSignonuiProxyPrivate
54 {
55     GSignondDbusSignonuiAdapter *signonui;
56     _UIQueryRequest *active_request; /* Active dialog */
57     GQueue *request_queue;           /* request queue */
58     gboolean is_idle;
59 };
60
61 G_DEFINE_TYPE (GSignondSignonuiProxy, gsignond_signonui_proxy, G_TYPE_OBJECT);
62 #define GSIGNOND_SIGNONUI_PROXY_GET_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_SIGNONUI_PROXY, GSignondSignonuiProxyPrivate)
63
64 static _UIQueryRequest *
65 _ui_query_request_new (GObject *caller,
66                        GSignondSignonuiData *ui_data,
67                        GSignondSignonuiProxyQueryDialogCb cb,
68                        GSignondSignonuiProxyRefreshCb refresh_cb,
69                        gpointer userdata)
70 {
71     _UIQueryRequest *req = g_new0(_UIQueryRequest, 1);
72
73     req->caller = caller;
74     req->ui_data = gsignond_signonui_data_ref (ui_data);
75     req->cb = cb;
76     req->refresh_cb = refresh_cb;
77     req->userdata = userdata;
78
79     return req;
80 }
81
82 static _UIRefreshRequest *
83 _ui_refresh_request_new (GSignondSignonuiProxyRefreshDialogCb cb, gpointer userdata)
84 {
85     _UIRefreshRequest *req = g_new0(_UIRefreshRequest, 1);
86         
87     req->cb = cb;
88     req->userdata = userdata;
89
90     return req;
91 }
92
93 static _UICancelRequest *
94 _ui_cancel_request_new (GSignondSignonuiProxyCancelRequestCb cb, gpointer userdata)
95 {
96     _UICancelRequest *req = g_new0(_UICancelRequest, 1);
97
98     req->cb = cb;
99     req->userdata = userdata;
100
101     return req;
102 }
103
104 static void
105 _ui_query_request_free (_UIQueryRequest *req)
106 {
107     if (!req) return;
108     if (req->ui_data) gsignond_signonui_data_unref (req->ui_data);
109     g_free (req);
110 }
111
112 static void
113 _dispose (GObject *object)
114 {
115     GSignondSignonuiProxy *self = GSIGNOND_SIGNONUI_PROXY (object);
116
117     if (self->priv->signonui) {
118         g_object_unref (self->priv->signonui);
119         self->priv->signonui = NULL;
120     }
121
122     G_OBJECT_CLASS (gsignond_signonui_proxy_parent_class)->dispose (object);
123 }
124
125 static void
126 _finalize (GObject *object)
127 {
128     GSignondSignonuiProxy *self = GSIGNOND_SIGNONUI_PROXY (object);
129
130     if (self->priv->request_queue) {
131         g_queue_free_full (self->priv->request_queue, (GDestroyNotify)_ui_query_request_free);
132         self->priv->request_queue = NULL;
133     }
134
135     G_OBJECT_CLASS (gsignond_signonui_proxy_parent_class)->finalize (object);
136 }
137
138 static void
139 gsignond_signonui_proxy_class_init (GSignondSignonuiProxyClass *klass)
140 {
141     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
142
143     g_type_class_add_private (gobject_class, sizeof (GSignondSignonuiProxyPrivate));
144     
145     gobject_class->dispose = _dispose;
146     gobject_class->finalize = _finalize;
147 }
148
149 static void
150 gsignond_signonui_proxy_init (GSignondSignonuiProxy *proxy)
151 {
152     proxy->priv = GSIGNOND_SIGNONUI_PROXY_GET_PRIV (proxy);
153
154     proxy->priv->signonui = gsignond_dbus_signonui_adapter_new ();
155
156     if (proxy->priv->signonui)
157         g_signal_connect_swapped (proxy->priv->signonui, "refresh", G_CALLBACK(_on_refresh_request), proxy);
158     proxy->priv->active_request = NULL;
159     proxy->priv->request_queue = g_queue_new ();
160     proxy->priv->is_idle = TRUE;
161 }
162
163 static void
164 _on_refresh_request (GSignondSignonuiProxy *proxy, gchar *request_id, gpointer userdata)
165 {
166     _UIQueryRequest *req = proxy->priv->active_request;
167
168     if (req && !g_strcmp0 (G_OBJECT_TYPE_NAME (req->caller), request_id)) {
169        if (req->refresh_cb) req->refresh_cb(req->ui_data, req->userdata);
170     }
171     else {
172         WARN("UI-Error: unhandled refresh request");
173     }
174 }
175
176 static void
177 _query_dialog_cb (GVariant *reply, GError *error, gpointer user_data)
178 {
179     GSignondSignonuiProxy *proxy = GSIGNOND_SIGNONUI_PROXY (user_data);
180
181     _UIQueryRequest *req = proxy->priv->active_request;
182
183     if (req && req->cb) 
184         req->cb (gsignond_signonui_data_new_from_variant (reply), error, req->userdata);
185     else if (error) {
186         WARN ("UI-Error: %s", error->message);
187         g_error_free (error);
188     }
189
190     _ui_query_request_free (req);
191
192     proxy->priv->active_request = NULL;
193
194     _process_next_request (proxy);
195 }
196
197 static void
198 _process_next_request (GSignondSignonuiProxy *proxy)
199 {
200     _UIQueryRequest *req = g_queue_pop_head (proxy->priv->request_queue);
201
202     if (!req) {
203         proxy->priv->is_idle = TRUE;
204         proxy->priv->active_request = NULL;
205         return;
206     }
207
208     proxy->priv->active_request = req;
209
210     /* update request id */
211     gsignond_signonui_data_set_request_id (req->ui_data, G_OBJECT_TYPE_NAME(req->caller));
212     gsignond_dbus_signonui_adapter_query_dialog (proxy->priv->signonui, 
213             gsignond_signonui_data_to_variant(req->ui_data), _query_dialog_cb, proxy);
214
215     proxy->priv->is_idle = FALSE;
216 }
217
218 gboolean
219 gsignond_signonui_proxy_query_dialog (GSignondSignonuiProxy *proxy,
220                                       GObject *caller,
221                                       GSignondSignonuiData *ui_data,
222                                       GSignondSignonuiProxyQueryDialogCb cb,
223                                       GSignondSignonuiProxyRefreshCb refresh_cb,
224                                       gpointer userdata)
225 {
226
227     g_queue_push_tail (proxy->priv->request_queue, 
228             _ui_query_request_new (caller, ui_data, cb, refresh_cb, userdata));
229
230     if (proxy->priv->is_idle) _process_next_request (proxy);
231
232     return TRUE;
233 }
234
235 static void
236 _refresh_dialog_cb (GError *error, gpointer user_data)
237 {
238     _UIRefreshRequest *req = (_UIRefreshRequest *)user_data;
239
240     if (req && req->cb){
241         req->cb(error, req->userdata);
242     } else if (error) {
243         WARN ("UI-Error : %s", error->message);
244         g_error_free (error);
245     }
246
247     g_free (req);
248 }
249
250 gboolean
251 gsignond_signonui_proxy_refresh_dialog (GSignondSignonuiProxy *proxy,
252                                         GObject *caller,
253                                         GSignondSignonuiData *ui_data,
254                                         GSignondSignonuiProxyRefreshDialogCb cb,
255                                         gpointer userdata)
256 {
257     if (proxy->priv->active_request
258         && proxy->priv->active_request->caller == caller) {
259         _UIRefreshRequest *req = _ui_refresh_request_new (cb, userdata);
260
261         /* FIXME: Is it required to set refresh id for refresh data */
262         gsignond_signonui_data_set_request_id (ui_data, G_OBJECT_TYPE_NAME(caller));
263         gsignond_dbus_signonui_adapter_refresh_dialog (proxy->priv->signonui,
264                 gsignond_signonui_data_to_variant (ui_data), _refresh_dialog_cb, req);
265
266         return TRUE;
267     }
268
269     return FALSE;
270 }
271
272 static void
273 _cancel_request_cb (GError *error, gpointer user_data)
274 {
275     _UICancelRequest *req = (_UICancelRequest*)user_data;
276
277     if (req && req->cb)
278         req->cb (error, req->userdata);
279     else if (error) {
280         WARN ("UI-Error : %s", error->message);
281         g_error_free (error);
282     }
283
284     g_free (req);
285 }
286
287 static gint
288 _find_request_by_caller (gconstpointer a, gconstpointer b)
289 {
290     _UIQueryRequest *req = (_UIQueryRequest *)a;
291     
292     return (req && req->caller == b) ? 0 : 1;
293 }
294
295 gboolean
296 gsignond_signonui_proxy_cancel_request (GSignondSignonuiProxy *proxy,
297                                         GObject *caller, 
298                                         GSignondSignonuiProxyCancelRequestCb cb,
299                                         gpointer userdata)
300 {
301     GList *element = NULL;
302     _UIQueryRequest *req = NULL;
303     /* if no active request to cacel */
304     if (!proxy->priv->active_request) return FALSE;
305
306     /* cancel active request */
307     if (proxy->priv->active_request->caller == caller) {
308         _UICancelRequest *req = _ui_cancel_request_new (cb, userdata);
309         gsignond_dbus_signonui_adapter_cancel_request (proxy->priv->signonui,
310             G_OBJECT_TYPE_NAME (caller), _cancel_request_cb, req);
311         return TRUE;
312     }
313
314     /* cancel pending request */
315     element = g_queue_find_custom (proxy->priv->request_queue, caller, _find_request_by_caller);
316
317     if (!element) return FALSE;
318     req = element->data;
319
320      if (req->cb) {
321         gsignond_signonui_data_ref (req->ui_data);
322         gsignond_signonui_data_set_query_error(req->ui_data, SIGNONUI_ERROR_CANCELED);
323
324         req->cb (req->ui_data, NULL, req->userdata);
325     }
326
327     if (cb) cb(NULL, userdata);
328
329     return TRUE;
330 }
331
332 GSignondSignonuiProxy *
333 gsignond_signonui_proxy_new ()
334 {
335     return g_object_new (GSIGNOND_TYPE_SIGNONUI_PROXY, NULL);
336 }