Rollback changes to submit TIZEN:COMMON project
[platform/core/connectivity/bluetooth-frwk.git] / bt-service / bt-service-opp-client.c
1 /*
2  * bluetooth-frwk
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <dbus/dbus-glib.h>
21 #include <dbus/dbus.h>
22 #include <glib.h>
23 #include <dlog.h>
24 #include <string.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
35 static GSList *transfer_list = NULL;
36
37 bt_sending_info_t *sending_info;
38
39 static int __bt_opp_client_start_sending(int request_id, char *address,
40                                         char **file_name_array, int file_count);
41
42 static gboolean __bt_sending_release();
43
44 static GQuark __bt_opc_error_quark(void)
45 {
46         static GQuark quark = 0;
47         if (!quark)
48                 quark = g_quark_from_static_string("agent");
49
50         return quark;
51 }
52
53 static void __bt_free_transfer_info(bt_transfer_info_t *info)
54 {
55         ret_if(info == NULL);
56
57         if (info->proxy)
58                 g_object_unref(info->proxy);
59
60         g_free(info->transfer_name);
61         g_free(info->file_name);
62         g_free(info);
63 }
64
65 static void __bt_free_sending_info(bt_sending_info_t *info)
66 {
67         ret_if(info == NULL);
68
69         /* Free the sending variable */
70         __bt_free_transfer_info(info->transfer_info);
71
72         g_free(info->file_name_array);
73         g_free(info->address);
74         g_free(info);
75 }
76
77 static void __bt_value_free(GValue *value)
78 {
79         g_value_unset(value);
80         g_free(value);
81 }
82
83 static gboolean __bt_cancel_push_cb(gpointer data)
84 {
85         int result = BLUETOOTH_ERROR_CANCEL_BY_USER;
86
87         retv_if(sending_info == NULL, FALSE);
88
89         /* Send the event in only error none case */
90         _bt_send_event(BT_OPP_CLIENT_EVENT,
91                         BLUETOOTH_EVENT_OPC_CONNECTED,
92                         DBUS_TYPE_INT32, &result,
93                         DBUS_TYPE_STRING, &sending_info->address,
94                         DBUS_TYPE_INT32, &sending_info->request_id,
95                         DBUS_TYPE_INVALID);
96
97         __bt_free_sending_info(sending_info);
98         sending_info = NULL;
99
100         _bt_opp_client_event_deinit();
101
102         /* Operate remain works */
103         if (g_slist_length(transfer_list) > 0) {
104                 bt_sending_data_t *node = NULL;
105
106                 node = transfer_list->data;
107                 if (node == NULL) {
108                         BT_DBG("data is NULL");
109                         return FALSE;
110                 }
111
112                 transfer_list = g_slist_remove(transfer_list, node);
113
114                 if (__bt_opp_client_start_sending(node->request_id,
115                                 node->address,
116                                 node->file_path,
117                                 node->file_count) != BLUETOOTH_ERROR_NONE) {
118                         BT_DBG("Fail to start sending");
119                 }
120         }
121
122         return FALSE;
123 }
124
125 gboolean _bt_obex_client_progress(int transferred)
126 {
127         int percentage_progress;
128         gint64 size;
129         int result = BLUETOOTH_ERROR_NONE;
130
131         retv_if(sending_info == NULL, TRUE);
132         retv_if(sending_info->transfer_info == NULL, TRUE);
133
134         size = sending_info->transfer_info->size;
135
136         if (size != 0)
137                 percentage_progress = (int)(((gdouble)transferred /
138                                 (gdouble)size) * 100);
139         else
140                 percentage_progress = 0;
141
142         /* Send the event in only error none case */
143         _bt_send_event(BT_OPP_CLIENT_EVENT,
144                         BLUETOOTH_EVENT_OPC_TRANSFER_PROGRESS,
145                         DBUS_TYPE_INT32, &result,
146                         DBUS_TYPE_STRING, &sending_info->transfer_info->file_name,
147                         DBUS_TYPE_UINT64, &sending_info->transfer_info->size,
148                         DBUS_TYPE_INT32, &percentage_progress,
149                         DBUS_TYPE_INT32, &sending_info->request_id,
150                         DBUS_TYPE_INVALID);
151
152         return TRUE;
153 }
154
155 gboolean _bt_obex_client_completed(gboolean success)
156 {
157         int result = BLUETOOTH_ERROR_NONE;
158
159         BT_DBG("Success [%d] \n", success);
160
161         result = (success == TRUE) ? BLUETOOTH_ERROR_NONE
162                                 : BLUETOOTH_ERROR_CANCEL;
163
164         /* Send the event in only error none case */
165         _bt_send_event(BT_OPP_CLIENT_EVENT,
166                         BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
167                         DBUS_TYPE_INT32, &result,
168                         DBUS_TYPE_STRING, &sending_info->transfer_info->file_name,
169                         DBUS_TYPE_UINT64, &sending_info->transfer_info->size,
170                         DBUS_TYPE_INT32, &sending_info->request_id,
171                         DBUS_TYPE_INVALID);
172
173         return TRUE;
174 }
175
176 gboolean _bt_obex_client_started(const char *transfer_path)
177 {
178         GValue *value;
179         const char *transfer_name;
180         const char *file_name;
181         int size;
182         int result = BLUETOOTH_ERROR_NONE;
183         GHashTable *hash = NULL;
184         GError *error;
185         DBusGConnection *g_conn;
186         DBusGProxy *transfer_proxy;
187
188         if (sending_info == NULL || sending_info->is_canceled == TRUE) {
189                 result = BLUETOOTH_ERROR_CANCEL_BY_USER;
190                 goto canceled;
191         }
192
193         /* Get the session bus. */
194         g_conn = _bt_get_session_gconn();
195         retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
196
197         __bt_free_transfer_info(sending_info->transfer_info);
198
199         sending_info->transfer_info = g_malloc0(sizeof(bt_transfer_info_t));
200
201         transfer_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEXD_DBUS_NAME,
202                                 transfer_path, BT_PROPERTIES_INTERFACE);
203
204         retv_if(transfer_proxy == NULL, FALSE);
205
206         sending_info->transfer_info->proxy = transfer_proxy;
207
208         if (!dbus_g_proxy_call(transfer_proxy, "GetAll", NULL,
209                                 G_TYPE_STRING, BT_OBEX_TRANSFER_INTERFACE,
210                                 G_TYPE_INVALID,
211                                 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
212                                 G_TYPE_VALUE), &hash, G_TYPE_INVALID))
213                 goto fail;
214
215         if (hash == NULL)
216                 goto fail;
217
218         value = g_hash_table_lookup(hash, "Name");
219         transfer_name = value ? g_value_get_string(value) : NULL;
220
221         value = g_hash_table_lookup(hash, "Filename");
222         file_name = value ? g_value_get_string(value) : NULL;
223
224         value = g_hash_table_lookup(hash, "Size");
225         size = value ? g_value_get_uint64(value) : 0;
226
227         sending_info->transfer_info->transfer_name = g_strdup(transfer_name);
228         sending_info->transfer_info->file_name = g_strdup(file_name);
229         sending_info->transfer_info->size = size;
230         sending_info->result = BLUETOOTH_ERROR_NONE;
231
232         g_hash_table_destroy(hash);
233
234         _bt_send_event(BT_OPP_CLIENT_EVENT,
235                         BLUETOOTH_EVENT_OPC_TRANSFER_STARTED,
236                         DBUS_TYPE_INT32, &result,
237                         DBUS_TYPE_STRING, &sending_info->transfer_info->file_name,
238                         DBUS_TYPE_UINT64, &sending_info->transfer_info->size,
239                         DBUS_TYPE_INT32, &sending_info->request_id,
240                         DBUS_TYPE_INVALID);
241
242         return TRUE;
243 canceled:
244         error = g_error_new(__bt_opc_error_quark(), BT_OBEX_AGENT_ERROR_CANCEL,
245                         "CancelledByUser");
246
247         g_error_free(error);
248
249         return FALSE;
250 fail:
251         result = BLUETOOTH_ERROR_INTERNAL;
252
253         /* Send the event in only error none case */
254         _bt_send_event(BT_OPP_CLIENT_EVENT,
255                         BLUETOOTH_EVENT_OPC_DISCONNECTED,
256                         DBUS_TYPE_INT32, &result,
257                         DBUS_TYPE_STRING, &sending_info->address,
258                         DBUS_TYPE_INT32, &sending_info->request_id,
259                         DBUS_TYPE_INVALID);
260
261         __bt_free_sending_info(sending_info);
262         sending_info = NULL;
263
264         _bt_opp_client_event_deinit();
265
266         return TRUE;
267 }
268
269 static void __bt_free_sending_data(gpointer data)
270 {
271         int i;
272         bt_sending_data_t *info = data;
273
274         ret_if(info == NULL);
275
276         for (i = 0; i < info->file_count; i++) {
277                 g_free(info->file_path[i]);
278         }
279
280         _bt_delete_request_id(info->request_id);
281
282         g_free(info->file_path);
283         g_free(info->address);
284         g_free(info);
285 }
286
287 static void __bt_send_files_cb(DBusGProxy *proxy, DBusGProxyCall *call,
288                                 void *user_data)
289 {
290         GError *error = NULL;
291         int result = BLUETOOTH_ERROR_NONE;
292
293         if (dbus_g_proxy_end_call(proxy, call, &error,
294                                         G_TYPE_INVALID) == FALSE) {
295
296                 BT_ERR("%s", error->message);
297                 g_error_free(error);
298
299                 result = BLUETOOTH_ERROR_INTERNAL;
300         }
301
302         g_object_unref(proxy);
303         ret_if(sending_info == NULL);
304
305         sending_info->sending_proxy = NULL;
306
307         /* Send the event in only error none case */
308         _bt_send_event(BT_OPP_CLIENT_EVENT,
309                         BLUETOOTH_EVENT_OPC_CONNECTED,
310                         DBUS_TYPE_INT32, &result,
311                         DBUS_TYPE_STRING, &sending_info->address,
312                         DBUS_TYPE_INT32, &sending_info->request_id,
313                         DBUS_TYPE_INVALID);
314
315         if (result != BLUETOOTH_ERROR_NONE) {
316                 __bt_free_sending_info(sending_info);
317                 sending_info = NULL;
318         }
319 }
320
321 static void _bt_remove_session()
322 {
323         DBusGConnection *g_conn;
324         DBusGProxy *session_proxy;
325
326         g_conn = _bt_get_session_gconn();
327         ret_if(g_conn == NULL);
328
329         session_proxy =  dbus_g_proxy_new_for_name(g_conn, BT_OBEXD_DBUS_NAME,
330                                         BT_OBEX_CLIENT_PATH, BT_OBEX_CLIENT_INTERFACE);
331
332         ret_if(session_proxy == NULL);
333
334         dbus_g_proxy_call(session_proxy, "RemoveSession",
335                 NULL, DBUS_TYPE_G_OBJECT_PATH, sending_info->session_path,
336                 G_TYPE_INVALID);
337
338 }
339
340 static gboolean __bt_sending_release()
341 {
342         retv_if(sending_info == NULL, FALSE);
343
344         _bt_remove_session();
345
346         /* Send the event in only error none case */
347         _bt_send_event(BT_OPP_CLIENT_EVENT,
348                         BLUETOOTH_EVENT_OPC_DISCONNECTED,
349                         DBUS_TYPE_INT32, &sending_info->result,
350                         DBUS_TYPE_STRING, &sending_info->address,
351                         DBUS_TYPE_INT32, &sending_info->request_id,
352                         DBUS_TYPE_INVALID);
353
354         __bt_free_sending_info(sending_info);
355         sending_info = NULL;
356
357         _bt_opp_client_event_deinit();
358
359         /* Operate remain works */
360         if (g_slist_length(transfer_list) > 0) {
361                 bt_sending_data_t *data = NULL;
362
363                 data = transfer_list->data;
364                 if (data == NULL)
365                         goto fail;
366
367                 transfer_list = g_slist_remove(transfer_list, data);
368
369                 if (__bt_opp_client_start_sending(data->request_id,
370                                 data->address,
371                                 data->file_path,
372                                 data->file_count) != BLUETOOTH_ERROR_NONE) {
373                         goto fail;
374                 }
375         }
376
377         return TRUE;
378 fail:
379         g_slist_free_full(transfer_list,
380                                 (GDestroyNotify)__bt_free_sending_data);
381         transfer_list = NULL;
382         return TRUE;
383 }
384
385 void _bt_sending_files()
386 {
387         DBusGConnection *g_conn;
388         DBusGProxy *client_proxy;
389         static int file_offset = 0;
390
391         BT_DBG("+");
392
393         if (sending_info == NULL)
394                 return;
395
396         if (file_offset < sending_info->file_count){
397                 /* Get the session bus. */
398                 g_conn = _bt_get_session_gconn();
399                 ret_if(g_conn == NULL);
400
401                 client_proxy =  dbus_g_proxy_new_for_name(g_conn,
402                                                 BT_OBEXD_DBUS_NAME,
403                                                 sending_info->session_path,
404                                                 BT_OBEX_OBJECT_PUSH_INTERFACE);
405
406                 ret_if(client_proxy == NULL);
407
408                 dbus_g_proxy_call(client_proxy, "SendFile",NULL,
409                                 G_TYPE_STRING,
410                                 sending_info->file_name_array[file_offset],
411                                 G_TYPE_INVALID);
412                 file_offset++;
413         }else{
414                 file_offset = 0;
415                 __bt_sending_release();
416         }
417
418         BT_DBG("-");
419 }
420
421 static void __bt_create_session_cb(DBusGProxy *proxy, DBusGProxyCall *call,
422                                         void *user_data)
423 {
424         GError *error = NULL;
425         int result = BLUETOOTH_ERROR_NONE;
426         char *session_path = NULL;
427
428         if (dbus_g_proxy_end_call(proxy, call, &error,
429                 DBUS_TYPE_G_OBJECT_PATH, &session_path, G_TYPE_INVALID) == FALSE) {
430
431                 BT_ERR("%s", error->message);
432                 g_error_free(error);
433
434                 result = BLUETOOTH_ERROR_INTERNAL;
435         }else{
436                 sending_info->session_path = g_strdup(session_path);
437         }
438
439         g_object_unref(proxy);
440         ret_if(sending_info == NULL);
441
442         sending_info->sending_proxy = NULL;
443
444         /* Send the event in only error none case */
445         _bt_send_event(BT_OPP_CLIENT_EVENT,
446                         BLUETOOTH_EVENT_OPC_CONNECTED,
447                         DBUS_TYPE_INT32, &result,
448                         DBUS_TYPE_STRING, &sending_info->address,
449                         DBUS_TYPE_INT32, &sending_info->request_id,
450                         DBUS_TYPE_INVALID);
451
452         if (result != BLUETOOTH_ERROR_NONE) {
453                 __bt_free_sending_info(sending_info);
454                 sending_info = NULL;
455         }else {
456                 _bt_sending_files();
457         }
458 }
459
460 static int __bt_opp_client_start_sending(int request_id, char *address,
461                                         char **file_name_array, int file_count)
462 {
463         GHashTable *hash;
464         GValue *value;
465         DBusGConnection *g_conn;
466         DBusGProxy *client_proxy;
467         DBusGProxyCall *proxy_call;
468         int i;
469
470         BT_CHECK_PARAMETER(address, return);
471         BT_CHECK_PARAMETER(file_name_array, return);
472
473         /* Get the session bus. */
474         g_conn = _bt_get_session_gconn();
475         retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
476
477         client_proxy =  dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME,
478                                         BT_OBEX_CLIENT_PATH, BT_OBEX_CLIENT_INTERFACE);
479
480         retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
481
482         hash = g_hash_table_new_full(g_str_hash, g_str_equal,
483                                 NULL, (GDestroyNotify)__bt_value_free);
484
485         value = g_new0(GValue, 1);
486         g_value_init(value, G_TYPE_STRING);
487         g_value_set_string(value, "OPP");
488         g_hash_table_insert(hash, "Target", value);
489
490         __bt_free_sending_info(sending_info);
491
492         sending_info = g_malloc0(sizeof(bt_sending_info_t));
493         sending_info->address = g_strdup(address);
494         sending_info->request_id = request_id;
495         sending_info->file_count = file_count;
496         sending_info->file_offset = 0;
497         sending_info->file_name_array = g_new0(char *, file_count + 1);
498
499         for (i = 0; i < file_count; i++) {
500                 sending_info->file_name_array[i] = g_strdup(file_name_array[i]);
501                 BT_DBG("file[%d]: %s", i, sending_info->file_name_array[i]);
502         }
503
504         _bt_opp_client_event_deinit();
505         _bt_opp_client_event_init();
506
507         proxy_call = dbus_g_proxy_begin_call(client_proxy, "CreateSession",
508                         __bt_create_session_cb, NULL, NULL,
509                         G_TYPE_STRING, address,
510                         dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
511                         hash, G_TYPE_INVALID);
512
513         if (proxy_call == NULL) {
514                         BT_ERR("Fail to Send files");
515                         g_hash_table_destroy(hash);
516                         g_object_unref(client_proxy);
517                         __bt_free_sending_info(sending_info);
518                         _bt_opp_client_event_deinit();
519                         sending_info = NULL;
520                         return BLUETOOTH_ERROR_INTERNAL;
521         }
522
523         sending_info->sending_proxy = proxy_call;
524         g_hash_table_destroy(hash);
525
526         return BLUETOOTH_ERROR_NONE;
527 }
528
529 int _bt_opp_client_push_files(int request_id, DBusGMethodInvocation *context,
530                                 bluetooth_device_address_t *remote_address,
531                                 char **file_path, int file_count)
532 {
533         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
534         bt_sending_data_t *data;
535         GArray *out_param1 = NULL;
536         GArray *out_param2 = NULL;
537         int result = BLUETOOTH_ERROR_NONE;
538         int i;
539
540         BT_CHECK_PARAMETER(remote_address, return);
541         BT_CHECK_PARAMETER(file_path, return);
542
543         /* Implement the queue */
544         _bt_convert_addr_type_to_string(address, remote_address->addr);
545
546         if (sending_info == NULL) {
547                 result = __bt_opp_client_start_sending(request_id,
548                                         address, file_path, file_count);
549         } else {
550                 /* Insert data in the queue */
551                 data = g_malloc0(sizeof(bt_sending_data_t));
552                 data->file_path = g_new0(char *, file_count + 1);
553                 data->address = g_strdup(address);
554                 data->file_count = file_count;
555                 data->request_id = request_id;
556
557                 for (i = 0; i < file_count; i++) {
558                         data->file_path[i] = g_strdup(file_path[i]);
559                         BT_DBG("file[%d]: %s", i, data->file_path[i]);
560                 }
561
562                 transfer_list = g_slist_append(transfer_list, data);
563         }
564
565         out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar));
566         out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar));
567
568         g_array_append_vals(out_param1, &request_id,
569                                 sizeof(int));
570         g_array_append_vals(out_param2, &result, sizeof(int));
571
572         dbus_g_method_return(context, out_param1, out_param2);
573
574         g_array_free(out_param1, TRUE);
575         g_array_free(out_param2, TRUE);
576
577         return result;
578 }
579
580 int _bt_opp_client_cancel_push(void)
581 {
582         DBusGConnection *g_conn;
583         DBusGProxy *client_proxy;
584
585         retv_if(sending_info == NULL, BLUETOOTH_ERROR_NOT_IN_OPERATION);
586
587         sending_info->is_canceled = TRUE;
588
589         if (sending_info->transfer_info) {
590                 dbus_g_proxy_call_no_reply(sending_info->transfer_info->proxy,
591                                         "Cancel", G_TYPE_INVALID,
592                                         G_TYPE_INVALID);
593         } else {
594                 retv_if(sending_info->sending_proxy == NULL,
595                                         BLUETOOTH_ERROR_INTERNAL);
596
597                 g_conn = _bt_get_session_gconn();
598                 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
599
600                 client_proxy =  dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME,
601                                                 BT_OBEX_CLIENT_PATH, BT_OBEX_CLIENT_INTERFACE);
602
603                 retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
604
605                 dbus_g_proxy_cancel_call(client_proxy,
606                                         sending_info->sending_proxy);
607
608                 g_idle_add(__bt_cancel_push_cb, NULL);
609         }
610
611         return BLUETOOTH_ERROR_NONE;
612 }
613
614 int _bt_opp_client_cancel_all_transfers(void)
615 {
616         if (transfer_list) {
617                 g_slist_free_full(transfer_list,
618                         (GDestroyNotify)__bt_free_sending_data);
619
620                 transfer_list = NULL;
621         }
622
623         _bt_opp_client_cancel_push();
624
625         return BLUETOOTH_ERROR_NONE;
626 }
627
628 int _bt_opp_client_is_sending(gboolean *sending)
629 {
630         BT_CHECK_PARAMETER(sending, return);
631
632         *sending = sending_info ? TRUE : FALSE;
633
634         return BLUETOOTH_ERROR_NONE;
635 }