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