4 * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <dbus/dbus-glib.h>
21 #include <dbus/dbus.h>
26 #include "bluetooth-api.h"
27 #include "bt-internal-types.h"
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"
35 static BtObexAgent *opc_obex_agent = NULL;
36 static GSList *transfer_list = NULL;
38 bt_sending_info_t *sending_info;
40 static gboolean __bt_release_callback(DBusGMethodInvocation *context,
43 static gboolean __bt_request_callback(DBusGMethodInvocation *context,
47 static gboolean __bt_progress_callback(DBusGMethodInvocation *context,
52 static gboolean __bt_complete_callback(DBusGMethodInvocation *context,
56 static gboolean __bt_error_callback(DBusGMethodInvocation *context,
62 static int __bt_opp_client_start_sending(int request_id, char *address,
63 char **file_name_array);
65 static int __bt_opp_client_agent_init(void)
67 opc_obex_agent = _bt_obex_agent_new();
68 retv_if(opc_obex_agent == NULL, BLUETOOTH_ERROR_INTERNAL);
70 _bt_obex_set_release_cb(opc_obex_agent,
71 __bt_release_callback, NULL);
72 _bt_obex_set_request_cb(opc_obex_agent,
73 __bt_request_callback, NULL);
74 _bt_obex_set_progress_cb(opc_obex_agent,
75 __bt_progress_callback, NULL);
76 _bt_obex_set_complete_cb(opc_obex_agent,
77 __bt_complete_callback, NULL);
78 _bt_obex_set_error_cb(opc_obex_agent,
79 __bt_error_callback, NULL);
81 _bt_obex_setup(opc_obex_agent, BT_OBEX_CLIENT_AGENT_PATH);
83 return BLUETOOTH_ERROR_NONE;
86 static void __bt_opp_client_agent_deinit(void)
88 ret_if(opc_obex_agent == NULL);
90 g_object_unref(opc_obex_agent);
91 opc_obex_agent = NULL;
94 static GQuark __bt_opc_error_quark(void)
96 static GQuark quark = 0;
98 quark = g_quark_from_static_string("agent");
103 static void __bt_free_transfer_info(bt_transfer_info_t *info)
105 ret_if(info == NULL);
108 g_object_unref(info->proxy);
110 g_free(info->transfer_name);
111 g_free(info->file_name);
115 static void __bt_free_sending_info(bt_sending_info_t *info)
117 ret_if(info == NULL);
119 /* Free the sending variable */
120 __bt_free_transfer_info(info->transfer_info);
122 g_free(info->address);
126 static void __bt_value_free(GValue *value)
128 g_value_unset(value);
132 static gboolean __bt_cancel_push_cb(gpointer data)
134 int result = BLUETOOTH_ERROR_CANCEL_BY_USER;
136 retv_if(sending_info == NULL, FALSE);
138 /* Send the event in only error none case */
139 _bt_send_event(BT_OPP_CLIENT_EVENT,
140 BLUETOOTH_EVENT_OPC_CONNECTED,
141 DBUS_TYPE_INT32, &result,
142 DBUS_TYPE_STRING, &sending_info->address,
143 DBUS_TYPE_INT32, &sending_info->request_id,
146 __bt_free_sending_info(sending_info);
149 __bt_opp_client_agent_deinit();
151 /* Operate remain works */
152 if (g_slist_length(transfer_list) > 0) {
153 bt_sending_data_t *node = NULL;
155 node = transfer_list->data;
157 BT_DBG("data is NULL");
161 transfer_list = g_slist_remove(transfer_list, node);
163 if (__bt_opp_client_start_sending(node->request_id,
165 node->file_path) != BLUETOOTH_ERROR_NONE) {
166 BT_DBG("Fail to start sending");
173 static gboolean __bt_progress_callback(DBusGMethodInvocation *context,
174 DBusGProxy *transfer,
178 int percentage_progress;
180 int result = BLUETOOTH_ERROR_NONE;
182 dbus_g_method_return(context);
184 retv_if(sending_info == NULL, TRUE);
185 retv_if(sending_info->transfer_info == NULL, TRUE);
187 size = sending_info->transfer_info->size;
190 percentage_progress = (int)(((gdouble)transferred /
191 (gdouble)size) * 100);
193 percentage_progress = 0;
195 /* Send the event in only error none case */
196 _bt_send_event(BT_OPP_CLIENT_EVENT,
197 BLUETOOTH_EVENT_OPC_TRANSFER_PROGRESS,
198 DBUS_TYPE_INT32, &result,
199 DBUS_TYPE_STRING, &sending_info->transfer_info->file_name,
200 DBUS_TYPE_UINT64, &sending_info->transfer_info->size,
201 DBUS_TYPE_INT32, &percentage_progress,
202 DBUS_TYPE_INT32, &sending_info->request_id,
208 static gboolean __bt_complete_callback(DBusGMethodInvocation *context,
209 DBusGProxy *transfer,
212 int result = BLUETOOTH_ERROR_NONE;
214 dbus_g_method_return(context);
216 /* Send the event in only error none case */
217 _bt_send_event(BT_OPP_CLIENT_EVENT,
218 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
219 DBUS_TYPE_INT32, &result,
220 DBUS_TYPE_STRING, &sending_info->transfer_info->file_name,
221 DBUS_TYPE_UINT64, &sending_info->transfer_info->size,
222 DBUS_TYPE_INT32, &sending_info->request_id,
228 static gboolean __bt_request_callback(DBusGMethodInvocation *context,
229 DBusGProxy *transfer,
233 const char *transfer_name;
234 const char *file_name;
236 int result = BLUETOOTH_ERROR_NONE;
237 GHashTable *hash = NULL;
240 if (sending_info == NULL || sending_info->is_canceled == TRUE) {
241 result = BLUETOOTH_ERROR_CANCEL_BY_USER;
245 dbus_g_method_return(context, "");
247 __bt_free_transfer_info(sending_info->transfer_info);
249 sending_info->transfer_info = g_malloc0(sizeof(bt_transfer_info_t));
250 sending_info->transfer_info->proxy = g_object_ref(transfer);
252 dbus_g_proxy_call(transfer, "GetProperties", NULL,
254 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
255 &hash, G_TYPE_INVALID);
260 value = g_hash_table_lookup(hash, "Name");
261 transfer_name = value ? g_value_get_string(value) : NULL;
263 value = g_hash_table_lookup(hash, "Filename");
264 file_name = value ? g_value_get_string(value) : NULL;
266 value = g_hash_table_lookup(hash, "Size");
267 size = value ? g_value_get_uint64(value) : 0;
269 sending_info->transfer_info->transfer_name = g_strdup(transfer_name);
270 sending_info->transfer_info->file_name = g_strdup(file_name);
271 sending_info->transfer_info->size = size;
272 sending_info->result = BLUETOOTH_ERROR_NONE;
274 g_hash_table_destroy(hash);
276 _bt_send_event(BT_OPP_CLIENT_EVENT,
277 BLUETOOTH_EVENT_OPC_TRANSFER_STARTED,
278 DBUS_TYPE_INT32, &result,
279 DBUS_TYPE_STRING, &sending_info->transfer_info->file_name,
280 DBUS_TYPE_UINT64, &sending_info->transfer_info->size,
281 DBUS_TYPE_INT32, &sending_info->request_id,
286 error = g_error_new(__bt_opc_error_quark(), BT_OBEX_AGENT_ERROR_CANCEL,
289 dbus_g_method_return_error(context, error);
294 result = BLUETOOTH_ERROR_INTERNAL;
296 /* Send the event in only error none case */
297 _bt_send_event(BT_OPP_CLIENT_EVENT,
298 BLUETOOTH_EVENT_OPC_DISCONNECTED,
299 DBUS_TYPE_INT32, &result,
300 DBUS_TYPE_STRING, &sending_info->address,
301 DBUS_TYPE_INT32, &sending_info->request_id,
304 __bt_free_sending_info(sending_info);
307 __bt_opp_client_agent_deinit();
312 static void __bt_free_sending_data(gpointer data)
315 bt_sending_data_t *info = data;
317 ret_if(info == NULL);
319 for (i = 0; i < info->file_count; i++) {
320 g_free(info->file_path[i]);
323 _bt_delete_request_id(info->request_id);
325 g_free(info->file_path);
326 g_free(info->address);
330 static gboolean __bt_release_callback(DBusGMethodInvocation *context,
333 dbus_g_method_return(context);
335 retv_if(sending_info == NULL, FALSE);
337 /* Send the event in only error none case */
338 _bt_send_event(BT_OPP_CLIENT_EVENT,
339 BLUETOOTH_EVENT_OPC_DISCONNECTED,
340 DBUS_TYPE_INT32, &sending_info->result,
341 DBUS_TYPE_STRING, &sending_info->address,
342 DBUS_TYPE_INT32, &sending_info->request_id,
345 __bt_free_sending_info(sending_info);
348 __bt_opp_client_agent_deinit();
350 /* Operate remain works */
351 if (g_slist_length(transfer_list) > 0) {
352 bt_sending_data_t *data = NULL;
354 data = transfer_list->data;
358 transfer_list = g_slist_remove(transfer_list, data);
360 if (__bt_opp_client_start_sending(data->request_id,
362 data->file_path) != BLUETOOTH_ERROR_NONE) {
369 g_slist_free_full(transfer_list,
370 (GDestroyNotify)__bt_free_sending_data);
371 transfer_list = NULL;
375 static gboolean __bt_error_callback(DBusGMethodInvocation *context,
376 DBusGProxy *transfer,
382 dbus_g_method_return(context);
384 retv_if(sending_info == NULL, FALSE);
385 retv_if(sending_info->transfer_info == NULL, FALSE);
387 if (sending_info->is_canceled == TRUE) {
388 result = BLUETOOTH_ERROR_CANCEL_BY_USER;
389 } else if (g_strcmp0(message, "Forbidden") == 0) {
390 result = BLUETOOTH_ERROR_ACCESS_DENIED;
391 } else if (g_str_has_prefix(message,
392 "Transport endpoint is not connected") == TRUE) {
393 result = BLUETOOTH_ERROR_NOT_CONNECTED;
394 } else if (g_strcmp0(message, "Database full") == 0) {
395 result = BLUETOOTH_ERROR_OUT_OF_MEMORY;
397 result = BLUETOOTH_ERROR_INTERNAL;
400 sending_info->result = result;
402 /* Send the event in only error none case */
403 _bt_send_event(BT_OPP_CLIENT_EVENT,
404 BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE,
405 DBUS_TYPE_INT32, &result,
406 DBUS_TYPE_STRING, &sending_info->transfer_info->file_name,
407 DBUS_TYPE_UINT64, &sending_info->transfer_info->size,
408 DBUS_TYPE_INT32, &sending_info->request_id,
413 static void __bt_send_files_cb(DBusGProxy *proxy, DBusGProxyCall *call,
416 GError *error = NULL;
417 int result = BLUETOOTH_ERROR_NONE;
419 if (dbus_g_proxy_end_call(proxy, call, &error,
420 G_TYPE_INVALID) == FALSE) {
422 BT_ERR("%s", error->message);
425 result = BLUETOOTH_ERROR_INTERNAL;
428 g_object_unref(proxy);
429 ret_if(sending_info == NULL);
431 sending_info->sending_proxy = NULL;
433 /* Send the event in only error none case */
434 _bt_send_event(BT_OPP_CLIENT_EVENT,
435 BLUETOOTH_EVENT_OPC_CONNECTED,
436 DBUS_TYPE_INT32, &result,
437 DBUS_TYPE_STRING, &sending_info->address,
438 DBUS_TYPE_INT32, &sending_info->request_id,
441 if (result != BLUETOOTH_ERROR_NONE) {
442 __bt_free_sending_info(sending_info);
447 static int __bt_opp_client_start_sending(int request_id, char *address,
448 char **file_name_array)
452 DBusGConnection *g_conn;
453 DBusGProxy *client_proxy;
454 DBusGProxyCall *proxy_call;
457 BT_CHECK_PARAMETER(address, return);
458 BT_CHECK_PARAMETER(file_name_array, return);
460 /* Get the session bus. */
461 g_conn = _bt_get_session_gconn();
462 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
464 client_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME,
465 "/", BT_OBEX_CLIENT_INTERFACE);
467 retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
469 hash = g_hash_table_new_full(g_str_hash, g_str_equal,
470 NULL, (GDestroyNotify)__bt_value_free);
472 value = g_new0(GValue, 1);
473 g_value_init(value, G_TYPE_STRING);
474 g_value_set_string(value, address);
475 g_hash_table_insert(hash, "Destination", value);
477 __bt_free_sending_info(sending_info);
479 sending_info = g_malloc0(sizeof(bt_sending_info_t));
480 sending_info->address = g_strdup(address);
481 sending_info->request_id = request_id;
483 __bt_opp_client_agent_deinit();
484 __bt_opp_client_agent_init();
486 agent_path = g_strdup(BT_OBEX_CLIENT_AGENT_PATH);
488 proxy_call = dbus_g_proxy_begin_call(client_proxy, "SendFiles",
489 __bt_send_files_cb, NULL, NULL,
490 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
492 G_TYPE_STRV, file_name_array,
493 DBUS_TYPE_G_OBJECT_PATH, agent_path,
498 if (proxy_call == NULL) {
499 BT_ERR("Fail to Send files");
500 g_hash_table_destroy(hash);
501 g_object_unref(client_proxy);
502 __bt_free_sending_info(sending_info);
503 __bt_opp_client_agent_deinit();
505 return BLUETOOTH_ERROR_INTERNAL;
508 sending_info->sending_proxy = proxy_call;
509 g_hash_table_destroy(hash);
511 return BLUETOOTH_ERROR_NONE;
514 int _bt_opp_client_push_files(int request_id, DBusGMethodInvocation *context,
515 bluetooth_device_address_t *remote_address,
516 char **file_path, int file_count)
518 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
519 bt_sending_data_t *data;
520 GArray *out_param1 = NULL;
521 GArray *out_param2 = NULL;
522 int result = BLUETOOTH_ERROR_NONE;
525 BT_CHECK_PARAMETER(remote_address, return);
526 BT_CHECK_PARAMETER(file_path, return);
528 /* Implement the queue */
529 _bt_convert_addr_type_to_string(address, remote_address->addr);
531 if (sending_info == NULL) {
532 result = __bt_opp_client_start_sending(request_id,
535 /* Insert data in the queue */
536 data = g_malloc0(sizeof(bt_sending_data_t));
537 data->file_path = g_new0(char *, file_count + 1);
538 data->address = g_strdup(address);
539 data->file_count = file_count;
540 data->request_id = request_id;
542 for (i = 0; i < file_count; i++) {
543 data->file_path[i] = g_strdup(file_path[i]);
544 BT_DBG("file[%d]: %s", i, data->file_path[i]);
547 transfer_list = g_slist_append(transfer_list, data);
550 out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar));
551 out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar));
553 g_array_append_vals(out_param1, &request_id,
555 g_array_append_vals(out_param2, &result, sizeof(int));
557 dbus_g_method_return(context, out_param1, out_param2);
559 g_array_free(out_param1, TRUE);
560 g_array_free(out_param2, TRUE);
565 int _bt_opp_client_cancel_push(void)
567 DBusGConnection *g_conn;
568 DBusGProxy *client_proxy;
570 retv_if(sending_info == NULL, BLUETOOTH_ERROR_NOT_IN_OPERATION);
572 sending_info->is_canceled = TRUE;
574 if (sending_info->transfer_info) {
575 dbus_g_proxy_call_no_reply(sending_info->transfer_info->proxy,
576 "Cancel", G_TYPE_INVALID,
579 retv_if(sending_info->sending_proxy == NULL,
580 BLUETOOTH_ERROR_INTERNAL);
582 g_conn = _bt_get_session_gconn();
583 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
585 client_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME,
586 "/", BT_OBEX_CLIENT_INTERFACE);
588 retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
590 dbus_g_proxy_cancel_call(client_proxy,
591 sending_info->sending_proxy);
593 g_idle_add(__bt_cancel_push_cb, NULL);
596 return BLUETOOTH_ERROR_NONE;
599 int _bt_opp_client_cancel_all_transfers(void)
602 g_slist_free_full(transfer_list,
603 (GDestroyNotify)__bt_free_sending_data);
605 transfer_list = NULL;
608 _bt_opp_client_cancel_push();
610 return BLUETOOTH_ERROR_NONE;
613 int _bt_opp_client_is_sending(gboolean *sending)
615 BT_CHECK_PARAMETER(sending, return);
617 *sending = sending_info ? TRUE : FALSE;
619 return BLUETOOTH_ERROR_NONE;