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 GSList *transfer_list = NULL;
37 bt_sending_info_t *sending_info;
39 static int __bt_opp_client_start_sending(int request_id, char *address,
40 char **file_name_array, int file_count);
42 static gboolean __bt_sending_release();
44 static GQuark __bt_opc_error_quark(void)
46 static GQuark quark = 0;
48 quark = g_quark_from_static_string("agent");
53 static void __bt_free_transfer_info(bt_transfer_info_t *info)
58 g_object_unref(info->proxy);
60 g_free(info->transfer_name);
61 g_free(info->file_name);
65 static void __bt_free_sending_info(bt_sending_info_t *info)
69 /* Free the sending variable */
70 __bt_free_transfer_info(info->transfer_info);
72 g_free(info->file_name_array);
73 g_free(info->address);
77 static void __bt_value_free(GValue *value)
83 static gboolean __bt_cancel_push_cb(gpointer data)
85 int result = BLUETOOTH_ERROR_CANCEL_BY_USER;
87 retv_if(sending_info == NULL, FALSE);
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,
97 __bt_free_sending_info(sending_info);
100 _bt_opp_client_event_deinit();
102 /* Operate remain works */
103 if (g_slist_length(transfer_list) > 0) {
104 bt_sending_data_t *node = NULL;
106 node = transfer_list->data;
108 BT_DBG("data is NULL");
112 transfer_list = g_slist_remove(transfer_list, node);
114 if (__bt_opp_client_start_sending(node->request_id,
117 node->file_count) != BLUETOOTH_ERROR_NONE) {
118 BT_DBG("Fail to start sending");
125 gboolean _bt_obex_client_progress(int transferred)
127 int percentage_progress;
129 int result = BLUETOOTH_ERROR_NONE;
131 retv_if(sending_info == NULL, TRUE);
132 retv_if(sending_info->transfer_info == NULL, TRUE);
134 size = sending_info->transfer_info->size;
137 percentage_progress = (int)(((gdouble)transferred /
138 (gdouble)size) * 100);
140 percentage_progress = 0;
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,
155 gboolean _bt_obex_client_completed(gboolean success)
157 int result = BLUETOOTH_ERROR_NONE;
159 BT_DBG("Success [%d] \n", success);
161 result = (success == TRUE) ? BLUETOOTH_ERROR_NONE
162 : BLUETOOTH_ERROR_CANCEL;
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,
176 gboolean _bt_obex_client_started(const char *transfer_path)
179 const char *transfer_name;
180 const char *file_name;
182 int result = BLUETOOTH_ERROR_NONE;
183 GHashTable *hash = NULL;
185 DBusGConnection *g_conn;
186 DBusGProxy *transfer_proxy;
188 if (sending_info == NULL || sending_info->is_canceled == TRUE) {
189 result = BLUETOOTH_ERROR_CANCEL_BY_USER;
193 /* Get the session bus. */
194 g_conn = _bt_get_session_gconn();
195 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
197 __bt_free_transfer_info(sending_info->transfer_info);
199 sending_info->transfer_info = g_malloc0(sizeof(bt_transfer_info_t));
201 transfer_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEXD_DBUS_NAME,
202 transfer_path, BT_PROPERTIES_INTERFACE);
204 retv_if(transfer_proxy == NULL, FALSE);
206 sending_info->transfer_info->proxy = transfer_proxy;
208 if (!dbus_g_proxy_call(transfer_proxy, "GetAll", NULL,
209 G_TYPE_STRING, BT_OBEX_TRANSFER_INTERFACE,
211 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
212 G_TYPE_VALUE), &hash, G_TYPE_INVALID))
218 value = g_hash_table_lookup(hash, "Name");
219 transfer_name = value ? g_value_get_string(value) : NULL;
221 value = g_hash_table_lookup(hash, "Filename");
222 file_name = value ? g_value_get_string(value) : NULL;
224 value = g_hash_table_lookup(hash, "Size");
225 size = value ? g_value_get_uint64(value) : 0;
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;
232 g_hash_table_destroy(hash);
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,
244 error = g_error_new(__bt_opc_error_quark(), BT_OBEX_AGENT_ERROR_CANCEL,
251 result = BLUETOOTH_ERROR_INTERNAL;
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,
261 __bt_free_sending_info(sending_info);
264 _bt_opp_client_event_deinit();
269 static void __bt_free_sending_data(gpointer data)
272 bt_sending_data_t *info = data;
274 ret_if(info == NULL);
276 for (i = 0; i < info->file_count; i++) {
277 g_free(info->file_path[i]);
280 _bt_delete_request_id(info->request_id);
282 g_free(info->file_path);
283 g_free(info->address);
287 static void __bt_send_files_cb(DBusGProxy *proxy, DBusGProxyCall *call,
290 GError *error = NULL;
291 int result = BLUETOOTH_ERROR_NONE;
293 if (dbus_g_proxy_end_call(proxy, call, &error,
294 G_TYPE_INVALID) == FALSE) {
296 BT_ERR("%s", error->message);
299 result = BLUETOOTH_ERROR_INTERNAL;
302 g_object_unref(proxy);
303 ret_if(sending_info == NULL);
305 sending_info->sending_proxy = NULL;
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,
315 if (result != BLUETOOTH_ERROR_NONE) {
316 __bt_free_sending_info(sending_info);
321 static void _bt_remove_session()
323 DBusGConnection *g_conn;
324 DBusGProxy *session_proxy;
326 g_conn = _bt_get_session_gconn();
327 ret_if(g_conn == NULL);
329 session_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEXD_DBUS_NAME,
330 BT_OBEX_CLIENT_PATH, BT_OBEX_CLIENT_INTERFACE);
332 ret_if(session_proxy == NULL);
334 dbus_g_proxy_call(session_proxy, "RemoveSession",
335 NULL, DBUS_TYPE_G_OBJECT_PATH, sending_info->session_path,
340 static gboolean __bt_sending_release()
342 retv_if(sending_info == NULL, FALSE);
344 _bt_remove_session();
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,
354 __bt_free_sending_info(sending_info);
357 _bt_opp_client_event_deinit();
359 /* Operate remain works */
360 if (g_slist_length(transfer_list) > 0) {
361 bt_sending_data_t *data = NULL;
363 data = transfer_list->data;
367 transfer_list = g_slist_remove(transfer_list, data);
369 if (__bt_opp_client_start_sending(data->request_id,
372 data->file_count) != BLUETOOTH_ERROR_NONE) {
379 g_slist_free_full(transfer_list,
380 (GDestroyNotify)__bt_free_sending_data);
381 transfer_list = NULL;
385 void _bt_sending_files()
387 DBusGConnection *g_conn;
388 DBusGProxy *client_proxy;
389 static int file_offset = 0;
393 if (sending_info == NULL)
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);
401 client_proxy = dbus_g_proxy_new_for_name(g_conn,
403 sending_info->session_path,
404 BT_OBEX_OBJECT_PUSH_INTERFACE);
406 ret_if(client_proxy == NULL);
408 dbus_g_proxy_call(client_proxy, "SendFile",NULL,
410 sending_info->file_name_array[file_offset],
415 __bt_sending_release();
421 static void __bt_create_session_cb(DBusGProxy *proxy, DBusGProxyCall *call,
424 GError *error = NULL;
425 int result = BLUETOOTH_ERROR_NONE;
426 char *session_path = NULL;
428 if (dbus_g_proxy_end_call(proxy, call, &error,
429 DBUS_TYPE_G_OBJECT_PATH, &session_path, G_TYPE_INVALID) == FALSE) {
431 BT_ERR("%s", error->message);
434 result = BLUETOOTH_ERROR_INTERNAL;
436 sending_info->session_path = g_strdup(session_path);
439 g_object_unref(proxy);
440 ret_if(sending_info == NULL);
442 sending_info->sending_proxy = NULL;
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,
452 if (result != BLUETOOTH_ERROR_NONE) {
453 __bt_free_sending_info(sending_info);
460 static int __bt_opp_client_start_sending(int request_id, char *address,
461 char **file_name_array, int file_count)
465 DBusGConnection *g_conn;
466 DBusGProxy *client_proxy;
467 DBusGProxyCall *proxy_call;
470 BT_CHECK_PARAMETER(address, return);
471 BT_CHECK_PARAMETER(file_name_array, return);
473 /* Get the session bus. */
474 g_conn = _bt_get_session_gconn();
475 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
477 client_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME,
478 BT_OBEX_CLIENT_PATH, BT_OBEX_CLIENT_INTERFACE);
480 retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
482 hash = g_hash_table_new_full(g_str_hash, g_str_equal,
483 NULL, (GDestroyNotify)__bt_value_free);
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);
490 __bt_free_sending_info(sending_info);
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);
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]);
504 _bt_opp_client_event_deinit();
505 _bt_opp_client_event_init();
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);
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();
520 return BLUETOOTH_ERROR_INTERNAL;
523 sending_info->sending_proxy = proxy_call;
524 g_hash_table_destroy(hash);
526 return BLUETOOTH_ERROR_NONE;
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)
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;
540 BT_CHECK_PARAMETER(remote_address, return);
541 BT_CHECK_PARAMETER(file_path, return);
543 /* Implement the queue */
544 _bt_convert_addr_type_to_string(address, remote_address->addr);
546 if (sending_info == NULL) {
547 result = __bt_opp_client_start_sending(request_id,
548 address, file_path, file_count);
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;
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]);
562 transfer_list = g_slist_append(transfer_list, data);
565 out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar));
566 out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar));
568 g_array_append_vals(out_param1, &request_id,
570 g_array_append_vals(out_param2, &result, sizeof(int));
572 dbus_g_method_return(context, out_param1, out_param2);
574 g_array_free(out_param1, TRUE);
575 g_array_free(out_param2, TRUE);
580 int _bt_opp_client_cancel_push(void)
582 DBusGConnection *g_conn;
583 DBusGProxy *client_proxy;
585 retv_if(sending_info == NULL, BLUETOOTH_ERROR_NOT_IN_OPERATION);
587 sending_info->is_canceled = TRUE;
589 if (sending_info->transfer_info) {
590 dbus_g_proxy_call_no_reply(sending_info->transfer_info->proxy,
591 "Cancel", G_TYPE_INVALID,
594 retv_if(sending_info->sending_proxy == NULL,
595 BLUETOOTH_ERROR_INTERNAL);
597 g_conn = _bt_get_session_gconn();
598 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
600 client_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME,
601 BT_OBEX_CLIENT_PATH, BT_OBEX_CLIENT_INTERFACE);
603 retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
605 dbus_g_proxy_cancel_call(client_proxy,
606 sending_info->sending_proxy);
608 g_idle_add(__bt_cancel_push_cb, NULL);
611 return BLUETOOTH_ERROR_NONE;
614 int _bt_opp_client_cancel_all_transfers(void)
617 g_slist_free_full(transfer_list,
618 (GDestroyNotify)__bt_free_sending_data);
620 transfer_list = NULL;
623 _bt_opp_client_cancel_push();
625 return BLUETOOTH_ERROR_NONE;
628 int _bt_opp_client_is_sending(gboolean *sending)
630 BT_CHECK_PARAMETER(sending, return);
632 *sending = sending_info ? TRUE : FALSE;
634 return BLUETOOTH_ERROR_NONE;