Merge "Invoke HAL_DISCOVERY_STATE_STOPPED event once" into tizen
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / bluez_hal / src / bt-hal-gap-agent.c
1 /*
2  * BLUETOOTH HAL
3  *
4  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Anupam Roy <anupam.r@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <vconf.h>
26 #include <vconf-keys.h>
27
28 #include  <bt-hal-gap-agent.h>
29 #include  <bt-hal-agent.h>
30 #include  <bt-hal-internal.h>
31
32 #include "bt-hal.h"
33 #include "bt-hal-log.h"
34 #include "bt-hal-msg.h"
35 #include "bt-hal-utils.h"
36
37 #include <glib.h>
38 #include <gio/gio.h>
39 #include <dlog.h>
40
41 #include "bt-hal-adapter-dbus-handler.h"
42 #include "bt-hal-dbus-common-utils.h"
43
44 static GDBusConnection *connection = NULL;
45
46 typedef enum {
47         GAP_AGENT_ERROR_REJECT,
48         GAP_AGENT_ERROR_CANCEL,
49         GAP_AGENT_ERROR_TIMEOUT,
50 } GapAgentError;
51
52 #define AGENT_ALREADY_EXIST 0x24
53
54 #define GAP_AGENT_ERROR (gap_agent_error_quark())
55
56 static GQuark gap_agent_error_quark(void)
57 {
58         static GQuark quark = 0;
59         if (!quark)
60                 quark = g_quark_from_static_string("agent");
61
62         return quark;
63 }
64
65
66 /* Forward declaration */
67 static gboolean __gap_agent_unregister(GapAgentPrivate *agent);
68 static GDBusNodeInfo *__bt_service_create_method_node_info
69 (const gchar *introspection_data);
70 static void __bt_gap_agent_method(GDBusConnection *connection,
71                 const gchar *sender,
72                 const gchar *object_path,
73                 const gchar *interface_name,
74                 const gchar *method_name,
75                 GVariant *parameters,
76                 GDBusMethodInvocation *invocation,
77                 gpointer user_data);
78 void _gap_agent_set_canceled(GapAgentPrivate *agent, gboolean value);
79
80 static gint gap_agent_id = -1;
81
82 #ifdef TIZEN_BT_HAL
83 static void __bt_hal_free_osp_server(gpointer data)
84 {
85         bt_hal_agent_osp_server_t *server = data;
86
87         if (!server)
88                 return;
89
90         g_free(server->uuid);
91         g_free(server->path);
92         g_free(server);
93 }
94
95 static void __bt_hal_gap_agent_remove_osp_servers(GSList *osp_servers)
96 {
97         if (!osp_servers) {
98                 ERR("osp_servers is NULL");
99                 return;
100
101         }
102
103         g_slist_free_full(osp_servers, __bt_hal_free_osp_server);
104 }
105 #endif
106
107 gboolean _gap_agent_register(GapAgentPrivate *agent)
108 {
109         GapAgentPrivate *priv = agent;
110         GDBusProxy *agent_manager;
111         GError *error = NULL;
112         GVariant *reply;
113
114         if (!priv)
115                 return FALSE;
116         if (!connection)
117                 return FALSE;
118
119         if (priv->agent_manager == NULL) {
120                 agent_manager = g_dbus_proxy_new_sync(connection,
121                                 G_DBUS_PROXY_FLAGS_NONE, NULL,
122                                 BT_HAL_BLUEZ_NAME, BT_HAL_BLUEZ_PATH,
123                                 BT_HAL_AGENT_MANAGER_INTERFACE, NULL, &error);
124                 if (!agent_manager) {
125                         if (error) {
126                                 ERR("Unable to create proxy: %s", error->message);
127                                 g_clear_error(&error);
128                         }
129                         return FALSE;
130                 }
131         } else {
132                 agent_manager = priv->agent_manager;
133         }
134
135         reply = g_dbus_proxy_call_sync(agent_manager, "RegisterAgent",
136 #ifdef TIZEN_BT_IO_CAPA_NO_INPUT_OUTPUT
137                         g_variant_new("(os)", priv->path, "NoInputNoOutput"),
138 #else
139                         g_variant_new("(os)", priv->path, "DisplayYesNo"),
140 #endif
141                         G_DBUS_CALL_FLAGS_NONE, -1,
142                         NULL, &error);
143         if (reply == NULL) {
144                 ERR("Agent registration failed");
145                 if (error) {
146                         ERR("Agent registration failed: errCode[%x], message[%s]",
147                                         error->code, error->message);
148
149                         if (error->code == AGENT_ALREADY_EXIST) {
150                                 DBG("Agent is already registered");
151                                 g_clear_error(&error);
152                         } else {
153                                 g_clear_error(&error);
154                                 g_object_unref(agent_manager);
155                                 priv->agent_manager = NULL;
156                                 return FALSE;
157                         }
158                 }
159         }
160         g_variant_unref(reply);
161         reply = NULL;
162
163         /* Set the defalut agent */
164         DBG("agent_manager[%p] priv->path[%s]", agent_manager, priv->path);
165         reply = g_dbus_proxy_call_sync(agent_manager, "RequestDefaultAgent",
166                         g_variant_new("(o)", priv->path),
167                         G_DBUS_CALL_FLAGS_NONE, -1,
168                         NULL, &error);
169         if (reply == NULL) {
170                 ERR("Request Default Agent failed");
171                 if (error) {
172                         ERR("Request Default Agent failed: errCode[%x], message[%s]",
173                                         error->code, error->message);
174                         g_clear_error(&error);
175                 }
176                 g_object_unref(agent_manager);
177                 priv->agent_manager = NULL;
178                 return FALSE;
179         }
180         g_variant_unref(reply);
181
182         priv->agent_manager = agent_manager;
183
184         return TRUE;
185 }
186
187 static const gchar gap_agent_bluez_introspection_xml[] =
188 "<node name='/'>"
189 "  <interface name='org.bluez.Agent1'>"
190 "    <method name='RequestPinCode'>"
191 "      <arg type='o' name='device' direction='in'/>"
192 "      <arg type='s' name='pincode' direction='out'/>"
193 "    </method>"
194 "    <method name='RequestPasskey'>"
195 "      <arg type='o' name='device' direction='in'/>"
196 "      <arg type='u' name='passkey' direction='out'/>"
197 "    </method>"
198 "    <method name='DisplayPasskey'>"
199 "      <arg type='o' name='device' direction='in'/>"
200 "      <arg type='u' name='passkey' direction='in'/>"
201 "      <arg type='q' name='entered' direction='in'/>"
202 "    </method>"
203 "    <method name='RequestConfirmation'>"
204 "      <arg type='o' name='device' direction='in'/>"
205 "      <arg type='u' name='passkey' direction='in'/>"
206 "    </method>"
207 "    <method name='RequestAuthorization'>"
208 "      <arg type='o' name='device' direction='in'/>"
209 "    </method>"
210 "    <method name='AuthorizeService'>"
211 "      <arg type='o' name='device' direction='in'/>"
212 "      <arg type='s' name='uuid' direction='in'/>"
213 "    </method>"
214 "    <method name='Cancel'>"
215 "    </method>"
216 "    <method name='Release'>"
217 "    </method>"
218 "    <method name='ReplyPinCode'>"
219 "      <arg type='u' name='accept' direction='in'/>"
220 "      <arg type='s' name='pincode' direction='in'/>"
221 "    </method>"
222 "    <method name='ReplyPasskey'>"
223 "      <arg type='u' name='accept' direction='in'/>"
224 "      <arg type='s' name='passkey' direction='in'/>"
225 "    </method>"
226 "    <method name='ReplyConfirmation'>"
227 "      <arg type='u' name='accept' direction='in'/>"
228 "    </method>"
229 "    <method name='ReplyAuthorize'>"
230 "      <arg type='u' name='accept' direction='in'/>"
231 "    </method>"
232 "    <method name='ConfirmModeChange'>"
233 "      <arg type='s' name='mode' direction='in'/>"
234 "    </method>"
235 "    <method name='GetDiscoverableTimeout'>"
236 "      <arg type='u' name='timeout' direction='out'/>"
237 "    </method>"
238 "  </interface>"
239 "</node>";
240
241
242 static const GDBusInterfaceVTable method_table = {
243         __bt_gap_agent_method,
244         NULL,
245         NULL,
246 };
247
248 void _gap_agent_setup_dbus(GapAgentPrivate *agent, GAP_AGENT_FUNC_CB *func_cb,
249                 const char *path,
250                 GDBusProxy *adapter)
251 {
252         GapAgentPrivate *priv = agent;
253         GDBusProxy *proxy;
254         GDBusNodeInfo *node_info;
255         GError *error = NULL;
256
257         priv->path = g_strdup(path);
258
259         node_info = __bt_service_create_method_node_info(
260                         gap_agent_bluez_introspection_xml);
261         if (node_info == NULL)
262                 return;
263
264         DBG("path is [%s]", path);
265
266         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
267         if (!connection) {
268                 if (error) {
269                         ERR("Unable to connect to gdbus: %s", error->message);
270                         g_clear_error(&error);
271                 }
272                 return;
273         }
274
275         if (gap_agent_id == -1) {
276                 gap_agent_id = g_dbus_connection_register_object(connection, path,
277                                 node_info->interfaces[0],
278                                 &method_table, priv,
279                                 NULL, &error);
280         }
281
282         g_dbus_node_info_unref(node_info);
283
284         if (gap_agent_id == 0) {
285                 ERR("Failed to register for Path: %s", path);
286                 if (error) {
287                         ERR("Failed to register: %s", error->message);
288                         g_clear_error(&error);
289                 }
290                 return;
291         }
292
293         memcpy(&priv->cb, func_cb, sizeof(GAP_AGENT_FUNC_CB));
294
295         priv->exec_type = GAP_AGENT_EXEC_NO_OPERATION;
296         memset(priv->pairing_addr, 0x00, sizeof(priv->pairing_addr));
297         memset(priv->authorize_addr, 0x00, sizeof(priv->authorize_addr));
298         priv->reply_context = NULL;
299
300         DBG("path: %s", path);
301
302         proxy =  g_dbus_proxy_new_sync(connection,
303                         G_DBUS_PROXY_FLAGS_NONE, NULL,
304                         BT_HAL_BLUEZ_NAME, path,
305                         BT_HAL_AGENT_INTERFACE, NULL, &error);
306
307         if (!proxy) {
308                 ERR("Unable to create proxy");
309                 if (error) {
310                         ERR("Error: %s", error->message);
311                         g_clear_error(&error);
312                 }
313                 priv->busname = NULL;
314         } else {
315                 priv->busname = g_strdup(g_dbus_proxy_get_name(proxy));
316                 g_object_unref(proxy);
317                 DBG("Busname: %s", priv->busname);
318         }
319 }
320
321 void _gap_agent_reset_dbus(GapAgentPrivate *agent)
322 {
323         GapAgentPrivate *priv = agent;
324
325         /* Fix : NULL_RETURNS */
326         if (priv == NULL)
327                 return ;
328
329         __gap_agent_unregister(agent);
330
331         if (gap_agent_id > 0) {
332
333                 if (connection)
334                         g_dbus_connection_unregister_object(connection,
335                                         gap_agent_id);
336                 gap_agent_id = -1;
337         }
338
339 #ifdef TIZEN_BT_HAL
340         if (priv->osp_servers)
341                 __bt_hal_gap_agent_remove_osp_servers(priv->osp_servers);
342 #endif
343
344         g_object_ref(priv->adapter);
345         priv->adapter = NULL;
346
347         g_free(priv->path);
348         priv->path = NULL;
349
350         g_free(priv->busname);
351         priv->busname = NULL;
352 }
353
354 gchar* _gap_agent_get_path(GapAgentPrivate *agent)
355 {
356         GapAgentPrivate *priv = agent;
357
358         /* Fix : NULL_RETURNS */
359         if (priv == NULL)
360                 return NULL;
361
362         return priv->path;
363 }
364
365 gboolean _gap_agent_is_canceled(GapAgentPrivate *agent)
366 {
367         GapAgentPrivate *priv = agent;
368
369         /* Fix : NULL_RETURNS */
370         if (priv == NULL)
371                 return  FALSE;
372
373         return priv->canceled;
374 }
375
376 void _gap_agent_set_canceled(GapAgentPrivate *agent, gboolean value)
377 {
378         GapAgentPrivate *priv = agent;
379
380         /* Fix : NULL_RETURNS */
381         if (priv == NULL)
382                 return;
383
384         priv->canceled = value;
385 }
386
387 static gboolean __gap_agent_unregister(GapAgentPrivate *agent)
388 {
389         GapAgentPrivate *priv = agent;
390         GDBusProxy *agent_manager;
391         GError *error = NULL;
392         GVariant *reply;
393
394         if (priv == NULL || priv->path == NULL || connection == NULL)
395                 return  FALSE;
396
397         if (priv->agent_manager == NULL) {
398                 agent_manager = g_dbus_proxy_new_sync(connection,
399                                 G_DBUS_PROXY_FLAGS_NONE, NULL,
400                                 BT_HAL_BLUEZ_NAME, BT_HAL_BLUEZ_PATH,
401                                 BT_HAL_AGENT_MANAGER_INTERFACE, NULL, &error);
402                 if (!agent_manager) {
403                         if (error) {
404                                 ERR("Unable to create proxy: %s", error->message);
405                                 g_clear_error(&error);
406                         }
407                         return FALSE;
408                 }
409         } else {
410                 agent_manager = priv->agent_manager;
411         }
412
413         reply = g_dbus_proxy_call_sync(agent_manager, "UnregisterAgent",
414                         g_variant_new("o", priv->path),
415                         G_DBUS_CALL_FLAGS_NONE, -1,
416                         NULL, &error);
417         g_object_unref(agent_manager);
418         priv->agent_manager = NULL;
419
420         if (reply == NULL) {
421                 ERR("Agent unregistration failed");
422                 if (error) {
423                         ERR("Agent unregistration failed: errCode[%x], message[%s]",
424                                         error->code, error->message);
425                         g_clear_error(&error);
426                 }
427                 return FALSE;
428         }
429         g_variant_unref(reply);
430
431         return TRUE;
432 }
433
434         static GDBusNodeInfo *__bt_service_create_method_node_info
435 (const gchar *introspection_data)
436 {
437         GError *err = NULL;
438         GDBusNodeInfo *node_info = NULL;
439
440         if (introspection_data == NULL)
441                 return NULL;
442
443         node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
444
445         if (err) {
446                 ERR("Unable to create node: %s", err->message);
447                 g_clear_error(&err);
448         }
449         return node_info;
450 }
451
452 static void __bt_gap_agent_method(GDBusConnection *connection,
453                         const gchar *sender,
454                         const gchar *object_path,
455                         const gchar *interface_name,
456                         const gchar *method_name,
457                         GVariant *parameters,
458                         GDBusMethodInvocation *invocation,
459                         gpointer user_data)
460 {
461         FN_START;
462
463         GError *err = NULL;
464         if (g_strcmp0(method_name, "RequestPinCode") == 0) {
465                 GapAgentPrivate *agent = user_data;
466                 GDBusProxy *device;
467                 char *addr;
468                 char *path;
469                 GDBusConnection *conn;
470
471                 if (sender == NULL)
472                         return;
473
474                 g_variant_get(parameters, "(&o)", &path);
475                 INFO("Request pin code, Device Path :%s", path);
476
477                 /* Need to check
478                    if (g_strcmp0(sender, agent->busname) != 0)
479                    return;
480                  */
481
482                 if (!agent->cb.passkey_func)
483                         return;
484                 conn = _bt_hal_get_system_gconn();
485                 if (conn == NULL)
486                         return;
487                 device = g_dbus_proxy_new_sync(conn,
488                                 G_DBUS_PROXY_FLAGS_NONE, NULL,
489                                 BT_HAL_BLUEZ_NAME, path,
490                                 BT_HAL_PROPERTIES_INTERFACE, NULL, &err);
491                 if (!device) {
492                         ERR("Fail to make device proxy");
493                         g_dbus_method_invocation_return_error(invocation,
494                                         GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
495                                         "No proxy for device");
496                         if (err) {
497                                 ERR("Unable to create proxy: %s", err->message);
498                                 g_clear_error(&err);
499                         }
500                         return;
501                 }
502
503                 agent->exec_type = GAP_AGENT_EXEC_PAIRING;
504                 agent->reply_context = invocation;
505
506                 addr = strstr(path, "dev_");
507                 if (addr != NULL) {
508                         char *pos = NULL;
509                         addr += 4;
510                         g_strlcpy(agent->pairing_addr, addr, sizeof(agent->pairing_addr));
511
512                         while ((pos = strchr(agent->pairing_addr, '_')) != NULL)
513                                 *pos = ':';
514                 }
515                 agent->cb.pincode_func(agent, device);
516                 g_object_unref(device);
517                 return;
518         } else if (g_strcmp0(method_name, "RequestPasskey") == 0) {
519                 GapAgentPrivate *priv = user_data;
520                 GDBusProxy *device;
521                 char *addr;
522                 char *path;
523                 GDBusConnection *conn;
524
525                 if (sender == NULL)
526                         return;
527
528                 g_variant_get(parameters, "(&o)", &path);
529                 INFO("Request passkey : sender %s priv->busname %s Device Path :%s",
530                                 sender, priv->busname, path);
531                 /* Need to check
532                    if (g_strcmp0(sender, agent->busname) != 0)
533                    return;
534                  */
535                 if (!priv->cb.passkey_func)
536                         return;
537                 conn = _bt_hal_get_system_gconn();
538                 if (conn == NULL)
539                         return;
540
541                 device = g_dbus_proxy_new_sync(conn,
542                                 G_DBUS_PROXY_FLAGS_NONE, NULL,
543                                 BT_HAL_BLUEZ_NAME, path,
544                                 BT_HAL_PROPERTIES_INTERFACE, NULL, &err);
545
546                 if (!device) {
547                         ERR("Fail to make device proxy");
548
549                         g_dbus_method_invocation_return_error(invocation,
550                                         GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
551                                         "No proxy for device");
552                         if (err) {
553                                 ERR("Unable to create proxy: %s", err->message);
554                                 g_clear_error(&err);
555                         }
556                         return;
557                 }
558                 priv->exec_type = GAP_AGENT_EXEC_PAIRING;
559                 priv->reply_context = invocation;
560
561                 addr = strstr(path, "dev_");
562                 if (addr != NULL) {
563                         char *pos = NULL;
564                         addr += 4;
565                         g_strlcpy(priv->pairing_addr, addr, sizeof(priv->pairing_addr));
566
567                         while ((pos = strchr(priv->pairing_addr, '_')) != NULL)
568                                 *pos = ':';
569                 }
570                 priv->cb.passkey_func(priv, device);
571                 g_object_unref(device);
572                 return;
573         } else if (g_strcmp0(method_name, "DisplayPasskey") == 0) {
574                 GapAgentPrivate *priv = user_data;
575                 GDBusProxy *device;
576                 guint passkey;
577                 guint16 entered;
578                 char *path;
579                 GDBusConnection *conn;
580
581                 if (sender == NULL)
582                         return;
583                 g_variant_get(parameters, "(&ouq)", &path, &passkey, &entered);
584                 INFO("Request passkey display :sender %s priv->busname %s"
585                                 " Device Path :%s, Passkey: %d, Entered: %d",
586                                 sender, priv->busname, path, passkey, entered);
587                 /* Do not show popup for Key event while typing*/
588                 if (entered)
589                         return;
590                 /* Need to check
591                    if (g_strcmp0(sender, agent->busname) != 0)
592                    return;
593                  */
594                 if (!priv->cb.display_func)
595                         return;
596
597                 conn = _bt_hal_get_system_gconn();
598                 if (conn == NULL)
599                         return;
600                 device = g_dbus_proxy_new_sync(conn,
601                                 G_DBUS_PROXY_FLAGS_NONE, NULL,
602                                 BT_HAL_BLUEZ_NAME, path,
603                                 BT_HAL_PROPERTIES_INTERFACE, NULL, &err);
604                 if (!device) {
605                         ERR("Fail to make device proxy");
606
607                         g_dbus_method_invocation_return_error(invocation,
608                                         GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
609                                         "No proxy for device");
610                         if (err) {
611                                 ERR("Unable to create proxy: %s", err->message);
612                                 g_clear_error(&err);
613                         }
614                         return;
615                 }
616                 g_dbus_method_invocation_return_value(invocation, NULL);
617                 priv->cb.display_func(priv, device, passkey);
618                 g_object_unref(device);
619                 return;
620         } else if (g_strcmp0(method_name, "RequestConfirmation") == 0) {
621                 GapAgentPrivate *priv = user_data;
622                 GDBusProxy *device;
623                 guint passkey;
624                 char *path;
625                 char *addr;
626                 GDBusConnection *conn;
627
628                 if (sender == NULL)
629                         return;
630
631                 g_variant_get(parameters, "(&ou)", &path, &passkey);
632                 INFO("Request passkey confirmation, Device Path :%s, Passkey: %d",
633                                 path, passkey);
634
635                 DBG("Sender: [%s] priv->busname: [%s]", sender, priv->busname);
636                 /* Need to check
637                    if (g_strcmp0(sender, agent->busname) != 0)
638                    return;
639                  */
640                 DBG("priv->cb.confirm_func [%p]", priv->cb.confirm_func);
641                 if (!priv->cb.confirm_func)
642                         return;
643                 conn = _bt_hal_get_system_gconn();
644                 if (conn == NULL)
645                         return;
646                 device = g_dbus_proxy_new_sync(conn,
647                                 G_DBUS_PROXY_FLAGS_NONE, NULL,
648                                 BT_HAL_BLUEZ_NAME, path,
649                                 BT_HAL_PROPERTIES_INTERFACE, NULL, &err);
650                 if (!device) {
651                         ERR("Fail to make device proxy");
652                         g_dbus_method_invocation_return_error(invocation,
653                                         GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
654                                         "No proxy for device");
655                         if (err) {
656                                 ERR("Unable to create proxy: %s", err->message);
657                                 g_clear_error(&err);
658                         }
659                         return;
660                 }
661                 priv->exec_type = GAP_AGENT_EXEC_PAIRING;
662                 priv->reply_context = invocation;
663                 addr = strstr(path, "dev_");
664                 if (addr != NULL) {
665                         char *pos = NULL;
666                         addr += 4;
667                         g_strlcpy(priv->pairing_addr, addr, sizeof(priv->pairing_addr));
668
669                         while ((pos = strchr(priv->pairing_addr, '_')) != NULL)
670                                 *pos = ':';
671                 }
672
673                 DBG("Pairing address [%s]", priv->pairing_addr);
674                 priv->cb.confirm_func(priv, device, passkey);
675                 g_object_unref(device);
676                 return;
677         } else if (g_strcmp0(method_name, "AuthorizeService") == 0) {
678                 GapAgentPrivate *priv = user_data;
679                 GDBusProxy *device;
680                 GDBusConnection *conn;
681                 char *addr;
682                 char *path;
683                 char *uuid;
684
685                 if (sender == NULL)
686                         return;
687
688                 g_variant_get(parameters, "(&o&s)", &path, &uuid);
689                 INFO("Request authorization :sender %s priv->busname %s "
690                                 "Device Path :%s UUID: %s",
691                                 sender, priv->busname, path, uuid);
692
693                 /* Need to check
694                    if (g_strcmp0(sender, agent->busname) != 0)
695                    return;
696                  */
697
698                 if (!priv->cb.authorize_func)
699                         return;
700
701                 conn = _bt_hal_get_system_gconn();
702                 if (conn == NULL)
703                         return;
704
705                 device = g_dbus_proxy_new_sync(conn,
706                                 G_DBUS_PROXY_FLAGS_NONE, NULL,
707                                 BT_HAL_BLUEZ_NAME, path,
708                                 BT_HAL_PROPERTIES_INTERFACE, NULL, &err);
709
710                 if (!device) {
711                         ERR("Fail to make device proxy");
712
713                         g_dbus_method_invocation_return_error(invocation,
714                                         GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
715                                         "No proxy for device");
716
717                         if (err) {
718                                 ERR("Unable to create proxy: %s", err->message);
719                                 g_clear_error(&err);
720                         }
721
722                         return;
723                 }
724
725                 priv->exec_type = GAP_AGENT_EXEC_AUTHORZATION;
726                 priv->reply_context = invocation;
727
728                 addr = strstr(path, "dev_");
729                 if (addr != NULL) {
730                         char *pos = NULL;
731                         addr += 4;
732                         g_strlcpy(priv->authorize_addr, addr,
733                                         sizeof(priv->authorize_addr));
734
735                         while ((pos = strchr(priv->authorize_addr, '_')) != NULL)
736                                 *pos = ':';
737                 }
738
739                 priv->cb.authorize_func(priv, device, uuid);
740
741                 g_object_unref(device);
742                 return;
743         } else if (g_strcmp0(method_name, "RequestAuthorization") == 0) {
744                 g_dbus_method_invocation_return_value(invocation, NULL);
745         } else if (g_strcmp0(method_name, "ConfirmModeChange") == 0) {
746                 g_dbus_method_invocation_return_value(invocation, NULL);
747         } else if (g_strcmp0(method_name, "Cancel") == 0) {
748                 GapAgentPrivate *priv = user_data;
749
750                 if (sender == NULL)
751                         return;
752                 INFO("Cancelled : agent %p sender %p", priv, sender);
753                 /* Need to check
754                    if (g_strcmp0(sender, agent->busname) != 0)
755                    return;
756                  */
757                 if (priv->cb.authorization_cancel_func &&
758                                 priv->exec_type == GAP_AGENT_EXEC_AUTHORZATION) {
759                         DBG("Call GAP agent cancel Authorization method.");
760                         priv->cb.authorization_cancel_func(priv,
761                                         priv->authorize_addr);
762                         memset(priv->authorize_addr, 0x00,
763                                         sizeof(priv->authorize_addr));
764                 } else if (priv->cb.pairing_cancel_func &&
765                                 priv->exec_type == GAP_AGENT_EXEC_PAIRING) {
766                         DBG("Call GAP agent cancel Pairing method.");
767                         priv->cb.pairing_cancel_func(priv,
768                                         priv->pairing_addr);
769                         memset(priv->pairing_addr, 0x00, sizeof(priv->pairing_addr));
770                 }
771                 if (priv->exec_type != GAP_AGENT_EXEC_CONFIRM_MODE &&
772                                 priv->exec_type != GAP_AGENT_EXEC_NO_OPERATION &&
773                                 priv->reply_context != NULL) {
774
775                         g_dbus_method_invocation_return_error(priv->reply_context,
776                                         GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
777                                         "Rejected by remote cancel");
778                 }
779
780                 /* Canceled flag is set when user cancels pairing request
781                  * Since here bluez has cancelled pairing request, we set the flag to false
782                  */
783                 priv->canceled = FALSE;
784                 priv->exec_type = GAP_AGENT_EXEC_NO_OPERATION;
785                 priv->reply_context = NULL;
786                 return;
787         } else if (g_strcmp0(method_name, "Release") == 0) {
788                 GapAgentPrivate *priv = user_data;
789
790                 if (sender == NULL)
791                         return;
792
793                 INFO("Released : sender %s\n", sender);
794
795                 /* Need to check
796                 if (g_strcmp0(sender, agent->busname) != 0)
797                         return;
798                  */
799
800                 g_dbus_method_invocation_return_value(invocation, NULL);
801
802                 if (priv) {
803                         priv->exec_type = GAP_AGENT_EXEC_NO_OPERATION;
804                         priv->reply_context = NULL;
805
806                         memset(priv->pairing_addr, 0x00, sizeof(priv->pairing_addr));
807                         memset(priv->authorize_addr, 0x00, sizeof(priv->authorize_addr));
808                 }
809                 return;
810         } else if (g_strcmp0(method_name, "GetDiscoverableTimeout") == 0) {
811                 /* TODO */
812         } else if (g_strcmp0(method_name, "ReplyPinCode") == 0) {
813                 GapAgentPrivate *priv = user_data;
814                 const char *pin_code;
815                 guint accept;
816
817                 g_variant_get(parameters, "(u&s)", &accept, &pin_code);
818                 INFO("Accept: %d PinCode: %s", accept, pin_code);
819                 gap_agent_reply_pin_code(priv, accept, pin_code, invocation);
820         } else if (g_strcmp0(method_name, "ReplyPasskey") == 0) {
821                 GapAgentPrivate *priv = user_data;
822                 const char *passkey;
823                 guint accept;
824
825                 g_variant_get(parameters, "(u&s)", &accept, &passkey);
826                 INFO("Accept: %d PinCode: %s", accept, passkey);
827                 gap_agent_reply_passkey(priv, accept, passkey, invocation);
828         } else if (g_strcmp0(method_name, "ReplyConfirmation") == 0) {
829                 GapAgentPrivate *priv = user_data;
830                 guint accept;
831
832                 g_variant_get(parameters, "(u)", &accept);
833                 INFO("Accept: %d", accept);
834                 gap_agent_reply_confirmation(priv, accept, invocation);
835         } else if (g_strcmp0(method_name, "ReplyAuthorize") == 0) {
836                 GapAgentPrivate *priv = user_data;
837                 guint accept;
838
839                 g_variant_get(parameters, "(u)", &accept);
840                 INFO("Accept: %d", accept);
841                 gap_agent_reply_authorize(priv, accept, invocation);
842         } else {
843                 ERR("Invalid method[%s] Object Path[%s] Interface Name[%s]",
844                         method_name, object_path, interface_name);
845         }
846 }
847
848 gboolean gap_agent_reply_confirmation(GapAgentPrivate *agent, const guint accept,
849                 GDBusMethodInvocation *context)
850 {
851         GapAgentPrivate *priv = agent;
852
853         /* Fix : NULL_RETURNS */
854         if (priv == NULL)
855                 return FALSE;
856
857         if (priv->exec_type != GAP_AGENT_EXEC_NO_OPERATION &&
858                         priv->reply_context != NULL) {
859                 if (accept == GAP_AGENT_ACCEPT || accept == GAP_AGENT_ACCEPT_ALWAYS) {
860                         g_dbus_method_invocation_return_value(priv->reply_context, NULL);
861                         priv->canceled = FALSE;
862                 } else {
863                         switch (accept) {
864                         case GAP_AGENT_CANCEL:
865                                 g_dbus_method_invocation_return_error(priv->reply_context,
866                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_CANCEL,
867                                                 "CanceledbyUser");
868                                 priv->canceled = TRUE;
869                                 break;
870                         case GAP_AGENT_TIMEOUT:
871                         case GAP_AGENT_REJECT:
872                         default:
873                                 g_dbus_method_invocation_return_error(priv->reply_context,
874                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
875                                                 "Confirmation request rejected");
876                                 priv->canceled = FALSE;
877                                 break;
878                         }
879                 }
880         }
881
882         priv->exec_type = GAP_AGENT_EXEC_NO_OPERATION;
883         priv->reply_context = NULL;
884         memset(priv->pairing_addr, 0x00, sizeof(priv->pairing_addr));
885
886         return TRUE;
887 }
888
889 gboolean gap_agent_reply_pin_code(GapAgentPrivate *agent, const guint accept,
890                 const char *pin_code,
891                 GDBusMethodInvocation *context)
892 {
893         GapAgentPrivate *priv = agent;
894
895         /* Fix : NULL_RETURNS */
896         if (priv == NULL)
897                 return FALSE;
898
899         if (priv->exec_type != GAP_AGENT_EXEC_NO_OPERATION &&
900                         priv->reply_context != NULL) {
901                 if (accept == GAP_AGENT_ACCEPT) {
902                         g_dbus_method_invocation_return_value(priv->reply_context,
903                                         g_variant_new("(s)", pin_code));
904                         priv->canceled = FALSE;
905                 } else {
906                         switch (accept) {
907                         case GAP_AGENT_CANCEL:
908                                 g_dbus_method_invocation_return_error(priv->reply_context,
909                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_CANCEL,
910                                                 "CanceledbyUser");
911                                 priv->canceled = TRUE;
912                                 break;
913                         case GAP_AGENT_TIMEOUT:
914                         case GAP_AGENT_REJECT:
915                         default:
916                                 g_dbus_method_invocation_return_error(priv->reply_context,
917                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
918                                                 "Pairing request rejected");
919                                 priv->canceled = FALSE;
920                                 break;
921                         }
922                 }
923         }
924         priv->exec_type = GAP_AGENT_EXEC_NO_OPERATION;
925         priv->reply_context = NULL;
926         memset(priv->pairing_addr, 0x00, sizeof(priv->pairing_addr));
927
928         return TRUE;
929 }
930
931 gboolean gap_agent_reply_passkey(GapAgentPrivate *agent, const guint accept,
932                 const char *passkey,
933                 GDBusMethodInvocation *context)
934 {
935         GapAgentPrivate *priv = agent;
936
937         /* Fix : NULL_RETURNS */
938         if (priv == NULL)
939                 return FALSE;
940
941         if (priv->exec_type != GAP_AGENT_EXEC_NO_OPERATION &&
942                         priv->reply_context != NULL) {
943                 if (accept == GAP_AGENT_ACCEPT) {
944                         guint pass_key = atoi(passkey);
945                         g_dbus_method_invocation_return_value(priv->reply_context,
946                                         g_variant_new("(u)", pass_key));
947                         priv->canceled = FALSE;
948                 } else {
949                         switch (accept) {
950                         case GAP_AGENT_CANCEL:
951                                 g_dbus_method_invocation_return_error(priv->reply_context,
952                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_CANCEL,
953                                                 "CanceledbyUser");
954                                 priv->canceled = TRUE;
955                                 break;
956                         case GAP_AGENT_TIMEOUT:
957                         case GAP_AGENT_REJECT:
958                         default:
959                                 g_dbus_method_invocation_return_error(priv->reply_context,
960                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
961                                                 "Passkey request rejected");
962                                 priv->canceled = FALSE;
963                                 break;
964                         }
965                 }
966         }
967
968         priv->exec_type = GAP_AGENT_EXEC_NO_OPERATION;
969         priv->reply_context = NULL;
970         memset(priv->pairing_addr, 0x00, sizeof(priv->pairing_addr));
971
972         return TRUE;
973 }
974
975 gboolean gap_agent_reply_authorize(GapAgentPrivate *agent, const guint accept,
976                 GDBusMethodInvocation *context)
977 {
978         gboolean ret = TRUE;
979         GapAgentPrivate *priv = agent;
980
981         /* Fix : NULL_RETURNS */
982         if (priv == NULL)
983                 return  FALSE;
984
985         if (priv->exec_type != GAP_AGENT_EXEC_NO_OPERATION &&
986                         priv->reply_context != NULL) {
987                 if (accept == GAP_AGENT_ACCEPT) {
988                         g_dbus_method_invocation_return_value(priv->reply_context, NULL);
989                 } else if (accept == GAP_AGENT_ACCEPT_ALWAYS) {
990                         /* TODO: Enable below logic after set authorization API implementation */
991                         g_dbus_method_invocation_return_value(priv->reply_context, NULL);
992                 } else {
993                         switch (accept) {
994                         case GAP_AGENT_CANCEL:
995                                 g_dbus_method_invocation_return_error(priv->reply_context,
996                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_CANCEL,
997                                                 "CanceledbyUser");
998                                 break;
999                         case GAP_AGENT_TIMEOUT:
1000                         case GAP_AGENT_REJECT:
1001                         default:
1002                                 g_dbus_method_invocation_return_error(priv->reply_context,
1003                                                 GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
1004                                                 "Authorization request rejected");
1005                                 break;
1006                         }
1007                 }
1008
1009                 if (context)
1010                         g_dbus_method_invocation_return_value(context, NULL);
1011         } else {
1012                 ERR("No context");
1013                 if (context)
1014                         g_dbus_method_invocation_return_error(context,
1015                                         GAP_AGENT_ERROR, GAP_AGENT_ERROR_REJECT,
1016                                         "No context");
1017                 ret = FALSE;
1018         }
1019
1020         priv->exec_type = GAP_AGENT_EXEC_NO_OPERATION;
1021         priv->reply_context = NULL;
1022         memset(priv->authorize_addr, 0x00, sizeof(priv->authorize_addr));
1023
1024         return ret;
1025 }
1026
1027 #ifdef TIZEN_BT_HAL
1028 bt_hal_agent_osp_server_t *_bt_hal_gap_agent_find_osp_server_by_type(GSList *servers, unsigned int type, const char *uuid)
1029 {
1030         GSList *l;
1031         bt_hal_agent_osp_server_t *server;
1032
1033         for (l = servers; l != NULL; l = g_slist_next(l)) {
1034                 server = l->data;
1035
1036                 if (server == NULL)
1037                         continue;
1038
1039                 /* No uuid in obex server */
1040                 if (type == BT_OSP_SERVER_OBEX
1041                                 && server->type == BT_OSP_SERVER_OBEX)
1042                         return server;
1043
1044                 if (g_strcmp0(server->uuid, uuid) == 0)
1045                         return server;
1046         }
1047
1048         return NULL;
1049 }
1050
1051 gboolean _bt_hal_gap_agent_register_osp_server(GapAgentPrivate *agent, unsigned int type, char *uuid, char *path, int fd)
1052 {
1053         bt_hal_agent_osp_server_t *server;
1054
1055         GapAgentPrivate *priv = agent;
1056         if (priv == NULL)
1057                 return FALSE;
1058
1059         if (type >= BT_OSP_SERVER_MAX)
1060                 return FALSE;
1061
1062         server = g_malloc0(sizeof(bt_hal_agent_osp_server_t));
1063         server->type = type;
1064         if (type == BT_OSP_SERVER_RFCOMM && uuid && path) {
1065                 server->uuid = g_strdup(uuid);
1066                 server->path = g_strdup(path);
1067                 server->fd = fd;
1068         }
1069         priv->osp_servers = g_slist_append(priv->osp_servers, server);
1070
1071         return TRUE;
1072 }
1073
1074 gboolean _bt_hal_gap_agent_unregister_osp_server(GapAgentPrivate *agent, unsigned int type, char *uuid)
1075 {
1076         bt_hal_agent_osp_server_t *server;
1077
1078         GapAgentPrivate *priv = agent;
1079
1080         if (priv == NULL)
1081                 return FALSE;
1082
1083         if (type >= BT_OSP_SERVER_MAX)
1084                 return FALSE;
1085
1086         server = _bt_hal_gap_agent_find_osp_server_by_type(priv->osp_servers, type, uuid);
1087         if (server == NULL)
1088                 return TRUE;
1089
1090         priv->osp_servers = g_slist_remove(priv->osp_servers, server);
1091         __bt_hal_free_osp_server(server);
1092
1093         return TRUE;
1094 }
1095 #endif