cb3570129d86bf6bfd718f610e10d0e006ca0278
[platform/core/connectivity/bluetooth-frwk.git] / bt-service / bt-service-opp-client.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 <dlog.h>
20 #include <string.h>
21 #include <mime_type.h>
22 #include <aul.h>
23 #include <glib.h>
24 #include <gio/gio.h>
25
26 #include "bluetooth-api.h"
27 #include "bt-internal-types.h"
28
29 #include "bt-service-common.h"
30 #include "bt-service-event.h"
31 #include "bt-service-util.h"
32 #include "bt-service-opp-client.h"
33 #include "bt-service-obex-agent.h"
34 #include "bt-service-adapter.h"
35
36 #define BT_MIME_TYPE_MAX_LEN    20
37
38 static GSList *transfer_list = NULL;
39 bt_sending_info_t *sending_info;
40 static int file_offset = 0;
41
42 #define DBUS_TIEMOUT 20 * 1000  /* 20 Seconds */
43 static gboolean __bt_sending_release();
44 static int _bt_remove_session();
45
46 static int __bt_opp_client_start_sending(int request_id, char *address,
47                                         char **file_name_array, int file_count);
48
49 static GQuark __bt_opc_error_quark(void)
50 {
51         static GQuark quark = 0;
52         if (!quark)
53                 quark = g_quark_from_static_string("agent");
54
55         return quark;
56 }
57
58 static void __bt_free_transfer_info(bt_transfer_info_t *info)
59 {
60         ret_if(info == NULL);
61
62         if (info->proxy)
63                 g_object_unref(info->proxy);
64
65         if (info->properties_proxy)
66                 g_object_unref(info->properties_proxy);
67
68
69         g_free(info->transfer_name);
70         g_free(info->file_name);
71         g_free(info);
72 }
73
74 static void __bt_free_sending_info(bt_sending_info_t *info)
75 {
76         ret_if(info == NULL);
77
78         /* Free the sending variable */
79         __bt_free_transfer_info(info->transfer_info);
80
81         g_free(info->file_name_array);
82
83         g_free(info->address);
84         g_free(info);
85 }
86
87 static gboolean __bt_cancel_push_cb(gpointer data)
88 {
89         BT_DBG("+");
90
91         int result = BLUETOOTH_ERROR_CANCEL_BY_USER;
92         GVariant *param = NULL;
93         retv_if(sending_info == NULL, FALSE);
94         sending_info->result = result;
95
96         param = g_variant_new("(isi)", result,
97                                 sending_info->address,
98                                 sending_info->request_id);
99         /* Send the event in only error none case */
100         _bt_send_event(BT_OPP_CLIENT_EVENT,
101                         BLUETOOTH_EVENT_OPC_CONNECTED,
102                         param);
103         __bt_free_sending_info(sending_info);
104         sending_info = NULL;
105
106         _bt_opp_client_event_deinit();
107
108         BT_DBG("Length of transfer list is %d", g_slist_length(transfer_list));
109
110          /*Operate remain works*/
111         if (g_slist_length(transfer_list) > 0) {
112                 bt_sending_data_t *node = NULL;
113
114                 node = transfer_list->data;
115                 if (node == NULL) {
116                         BT_ERR("data is NULL");
117                         return FALSE;
118                 }
119
120                 transfer_list = g_slist_remove(transfer_list, node);
121
122                 if (__bt_opp_client_start_sending(node->request_id,
123                                 node->address, node->file_path,
124                                 node->file_count) != BLUETOOTH_ERROR_NONE) {
125                         BT_ERR("Fail to start sending");
126                 }
127         }
128         BT_DBG("-");
129         return FALSE;
130 }
131
132 gboolean _bt_obex_client_progress(const char *transfer_path, guint64 transferred)
133 {
134         BT_DBG("+");
135
136         int percentage_progress;
137         int previous_progress;
138         guint64 size;
139         int result = BLUETOOTH_ERROR_NONE;
140         GVariant *param = NULL;
141         retv_if(sending_info == NULL, TRUE);
142         retv_if(sending_info->transfer_info == NULL, TRUE);
143
144         if (g_strcmp0(sending_info->transfer_info->transfer_path,
145                         transfer_path) != 0) {
146                 BT_INFO("Path mismatch, previous transfer failed! Returning");
147                 return FALSE;
148         }
149
150         size = sending_info->transfer_info->size;
151         if (size != 0)
152                 percentage_progress = (int)(((gdouble)transferred /(gdouble)size) * 100);
153         else
154                 percentage_progress = 0;
155
156         sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_PROGRESS;
157         sending_info->result = result;
158
159         previous_progress = (int)(((gdouble)sending_info->transfer_info->progress /(gdouble)size) * 100);
160         if (percentage_progress == previous_progress &&
161                                                         sending_info->transfer_info->progress) {
162                 sending_info->transfer_info->progress = transferred;
163                 return TRUE;
164         }
165                 BT_DBG("Sending progress [prev %d] [curr %d]",
166                                                         previous_progress, percentage_progress);
167
168         sending_info->transfer_info->progress = transferred;
169
170         /* Send the event in only error none case */
171         param = g_variant_new("(istii)", result,
172                                 sending_info->transfer_info->file_name,
173                                 sending_info->transfer_info->size,
174                                 percentage_progress,
175                                 sending_info->request_id);
176
177
178         _bt_send_event(BT_OPP_CLIENT_EVENT,
179                         BLUETOOTH_EVENT_OPC_TRANSFER_PROGRESS,
180                         param);
181         BT_DBG("-");
182
183         return TRUE;
184 }
185
186 gboolean _bt_obex_client_completed(const char *transfer_path, gboolean success)
187 {
188         BT_DBG("+");
189
190         int result = BLUETOOTH_ERROR_NONE;
191         GVariant *param = NULL;
192         retv_if(sending_info == NULL, TRUE);
193         retv_if(sending_info->transfer_info == NULL, TRUE);
194
195         if (g_strcmp0(sending_info->transfer_info->transfer_path,
196                         transfer_path) != 0) {
197                 BT_INFO("Path mismatch, previous transfer failed! Returning");
198                 return FALSE;
199         }
200
201         result = (success == TRUE) ? BLUETOOTH_ERROR_NONE : BLUETOOTH_ERROR_CANCEL;
202
203         sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_COMPLETED;
204         sending_info->result = result;
205
206         if (!success) { /*In case of remote device reject, we need to send BLUETOOTH_EVENT_OPC_DISCONNECTED */
207                 BT_DBG("completed with error");
208                 if (!sending_info->is_canceled) {
209                         param = g_variant_new("(issti)", result,
210                                                 sending_info->address,
211                                                 sending_info->transfer_info->file_name,
212                                                 sending_info->transfer_info->size,
213                                                 sending_info->request_id);
214                         _bt_send_event(BT_OPP_CLIENT_EVENT,
215                                         BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
216                                         param);
217                    __bt_free_transfer_info(sending_info->transfer_info);
218                    sending_info->transfer_info = NULL;
219                    /* Reset the file offset as we will cancelled remaining files also */
220                    file_offset = 0;
221                 }
222                 param = g_variant_new("(isi)", sending_info->result,
223                                         sending_info->address,
224                                         sending_info->request_id);
225                 _bt_send_event(BT_OPP_CLIENT_EVENT,
226                                 BLUETOOTH_EVENT_OPC_DISCONNECTED,
227                                 param);
228                 __bt_sending_release();
229                 /* Sending info should not freed after sending_release it's
230                  * already freed in that API and if any pending request is
231                  * present then it recreate sending_info again.
232                  * And if we free it here then CreateSession method call will
233                  * made but RemoveSession method call will not done.
234                  */
235         } else {
236                 BT_DBG("complete success");
237                 /* Send the event in only error none case */
238                 param = g_variant_new("(issti)", result,
239                                         sending_info->address,
240                                         sending_info->transfer_info->file_name,
241                                         sending_info->transfer_info->size,
242                                         sending_info->request_id);
243                 _bt_send_event(BT_OPP_CLIENT_EVENT,
244                                 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
245                                 param);
246            __bt_free_transfer_info(sending_info->transfer_info);
247            sending_info->transfer_info = NULL;
248         }
249
250         BT_DBG("-");
251
252         return TRUE;
253 }
254
255 gboolean _bt_obex_client_started(const char *transfer_path)
256 {
257         BT_DBG("+");
258
259         int result = BLUETOOTH_ERROR_NONE;
260         GError *error = NULL;
261         GVariant *param = NULL;
262         GDBusConnection *g_conn;
263         GDBusProxy *properties_proxy;
264         GDBusProxy *transfer_proxy;
265
266         if (sending_info == NULL || sending_info->is_canceled == TRUE) {
267                 result = BLUETOOTH_ERROR_CANCEL_BY_USER;
268                 goto canceled;
269         }
270
271         /* Get the session bus. */
272         g_conn = _bt_get_session_gconn();
273         retv_if(g_conn == NULL, FALSE);
274         properties_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
275                                                 NULL, BT_OBEXD_DBUS_NAME,
276                                                 transfer_path, BT_PROPERTIES_INTERFACE,
277                                                 NULL, &error);
278
279         retv_if(properties_proxy == NULL, FALSE);
280
281         sending_info->transfer_info->properties_proxy = properties_proxy;
282
283         transfer_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
284                                                 NULL, BT_OBEXD_DBUS_NAME,
285                                                 transfer_path, BT_OBEX_TRANSFER_INTERFACE,
286                                                 NULL, &error);
287
288         retv_if(transfer_proxy == NULL, FALSE);
289
290         sending_info->transfer_info->proxy = transfer_proxy;
291
292         sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_STARTED;
293         sending_info->result = result;
294
295         param = g_variant_new("(issti)", result,
296                                 sending_info->address,
297                                 sending_info->transfer_info->file_name,
298                                 sending_info->transfer_info->size,
299                                 sending_info->request_id);
300         _bt_send_event(BT_OPP_CLIENT_EVENT,
301                         BLUETOOTH_EVENT_OPC_TRANSFER_STARTED,
302                         param);
303
304         BT_DBG("-");
305         return TRUE;
306 canceled:
307         error = g_error_new(__bt_opc_error_quark(), BT_OBEX_AGENT_ERROR_CANCEL,
308                         "CancelledByUser");
309
310         g_error_free(error);
311
312         BT_DBG("-");
313         return FALSE;
314 }
315
316 static void __bt_free_sending_data(gpointer data)
317 {
318         int i;
319         bt_sending_data_t *info = data;
320
321         ret_if(info == NULL);
322
323         for (i = 0; i < info->file_count; i++) {
324                 g_free(info->file_path[i]);
325         }
326
327         _bt_delete_request_id(info->request_id);
328
329         g_free(info->file_path);
330         g_free(info->address);
331         g_free(info);
332 }
333
334 static void __bt_sending_release_cb(GDBusProxy *proxy,
335                                 GAsyncResult *res, gpointer user_data)
336 {
337         BT_DBG("+");
338         ret_if(sending_info == NULL);
339
340         GError *error = NULL;
341         int result = BLUETOOTH_ERROR_NONE;
342         GVariant *param = NULL;
343         g_dbus_proxy_call_finish(proxy, res, &error);
344         if (proxy)
345                 g_object_unref(proxy);
346
347         if (error) {
348                 BT_ERR("%s", error->message);
349                 g_error_free(error);
350
351                 result = BLUETOOTH_ERROR_INTERNAL;
352         } else {
353                 file_offset = 0;
354                 BT_DBG("Session Removed");
355         }
356
357         sending_info->result = result;
358         param = g_variant_new("(isi)", sending_info->result,
359                                 sending_info->address,
360                                 sending_info->request_id);
361         /* Send the event in only error none case */
362         _bt_send_event(BT_OPP_CLIENT_EVENT,
363                         BLUETOOTH_EVENT_OPC_DISCONNECTED,
364                         param);
365
366         __bt_free_sending_info(sending_info);
367         sending_info = NULL;
368
369         _bt_opp_client_event_deinit();
370
371         /* Operate remain works */
372         if (g_slist_length(transfer_list) > 0) {
373                 bt_sending_data_t *data = NULL;
374
375                 data = transfer_list->data;
376                 if (data == NULL)
377                         goto fail;
378
379                 transfer_list = g_slist_remove(transfer_list, data);
380
381                 BT_DBG("calling __bt_opp_client_start_sending");
382
383                 if (__bt_opp_client_start_sending(data->request_id,
384                                 data->address, data->file_path,
385                                 data->file_count) != BLUETOOTH_ERROR_NONE) {
386                         goto fail;
387                 }
388         }
389
390         return;
391 fail:
392         g_slist_free_full(transfer_list,
393                                 (GDestroyNotify)__bt_free_sending_data);
394         transfer_list = NULL;
395
396         BT_DBG("-");
397
398         return;
399 }
400
401 static int _bt_remove_session()
402 {
403         GDBusConnection *g_conn;
404         GDBusProxy *session_proxy;
405         GError *err = NULL;
406
407         g_conn = _bt_get_session_gconn();
408         retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
409         retv_if(sending_info->session_path == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
410
411         session_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
412                                                 NULL, BT_OBEXD_DBUS_NAME,
413                                                 BT_OBEX_CLIENT_PATH,
414                                                 BT_OBEX_CLIENT_INTERFACE,
415                                                 NULL, &err);
416
417         retv_if(session_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
418
419         g_dbus_proxy_call(session_proxy, "RemoveSession",
420                 g_variant_new("(o)", sending_info->session_path),
421                 G_DBUS_CALL_FLAGS_NONE,
422                 DBUS_TIEMOUT, NULL,
423                 (GAsyncReadyCallback)__bt_sending_release_cb,
424                 NULL);
425
426         return BLUETOOTH_ERROR_NONE;
427 }
428
429 static gboolean __bt_sending_release()
430 {
431         BT_DBG("+");
432
433         retv_if(sending_info == NULL, FALSE);
434
435         retv_if(_bt_remove_session() != BLUETOOTH_ERROR_NONE, FALSE);
436
437         BT_DBG("-");
438         return TRUE;
439 }
440
441 void _bt_opc_disconnected(const char *session_path)
442 {
443         BT_DBG("+");
444         GVariant *param = NULL;
445         ret_if(sending_info == NULL);
446
447         if (g_strcmp0(sending_info->session_path,
448                         session_path) != 0) {
449                 BT_INFO("Path mismatch, previous transfer failed! Returning");
450                 return;
451         }
452
453         if (sending_info->transfer_info) {
454                 if (sending_info->transfer_info->transfer_status == BT_TRANSFER_STATUS_PROGRESS ||
455                                 sending_info->transfer_info->transfer_status == BT_TRANSFER_STATUS_STARTED) {
456                         BT_INFO("Abnormal termination");
457                         param = g_variant_new("(issti)", sending_info->result,
458                                                 sending_info->address,
459                                                 sending_info->transfer_info->file_name,
460                                                 sending_info->transfer_info->size,
461                                                 sending_info->request_id);
462                         _bt_send_event(BT_OPP_CLIENT_EVENT,
463                                         BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
464                                         param);
465                         __bt_free_transfer_info(sending_info->transfer_info);
466                 }
467         }
468         param = g_variant_new("(isi)", sending_info->result,
469                                 sending_info->address,
470                                 sending_info->request_id);
471         _bt_send_event(BT_OPP_CLIENT_EVENT,
472                         BLUETOOTH_EVENT_OPC_DISCONNECTED,
473                         param);
474
475         __bt_free_sending_info(sending_info);
476         sending_info = NULL;
477
478         BT_DBG("-");
479 }
480
481 static void __bt_send_file_cb(GDBusProxy *proxy,
482                                 GAsyncResult *res, gpointer user_data)
483 {
484         BT_DBG("+");
485         GVariant *value = NULL;
486         GError *error = NULL;
487         char *session_path = NULL;
488         const char *transfer_name = NULL;
489         const char *file_name = NULL;
490         int size = 0;
491         GVariantIter *iter = NULL;
492         value = g_dbus_proxy_call_finish(proxy, res, &error);
493         if (error) {
494                 g_dbus_error_strip_remote_error(error);
495                 BT_ERR("%s", error->message);
496                 /* If Obex is not able to open a file then continue with other if any */
497                 if (g_strcmp0("Unable to open file", error->message) == 0) {
498                         GVariant *param = NULL;
499                         gint64 size = 0;
500
501                         BT_ERR("Unable to open file [%s]", sending_info->file_name_array[file_offset]);
502
503                         param = g_variant_new("(issti)", BLUETOOTH_ERROR_NOT_FOUND,
504                                         sending_info->address,
505                                         sending_info->file_name_array[file_offset],
506                                         size,
507                                         sending_info->request_id);
508                         _bt_send_event(BT_OPP_CLIENT_EVENT,
509                                         BLUETOOTH_EVENT_OPC_TRANSFER_STARTED,
510                                         param);
511
512                         param = g_variant_new("(issti)", BLUETOOTH_ERROR_NOT_FOUND,
513                                                 sending_info->address,
514                                                 sending_info->file_name_array[file_offset],
515                                                 size,
516                                                 sending_info->request_id);
517                         _bt_send_event(BT_OPP_CLIENT_EVENT,
518                                         BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
519                                         param);
520                         g_error_free(error);
521                         if (proxy)
522                                 g_object_unref(proxy);
523                         file_offset++;
524                         _bt_sending_files();
525                 }
526                 return;
527         }
528         if (proxy)
529                 g_object_unref(proxy);
530
531         if (value) {
532                 g_variant_get(value, "(oa{sv})", &session_path, &iter);
533                 g_variant_unref(value);
534         }
535
536         __bt_free_transfer_info(sending_info->transfer_info);
537
538         sending_info->transfer_info = g_malloc0(sizeof(bt_transfer_info_t));
539
540         if (iter) {
541                 const gchar *key;
542                 GVariant *val;
543                 gsize len = 0;
544                 while (g_variant_iter_loop(iter, "{sv}", &key, &val)) {
545                         if (g_strcmp0(key, "Name") == 0) {
546                                 transfer_name = g_variant_dup_string(val, &len);
547                         } else if (g_strcmp0(key, "Filename") == 0) {
548                                 file_name = g_variant_dup_string(val, &len);
549                         } else if (g_strcmp0(key, "Size") == 0) {
550                                 size = g_variant_get_uint64(val);
551                         }
552                 }
553                 g_variant_iter_free(iter);
554         }
555
556         sending_info->transfer_info->transfer_name = g_strdup(transfer_name);
557         sending_info->transfer_info->file_name = g_strdup(file_name);
558         sending_info->transfer_info->size = size;
559         sending_info->transfer_info->progress = 0;
560         sending_info->transfer_info->transfer_path = session_path;
561         sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_QUEUED;
562         sending_info->result = BLUETOOTH_ERROR_NONE;
563         file_offset++;
564 }
565
566 void _bt_sending_files(void)
567 {
568         BT_DBG("+");
569
570         GError *err = NULL;
571         GDBusConnection *g_conn;
572         GDBusProxy *client_proxy;
573         char mime_type[BT_MIME_TYPE_MAX_LEN + 1] = { 0 };
574
575         if (sending_info == NULL)
576                 return;
577         if (file_offset < sending_info->file_count) {
578                 /* Get the session bus. */
579                 g_conn = _bt_get_session_gconn();
580                 ret_if(g_conn == NULL);
581
582                 client_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
583                                                 NULL, BT_OBEXD_DBUS_NAME,
584                                                 sending_info->session_path,
585                                                 BT_OBEX_OBJECT_PUSH_INTERFACE,
586                                                 NULL, &err);
587                 ret_if(client_proxy == NULL);
588                 if (aul_get_mime_from_file(sending_info->file_name_array[file_offset],
589                                 mime_type, BT_MIME_TYPE_MAX_LEN) == AUL_R_OK) {
590                                 BT_DBG("MLME type = %s", mime_type);
591
592                                 /* For IOPT compliance, change "text/x-iMelody" to "audio/imelody"
593                                  * because few devices(multimedia players) reject the OPP put for text objects
594                                  * since they support only multimedia files exchange */
595                                 if(!strcasecmp(mime_type, "text/x-iMelody")) {
596                                         strncpy(mime_type, "audio/imelody", BT_MIME_TYPE_MAX_LEN);
597                                         BT_DBG("over writing mime type to  = %s", mime_type);
598                                 }
599                                 if(!strcasecmp(mime_type, "text/vcard")) {
600                                         strncpy(mime_type, "text/x-vcard", BT_MIME_TYPE_MAX_LEN);
601                                         BT_DBG("over writing mime type to  = %s", mime_type);
602                                 }
603                 }
604
605                 BT_DBG("Calling SendFile");
606                 g_dbus_proxy_call(client_proxy, "SendFile",
607                                 g_variant_new("(ss)", sending_info->file_name_array[file_offset],
608                                                                 mime_type),
609                                 G_DBUS_CALL_FLAGS_NONE,
610                                 DBUS_TIEMOUT, NULL,
611                                 (GAsyncReadyCallback)__bt_send_file_cb,
612                                 sending_info);
613                 if (err != NULL) {
614                         BT_ERR("Calling SendFile failed: [%s]\n", err->message);
615                         g_clear_error(&err);
616                         return;
617                 }
618
619         }else{
620                 file_offset = 0;
621                 __bt_sending_release();
622         }
623
624         BT_DBG("-");
625 }
626
627 static void __bt_create_session_cb(GDBusProxy *proxy,
628                                 GAsyncResult *res, gpointer user_data)
629 {
630         BT_DBG("+");
631
632         GError *error = NULL;
633         GVariant *value;
634         int result = BLUETOOTH_ERROR_NONE;
635         char *session_path = NULL;
636         GVariant *param = NULL;
637
638         value = g_dbus_proxy_call_finish(proxy, res, &error);
639         if (value) {
640                 g_variant_get(value, "(o)", &session_path);
641                 g_variant_unref(value);
642         }
643         if (error) {
644
645                 BT_ERR("%s", error->message);
646                 g_clear_error(&error);
647
648                 result = BLUETOOTH_ERROR_INTERNAL;
649         } else {
650                 BT_DBG("Session created");
651                 if (sending_info != NULL)
652                         sending_info->session_path = g_strdup(session_path);
653         }
654         g_free(session_path);
655         g_object_unref(proxy);
656         ret_if(sending_info == NULL);
657
658         sending_info->result = result;
659         param = g_variant_new("(isi)", result,
660                                 sending_info->address,
661                                 sending_info->request_id);
662         /* Send the event in only error none case */
663         _bt_send_event(BT_OPP_CLIENT_EVENT,
664                         BLUETOOTH_EVENT_OPC_CONNECTED,
665                         param);
666
667         if (result != BLUETOOTH_ERROR_NONE) {
668                 BT_ERR("Calling __bt_sending_release");
669                 gboolean ret = __bt_sending_release();
670
671                 __bt_free_sending_info(sending_info);
672                 sending_info = NULL;
673
674                 if (ret == FALSE) {
675                         BT_DBG("ReleaseSession Not called");
676                         /* Operate remain works */
677                         if (g_slist_length(transfer_list) > 0) {
678                                 bt_sending_data_t *data = NULL;
679
680                                 data = transfer_list->data;
681                                 ret_if(data == NULL);
682
683                                 transfer_list = g_slist_remove(transfer_list, data);
684
685                                 BT_DBG("calling __bt_opp_client_start_sending");
686
687                                 if (__bt_opp_client_start_sending(data->request_id,
688                                                 data->address, data->file_path,
689                                                 data->file_count) != BLUETOOTH_ERROR_NONE) {
690                                         BT_ERR("Sending Enqueued Transfer Failed");
691                                 }
692                         }
693                 }
694         } else {
695                 BT_DBG("Calling sending_files");
696                 _bt_sending_files();
697         }
698         BT_DBG("-");
699
700 }
701
702 static int __bt_opp_client_start_sending(int request_id, char *address,
703                                         char **file_name_array, int file_count)
704 {
705         GVariantBuilder *builder;
706         int i;
707         GDBusConnection *g_conn;
708         GDBusProxy *client_proxy;
709         GError *error = NULL;
710         BT_DBG("+");
711
712         BT_CHECK_PARAMETER(address, return);
713         BT_CHECK_PARAMETER(file_name_array, return);
714
715         /* Get the session bus. */
716         g_conn = _bt_get_session_gconn();
717         retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
718
719         client_proxy =  g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
720                                         NULL, BT_OBEX_SERVICE_NAME,
721                                         BT_OBEX_CLIENT_PATH,
722                                         BT_OBEX_CLIENT_INTERFACE,
723                                         NULL, &error);
724
725         if (error) {
726                 BT_ERR("Unable to create client proxy: %s", error->message);
727                 g_clear_error(&error);
728         }
729
730         retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
731
732         builder = g_variant_builder_new(
733                                 G_VARIANT_TYPE("a{sv}"));
734
735         g_variant_builder_add(builder, "{sv}", "Target",
736                 g_variant_new_string("OPP"));
737
738         __bt_free_sending_info(sending_info);
739
740         sending_info = g_malloc0(sizeof(bt_sending_info_t));
741         sending_info->address = g_strdup(address);
742         sending_info->request_id = request_id;
743
744         sending_info->file_count = file_count;
745         sending_info->file_offset = 0;
746         sending_info->file_name_array = g_new0(char *, file_count + 1);
747
748         for (i = 0; i < file_count; i++) {
749                 sending_info->file_name_array[i] = g_strdup(file_name_array[i]);
750                 BT_DBG("file[%d]: %s", i, sending_info->file_name_array[i]);
751         }
752
753         _bt_opp_client_event_deinit();
754         _bt_opp_client_event_init();
755         //_bt_obex_client_started(agent_path);
756
757         BT_DBG("Adapter Status %d", _bt_adapter_get_status());
758         if (_bt_adapter_get_status() == BT_ACTIVATED) {
759                 BT_DBG("Going to call CreateSession");
760                 g_dbus_proxy_call(client_proxy, "CreateSession",
761                                                 g_variant_new("(sa{sv})", address, builder),
762                                                 G_DBUS_CALL_FLAGS_NONE,
763                                                 DBUS_TIEMOUT, NULL,
764                                                 (GAsyncReadyCallback)__bt_create_session_cb,
765                                                 NULL);
766         } else {
767                 GVariant *param = g_variant_new("(isi)", BLUETOOTH_ERROR_INTERNAL,
768                                 sending_info->address, sending_info->request_id);
769
770                 BT_DBG("Address[%s] RequestID[%d]", sending_info->address, sending_info->request_id);
771                 _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_CONNECTED,
772                                                                         param);
773                 __bt_free_sending_info(sending_info);
774                 sending_info = NULL;
775         }
776         g_variant_builder_unref(builder);
777
778         BT_DBG("-");
779
780         return BLUETOOTH_ERROR_NONE;
781 }
782
783 int _bt_opp_client_push_files(int request_id, GDBusMethodInvocation *context,
784                                 bluetooth_device_address_t *remote_address,
785                                 char **file_path, int file_count)
786 {
787         BT_DBG("+");
788         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
789         bt_sending_data_t *data;
790
791         GVariant *out_param1 = NULL;
792
793         int result = BLUETOOTH_ERROR_NONE;
794         int i;
795
796         BT_CHECK_PARAMETER(remote_address, return);
797         BT_CHECK_PARAMETER(file_path, return);
798
799         /* Implement the queue */
800         _bt_convert_addr_type_to_string(address, remote_address->addr);
801
802         if (sending_info == NULL) {
803                 result = __bt_opp_client_start_sending(request_id,
804                                                 address, file_path, file_count);
805                 if (result != BLUETOOTH_ERROR_NONE)
806                         return result;
807         } else {
808                 /* Insert data in the queue */
809                 data = g_malloc0(sizeof(bt_sending_data_t));
810                 if (data == NULL)
811                         return BLUETOOTH_ERROR_MEMORY_ALLOCATION;
812
813                 data->file_path = g_new0(char *, file_count + 1);
814                 data->address = g_strdup(address);
815                 data->file_count = file_count;
816                 data->request_id = request_id;
817
818                 for (i = 0; i < file_count; i++) {
819                         data->file_path[i] = g_strdup(file_path[i]);
820                         DBG_SECURE("file[%d]: %s", i, data->file_path[i]);
821                 }
822
823                 transfer_list = g_slist_append(transfer_list, data);
824         }
825
826         out_param1 = g_variant_new_from_data((const GVariantType *)"ay",
827                                                         &request_id, sizeof(int),
828                                                         TRUE, NULL, NULL);
829
830
831         g_dbus_method_invocation_return_value(context,
832                         g_variant_new("(iv)", result, out_param1));
833
834         BT_DBG("-");
835
836         return result;
837 }
838
839 int _bt_opp_client_cancel_push(void)
840 {
841         BT_DBG("+");
842
843         GError *err = NULL;
844         int result = BLUETOOTH_ERROR_CANCEL_BY_USER;
845         GVariant *ret = NULL;
846         GVariant *param = NULL;
847         retv_if(sending_info == NULL, BLUETOOTH_ERROR_NOT_IN_OPERATION);
848
849         sending_info->is_canceled = TRUE;
850         sending_info->result = result;
851
852         if (sending_info->transfer_info) {
853
854                 ret = g_dbus_proxy_call_sync(sending_info->transfer_info->proxy,
855                                         "Cancel", NULL,
856                                         G_DBUS_CALL_FLAGS_NONE, -1,
857                                         NULL, &err);
858                 if (ret == NULL) {
859                         if (err != NULL) {
860                                 BT_ERR("Cancel Error: %s\n", err->message);
861                                 g_error_free(err);
862                         }
863                 } else {
864                         g_variant_unref(ret);
865                 }
866
867                 param = g_variant_new("(issti)", result,
868                                         sending_info->address,
869                                         sending_info->transfer_info->file_name,
870                                         sending_info->transfer_info->size,
871                                         sending_info->request_id);
872                 _bt_send_event(BT_OPP_CLIENT_EVENT,
873                                 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
874                                 param);
875
876                 if (result == BLUETOOTH_ERROR_CANCEL_BY_USER) {
877                         BT_ERR("result is not BLUETOOTH_ERROR_NONE");
878                         __bt_sending_release();
879                         file_offset = 0;
880                 }
881
882         } else {
883                 g_idle_add(__bt_cancel_push_cb, NULL);
884         }
885
886         BT_DBG("-");
887
888         return BLUETOOTH_ERROR_NONE;
889 }
890
891 int _bt_opp_client_cancel_all_transfers(void)
892 {
893         BT_DBG("+");
894         if (transfer_list) {
895                 g_slist_free_full(transfer_list,
896                         (GDestroyNotify)__bt_free_sending_data);
897
898                 transfer_list = NULL;
899         }
900
901         _bt_opp_client_cancel_push();
902         BT_DBG("-");
903         return BLUETOOTH_ERROR_NONE;
904 }
905
906 int _bt_opp_client_is_sending(gboolean *sending)
907 {
908         BT_CHECK_PARAMETER(sending, return);
909
910         *sending = sending_info ? TRUE : FALSE;
911
912         return BLUETOOTH_ERROR_NONE;
913 }
914
915 void _bt_opp_client_check_pending_transfer(const char *address)
916 {
917         BT_DBG("+");
918
919         int result = BLUETOOTH_ERROR_CANCEL;
920         GVariant *param = NULL;
921         ret_if(sending_info == NULL);
922         ret_if(sending_info->transfer_info == NULL);
923
924         if (g_strcmp0(sending_info->address, address) == 0) {
925                 BT_INFO("Address Match.Cancel current transfer");
926                 sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_COMPLETED;
927                 sending_info->result = result;
928
929                 if (!sending_info->is_canceled) {
930                         param = g_variant_new("(issti)", result,
931                                                 sending_info->address,
932                                                 sending_info->transfer_info->file_name,
933                                                 sending_info->transfer_info->size,
934                                                 sending_info->request_id);
935                         _bt_send_event(BT_OPP_CLIENT_EVENT,
936                                         BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
937                                         param);
938                         __bt_free_transfer_info(sending_info->transfer_info);
939                         sending_info->transfer_info = NULL;
940                         /* Reset the file offset as we will cancelled remaining files also */
941                         file_offset = 0;
942                 }
943                 param = g_variant_new("(isi)", sending_info->result,
944                                         sending_info->address,
945                                         sending_info->request_id);
946                 _bt_send_event(BT_OPP_CLIENT_EVENT,
947                                 BLUETOOTH_EVENT_OPC_DISCONNECTED,
948                                 param);
949
950                 __bt_sending_release();
951         }
952         BT_DBG("-");
953 }
954
955 int _bt_opp_get_client_progress(guint8 *progress)
956 {
957         if (sending_info == NULL || sending_info->transfer_info == NULL) {
958                 BT_ERR("No Active Outbound transfer");
959                 return BLUETOOTH_ERROR_NOT_FOUND;
960         }
961
962         *progress = (int)(((double)sending_info->transfer_info->progress /
963                         sending_info->transfer_info->size) * 100);
964
965         BT_DBG("Percentage: %d", *progress);
966         return BLUETOOTH_ERROR_NONE;
967 }
968
969 void _bt_cancel_queued_transfers(void)
970 {
971         bt_sending_data_t *data = NULL;
972         GVariant *param = NULL;
973
974         BT_INFO("Cancel queued Transfers:: Length of transfer list is %d",
975                                         g_slist_length(transfer_list));
976
977         while (transfer_list) {
978                 data = transfer_list->data;
979                 param = g_variant_new("(isi)", BLUETOOTH_ERROR_INTERNAL,
980                                 data->address, data->request_id);
981
982                 BT_DBG("Address[%s] RequestID[%d]", data->address, data->request_id);
983                 _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_CONNECTED,
984                                                                         param);
985
986                 transfer_list = g_slist_remove(transfer_list, data);
987         }
988 }