[OTP] Add support for OACP Read
[platform/core/connectivity/bluetooth-frwk.git] / bt-service / bt-service-otp.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <glib.h>
19 #include <gio/gio.h>
20 #include <dlog.h>
21 #include <string.h>
22 #include <syspopup_caller.h>
23 #include <vconf.h>
24 #include <bundle_internal.h>
25
26 #include "bluetooth-api.h"
27 #include "bt-internal-types.h"
28
29 #include "bt-service-common.h"
30 #include "bt-service-device.h"
31 #include "bt-service-util.h"
32 #include "bt-service-event.h"
33 #include "bt-service-otp.h"
34
35 #define BT_OTP_SERVICE_NAME "org.projectx.otp"
36 #define BT_OTP_OBJECT_PATH "/org/projectx/otp"
37 #define BT_OTP_INTERFACE_NAME "org.projectx.otp_service"
38
39 #define BT_OTP_BASE_DIR_PATH "/home/owner/media/otp/"
40
41 #define GATT_CHAR_INTERFACE             "org.bluez.GattCharacteristic1"
42
43 #define GATT_DEFAULT_TIMEOUT  (6 * 1000) /* Dependent on supervision timeout 6 sec */
44 #define BT_INDICATION_TIMEOUT_MAX 30000 /* Timeout for Indication from OTP Server in msec */
45
46 /* OTP Notification Request structure */
47 typedef struct {
48         char *handle;
49         char *sender;
50         unsigned int notification_timeout_id;
51         int req_id;
52 } bt_otp_notification_info;
53
54 /* OTP transport specific data read Request info structure */
55 typedef struct {
56         char *handle;
57         char *sender;
58         int req_id;
59 } bt_otp_read_req_info;
60
61 static GSList *otp_read_req_info_list = NULL;
62
63 static GSList *otp_notification_info_list = NULL;
64
65 static GDBusProxy *otp_gproxy;
66
67 static GDBusProxy *_bt_core_gdbus_init_otp_proxy(void)
68 {
69         GDBusProxy *proxy;
70         GError *err = NULL;
71         GDBusConnection *conn;
72
73         BT_DBG(" ");
74
75         conn = _bt_gdbus_get_system_gconn();
76         if (!conn)
77                 return NULL;
78
79         proxy =  g_dbus_proxy_new_sync(conn,
80                         G_DBUS_PROXY_FLAGS_NONE, NULL,
81                         BT_OTP_SERVICE_NAME,
82                         BT_OTP_OBJECT_PATH,
83                         BT_OTP_INTERFACE_NAME,
84                         NULL, &err);
85         if (proxy == NULL) {
86                 if (err) {
87                          BT_ERR("Unable to create proxy: %s", err->message);
88                          g_clear_error(&err);
89                 }
90                 return NULL;
91         }
92         BT_DBG("1");
93         otp_gproxy = proxy;
94
95         return proxy;
96 }
97
98 GDBusProxy *_bt_core_gdbus_get_otp_proxy(void)
99 {
100         return (otp_gproxy) ? otp_gproxy : _bt_core_gdbus_init_otp_proxy();
101 }
102
103 void server_init_cb(GObject *object, GAsyncResult *res,
104                                 gpointer user_data)
105 {
106         BT_INFO("Server Init completed");
107         GError *error = NULL;
108         GVariant *result, *out_param, *param;
109         request_info_t *req_info = NULL;
110         int status = BLUETOOTH_ERROR_NONE;
111         bool server_state = false;
112
113         result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
114
115         if (result == NULL) {
116                 BT_ERR("Dbus-RPC is failed\n");
117                 if (error != NULL) {
118                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
119                                 error->code, error->message);
120                         g_clear_error(&error);
121                         status = BLUETOOTH_ERROR_INTERNAL;
122                 }
123         }
124
125         if (result) {
126                 g_variant_get(result, "(i)", &status);
127         }
128
129         BT_DBG("Status [%d]", status);
130
131         if (status == BLUETOOTH_ERROR_NONE)
132                 server_state = true;
133
134         param = g_variant_new("(ib)", status, server_state);
135
136         req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
137
138         /* Send the event to application */
139         _bt_send_event(BT_OTP_EVENT,
140                 BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
141                 param);
142
143         out_param = g_variant_new_from_data((const GVariantType*)"i",
144                                 result, sizeof(int), TRUE, NULL, NULL);
145
146         if (req_info) {
147                 g_dbus_method_invocation_return_value(req_info->context,
148                                 g_variant_new("(iv)", status, out_param));
149
150                 _bt_delete_request_list(req_info->req_id);
151         }
152
153         g_variant_unref(result);
154 }
155
156 int bt_otp_server_init(int request_id, const char *directory)
157 {
158         BT_INFO("relative_path: [%s]", directory);
159         char *base_dir = g_strconcat(BT_OTP_BASE_DIR_PATH, directory, NULL);
160
161         BT_DBG(" ");
162
163         otp_gproxy = _bt_core_gdbus_get_otp_proxy();
164         if (!otp_gproxy) {
165                 BT_DBG("Couldn't get service proxy");
166                 g_free(base_dir);
167                 return BLUETOOTH_ERROR_INTERNAL;
168         }
169
170         g_dbus_proxy_call(otp_gproxy,
171                         "enable",
172                         g_variant_new("(s)",
173                                 base_dir),
174                         G_DBUS_CALL_FLAGS_NONE, -1,
175                         NULL,
176                         (GAsyncReadyCallback) server_init_cb,
177                         GINT_TO_POINTER(request_id));
178
179         g_free(base_dir);
180
181         return BLUETOOTH_ERROR_NONE;
182 }
183
184 void server_deinit_cb(GObject *object, GAsyncResult *res,
185                                 gpointer user_data)
186 {
187         BT_INFO("Server Deinit completed");
188         GError *error = NULL;
189         GVariant *result, *out_param, *param;
190         request_info_t *req_info = NULL;
191         int status = BLUETOOTH_ERROR_NONE;
192         bool server_state = false;
193
194         result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
195
196         if (result == NULL) {
197                 BT_ERR("Dbus-RPC is failed\n");
198                 if (error != NULL) {
199                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
200                                 error->code, error->message);
201                         g_clear_error(&error);
202                         status = BLUETOOTH_ERROR_INTERNAL;
203                 }
204         }
205
206         if (result) {
207                 g_variant_get(result, "(i)", &status);
208         }
209
210         BT_DBG("Status [%d]", status);
211
212         param = g_variant_new("(ib)", status, server_state);
213
214         req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
215
216         /* Send the event to application */
217         _bt_send_event(BT_OTP_EVENT,
218                         BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
219                         param);
220
221         if (req_info) {
222                 out_param = g_variant_new_from_data((const GVariantType*)"i",
223                                 result, sizeof(int), TRUE, NULL, NULL);
224
225                 g_dbus_method_invocation_return_value(req_info->context,
226                                 g_variant_new("(iv)", status, out_param));
227
228                 _bt_delete_request_list(req_info->req_id);
229         }
230
231         g_variant_unref(result);
232
233         if (otp_gproxy) {
234                 g_object_unref(otp_gproxy);
235                 otp_gproxy = NULL;
236         }
237 }
238
239 int bt_otp_server_deinit(int request_id)
240 {
241         BT_DBG("+");
242
243         otp_gproxy = _bt_core_gdbus_get_otp_proxy();
244         if (!otp_gproxy) {
245                 BT_DBG("Couldn't get service proxy");
246                 return BLUETOOTH_ERROR_INTERNAL;
247         }
248
249         g_dbus_proxy_call(otp_gproxy,
250                         "disable",
251                         NULL, G_DBUS_CALL_FLAGS_NONE,
252                         -1, NULL,
253                         (GAsyncReadyCallback) server_deinit_cb,
254                         GINT_TO_POINTER(request_id));
255
256         BT_DBG("-");
257         return BLUETOOTH_ERROR_NONE;
258 }
259
260 int __get_handle_length(char *handle)
261 {
262         int i = 0;
263         while (handle && (handle[i] != '\0')) {
264                 i++;
265         }
266         return i;
267 }
268
269 static bt_otp_read_req_info *__bt_otp_get_read_info(char *handle)
270 {
271         GSList *l;
272         bt_otp_read_req_info *info = NULL;
273         BT_INFO("Found waiting for OTP Read from charc handle[%s]", handle);
274         for (l = otp_read_req_info_list; l != NULL; l = g_slist_next(l)) {
275                 info = (bt_otp_read_req_info *)l->data;
276                 if (info == NULL)
277                         continue;
278
279                 if (!g_strcmp0(info->handle, handle)) {
280                         BT_INFO("Found waiting for OTP Read from remote addr[%s]",
281                                         info->handle);
282                         return info;
283                 }
284         }
285         return NULL;
286 }
287
288 static void __bt_otp_remove_read_info(bt_otp_read_req_info *info)
289 {
290         BT_DBG("Removing Read Req Info [%s]", info->handle);
291
292         otp_read_req_info_list = g_slist_remove(otp_read_req_info_list, info);
293         if (info->handle)
294                 g_free(info->handle);
295         if (info->sender)
296                 g_free(info->sender);
297         g_free(info);
298 }
299
300 static void __bt_otp_read_char_cb(GObject *source_object,
301                         GAsyncResult *res, gpointer user_data)
302 {
303         bt_gatt_char_descriptor_property_t att_value =  { 0, };
304         GDBusConnection *system_gconn = NULL;
305         GVariant *var_data, *param = NULL;
306         int result = BLUETOOTH_ERROR_NONE;
307         bt_otp_read_req_info *info = NULL;
308         GByteArray *gp_byte_array = NULL;
309         request_info_t *req_info = NULL;
310         GVariantIter *iter = NULL;
311         GVariant *value = NULL;
312         char *otp_data = NULL;
313         GVariant *out_param1;
314         GError *error = NULL;
315         guint8 g_byte, att_error_code;
316         char *handle;
317
318         BT_DBG("+");
319         system_gconn = _bt_gdbus_get_system_gconn();
320
321         handle = (char *)user_data;
322         info = __bt_otp_get_read_info(handle);
323
324         value = g_dbus_connection_call_finish(system_gconn, res, &error);
325
326         if (error) {
327                 BT_ERR("Error : %s \n", error->message);
328                 att_value.val_len = 0;
329                 result = BLUETOOTH_ERROR_INTERNAL;
330                 goto dbus_return;
331         }
332
333         g_variant_get(value, "(yay)", &att_error_code, &iter);
334
335         if (att_error_code != 0) {
336                 BT_ERR("ATT err code : [%d]", att_error_code);
337                 att_value.val_len = 0;
338                 result = att_error_code;
339                 goto dbus_return;
340         }
341
342         gp_byte_array = g_byte_array_new();
343
344         while (g_variant_iter_loop(iter, "y",  &g_byte))
345                 g_byte_array_append(gp_byte_array, &g_byte, 1);
346
347         if (gp_byte_array->len != 0) {
348                 att_value.val_len = (unsigned int)gp_byte_array->len;
349                 att_value.val = (unsigned char *)gp_byte_array->data;
350         }
351
352         otp_data = (char *)g_memdup(att_value.val, att_value.val_len);
353
354 dbus_return:
355         var_data = g_variant_new_from_data((const GVariantType*)"ay",
356                         otp_data, att_value.val_len, TRUE, NULL, NULL);
357
358         if (info) {
359                 param = g_variant_new("(isn@ay)", result, handle, att_value.val_len, var_data);
360                 _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
361                                 BLUETOOTH_EVENT_OTP_READ_CHAR_VAL,
362                                 param);
363         }
364
365         req_info = _bt_get_request_info(info->req_id);
366         __bt_otp_remove_read_info(info);
367
368         if (req_info == NULL) {
369                 BT_ERR("OTP data read Request not found!!");
370                 goto done;
371         }
372
373         if (req_info->context == NULL)
374                 goto done;
375
376         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
377                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
378         g_dbus_method_invocation_return_value(req_info->context,
379                         g_variant_new("(iv)", result, out_param1));
380
381         _bt_delete_request_list(req_info->req_id);
382
383 done:
384         /* Data free */
385         if (error)
386                 g_clear_error(&error);
387         if (gp_byte_array)
388                 g_byte_array_free(gp_byte_array, TRUE);
389         if (handle)
390                 g_free(handle);
391         if (value)
392                 g_variant_unref(value);
393         if (iter)
394                 g_variant_iter_free(iter);
395         if (otp_data)
396                 g_free(otp_data);
397         BT_DBG("-");
398 }
399
400 int _bt_otp_read_characteristic_value(int request_id, char *sender, char *handle)
401 {
402         GDBusConnection *conn;
403         bt_otp_read_req_info *info = NULL;
404         char *charc_handle = g_strdup(handle);
405         GVariantBuilder *builder = NULL;
406         guint16 offset = 0;
407
408         BT_CHECK_PARAMETER(handle, return);
409         BT_CHECK_PARAMETER(sender, return);
410
411         conn = _bt_gdbus_get_system_gconn();
412         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
413
414         BT_DBG("Read OTP Characteristic from server handle [%s]", handle);
415
416         /* If OTP data read already pending on same Server, then return In progress */
417         if (__bt_otp_get_read_info(handle) != NULL) {
418                 BT_ERR("Read Req is ongoing in remote server [%s]", charc_handle);
419                 g_free(charc_handle);
420                 return BLUETOOTH_ERROR_IN_PROGRESS;
421         }
422
423         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
424         /*offset*/
425         g_variant_builder_add(builder, "{sv}", "offset",
426                 g_variant_new("q", offset));
427
428         g_dbus_connection_call(conn,
429                         BT_BLUEZ_NAME,
430                         handle,
431                         GATT_CHAR_INTERFACE,
432                         "ReadValue",
433                         g_variant_new("(a{sv})", builder),
434                         G_VARIANT_TYPE("(yay)"),
435                         G_DBUS_CALL_FLAGS_NONE,
436                         -1,
437                         NULL,
438                         (GAsyncReadyCallback)__bt_otp_read_char_cb,
439                         (gpointer)charc_handle);
440
441         /* Save Info in pending list */
442         info = g_malloc0(sizeof(bt_otp_read_req_info));
443         info->handle = g_strdup(handle);
444         BT_INFO("Found waiting for OTP Read from charc handle[%s] [%s]", info->handle, handle);
445         info->sender = g_strdup(sender);
446         info->req_id = request_id;
447         otp_read_req_info_list = g_slist_append(otp_read_req_info_list, info);
448
449         BT_DBG("-");
450         return BLUETOOTH_ERROR_NONE;
451 }
452
453 static bt_otp_notification_info *__bt_otp_get_notification_info(char *handle)
454 {
455         GSList *l;
456         bt_otp_notification_info *info = NULL;
457
458         for (l = otp_notification_info_list; l != NULL; l = g_slist_next(l)) {
459                 info = (bt_otp_notification_info *)l->data;
460                 if (info == NULL)
461                         continue;
462
463                 if (!g_strcmp0(info->handle, handle)) {
464                         BT_INFO("Found waiting for Ind from Server addr[%s]",
465                                         info->handle);
466                                 return info;
467                 }
468         }
469         return NULL;
470 }
471
472 static void __bt_otp_remove_notification_info(bt_otp_notification_info *info)
473 {
474         BT_DBG("Removing Notification Info [%s]", info->handle);
475
476         otp_notification_info_list = g_slist_remove(otp_notification_info_list, info);
477         if (info->handle)
478                 g_free(info->handle);
479         if (info->sender)
480                 g_free(info->sender);
481         if (info->notification_timeout_id > 0) {
482                 g_source_remove(info->notification_timeout_id);
483                 info->notification_timeout_id = 0;
484         }
485         g_free(info);
486 }
487
488 static void __bt_otp_notification_enable_request_cb(GObject *source_object,
489                         GAsyncResult *res, gpointer user_data)
490 {
491         GError *error = NULL;
492         GDBusConnection *system_gconn = NULL;
493         GVariant *value = NULL;
494         GVariant *param = NULL;
495         GVariant *out_param1 = NULL;
496         int result = BLUETOOTH_ERROR_NONE;
497         char *handle = NULL;
498         bt_otp_notification_info *info = NULL;
499         request_info_t *req_info = NULL;
500         BT_DBG("+");
501
502         system_gconn = _bt_gdbus_get_system_gconn();
503         value = g_dbus_connection_call_finish(system_gconn, res, &error);
504
505         if (error) {
506                 BT_ERR("Error : %s \n", error->message);
507                 if (g_strrstr(error->message, "Already notifying"))
508                         result = BLUETOOTH_ERROR_NONE;
509                 else if (g_strrstr(error->message, "In Progress"))
510                         result = BLUETOOTH_ERROR_IN_PROGRESS;
511                 else if (g_strrstr(error->message, "Operation is not supported"))
512                         result = BLUETOOTH_ERROR_NOT_SUPPORT;
513                 else if (g_strrstr(error->message, "Write not permitted") ||
514                                 g_strrstr(error->message, "Operation Not Authorized"))
515                         result = BLUETOOTH_ERROR_PERMISSION_DEINED;
516                 else if (g_strrstr(error->message, "Not paired"))
517                         result = BLUETOOTH_ERROR_NOT_PAIRED;
518                 else
519                         result = BLUETOOTH_ERROR_INTERNAL;
520         } else {
521                 BT_DBG("OTP CCCD enable request successful, send event to BT App");
522         }
523
524         handle = (char *)user_data;
525         info = __bt_otp_get_notification_info(handle);
526
527         if (info)
528                 req_info = _bt_get_request_info(info->req_id);
529
530         /* If CCCD Enable request failed for any reason, reset timer */
531         if (result != BLUETOOTH_ERROR_NONE && info != NULL) {
532                 BT_ERR("Activation Request failed");
533                 /* Reset Timer */
534                 if (info->notification_timeout_id > 0) {
535                         g_source_remove(info->notification_timeout_id);
536                         info->notification_timeout_id = 0;
537                 }
538
539                 /* Remove Indication Info */
540                 __bt_otp_remove_notification_info(info);
541         } else {
542                 /* CCCD Enable Request successful */
543                 if (info) {
544                         param = g_variant_new("(is)", result, handle);
545                         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
546                                         BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED,
547                                         param);
548                 }
549         }
550
551         if (req_info == NULL) {
552                 BT_ERR("OTP Control Point CCCD Enable Request is not found!!");
553                 goto done;
554         }
555
556         if (req_info->context == NULL)
557                 goto done;
558
559         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
560                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
561         g_dbus_method_invocation_return_value(req_info->context,
562                         g_variant_new("(iv)", result, out_param1));
563
564         _bt_delete_request_list(req_info->req_id);
565
566 done:
567         if (value)
568                 g_variant_unref(value);
569         if (error)
570                 g_clear_error(&error);
571         if (handle)
572                 g_free(handle);
573
574         BT_DBG("-");
575         return;
576 }
577
578 int _bt_otp_enable_notification(int request_id, char *sender, char *handle)
579 {
580         bt_otp_notification_info *info = NULL;
581         char *charc_handle = g_strdup(handle);
582         GDBusConnection *conn;
583
584         BT_CHECK_PARAMETER(handle, return);
585         BT_CHECK_PARAMETER(sender, return);
586
587         conn = _bt_gdbus_get_system_gconn();
588         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
589
590         BT_DBG("OTP Control point CCCD Handle [%s]", handle);
591
592         if (__bt_otp_get_notification_info(handle) != NULL) {
593                 BT_ERR("Activation is already ongoing for same remote server");
594                 g_free(charc_handle);
595                 return BLUETOOTH_ERROR_IN_PROGRESS;
596         }
597
598         BT_INFO("Start Notify to Bluez");
599         g_dbus_connection_call(conn,
600                         BT_BLUEZ_NAME,
601                         handle,
602                         GATT_CHAR_INTERFACE,
603                         "StartNotify",
604                         NULL,
605                         NULL,
606                         G_DBUS_CALL_FLAGS_NONE,
607                         GATT_DEFAULT_TIMEOUT, NULL,
608                         (GAsyncReadyCallback)__bt_otp_notification_enable_request_cb,
609                         (gpointer)charc_handle);
610
611         info = g_malloc0(sizeof(bt_otp_notification_info));
612         info->handle = g_strdup(handle);
613         info->sender = g_strdup(sender);
614         info->req_id = request_id;
615         otp_notification_info_list = g_slist_append(otp_notification_info_list, info);
616
617         BT_DBG("-");
618         return BLUETOOTH_ERROR_NONE;
619 }
620
621 static void __bt_otp_write_request_cb(GObject *source_object,
622                         GAsyncResult *res, gpointer user_data)
623 {
624         GError *error = NULL;
625         GDBusConnection *system_gconn = NULL;
626         GVariant *value = NULL;
627         GVariant *param = NULL;
628         GVariant *out_param1 = NULL;
629         int result = BLUETOOTH_ERROR_NONE;
630         char *handle = NULL;
631         bt_otp_notification_info *info = NULL;
632         request_info_t *req_info = NULL;
633         guint8 att_ecode = 0;
634         BT_DBG("+");
635
636         system_gconn = _bt_gdbus_get_system_gconn();
637         value = g_dbus_connection_call_finish(system_gconn, res, &error);
638
639         if (error) {
640                 BT_ERR("Error : %s \n", error->message);
641                 /* Process error->message to narrow down the att_ecode */
642                 result = BLUETOOTH_ERROR_INTERNAL;
643         } else {
644                 g_variant_get(value, "(y)", &att_ecode);
645                 if (att_ecode) {
646                         result =  att_ecode;
647                         BT_ERR("ATT Error code: %d \n", att_ecode);
648                 }
649         }
650
651         handle = (char *)user_data;
652         info = __bt_otp_get_notification_info(handle);
653         if (info)
654                 req_info = _bt_get_request_info(info->req_id);
655
656         /* Is Activation request failed for any reason, reset timer */
657         if (result != BLUETOOTH_ERROR_NONE && info != NULL) {
658                 BT_ERR("Activation Request failed");
659                 /* Remove Indication Info */
660                 __bt_otp_remove_notification_info(info);
661         }
662
663         /* Activation Request successful */
664         if (info) {
665                 param = g_variant_new("(is)", result, handle);
666                 _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
667                                 BLUETOOTH_EVENT_OTP_WRITE_CHAR_VAL,
668                                 param);
669         }
670
671         if (req_info == NULL) {
672                 BT_ERR("OTP Write Request is not found!!");
673                 goto done;
674         }
675
676         if (req_info->context == NULL)
677                 goto done;
678
679         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
680                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
681         g_dbus_method_invocation_return_value(req_info->context,
682                         g_variant_new("(iv)", result, out_param1));
683
684         _bt_delete_request_list(req_info->req_id);
685
686 done:
687         if (value)
688                 g_variant_unref(value);
689         if (error)
690                 g_clear_error(&error);
691         if (handle)
692                 g_free(handle);
693
694         BT_DBG("-");
695         return;
696 }
697
698 static void __bt_otp_send_indication_event(bt_otp_notification_info *info,
699                                                 unsigned char *buffer, int len, int result)
700 {
701         GVariant *otp_data;
702         GVariant *param;
703
704         otp_data = g_variant_new_from_data((const GVariantType*)"ay",
705                         buffer, len, TRUE, NULL, NULL);
706
707         BT_DBG("Send Indication event to sender");
708         param = g_variant_new("(is@ay)", result, info->handle, otp_data);
709         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
710                                         BLUETOOTH_EVENT_OTP_INDICATION,
711                                         param);
712
713         /* Remove info from list */
714         __bt_otp_remove_notification_info(info);
715 }
716
717 static bool __bt_otp_indication_timeout_cb(gpointer user_data)
718 {
719         char *handle = NULL;
720         handle = (char *) user_data;
721         bt_otp_notification_info *info = NULL;
722         /* Indication:Fail*/
723         info = __bt_otp_get_notification_info(handle);
724         if (info) {
725                 BT_DBG("Activation timer Expired [Server] [%s]", info->handle);
726                 __bt_otp_send_indication_event(info, NULL, 0, BLUETOOTH_ERROR_INTERNAL);
727         }
728
729         return FALSE;
730 }
731
732 int _bt_otp_write_characteristic_value(int request_id, char *sender, char *handle,
733                                                         unsigned char *param, int length)
734 {
735         GVariantBuilder *builder1;
736         GVariant *val;
737         GVariant *options;
738         GVariantBuilder *builder2;
739         guint16 offset = 0;
740         bt_otp_notification_info *info = NULL;
741         GDBusConnection *conn;
742         char *charc_handle = g_strdup(handle);
743         int i;
744
745         BT_DBG("+");
746
747         BT_CHECK_PARAMETER(handle, return);
748         BT_CHECK_PARAMETER(sender, return);
749         BT_CHECK_PARAMETER(param, return);
750
751         conn = _bt_gdbus_get_system_gconn();
752         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
753
754         BT_DBG("OTP Write Characteristic value handle [%s] data length [%d]", handle, length);
755         /* Check if activation is ongoing for the same Remote Server */
756
757         info = __bt_otp_get_notification_info(handle);
758         if (info && info->notification_timeout_id > 0) {
759                 BT_ERR("Write Request is already ongoing in remote server");
760                 g_free(charc_handle);
761                 return BLUETOOTH_ERROR_IN_PROGRESS;
762         }
763
764         builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
765
766         for (i = 0; i < length; i++) {
767                 g_variant_builder_add(builder1, "y", param[i]);
768         }
769
770         val = g_variant_new("ay", builder1);
771         builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
772         /*offset*/
773         g_variant_builder_add(builder2, "{sv}", "offset",
774                                 g_variant_new_uint16(offset));
775
776         options = g_variant_new("a{sv}", builder2);
777
778         /* Activate Control Point */
779         g_dbus_connection_call(conn,
780                         BT_BLUEZ_NAME,
781                         handle,
782                         GATT_CHAR_INTERFACE,
783                         "WriteValue",
784                         g_variant_new("(@ay@a{sv})",
785                         val, options),
786                         NULL,
787                         G_DBUS_CALL_FLAGS_NONE,
788                         -1, NULL,
789                         (GAsyncReadyCallback)__bt_otp_write_request_cb,
790                         (gpointer)charc_handle);
791
792         g_variant_builder_unref(builder1);
793         g_variant_builder_unref(builder2);
794
795         if (info == NULL) {
796                 info = g_malloc0(sizeof(bt_otp_notification_info));
797                 info->handle = g_strdup(handle);
798                 info->sender = g_strdup(sender);
799                 otp_notification_info_list = g_slist_append(otp_notification_info_list, info);
800         }
801         info->req_id = request_id;
802         info->notification_timeout_id = g_timeout_add(BT_INDICATION_TIMEOUT_MAX,
803                         (GSourceFunc)__bt_otp_indication_timeout_cb, (gpointer)info->handle);
804
805         BT_DBG("-");
806         return BLUETOOTH_ERROR_NONE;
807 }
808
809 void _bt_otp_check_indication(const char *path, GVariant *msg)
810 {
811         bt_otp_notification_info *info = NULL;
812         unsigned char *buffer = NULL;
813         int len = 0;
814         int i;
815         GVariant *value = NULL;
816         BT_DBG("+");
817
818         info = __bt_otp_get_notification_info((char *)path);
819
820         if (info) {
821                 g_variant_get(msg, "(is@ay)", NULL, NULL, &value);
822                 len = g_variant_get_size(value);
823                 BT_DBG("Indication data from Server len[%d]", len);
824                 if (len > 0) {
825                         buffer = (unsigned char *)g_variant_get_data(value);
826                         /* DEBUG */
827                         for (i = 0; i < len; i++)
828                                 BT_DBG("%.2x", buffer[i]);
829                 }
830
831                 /* Reset Timer */
832                 if (info->notification_timeout_id > 0)
833                         g_source_remove(info->notification_timeout_id);
834
835                 /* Send Indication & info removed internally */
836                 __bt_otp_send_indication_event(info, buffer, len, BLUETOOTH_ERROR_NONE);
837
838                 if (value)
839                         g_variant_unref(value);
840         }
841         BT_DBG("-");
842 }
843
844 int _bt_otp_connect_otc(int req_id, const bluetooth_device_address_t *bd_addr)
845 {
846         char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
847         gchar *device_path = NULL;
848         GDBusProxy *device_proxy = NULL;
849         GDBusConnection *conn;
850         int ret = BLUETOOTH_ERROR_NONE;
851         GVariant *result = NULL;
852         GError *err = NULL;
853
854         BT_CHECK_PARAMETER(bd_addr, return);
855
856         _bt_convert_addr_type_to_string(device_address,
857                         (unsigned char *)bd_addr->addr);
858
859         conn = _bt_gdbus_get_system_gconn();
860         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
861
862         device_path = _bt_get_device_object_path(device_address);
863         if (device_path == NULL) {
864                 BT_DBG("device_path NULL");
865                 ret = BLUETOOTH_ERROR_INTERNAL;
866                 goto fail;
867         }
868
869         retv_if(device_path == NULL, BLUETOOTH_ERROR_INTERNAL);
870
871         device_proxy = g_dbus_proxy_new_sync(conn,
872                                         G_DBUS_PROXY_FLAGS_NONE,
873                                         NULL, BT_BLUEZ_NAME,
874                                         device_path, BT_DEVICE_INTERFACE,
875                                         NULL, NULL);
876         g_free(device_path);
877         retv_if(device_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
878
879         result = g_dbus_proxy_call_sync(device_proxy, "ConnectOtc",
880                                 NULL,
881                                 G_DBUS_CALL_FLAGS_NONE,
882                                 -1,
883                                 NULL,
884                                 &err);
885
886         if (result == NULL) {
887                 if (err != NULL) {
888                         g_dbus_error_strip_remote_error(err);
889                         BT_ERR("OTC Connect Error: %s\n", err->message);
890                         if (g_strcmp0(err->message, "Already Exists") == 0)
891                                 ret = BLUETOOTH_ERROR_ALREADY_INITIALIZED;
892                         else
893                                 ret = BLUETOOTH_ERROR_INTERNAL;
894                         g_error_free(err);
895                 }
896         }
897         g_variant_unref(result);
898
899 fail:
900         g_object_unref(device_proxy);
901         return ret;
902 }
903
904 int _bt_otp_disconnect_otc(const bluetooth_device_address_t *bd_addr)
905 {
906         char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
907         gchar *device_path = NULL;
908         GError *error = NULL;
909         GDBusProxy *device_proxy = NULL;
910         GDBusProxy *adapter_proxy;
911         GDBusConnection *conn;
912         int ret = BLUETOOTH_ERROR_NONE;
913
914         BT_CHECK_PARAMETER(bd_addr, return);
915
916         _bt_convert_addr_type_to_string(device_address,
917                         (unsigned char *)bd_addr->addr);
918
919         conn = _bt_gdbus_get_system_gconn();
920         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
921
922         adapter_proxy = _bt_get_adapter_proxy();
923         retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
924
925         device_path = _bt_get_device_object_path(device_address);
926         if (device_path == NULL) {
927                 BT_DBG("device_path NULL");
928                 return BLUETOOTH_ERROR_INTERNAL;
929         }
930
931         retv_if(device_path == NULL, BLUETOOTH_ERROR_INTERNAL);
932
933         device_proxy = g_dbus_proxy_new_sync(conn,
934                                         G_DBUS_PROXY_FLAGS_NONE,
935                                         NULL, BT_BLUEZ_NAME,
936                                         device_path,
937                                         BT_DEVICE_INTERFACE,
938                                         NULL, NULL);
939         g_free(device_path);
940         retv_if(device_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
941
942         g_dbus_proxy_call_sync(device_proxy, "DisconnectOtc",
943                                 NULL,
944                                 G_DBUS_CALL_FLAGS_NONE,
945                                 -1,
946                                 NULL,
947                                 &error);
948
949         if (error) {
950                 BT_ERR("DisconnectOtc Call Error %s[%s]",
951                                 error->message, device_address);
952                 g_error_free(error);
953                 g_object_unref(device_proxy);
954                 return BLUETOOTH_ERROR_INTERNAL;
955         }
956
957         if (device_proxy)
958                 g_object_unref(device_proxy);
959
960         return ret;
961 }