e62e809cd373755afb64e4b80e65462162a41eb6
[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 15000 /* 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;
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                 g_free(handle);
329                 if (info) {
330                         req_info = _bt_get_request_info(info->req_id);
331                         __bt_otp_remove_read_info(info);
332                 }
333                 result = BLUETOOTH_ERROR_INTERNAL;
334                 goto dbus_return;
335         }
336
337         gp_byte_array = g_byte_array_new();
338         g_variant_get(value, "(ay)", &iter);
339
340         while (g_variant_iter_loop(iter, "y",  &g_byte))
341                 g_byte_array_append(gp_byte_array, &g_byte, 1);
342
343         if (gp_byte_array->len != 0) {
344                 att_value.val_len = (unsigned int)gp_byte_array->len;
345                 att_value.val = (unsigned char *)gp_byte_array->data;
346         }
347
348         otp_data = (char *)g_memdup(att_value.val, att_value.val_len);
349
350         var_data = g_variant_new_from_data((const GVariantType*)"ay",
351                         otp_data, att_value.val_len, TRUE, NULL, NULL);
352
353         if (info) {
354                 param = g_variant_new("(isn@ay)", result, handle, att_value.val_len, var_data);
355                 _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
356                                 BLUETOOTH_EVENT_OTP_READ_CHAR_VAL,
357                                 param);
358                 req_info = _bt_get_request_info(info->req_id);
359                 __bt_otp_remove_read_info(info);
360         }
361
362 dbus_return:
363         if (req_info == NULL) {
364                 BT_ERR("OTP data read Request not found!!");
365                 goto done;
366         }
367
368         if (req_info->context == NULL)
369                 goto done;
370
371         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
372                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
373         g_dbus_method_invocation_return_value(req_info->context,
374                         g_variant_new("(iv)", result, out_param1));
375
376         _bt_delete_request_list(req_info->req_id);
377
378 done:
379         /* Data free */
380         if (error)
381                 g_clear_error(&error);
382         if (gp_byte_array)
383                 g_byte_array_free(gp_byte_array, TRUE);
384         if (handle)
385                 g_free(handle);
386         if (value)
387                 g_variant_unref(value);
388         if (iter)
389                 g_variant_iter_free(iter);
390         if (otp_data)
391                 g_free(otp_data);
392         BT_DBG("-");
393 }
394
395 int _bt_otp_read_characteristic_value(int request_id, char *sender, char *handle)
396 {
397         GDBusConnection *conn;
398         bt_otp_read_req_info *info = NULL;
399         char *charc_handle = g_strdup(handle);
400         GVariantBuilder *builder = NULL;
401         guint16 offset = 0;
402
403         BT_CHECK_PARAMETER(handle, return);
404         BT_CHECK_PARAMETER(sender, return);
405
406         conn = _bt_gdbus_get_system_gconn();
407         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
408
409         BT_DBG("Read OTP Characteristic from server handle [%s]", handle);
410
411         /* If OTP data read already pending on same Server, then return In progress */
412         if (__bt_otp_get_read_info(handle) != NULL) {
413                 BT_ERR("Read Req is ongoing in remote server [%s]", charc_handle);
414                 g_free(charc_handle);
415                 return BLUETOOTH_ERROR_IN_PROGRESS;
416         }
417
418         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
419         /*offset*/
420         g_variant_builder_add(builder, "{sv}", "offset",
421                 g_variant_new("q", offset));
422
423         g_dbus_connection_call(conn,
424                         BT_BLUEZ_NAME,
425                         handle,
426                         GATT_CHAR_INTERFACE,
427                         "ReadValue",
428                         g_variant_new("(a{sv})", builder),
429                         G_VARIANT_TYPE("(ay)"),
430                         G_DBUS_CALL_FLAGS_NONE,
431                         -1,
432                         NULL,
433                         (GAsyncReadyCallback)__bt_otp_read_char_cb,
434                         (gpointer)charc_handle);
435
436         /* Save Info in pending list */
437         info = g_malloc0(sizeof(bt_otp_read_req_info));
438         info->handle = g_strdup(handle);
439         BT_INFO("Found waiting for OTP Read from charc handle[%s] [%s]", info->handle, handle);
440         info->sender = g_strdup(sender);
441         info->req_id = request_id;
442         otp_read_req_info_list = g_slist_append(otp_read_req_info_list, info);
443
444         BT_DBG("-");
445         return BLUETOOTH_ERROR_NONE;
446 }
447
448 static bt_otp_notification_info *__bt_otp_get_notification_info(char *handle)
449 {
450         GSList *l;
451         bt_otp_notification_info *info = NULL;
452
453         for (l = otp_notification_info_list; l != NULL; l = g_slist_next(l)) {
454                 info = (bt_otp_notification_info *)l->data;
455                 if (info == NULL)
456                         continue;
457
458                 if (!g_strcmp0(info->handle, handle)) {
459                         BT_INFO("Found waiting for Ind from Server addr[%s]",
460                                         info->handle);
461                                 return info;
462                 }
463         }
464         return NULL;
465 }
466
467 static void __bt_otp_remove_notification_info(bt_otp_notification_info *info)
468 {
469         BT_DBG("Removing Notification Info [%s]", info->handle);
470
471         otp_notification_info_list = g_slist_remove(otp_notification_info_list, info);
472         if (info->handle)
473                 g_free(info->handle);
474         if (info->sender)
475                 g_free(info->sender);
476         if (info->notification_timeout_id > 0) {
477                 g_source_remove(info->notification_timeout_id);
478                 info->notification_timeout_id = 0;
479         }
480         g_free(info);
481 }
482
483 static void __bt_otp_notification_enable_request_cb(GObject *source_object,
484                         GAsyncResult *res, gpointer user_data)
485 {
486         GError *error = NULL;
487         GDBusConnection *system_gconn = NULL;
488         GVariant *value = NULL;
489         GVariant *param = NULL;
490         GVariant *out_param1 = NULL;
491         int result = BLUETOOTH_ERROR_NONE;
492         char *handle = NULL;
493         bt_otp_notification_info *info = NULL;
494         request_info_t *req_info = NULL;
495         BT_DBG("+");
496
497         system_gconn = _bt_gdbus_get_system_gconn();
498         value = g_dbus_connection_call_finish(system_gconn, res, &error);
499
500         if (error) {
501                 BT_ERR("Error : %s \n", error->message);
502                 if (g_strrstr(error->message, "Already notifying"))
503                         result = BLUETOOTH_ERROR_NONE;
504                 else if (g_strrstr(error->message, "In Progress"))
505                         result = BLUETOOTH_ERROR_IN_PROGRESS;
506                 else if (g_strrstr(error->message, "Operation is not supported"))
507                         result = BLUETOOTH_ERROR_NOT_SUPPORT;
508                 else if (g_strrstr(error->message, "Write not permitted") ||
509                                 g_strrstr(error->message, "Operation Not Authorized"))
510                         result = BLUETOOTH_ERROR_PERMISSION_DEINED;
511                 else if (g_strrstr(error->message, "Not paired"))
512                         result = BLUETOOTH_ERROR_NOT_PAIRED;
513                 else
514                         result = BLUETOOTH_ERROR_INTERNAL;
515         } else {
516                 BT_DBG("OTP CCCD enable request successful, send event to BT App");
517         }
518
519         handle = (char *)user_data;
520         info = __bt_otp_get_notification_info(handle);
521
522         if (info)
523                 req_info = _bt_get_request_info(info->req_id);
524
525         /* If CCCD Enable request failed for any reason, reset timer */
526         if (result != BLUETOOTH_ERROR_NONE && info != NULL) {
527                 BT_ERR("Activation Request failed");
528                 /* Reset Timer */
529                 if (info->notification_timeout_id > 0) {
530                         g_source_remove(info->notification_timeout_id);
531                         info->notification_timeout_id = 0;
532                 }
533
534                 /* Remove Indication Info */
535                 __bt_otp_remove_notification_info(info);
536         } else {
537                 /* CCCD Enable Request successful */
538                 if (info) {
539                         param = g_variant_new("(is)", result, handle);
540                         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
541                                         BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED,
542                                         param);
543                 }
544         }
545
546         if (req_info == NULL) {
547                 BT_ERR("OTP Control Point CCCD Enable Request is not found!!");
548                 goto done;
549         }
550
551         if (req_info->context == NULL)
552                 goto done;
553
554         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
555                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
556         g_dbus_method_invocation_return_value(req_info->context,
557                         g_variant_new("(iv)", result, out_param1));
558
559         _bt_delete_request_list(req_info->req_id);
560
561 done:
562         if (value)
563                 g_variant_unref(value);
564         if (error)
565                 g_clear_error(&error);
566         if (handle)
567                 g_free(handle);
568
569         BT_DBG("-");
570         return;
571 }
572
573 int _bt_otp_enable_notification(int request_id, char *sender, char *handle)
574 {
575         bt_otp_notification_info *info = NULL;
576         char *charc_handle = g_strdup(handle);
577         GDBusConnection *conn;
578
579         BT_CHECK_PARAMETER(handle, return);
580         BT_CHECK_PARAMETER(sender, return);
581
582         conn = _bt_gdbus_get_system_gconn();
583         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
584
585         BT_DBG("OTP Control point CCCD Handle [%s]", handle);
586
587         if (__bt_otp_get_notification_info(handle) != NULL) {
588                 BT_ERR("Activation is already ongoing for same remote server");
589                 g_free(charc_handle);
590                 return BLUETOOTH_ERROR_IN_PROGRESS;
591         }
592
593         BT_INFO("Start Notify to Bluez");
594         g_dbus_connection_call(conn,
595                         BT_BLUEZ_NAME,
596                         handle,
597                         GATT_CHAR_INTERFACE,
598                         "StartNotify",
599                         NULL,
600                         NULL,
601                         G_DBUS_CALL_FLAGS_NONE,
602                         GATT_DEFAULT_TIMEOUT, NULL,
603                         (GAsyncReadyCallback)__bt_otp_notification_enable_request_cb,
604                         (gpointer)charc_handle);
605
606         info = g_malloc0(sizeof(bt_otp_notification_info));
607         info->handle = g_strdup(handle);
608         info->sender = g_strdup(sender);
609         info->req_id = request_id;
610         otp_notification_info_list = g_slist_append(otp_notification_info_list, info);
611
612         BT_DBG("-");
613         return BLUETOOTH_ERROR_NONE;
614 }
615
616 static void __bt_otp_write_request_cb(GObject *source_object,
617                         GAsyncResult *res, gpointer user_data)
618 {
619         GError *error = NULL;
620         GDBusConnection *system_gconn = NULL;
621         GVariant *value = NULL;
622         GVariant *param = NULL;
623         GVariant *out_param1 = NULL;
624         int result = BLUETOOTH_ERROR_NONE;
625         char *handle = NULL;
626         bt_otp_notification_info *info = NULL;
627         request_info_t *req_info = NULL;
628         BT_DBG("+");
629
630         system_gconn = _bt_gdbus_get_system_gconn();
631         value = g_dbus_connection_call_finish(system_gconn, res, &error);
632
633         if (error) {
634                 BT_ERR("Error : %s \n", error->message);
635                 /* Process error->message to narrow down the att_ecode */
636                 result = BLUETOOTH_ERROR_INTERNAL;
637         }
638
639         handle = (char *)user_data;
640         info = __bt_otp_get_notification_info(handle);
641         if (info)
642                 req_info = _bt_get_request_info(info->req_id);
643
644         /* Is Activation request failed for any reason, reset timer */
645         if (result != BLUETOOTH_ERROR_NONE && info != NULL) {
646                 BT_ERR("Activation Request failed");
647                 /* Remove Indication Info */
648                 __bt_otp_remove_notification_info(info);
649         } else {
650                 /* Activation Request successful */
651                 if (info) {
652                         param = g_variant_new("(is)", result, handle);
653                         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
654                                         BLUETOOTH_EVENT_OTP_WRITE_CHAR_VAL,
655                                         param);
656                 }
657         }
658
659         if (req_info == NULL) {
660                 BT_ERR("OTP Write Request is not found!!");
661                 goto done;
662         }
663
664         if (req_info->context == NULL)
665                 goto done;
666
667         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
668                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
669         g_dbus_method_invocation_return_value(req_info->context,
670                         g_variant_new("(iv)", result, out_param1));
671
672         _bt_delete_request_list(req_info->req_id);
673
674 done:
675         if (value)
676                 g_variant_unref(value);
677         if (error)
678                 g_clear_error(&error);
679         if (handle)
680                 g_free(handle);
681
682         BT_DBG("-");
683         return;
684 }
685
686 static void __bt_otp_send_indication_event(bt_otp_notification_info *info,
687                                                 unsigned char *buffer, int len, int result)
688 {
689         GVariant *otp_data;
690         GVariant *param;
691
692         otp_data = g_variant_new_from_data((const GVariantType*)"ay",
693                         buffer, len, TRUE, NULL, NULL);
694
695         BT_DBG("Send Indication event to sender");
696         param = g_variant_new("(is@ay)", result, info->handle, otp_data);
697         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
698                                         BLUETOOTH_EVENT_OTP_INDICATION,
699                                         param);
700
701         /* Remove info from list */
702         __bt_otp_remove_notification_info(info);
703 }
704
705 static bool __bt_otp_indication_timeout_cb(gpointer user_data)
706 {
707         char *handle = NULL;
708         handle = (char *) user_data;
709         bt_otp_notification_info *info = NULL;
710         /* Indication:Fail*/
711         info = __bt_otp_get_notification_info(handle);
712         BT_DBG("Activation timer Expired [Server] [%s]", info->handle);
713         if (info)
714                 __bt_otp_send_indication_event(info, NULL, 0, BLUETOOTH_ERROR_INTERNAL);
715
716         return FALSE;
717 }
718
719 int _bt_otp_write_characteristic_value(int request_id, char *sender, char *handle,
720                                                         unsigned char *param, int length)
721 {
722         GVariantBuilder *builder1;
723         GVariant *val;
724         GVariant *options;
725         GVariantBuilder *builder2;
726         guint16 offset = 0;
727         bt_otp_notification_info *info = NULL;
728         GDBusConnection *conn;
729         char *charc_handle = g_strdup(handle);
730         int i;
731
732         BT_DBG("+");
733
734         BT_CHECK_PARAMETER(handle, return);
735         BT_CHECK_PARAMETER(sender, return);
736         BT_CHECK_PARAMETER(param, return);
737
738         conn = _bt_gdbus_get_system_gconn();
739         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
740
741         BT_DBG("OTP Write Characteristic value handle [%s] data length [%d]", handle, length);
742         /* Check if activation is ongoing for the same Remote Server */
743
744         info = __bt_otp_get_notification_info(handle);
745         if (info && info->notification_timeout_id > 0) {
746                 BT_ERR("Write Request is already ongoing in remote server");
747                 g_free(charc_handle);
748                 return BLUETOOTH_ERROR_IN_PROGRESS;
749         }
750
751         builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
752
753         for (i = 0; i < length; i++) {
754                 g_variant_builder_add(builder1, "y", param[i]);
755         }
756
757         val = g_variant_new("(ay)", builder1);
758         builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
759         /*offset*/
760         g_variant_builder_add(builder2, "{sv}", "offset",
761                                 g_variant_new_uint16(offset));
762
763         options = g_variant_new("a{sv}", builder2);
764
765         /* Activate Control Point */
766         g_dbus_connection_call(conn,
767                         BT_BLUEZ_NAME,
768                         handle,
769                         GATT_CHAR_INTERFACE,
770                         "WriteValue",
771                         g_variant_new("(@ay@a{sv})",
772                         val, options),
773                         NULL,
774                         G_DBUS_CALL_FLAGS_NONE,
775                         -1, NULL,
776                         (GAsyncReadyCallback)__bt_otp_write_request_cb,
777                         (gpointer)charc_handle);
778
779         g_variant_builder_unref(builder1);
780         g_variant_builder_unref(builder2);
781
782         if (info == NULL) {
783                 info = g_malloc0(sizeof(bt_otp_notification_info));
784                 info->handle = g_strdup(handle);
785                 info->sender = g_strdup(sender);
786                 otp_notification_info_list = g_slist_append(otp_notification_info_list, info);
787         }
788         info->req_id = request_id;
789         info->notification_timeout_id = g_timeout_add(BT_INDICATION_TIMEOUT_MAX,
790                         (GSourceFunc)__bt_otp_indication_timeout_cb, (gpointer)info->handle);
791
792         BT_DBG("-");
793         return BLUETOOTH_ERROR_NONE;
794 }
795
796 void _bt_otp_check_indication(const char *path, GVariant *msg)
797 {
798         bt_otp_notification_info *info = NULL;
799         unsigned char *buffer = NULL;
800         int len = 0;
801         int i;
802         GVariant *value = NULL;
803         BT_DBG("+");
804
805         info = __bt_otp_get_notification_info((char *)path);
806
807         if (info) {
808                 g_variant_get(msg, "(is@ay)", NULL, NULL, &value);
809                 len = g_variant_get_size(value);
810                 BT_DBG("Indication data from Server len[%d]", len);
811                 if (len > 0) {
812                         buffer = (unsigned char *)g_variant_get_data(value);
813                         /* DEBUG */
814                         for (i = 0; i < len; i++)
815                                 BT_DBG("%.2x", buffer[i]);
816                 }
817
818                 /* Reset Timer */
819                 if (info->notification_timeout_id > 0)
820                         g_source_remove(info->notification_timeout_id);
821
822                 /* Send Indication & info removed internally */
823                 __bt_otp_send_indication_event(info, buffer, len, BLUETOOTH_ERROR_NONE);
824
825                 if (value)
826                         g_variant_unref(value);
827         }
828         BT_DBG("-");
829 }