4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Girishashok Joshi <girish.joshi@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
27 #include <mime_type.h>
32 #include "bluetooth-api.h"
33 #include "bt-internal-types.h"
35 #include "bt-service-common.h"
36 #include "bt-service-event.h"
37 #include "bt-service-util.h"
38 #include "bt-service-opp-client.h"
39 #include "bt-service-obex-agent.h"
41 static GSList *transfer_list = NULL;
42 bt_sending_info_t *sending_info;
43 static int file_offset = 0;
45 #define DBUS_TIEMOUT 20 * 1000 /* 20 Seconds */
46 static gboolean __bt_sending_release();
47 static void _bt_remove_session();
49 static int __bt_opp_client_start_sending(int request_id, char *address,
50 char **file_name_array, int file_count);
52 static GQuark __bt_opc_error_quark(void)
54 static GQuark quark = 0;
56 quark = g_quark_from_static_string("agent");
61 static void __bt_free_transfer_info(bt_transfer_info_t *info)
66 g_object_unref(info->proxy);
68 if (info->properties_proxy)
69 g_object_unref(info->properties_proxy);
72 g_free(info->transfer_name);
73 g_free(info->file_name);
77 static void __bt_free_sending_info(bt_sending_info_t *info)
81 /* Free the sending variable */
82 __bt_free_transfer_info(info->transfer_info);
84 g_free(info->file_name_array);
86 g_free(info->address);
90 static gboolean __bt_cancel_push_cb(gpointer data)
94 int result = BLUETOOTH_ERROR_CANCEL_BY_USER;
95 GVariant *param = NULL;
96 retv_if(sending_info == NULL, FALSE);
97 sending_info->result = result;
99 param = g_variant_new("(isi)", result,
100 sending_info->address,
101 sending_info->request_id);
102 /* Send the event in only error none case */
103 _bt_send_event(BT_OPP_CLIENT_EVENT,
104 BLUETOOTH_EVENT_OPC_CONNECTED,
106 __bt_free_sending_info(sending_info);
109 _bt_opp_client_event_deinit();
111 BT_DBG("Length of transfer list is %d", g_slist_length(transfer_list));
113 /*Operate remain works*/
114 if (g_slist_length(transfer_list) > 0) {
115 bt_sending_data_t *node = NULL;
117 node = transfer_list->data;
119 BT_ERR("data is NULL");
123 transfer_list = g_slist_remove(transfer_list, node);
125 if (__bt_opp_client_start_sending(node->request_id,
126 node->address, node->file_path,
127 node->file_count) != BLUETOOTH_ERROR_NONE) {
128 BT_ERR("Fail to start sending");
135 gboolean _bt_obex_client_progress(const char *transfer_path, int transferred)
139 int percentage_progress;
141 int result = BLUETOOTH_ERROR_NONE;
142 GVariant *param = NULL;
143 retv_if(sending_info == NULL, TRUE);
144 retv_if(sending_info->transfer_info == NULL, TRUE);
146 if (g_strcmp0(sending_info->transfer_info->transfer_path,
147 transfer_path) != 0) {
148 BT_INFO("Path mismatch, previous transfer failed! Returning");
152 size = sending_info->transfer_info->size;
155 percentage_progress = (int)(((gdouble)transferred /
156 (gdouble)size) * 100);
158 percentage_progress = 0;
160 sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_PROGRESS;
161 sending_info->result = result;
163 /* Send the event in only error none case */
164 param = g_variant_new("(istii)", result,
165 sending_info->transfer_info->file_name,
166 sending_info->transfer_info->size,
168 sending_info->request_id);
169 _bt_send_event(BT_OPP_CLIENT_EVENT,
170 BLUETOOTH_EVENT_OPC_TRANSFER_PROGRESS,
177 gboolean _bt_obex_client_completed(const char *transfer_path, gboolean success)
181 int result = BLUETOOTH_ERROR_NONE;
182 GVariant *param = NULL;
183 retv_if(sending_info == NULL, TRUE);
184 retv_if(sending_info->transfer_info == NULL, TRUE);
186 if (g_strcmp0(sending_info->transfer_info->transfer_path,
187 transfer_path) != 0) {
188 BT_INFO("Path mismatch, previous transfer failed! Returning");
192 result = (success == TRUE) ? BLUETOOTH_ERROR_NONE : BLUETOOTH_ERROR_CANCEL;
194 sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_COMPLETED;
195 sending_info->result = result;
197 if (!success) { /*In case of remote device reject, we need to send BLUETOOTH_EVENT_OPC_DISCONNECTED */
198 BT_DBG("completed with error");
199 if (!sending_info->is_canceled) {
200 param = g_variant_new("(isti)", result,
201 sending_info->transfer_info->file_name,
202 sending_info->transfer_info->size,
203 sending_info->request_id);
204 _bt_send_event(BT_OPP_CLIENT_EVENT,
205 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
207 __bt_free_transfer_info(sending_info->transfer_info);
208 sending_info->transfer_info = NULL;
209 /* Reset the file offset as we will cancelled remaining files also */
212 param = g_variant_new("(isi)", sending_info->result,
213 sending_info->address,
214 sending_info->request_id);
215 _bt_send_event(BT_OPP_CLIENT_EVENT,
216 BLUETOOTH_EVENT_OPC_DISCONNECTED,
218 __bt_sending_release();
219 /* Sending info should not freed after sending_release it's
220 * already freed in that API and if any pending request is
221 * present then it recreate sending_info again.
222 * And if we free it here then CreateSession method call will
223 * made but RemoveSession method call will not done.
226 BT_DBG("complete success");
227 /* Send the event in only error none case */
228 param = g_variant_new("(isti)", result,
229 sending_info->transfer_info->file_name,
230 sending_info->transfer_info->size,
231 sending_info->request_id);
232 _bt_send_event(BT_OPP_CLIENT_EVENT,
233 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
235 __bt_free_transfer_info(sending_info->transfer_info);
236 sending_info->transfer_info = NULL;
244 gboolean _bt_obex_client_started(const char *transfer_path)
248 int result = BLUETOOTH_ERROR_NONE;
249 GError *error = NULL;
250 GVariant *param = NULL;
251 GDBusConnection *g_conn;
252 GDBusProxy *properties_proxy;
253 GDBusProxy *transfer_proxy;
255 if (sending_info == NULL || sending_info->is_canceled == TRUE) {
256 result = BLUETOOTH_ERROR_CANCEL_BY_USER;
260 /* Get the session bus. */
261 g_conn = _bt_get_session_gconn();
262 retv_if(g_conn == NULL, FALSE);
263 properties_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
264 NULL,BT_OBEXD_DBUS_NAME,
265 transfer_path, BT_PROPERTIES_INTERFACE,
268 retv_if(properties_proxy == NULL, FALSE);
270 sending_info->transfer_info->properties_proxy = properties_proxy;
272 transfer_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
273 NULL, BT_OBEXD_DBUS_NAME,
274 transfer_path, BT_OBEX_TRANSFER_INTERFACE,
277 retv_if(transfer_proxy == NULL, FALSE);
279 sending_info->transfer_info->proxy = transfer_proxy;
281 sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_STARTED;
282 sending_info->result = result;
283 param = g_variant_new("(isti)", result,
284 sending_info->transfer_info->file_name,
285 sending_info->transfer_info->size,
286 sending_info->request_id);
287 _bt_send_event(BT_OPP_CLIENT_EVENT,
288 BLUETOOTH_EVENT_OPC_TRANSFER_STARTED,
294 error = g_error_new(__bt_opc_error_quark(), BT_OBEX_AGENT_ERROR_CANCEL,
303 static void __bt_free_sending_data(gpointer data)
306 bt_sending_data_t *info = data;
308 ret_if(info == NULL);
310 for (i = 0; i < info->file_count; i++) {
311 g_free(info->file_path[i]);
314 _bt_delete_request_id(info->request_id);
316 g_free(info->file_path);
317 g_free(info->address);
321 static void __bt_sending_release_cb(GDBusProxy *proxy,
322 GAsyncResult *res, gpointer user_data)
325 ret_if(sending_info == NULL);
327 GError *error = NULL;
328 int result = BLUETOOTH_ERROR_NONE;
329 GVariant *param = NULL;
330 g_dbus_proxy_call_finish(proxy, res, &error);
332 g_object_unref(proxy);
335 BT_ERR("%s", error->message);
338 result = BLUETOOTH_ERROR_INTERNAL;
341 BT_DBG("Session Removed");
344 sending_info->result = result;
345 param = g_variant_new("(isi)", sending_info->result,
346 sending_info->address,
347 sending_info->request_id);
348 /* Send the event in only error none case */
349 _bt_send_event(BT_OPP_CLIENT_EVENT,
350 BLUETOOTH_EVENT_OPC_DISCONNECTED,
353 __bt_free_sending_info(sending_info);
356 _bt_opp_client_event_deinit();
358 /* Operate remain works */
359 if (g_slist_length(transfer_list) > 0) {
360 bt_sending_data_t *data = NULL;
362 data = transfer_list->data;
366 transfer_list = g_slist_remove(transfer_list, data);
368 BT_DBG("calling __bt_opp_client_start_sending");
370 if (__bt_opp_client_start_sending(data->request_id,
371 data->address, data->file_path,
372 data->file_count) != BLUETOOTH_ERROR_NONE) {
379 g_slist_free_full(transfer_list,
380 (GDestroyNotify)__bt_free_sending_data);
381 transfer_list = NULL;
388 static void _bt_remove_session()
390 GDBusConnection *g_conn;
391 GDBusProxy *session_proxy;
394 g_conn = _bt_get_session_gconn();
395 ret_if(g_conn == NULL);
396 ret_if(sending_info->session_path == NULL);
398 session_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
399 NULL, BT_OBEXD_DBUS_NAME,
401 BT_OBEX_CLIENT_INTERFACE,
404 ret_if(session_proxy == NULL);
406 g_dbus_proxy_call(session_proxy, "RemoveSession",
407 g_variant_new("(o)", sending_info->session_path),
408 G_DBUS_CALL_FLAGS_NONE,
410 (GAsyncReadyCallback)__bt_sending_release_cb,
415 static gboolean __bt_sending_release()
419 retv_if(sending_info == NULL, FALSE);
421 _bt_remove_session();
426 void _bt_opc_disconnected(const char *session_path)
429 GVariant *param = NULL;
430 ret_if(sending_info == NULL);
432 if (g_strcmp0(sending_info->session_path,
433 session_path) != 0) {
434 BT_INFO("Path mismatch, previous transfer failed! Returning");
438 if (sending_info->transfer_info) {
439 if (sending_info->transfer_info->transfer_status == BT_TRANSFER_STATUS_PROGRESS ||
440 sending_info->transfer_info->transfer_status == BT_TRANSFER_STATUS_STARTED) {
441 BT_INFO("Abnormal termination");
442 param = g_variant_new("(isti)", sending_info->result,
443 sending_info->transfer_info->file_name,
444 sending_info->transfer_info->size,
445 sending_info->request_id);
446 _bt_send_event(BT_OPP_CLIENT_EVENT,
447 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
449 __bt_free_transfer_info(sending_info->transfer_info);
452 param = g_variant_new("(isi)", sending_info->result,
453 sending_info->address,
454 sending_info->request_id);
455 _bt_send_event(BT_OPP_CLIENT_EVENT,
456 BLUETOOTH_EVENT_OPC_DISCONNECTED,
459 __bt_free_sending_info(sending_info);
465 static void __bt_send_file_cb(GDBusProxy *proxy,
466 GAsyncResult *res, gpointer user_data)
469 GVariant *value = NULL;
470 GError *error = NULL;
471 char *session_path = NULL;
472 const char *transfer_name = NULL;
473 const char *file_name = NULL;
476 value = g_dbus_proxy_call_finish(proxy, res, &error);
478 BT_ERR("%s", error->message);
481 g_object_unref(proxy);
485 g_object_unref(proxy);
488 g_variant_get(value, "(oa{sv})", &session_path, &iter);
489 g_variant_unref(value);
492 __bt_free_transfer_info(sending_info->transfer_info);
494 sending_info->transfer_info = g_malloc0(sizeof(bt_transfer_info_t));
500 while (g_variant_iter_loop(iter, "{sv}", &key, &val)) {
501 if (g_strcmp0(key, "Name") == 0) {
502 transfer_name = g_variant_dup_string(val,&len);
503 } else if (g_strcmp0(key, "Filename") == 0) {
504 file_name = g_variant_dup_string(val, &len);
505 } else if (g_strcmp0(key, "Size") == 0) {
506 size = g_variant_get_uint64(val);
509 g_variant_iter_free(iter);
512 sending_info->transfer_info->transfer_name = g_strdup(transfer_name);
513 sending_info->transfer_info->file_name = g_strdup(file_name);
514 sending_info->transfer_info->size = size;
515 sending_info->transfer_info->transfer_path = session_path;
516 sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_QUEUED;
517 sending_info->result = BLUETOOTH_ERROR_NONE;
522 void _bt_sending_files(void)
527 GDBusConnection *g_conn;
528 GDBusProxy *client_proxy;
529 char *mimetype = NULL;
532 if (sending_info == NULL)
534 if (file_offset < sending_info->file_count){
535 /* Get the session bus. */
536 g_conn = _bt_get_session_gconn();
537 ret_if(g_conn == NULL);
539 client_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
540 NULL, BT_OBEXD_DBUS_NAME,
541 sending_info->session_path,
542 BT_OBEX_OBJECT_PUSH_INTERFACE,
544 ret_if(client_proxy == NULL);
546 BT_DBG("Calling SendFile");
547 ext = strrchr(sending_info->file_name_array[file_offset], '.');
549 if (ext != NULL && (!strcmp(ext, ".imy")))
550 mimetype = g_strdup("audio/imelody");
551 g_dbus_proxy_call(client_proxy, "SendFile",
552 g_variant_new("(ss)", sending_info->file_name_array[file_offset],
554 G_DBUS_CALL_FLAGS_NONE,
556 (GAsyncReadyCallback)__bt_send_file_cb,
559 BT_ERR("Calling SendFile failed: [%s]\n", err->message);
568 __bt_sending_release();
574 static void __bt_create_session_cb(GDBusProxy *proxy,
575 GAsyncResult *res, gpointer user_data)
579 GError *error = NULL;
581 int result = BLUETOOTH_ERROR_NONE;
582 char *session_path = NULL;
583 GVariant *param = NULL;
585 value = g_dbus_proxy_call_finish(proxy, res, &error);
587 g_object_unref(proxy);
590 g_variant_get(value, "(o)", &session_path);
591 g_variant_unref(value);
595 BT_ERR("%s", error->message);
596 g_clear_error(&error);
598 result = BLUETOOTH_ERROR_INTERNAL;
600 BT_DBG("Session created");
601 if(sending_info != NULL)
602 sending_info->session_path = g_strdup(session_path);
604 g_free(session_path);
605 ret_if(sending_info == NULL);
607 sending_info->result = result;
608 param = g_variant_new("(isi)", result,
609 sending_info->address,
610 sending_info->request_id);
611 /* Send the event in only error none case */
612 _bt_send_event(BT_OPP_CLIENT_EVENT,
613 BLUETOOTH_EVENT_OPC_CONNECTED,
616 if (result != BLUETOOTH_ERROR_NONE) {
617 BT_ERR("Calling __bt_sending_release");
618 __bt_sending_release();
620 __bt_free_sending_info(sending_info);
623 BT_DBG("Calling sending_files");
630 static int __bt_opp_client_start_sending(int request_id, char *address,
631 char **file_name_array, int file_count)
633 GVariantBuilder *builder;
635 GDBusConnection *g_conn;
636 GDBusProxy *client_proxy;
637 GError *error = NULL;
640 BT_CHECK_PARAMETER(address, return);
641 BT_CHECK_PARAMETER(file_name_array, return);
643 /* Get the session bus. */
644 g_conn = _bt_get_session_gconn();
645 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
647 client_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE,
648 NULL, BT_OBEX_SERVICE_NAME,
650 BT_OBEX_CLIENT_INTERFACE,
654 BT_ERR("Unable to create client proxy: %s", error->message);
655 g_clear_error(&error);
658 retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
660 builder = g_variant_builder_new(
661 G_VARIANT_TYPE("a{sv}"));
663 g_variant_builder_add(builder, "{sv}", "Target",
664 g_variant_new_string("OPP"));
666 __bt_free_sending_info(sending_info);
668 sending_info = g_malloc0(sizeof(bt_sending_info_t));
669 sending_info->address = g_strdup(address);
670 sending_info->request_id = request_id;
672 sending_info->file_count = file_count;
673 sending_info->file_offset = 0;
674 sending_info->file_name_array = g_new0(char *, file_count + 1);
676 for (i = 0; i < file_count; i++) {
677 sending_info->file_name_array[i] = g_strdup(file_name_array[i]);
678 BT_DBG("file[%d]: %s", i, sending_info->file_name_array[i]);
681 _bt_opp_client_event_deinit();
682 _bt_opp_client_event_init();
683 //_bt_obex_client_started(agent_path);
685 BT_DBG("Going to call CreateSession");
687 g_dbus_proxy_call(client_proxy, "CreateSession",
688 g_variant_new("(sa{sv})", address, builder),
689 G_DBUS_CALL_FLAGS_NONE,
691 (GAsyncReadyCallback)__bt_create_session_cb,
693 g_variant_builder_unref(builder);
697 return BLUETOOTH_ERROR_NONE;
700 int _bt_opp_client_push_files(int request_id, GDBusMethodInvocation *context,
701 bluetooth_device_address_t *remote_address,
702 char **file_path, int file_count)
705 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
706 bt_sending_data_t *data;
708 GVariant *out_param1 = NULL;
710 int result = BLUETOOTH_ERROR_NONE;
713 BT_CHECK_PARAMETER(remote_address, return);
714 BT_CHECK_PARAMETER(file_path, return);
716 /* Implement the queue */
717 _bt_convert_addr_type_to_string(address, remote_address->addr);
719 if (sending_info == NULL) {
720 result = __bt_opp_client_start_sending(request_id,
721 address, file_path, file_count);
722 if (result != BLUETOOTH_ERROR_NONE)
725 /* Insert data in the queue */
726 data = g_malloc0(sizeof(bt_sending_data_t));
727 /* Fix : NULL_RETURNS */
729 return BLUETOOTH_ERROR_MEMORY_ALLOCATION;
731 data->file_path = g_new0(char *, file_count + 1);
732 data->address = g_strdup(address);
733 data->file_count = file_count;
734 data->request_id = request_id;
736 for (i = 0; i < file_count; i++) {
737 data->file_path[i] = g_strdup(file_path[i]);
738 DBG_SECURE("file[%d]: %s", i, data->file_path[i]);
741 transfer_list = g_slist_append(transfer_list, data);
744 out_param1 = g_variant_new_from_data((const GVariantType *)"ay",
745 &request_id, sizeof(int),
749 g_dbus_method_invocation_return_value(context,
750 g_variant_new("(iv)", result, out_param1));
757 int _bt_opp_client_cancel_push(void)
762 int result = BLUETOOTH_ERROR_CANCEL_BY_USER;
763 GVariant *param = NULL;
764 retv_if(sending_info == NULL, BLUETOOTH_ERROR_NOT_IN_OPERATION);
766 sending_info->is_canceled = TRUE;
767 sending_info->result = result;
769 if (sending_info->transfer_info) {
771 g_dbus_proxy_call_sync(sending_info->transfer_info->proxy,
773 G_DBUS_CALL_FLAGS_NONE, -1,
775 param = g_variant_new("(isti)", result,
776 sending_info->transfer_info->file_name,
777 sending_info->transfer_info->size,
778 sending_info->request_id);
779 _bt_send_event(BT_OPP_CLIENT_EVENT,
780 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
783 if (result == BLUETOOTH_ERROR_CANCEL_BY_USER) {
784 BT_ERR("result is not BLUETOOTH_ERROR_NONE");
785 __bt_sending_release();
790 g_idle_add(__bt_cancel_push_cb, NULL);
795 return BLUETOOTH_ERROR_NONE;
798 int _bt_opp_client_cancel_all_transfers(void)
802 g_slist_free_full(transfer_list,
803 (GDestroyNotify)__bt_free_sending_data);
805 transfer_list = NULL;
808 _bt_opp_client_cancel_push();
810 return BLUETOOTH_ERROR_NONE;
813 int _bt_opp_client_is_sending(gboolean *sending)
815 BT_CHECK_PARAMETER(sending, return);
817 *sending = sending_info ? TRUE : FALSE;
819 return BLUETOOTH_ERROR_NONE;
822 void _bt_opp_client_check_pending_transfer(const char *address)
826 int result = BLUETOOTH_ERROR_CANCEL;
827 GVariant *param = NULL;
828 ret_if(sending_info == NULL);
829 ret_if(sending_info->transfer_info == NULL);
831 if (g_strcmp0(sending_info->address, address) == 0) {
832 BT_INFO("Address Match.Cancel current transfer");
833 sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_COMPLETED;
834 sending_info->result = result;
836 if (!sending_info->is_canceled) {
837 param = g_variant_new("(isti)", result,
838 sending_info->transfer_info->file_name,
839 sending_info->transfer_info->size,
840 sending_info->request_id);
841 _bt_send_event(BT_OPP_CLIENT_EVENT,
842 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
844 __bt_free_transfer_info(sending_info->transfer_info);
845 sending_info->transfer_info = NULL;
846 /* Reset the file offset as we will cancelled remaining files also */
849 param = g_variant_new("(isi)", sending_info->result,
850 sending_info->address,
851 sending_info->request_id);
852 _bt_send_event(BT_OPP_CLIENT_EVENT,
853 BLUETOOTH_EVENT_OPC_DISCONNECTED,
856 __bt_sending_release();