X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-service%2Fbt-service-opp-client.c;h=3e83f72e9ba222317d335f52a7195e6bb6ca71e0;hb=a0e93a330aa0362824aa37ab8aebd20a3127a434;hp=c0c7d080b0b95099419262b233850dd5ce97935c;hpb=5f5b6fa5e56703d0d16409aee366a7701888a583;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-service/bt-service-opp-client.c b/bt-service/bt-service-opp-client.c index c0c7d08..3e83f72 100644 --- a/bt-service/bt-service-opp-client.c +++ b/bt-service/bt-service-opp-client.c @@ -1,13 +1,11 @@ /* - * bluetooth-frwk - * - * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,11 +15,13 @@ * */ -#include -#include #include #include #include +#include +#include +#include +#include #include "bluetooth-api.h" #include "bt-internal-types.h" @@ -31,65 +31,20 @@ #include "bt-service-util.h" #include "bt-service-opp-client.h" #include "bt-service-obex-agent.h" +#include "bt-service-adapter.h" -static BtObexAgent *opc_obex_agent = NULL; -static GSList *transfer_list = NULL; +#define BT_MIME_TYPE_MAX_LEN 20 +static GSList *transfer_list = NULL; bt_sending_info_t *sending_info; +static int file_offset = 0; -static gboolean __bt_release_callback(DBusGMethodInvocation *context, - gpointer user_data); - -static gboolean __bt_request_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - gpointer user_data); - -static gboolean __bt_progress_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - guint64 transferred, - gpointer user_data); - -static gboolean __bt_complete_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - gpointer user_data); - -static gboolean __bt_error_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - const char *message, - gpointer user_data); - +#define DBUS_TIEMOUT 20 * 1000 /* 20 Seconds */ +static gboolean __bt_sending_release(); +static int _bt_remove_session(); static int __bt_opp_client_start_sending(int request_id, char *address, - char **file_name_array); - -static int __bt_opp_client_agent_init(void) -{ - opc_obex_agent = _bt_obex_agent_new(); - retv_if(opc_obex_agent == NULL, BLUETOOTH_ERROR_INTERNAL); - - _bt_obex_set_release_cb(opc_obex_agent, - __bt_release_callback, NULL); - _bt_obex_set_request_cb(opc_obex_agent, - __bt_request_callback, NULL); - _bt_obex_set_progress_cb(opc_obex_agent, - __bt_progress_callback, NULL); - _bt_obex_set_complete_cb(opc_obex_agent, - __bt_complete_callback, NULL); - _bt_obex_set_error_cb(opc_obex_agent, - __bt_error_callback, NULL); - - _bt_obex_setup(opc_obex_agent, BT_OBEX_CLIENT_AGENT_PATH); - - return BLUETOOTH_ERROR_NONE; -} - -static void __bt_opp_client_agent_deinit(void) -{ - ret_if(opc_obex_agent == NULL); - - g_object_unref(opc_obex_agent); - opc_obex_agent = NULL; -} + char **file_name_array, int file_count); static GQuark __bt_opc_error_quark(void) { @@ -107,6 +62,10 @@ static void __bt_free_transfer_info(bt_transfer_info_t *info) if (info->proxy) g_object_unref(info->proxy); + if (info->properties_proxy) + g_object_unref(info->properties_proxy); + + g_free(info->transfer_name); g_free(info->file_name); g_free(info); @@ -119,194 +78,239 @@ static void __bt_free_sending_info(bt_sending_info_t *info) /* Free the sending variable */ __bt_free_transfer_info(info->transfer_info); + g_free(info->file_name_array); + g_free(info->address); g_free(info); } -static void __bt_value_free(GValue *value) -{ - g_value_unset(value); - g_free(value); -} - static gboolean __bt_cancel_push_cb(gpointer data) { - int result = BLUETOOTH_ERROR_CANCEL_BY_USER; + BT_DBG("+"); + int result = BLUETOOTH_ERROR_CANCEL_BY_USER; + GVariant *param = NULL; retv_if(sending_info == NULL, FALSE); + sending_info->result = result; + param = g_variant_new("(isi)", result, + sending_info->address, + sending_info->request_id); /* Send the event in only error none case */ _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_CONNECTED, - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &sending_info->address, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); - + param); __bt_free_sending_info(sending_info); sending_info = NULL; - __bt_opp_client_agent_deinit(); + _bt_opp_client_event_deinit(); - /* Operate remain works */ + BT_DBG("Length of transfer list is %d", g_slist_length(transfer_list)); + + /*Operate remain works*/ if (g_slist_length(transfer_list) > 0) { bt_sending_data_t *node = NULL; node = transfer_list->data; if (node == NULL) { - BT_DBG("data is NULL"); + BT_ERR("data is NULL"); return FALSE; } transfer_list = g_slist_remove(transfer_list, node); if (__bt_opp_client_start_sending(node->request_id, - node->address, - node->file_path) != BLUETOOTH_ERROR_NONE) { - BT_DBG("Fail to start sending"); + node->address, node->file_path, + node->file_count) != BLUETOOTH_ERROR_NONE) { + BT_ERR("Fail to start sending"); } } - + BT_DBG("-"); return FALSE; } -static gboolean __bt_progress_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - guint64 transferred, - gpointer user_data) +gboolean _bt_obex_client_progress(const char *transfer_path, guint64 transferred) { + BT_DBG("+"); + int percentage_progress; - gint64 size; + int previous_progress; + guint64 size; int result = BLUETOOTH_ERROR_NONE; - - dbus_g_method_return(context); - + GVariant *param = NULL; retv_if(sending_info == NULL, TRUE); retv_if(sending_info->transfer_info == NULL, TRUE); - size = sending_info->transfer_info->size; + if (g_strcmp0(sending_info->transfer_info->transfer_path, + transfer_path) != 0) { + BT_INFO("Path mismatch, previous transfer failed! Returning"); + return FALSE; + } + size = sending_info->transfer_info->size; if (size != 0) - percentage_progress = (int)(((gdouble)transferred / - (gdouble)size) * 100); + percentage_progress = (int)(((gdouble)transferred /(gdouble)size) * 100); else percentage_progress = 0; + sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_PROGRESS; + sending_info->result = result; + + previous_progress = (int)(((gdouble)sending_info->transfer_info->progress /(gdouble)size) * 100); + if (percentage_progress == previous_progress && + sending_info->transfer_info->progress) { + sending_info->transfer_info->progress = transferred; + return TRUE; + } + BT_DBG("Sending progress [prev %d] [curr %d]", + previous_progress, percentage_progress); + + sending_info->transfer_info->progress = transferred; + /* Send the event in only error none case */ + param = g_variant_new("(istii)", result, + sending_info->transfer_info->file_name, + sending_info->transfer_info->size, + percentage_progress, + sending_info->request_id); + + _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_TRANSFER_PROGRESS, - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &sending_info->transfer_info->file_name, - DBUS_TYPE_UINT64, &sending_info->transfer_info->size, - DBUS_TYPE_INT32, &percentage_progress, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); + param); + BT_DBG("-"); return TRUE; } -static gboolean __bt_complete_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - gpointer user_data) +gboolean _bt_obex_client_completed(const char *transfer_path, gboolean success) { + BT_DBG("+"); + int result = BLUETOOTH_ERROR_NONE; + GVariant *param = NULL; + retv_if(sending_info == NULL, TRUE); + retv_if(sending_info->transfer_info == NULL, TRUE); - dbus_g_method_return(context); + if (g_strcmp0(sending_info->transfer_info->transfer_path, + transfer_path) != 0) { + BT_INFO("Path mismatch, previous transfer failed! Returning"); + return FALSE; + } - /* Send the event in only error none case */ - _bt_send_event(BT_OPP_CLIENT_EVENT, - BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &sending_info->transfer_info->file_name, - DBUS_TYPE_UINT64, &sending_info->transfer_info->size, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); + result = (success == TRUE) ? BLUETOOTH_ERROR_NONE : BLUETOOTH_ERROR_CANCEL; + + sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_COMPLETED; + sending_info->result = result; + + if (!success) { /*In case of remote device reject, we need to send BLUETOOTH_EVENT_OPC_DISCONNECTED */ + BT_DBG("completed with error"); + if (!sending_info->is_canceled) { + param = g_variant_new("(issti)", result, + sending_info->address, + sending_info->transfer_info->file_name, + sending_info->transfer_info->size, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, + param); + __bt_free_transfer_info(sending_info->transfer_info); + sending_info->transfer_info = NULL; + /* Reset the file offset as we will cancelled remaining files also */ + file_offset = 0; + } + param = g_variant_new("(isi)", sending_info->result, + sending_info->address, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_DISCONNECTED, + param); + __bt_sending_release(); + /* Sending info should not freed after sending_release it's + * already freed in that API and if any pending request is + * present then it recreate sending_info again. + * And if we free it here then CreateSession method call will + * made but RemoveSession method call will not done. + */ + } else { + BT_DBG("complete success"); + /* Send the event in only error none case */ + param = g_variant_new("(issti)", result, + sending_info->address, + sending_info->transfer_info->file_name, + sending_info->transfer_info->size, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, + param); + __bt_free_transfer_info(sending_info->transfer_info); + sending_info->transfer_info = NULL; + } + + BT_DBG("-"); return TRUE; } -static gboolean __bt_request_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - gpointer user_data) +gboolean _bt_obex_client_started(const char *transfer_path) { - GValue *value; - const char *transfer_name; - const char *file_name; - int size; + BT_DBG("+"); + int result = BLUETOOTH_ERROR_NONE; - GHashTable *hash = NULL; - GError *error; + GError *error = NULL; + GVariant *param = NULL; + GDBusConnection *g_conn; + GDBusProxy *properties_proxy; + GDBusProxy *transfer_proxy; if (sending_info == NULL || sending_info->is_canceled == TRUE) { result = BLUETOOTH_ERROR_CANCEL_BY_USER; goto canceled; } - dbus_g_method_return(context, ""); - - __bt_free_transfer_info(sending_info->transfer_info); - - sending_info->transfer_info = g_malloc0(sizeof(bt_transfer_info_t)); - sending_info->transfer_info->proxy = g_object_ref(transfer); + /* Get the session bus. */ + g_conn = _bt_gdbus_get_session_gconn(); + retv_if(g_conn == NULL, FALSE); + properties_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_OBEXD_DBUS_NAME, + transfer_path, BT_PROPERTIES_INTERFACE, + NULL, &error); - dbus_g_proxy_call(transfer, "GetProperties", NULL, - G_TYPE_INVALID, - dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), - &hash, G_TYPE_INVALID); + retv_if(properties_proxy == NULL, FALSE); - if (hash == NULL) - goto fail; + sending_info->transfer_info->properties_proxy = properties_proxy; - value = g_hash_table_lookup(hash, "Name"); - transfer_name = value ? g_value_get_string(value) : NULL; + transfer_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_OBEXD_DBUS_NAME, + transfer_path, BT_OBEX_TRANSFER_INTERFACE, + NULL, &error); - value = g_hash_table_lookup(hash, "Filename"); - file_name = value ? g_value_get_string(value) : NULL; + retv_if(transfer_proxy == NULL, FALSE); - value = g_hash_table_lookup(hash, "Size"); - size = value ? g_value_get_uint64(value) : 0; + sending_info->transfer_info->proxy = transfer_proxy; - sending_info->transfer_info->transfer_name = g_strdup(transfer_name); - sending_info->transfer_info->file_name = g_strdup(file_name); - sending_info->transfer_info->size = size; - sending_info->result = BLUETOOTH_ERROR_NONE; - - g_hash_table_destroy(hash); + sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_STARTED; + sending_info->result = result; + param = g_variant_new("(issti)", result, + sending_info->address, + sending_info->transfer_info->file_name, + sending_info->transfer_info->size, + sending_info->request_id); _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_TRANSFER_STARTED, - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &sending_info->transfer_info->file_name, - DBUS_TYPE_UINT64, &sending_info->transfer_info->size, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); + param); + BT_DBG("-"); return TRUE; canceled: error = g_error_new(__bt_opc_error_quark(), BT_OBEX_AGENT_ERROR_CANCEL, "CancelledByUser"); - dbus_g_method_return_error(context, error); g_error_free(error); + BT_DBG("-"); return FALSE; -fail: - result = BLUETOOTH_ERROR_INTERNAL; - - /* Send the event in only error none case */ - _bt_send_event(BT_OPP_CLIENT_EVENT, - BLUETOOTH_EVENT_OPC_DISCONNECTED, - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &sending_info->address, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); - - __bt_free_sending_info(sending_info); - sending_info = NULL; - - __bt_opp_client_agent_deinit(); - - return TRUE; } static void __bt_free_sending_data(gpointer data) @@ -316,9 +320,8 @@ static void __bt_free_sending_data(gpointer data) ret_if(info == NULL); - for (i = 0; i < info->file_count; i++) { + for (i = 0; i < info->file_count; i++) g_free(info->file_path[i]); - } _bt_delete_request_id(info->request_id); @@ -327,25 +330,46 @@ static void __bt_free_sending_data(gpointer data) g_free(info); } -static gboolean __bt_release_callback(DBusGMethodInvocation *context, - gpointer user_data) +static void __bt_sending_release_cb(GDBusProxy *proxy, + GAsyncResult *res, gpointer user_data) { - dbus_g_method_return(context); + BT_DBG("+"); + ret_if(sending_info == NULL); - retv_if(sending_info == NULL, FALSE); + GError *error = NULL; + int result = BLUETOOTH_ERROR_NONE; + GVariant *param = NULL; + GVariant *reply = NULL; + reply = g_dbus_proxy_call_finish(proxy, res, &error); + if (proxy) + g_object_unref(proxy); + if (reply) + g_variant_unref(reply); + + if (error) { + BT_ERR("%s", error->message); + g_error_free(error); + + result = BLUETOOTH_ERROR_INTERNAL; + } else { + file_offset = 0; + BT_DBG("Session Removed"); + } + + sending_info->result = result; + param = g_variant_new("(isi)", sending_info->result, + sending_info->address, + sending_info->request_id); /* Send the event in only error none case */ _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_DISCONNECTED, - DBUS_TYPE_INT32, &sending_info->result, - DBUS_TYPE_STRING, &sending_info->address, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); + param); __bt_free_sending_info(sending_info); sending_info = NULL; - __bt_opp_client_agent_deinit(); + _bt_opp_client_event_deinit(); /* Operate remain works */ if (g_slist_length(transfer_list) > 0) { @@ -357,122 +381,364 @@ static gboolean __bt_release_callback(DBusGMethodInvocation *context, transfer_list = g_slist_remove(transfer_list, data); + BT_DBG("calling __bt_opp_client_start_sending"); + if (__bt_opp_client_start_sending(data->request_id, - data->address, - data->file_path) != BLUETOOTH_ERROR_NONE) { + data->address, data->file_path, + data->file_count) != BLUETOOTH_ERROR_NONE) { goto fail; } } - return TRUE; + return; fail: g_slist_free_full(transfer_list, (GDestroyNotify)__bt_free_sending_data); transfer_list = NULL; - return TRUE; + + BT_DBG("-"); + + return; } -static gboolean __bt_error_callback(DBusGMethodInvocation *context, - DBusGProxy *transfer, - const char *message, - gpointer user_data) +static int _bt_remove_session() { - int result; + GDBusConnection *g_conn; + GDBusProxy *session_proxy; + GError *err = NULL; - dbus_g_method_return(context); + g_conn = _bt_gdbus_get_session_gconn(); + retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL); + retv_if(sending_info->session_path == NULL, BLUETOOTH_ERROR_INVALID_PARAM); + + session_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_OBEXD_DBUS_NAME, + BT_OBEX_CLIENT_PATH, + BT_OBEX_CLIENT_INTERFACE, + NULL, &err); + + retv_if(session_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + + g_dbus_proxy_call(session_proxy, "RemoveSession", + g_variant_new("(o)", sending_info->session_path), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIEMOUT, NULL, + (GAsyncReadyCallback)__bt_sending_release_cb, + NULL); + + return BLUETOOTH_ERROR_NONE; +} + +static gboolean __bt_sending_release() +{ + BT_DBG("+"); retv_if(sending_info == NULL, FALSE); - retv_if(sending_info->transfer_info == NULL, FALSE); - if (sending_info->is_canceled == TRUE) { - result = BLUETOOTH_ERROR_CANCEL_BY_USER; - } else if (g_strcmp0(message, "Forbidden") == 0) { - result = BLUETOOTH_ERROR_ACCESS_DENIED; - } else if (g_str_has_prefix(message, - "Transport endpoint is not connected") == TRUE) { - result = BLUETOOTH_ERROR_NOT_CONNECTED; - } else if (g_strcmp0(message, "Database full") == 0) { - result = BLUETOOTH_ERROR_OUT_OF_MEMORY; - } else { - result = BLUETOOTH_ERROR_INTERNAL; - } + retv_if(_bt_remove_session() != BLUETOOTH_ERROR_NONE, FALSE); - sending_info->result = result; + BT_DBG("-"); + return TRUE; +} - /* Send the event in only error none case */ +void _bt_opc_disconnected(const char *session_path) +{ + BT_DBG("+"); + GVariant *param = NULL; + ret_if(sending_info == NULL); + + if (g_strcmp0(sending_info->session_path, + session_path) != 0) { + BT_INFO("Path mismatch, previous transfer failed! Returning"); + return; + } + + if (sending_info->transfer_info) { + if (sending_info->transfer_info->transfer_status == BT_TRANSFER_STATUS_PROGRESS || + sending_info->transfer_info->transfer_status == BT_TRANSFER_STATUS_STARTED) { + BT_INFO("Abnormal termination"); + param = g_variant_new("(issti)", sending_info->result, + sending_info->address, + sending_info->transfer_info->file_name, + sending_info->transfer_info->size, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, + param); + __bt_free_transfer_info(sending_info->transfer_info); + } + } + param = g_variant_new("(isi)", sending_info->result, + sending_info->address, + sending_info->request_id); _bt_send_event(BT_OPP_CLIENT_EVENT, - BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &sending_info->transfer_info->file_name, - DBUS_TYPE_UINT64, &sending_info->transfer_info->size, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); - return TRUE; + BLUETOOTH_EVENT_OPC_DISCONNECTED, + param); + + __bt_free_sending_info(sending_info); + sending_info = NULL; + + BT_DBG("-"); } -static void __bt_send_files_cb(DBusGProxy *proxy, DBusGProxyCall *call, - void *user_data) +static void __bt_send_file_cb(GDBusProxy *proxy, + GAsyncResult *res, gpointer user_data) { + BT_DBG("+"); + GVariant *value = NULL; GError *error = NULL; + char *session_path = NULL; + const char *transfer_name = NULL; + const char *file_name = NULL; + int size = 0; + GVariantIter *iter = NULL; + value = g_dbus_proxy_call_finish(proxy, res, &error); + if (error) { + g_dbus_error_strip_remote_error(error); + BT_ERR("%s", error->message); + /* If Obex is not able to open a file then continue with other if any */ + if (g_strcmp0("Unable to open file", error->message) == 0) { + GVariant *param = NULL; + gint64 size = 0; + + BT_ERR("Unable to open file [%s]", sending_info->file_name_array[file_offset]); + + param = g_variant_new("(issti)", BLUETOOTH_ERROR_NOT_FOUND, + sending_info->address, + sending_info->file_name_array[file_offset], + size, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_TRANSFER_STARTED, + param); + + param = g_variant_new("(issti)", BLUETOOTH_ERROR_NOT_FOUND, + sending_info->address, + sending_info->file_name_array[file_offset], + size, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, + param); + g_error_free(error); + if (proxy) + g_object_unref(proxy); + file_offset++; + _bt_sending_files(); + } + return; + } + if (proxy) + g_object_unref(proxy); + + if (value) { + g_variant_get(value, "(oa{sv})", &session_path, &iter); + g_variant_unref(value); + } + + __bt_free_transfer_info(sending_info->transfer_info); + + sending_info->transfer_info = g_malloc0(sizeof(bt_transfer_info_t)); + + if (iter) { + const gchar *key; + GVariant *val; + gsize len = 0; + while (g_variant_iter_loop(iter, "{sv}", &key, &val)) { + if (g_strcmp0(key, "Name") == 0) + transfer_name = g_variant_dup_string(val, &len); + else if (g_strcmp0(key, "Filename") == 0) + file_name = g_variant_dup_string(val, &len); + else if (g_strcmp0(key, "Size") == 0) + size = g_variant_get_uint64(val); + } + g_variant_iter_free(iter); + } + + sending_info->transfer_info->transfer_name = g_strdup(transfer_name); + sending_info->transfer_info->file_name = g_strdup(file_name); + sending_info->transfer_info->size = size; + sending_info->transfer_info->progress = 0; + sending_info->transfer_info->transfer_path = session_path; + sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_QUEUED; + sending_info->result = BLUETOOTH_ERROR_NONE; + file_offset++; + + g_free((gchar *)transfer_name); + g_free((gchar *)file_name); +} + +void _bt_sending_files(void) +{ + BT_DBG("+"); + + GError *err = NULL; + GDBusConnection *g_conn; + GDBusProxy *client_proxy; + char mime_type[BT_MIME_TYPE_MAX_LEN + 1] = { 0 }; + + if (sending_info == NULL) + return; + if (file_offset < sending_info->file_count) { + /* Get the session bus. */ + g_conn = _bt_gdbus_get_session_gconn(); + ret_if(g_conn == NULL); + + client_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_OBEXD_DBUS_NAME, + sending_info->session_path, + BT_OBEX_OBJECT_PUSH_INTERFACE, + NULL, &err); + ret_if(client_proxy == NULL); + if (aul_get_mime_from_file(sending_info->file_name_array[file_offset], + mime_type, BT_MIME_TYPE_MAX_LEN) == AUL_R_OK) { + BT_DBG("MLME type = %s", mime_type); + + /* For IOPT compliance, change "text/x-iMelody" to "audio/imelody" + * because few devices(multimedia players) reject the OPP put for text objects + * since they support only multimedia files exchange */ + if (!strcasecmp(mime_type, "text/x-iMelody")) { + strncpy(mime_type, "audio/imelody", BT_MIME_TYPE_MAX_LEN); + BT_DBG("over writing mime type to = %s", mime_type); + } + if (!strcasecmp(mime_type, "text/vcard")) { + strncpy(mime_type, "text/x-vcard", BT_MIME_TYPE_MAX_LEN); + BT_DBG("over writing mime type to = %s", mime_type); + } + } + + BT_DBG("Calling SendFile"); + g_dbus_proxy_call(client_proxy, "SendFile", + g_variant_new("(ss)", sending_info->file_name_array[file_offset], + mime_type), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIEMOUT, NULL, + (GAsyncReadyCallback)__bt_send_file_cb, + sending_info); + if (err != NULL) { + BT_ERR("Calling SendFile failed: [%s]\n", err->message); + g_clear_error(&err); + return; + } + + } else { + file_offset = 0; + __bt_sending_release(); + } + + BT_DBG("-"); +} + +static void __bt_create_session_cb(GDBusProxy *proxy, + GAsyncResult *res, gpointer user_data) +{ + BT_DBG("+"); + + GError *error = NULL; + GVariant *value; int result = BLUETOOTH_ERROR_NONE; + char *session_path = NULL; + GVariant *param = NULL; - if (dbus_g_proxy_end_call(proxy, call, &error, - G_TYPE_INVALID) == FALSE) { + value = g_dbus_proxy_call_finish(proxy, res, &error); + if (value) { + g_variant_get(value, "(o)", &session_path); + g_variant_unref(value); + } + if (error) { BT_ERR("%s", error->message); - g_error_free(error); + g_clear_error(&error); result = BLUETOOTH_ERROR_INTERNAL; + } else { + BT_DBG("Session created"); + if (sending_info != NULL) + sending_info->session_path = g_strdup(session_path); } - + g_free(session_path); g_object_unref(proxy); ret_if(sending_info == NULL); - sending_info->sending_proxy = NULL; - + sending_info->result = result; + param = g_variant_new("(isi)", result, + sending_info->address, + sending_info->request_id); /* Send the event in only error none case */ _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_CONNECTED, - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &sending_info->address, - DBUS_TYPE_INT32, &sending_info->request_id, - DBUS_TYPE_INVALID); + param); if (result != BLUETOOTH_ERROR_NONE) { + BT_ERR("Calling __bt_sending_release"); + gboolean ret = __bt_sending_release(); + __bt_free_sending_info(sending_info); sending_info = NULL; + + if (ret == FALSE) { + BT_DBG("ReleaseSession Not called"); + /* Operate remain works */ + if (g_slist_length(transfer_list) > 0) { + bt_sending_data_t *data = NULL; + + data = transfer_list->data; + ret_if(data == NULL); + + transfer_list = g_slist_remove(transfer_list, data); + + BT_DBG("calling __bt_opp_client_start_sending"); + + if (__bt_opp_client_start_sending(data->request_id, + data->address, data->file_path, + data->file_count) != BLUETOOTH_ERROR_NONE) { + BT_ERR("Sending Enqueued Transfer Failed"); + } + } + } + } else { + BT_DBG("Calling sending_files"); + _bt_sending_files(); } + BT_DBG("-"); + } static int __bt_opp_client_start_sending(int request_id, char *address, - char **file_name_array) + char **file_name_array, int file_count) { - GHashTable *hash; - GValue *value; - DBusGConnection *g_conn; - DBusGProxy *client_proxy; - DBusGProxyCall *proxy_call; - char *agent_path; + GVariantBuilder *builder; + int i; + GDBusConnection *g_conn; + GDBusProxy *client_proxy; + GError *error = NULL; + BT_DBG("+"); - BT_CHECK_PARAMETER(address); - BT_CHECK_PARAMETER(file_name_array); + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(file_name_array, return); /* Get the session bus. */ - g_conn = _bt_get_session_gconn(); + g_conn = _bt_gdbus_get_session_gconn(); retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL); - client_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME, - "/", BT_OBEX_CLIENT_INTERFACE); + client_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_OBEX_SERVICE_NAME, + BT_OBEX_CLIENT_PATH, + BT_OBEX_CLIENT_INTERFACE, + NULL, &error); + + if (error) { + BT_ERR("Unable to create client proxy: %s", error->message); + g_clear_error(&error); + } retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); - hash = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, (GDestroyNotify)__bt_value_free); + builder = g_variant_builder_new( + G_VARIANT_TYPE("a{sv}")); - value = g_new0(GValue, 1); - g_value_init(value, G_TYPE_STRING); - g_value_set_string(value, address); - g_hash_table_insert(hash, "Destination", value); + g_variant_builder_add(builder, "{sv}", "Target", + g_variant_new_string("OPP")); __bt_free_sending_info(sending_info); @@ -480,60 +746,75 @@ static int __bt_opp_client_start_sending(int request_id, char *address, sending_info->address = g_strdup(address); sending_info->request_id = request_id; - __bt_opp_client_agent_deinit(); - __bt_opp_client_agent_init(); - - agent_path = g_strdup(BT_OBEX_CLIENT_AGENT_PATH); - - proxy_call = dbus_g_proxy_begin_call(client_proxy, "SendFiles", - __bt_send_files_cb, NULL, NULL, - dbus_g_type_get_map("GHashTable", G_TYPE_STRING, - G_TYPE_VALUE), hash, - G_TYPE_STRV, file_name_array, - DBUS_TYPE_G_OBJECT_PATH, agent_path, - G_TYPE_INVALID); - - g_free(agent_path); - - if (proxy_call == NULL) { - BT_ERR("Fail to Send files"); - g_hash_table_destroy(hash); - g_object_unref(client_proxy); - __bt_free_sending_info(sending_info); - __bt_opp_client_agent_deinit(); - sending_info = NULL; - return BLUETOOTH_ERROR_INTERNAL; + sending_info->file_count = file_count; + sending_info->file_offset = 0; + sending_info->file_name_array = g_new0(char *, file_count + 1); + + for (i = 0; i < file_count; i++) { + sending_info->file_name_array[i] = g_strdup(file_name_array[i]); + BT_DBG("file[%d]: %s", i, sending_info->file_name_array[i]); } - sending_info->sending_proxy = proxy_call; - g_hash_table_destroy(hash); + _bt_opp_client_event_deinit(); + _bt_opp_client_event_init(); + //_bt_obex_client_started(agent_path); + + BT_DBG("Adapter Status %d", _bt_adapter_get_status()); + if (_bt_adapter_get_status() == BT_ACTIVATED) { + BT_DBG("Going to call CreateSession"); + g_dbus_proxy_call(client_proxy, "CreateSession", + g_variant_new("(sa{sv})", address, builder), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIEMOUT, NULL, + (GAsyncReadyCallback)__bt_create_session_cb, + NULL); + } else { + GVariant *param = g_variant_new("(isi)", BLUETOOTH_ERROR_INTERNAL, + sending_info->address, sending_info->request_id); + + BT_DBG("Address[%s] RequestID[%d]", sending_info->address, sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_CONNECTED, + param); + __bt_free_sending_info(sending_info); + sending_info = NULL; + } + g_variant_builder_unref(builder); + + BT_DBG("-"); return BLUETOOTH_ERROR_NONE; } -int _bt_opp_client_push_files(int request_id, DBusGMethodInvocation *context, +int _bt_opp_client_push_files(int request_id, GDBusMethodInvocation *context, bluetooth_device_address_t *remote_address, char **file_path, int file_count) { + BT_DBG("+"); char address[BT_ADDRESS_STRING_SIZE] = { 0 }; bt_sending_data_t *data; - GArray *out_param1 = NULL; - GArray *out_param2 = NULL; + + GVariant *out_param1 = NULL; + int result = BLUETOOTH_ERROR_NONE; int i; - BT_CHECK_PARAMETER(remote_address); - BT_CHECK_PARAMETER(file_path); + BT_CHECK_PARAMETER(remote_address, return); + BT_CHECK_PARAMETER(file_path, return); /* Implement the queue */ _bt_convert_addr_type_to_string(address, remote_address->addr); if (sending_info == NULL) { result = __bt_opp_client_start_sending(request_id, - address, file_path); + address, file_path, file_count); + if (result != BLUETOOTH_ERROR_NONE) + return result; } else { /* Insert data in the queue */ data = g_malloc0(sizeof(bt_sending_data_t)); + if (data == NULL) + return BLUETOOTH_ERROR_MEMORY_ALLOCATION; + data->file_path = g_new0(char *, file_count + 1); data->address = g_strdup(address); data->file_count = file_count; @@ -541,63 +822,80 @@ int _bt_opp_client_push_files(int request_id, DBusGMethodInvocation *context, for (i = 0; i < file_count; i++) { data->file_path[i] = g_strdup(file_path[i]); - BT_DBG("file[%d]: %s", i, data->file_path[i]); + DBG_SECURE("file[%d]: %s", i, data->file_path[i]); } transfer_list = g_slist_append(transfer_list, data); } - out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar)); - out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar)); + out_param1 = g_variant_new_from_data((const GVariantType *)"ay", + &request_id, sizeof(int), + TRUE, NULL, NULL); - g_array_append_vals(out_param1, &request_id, - sizeof(int)); - g_array_append_vals(out_param2, &result, sizeof(int)); - dbus_g_method_return(context, out_param1, out_param2); + g_dbus_method_invocation_return_value(context, + g_variant_new("(iv)", result, out_param1)); - g_array_free(out_param1, TRUE); - g_array_free(out_param2, TRUE); + BT_DBG("-"); return result; } int _bt_opp_client_cancel_push(void) { - DBusGConnection *g_conn; - DBusGProxy *client_proxy; + BT_DBG("+"); + GError *err = NULL; + int result = BLUETOOTH_ERROR_CANCEL_BY_USER; + GVariant *ret = NULL; + GVariant *param = NULL; retv_if(sending_info == NULL, BLUETOOTH_ERROR_NOT_IN_OPERATION); sending_info->is_canceled = TRUE; + sending_info->result = result; if (sending_info->transfer_info) { - dbus_g_proxy_call_no_reply(sending_info->transfer_info->proxy, - "Cancel", G_TYPE_INVALID, - G_TYPE_INVALID); - } else { - retv_if(sending_info->sending_proxy == NULL, - BLUETOOTH_ERROR_INTERNAL); - g_conn = _bt_get_session_gconn(); - retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL); - - client_proxy = dbus_g_proxy_new_for_name(g_conn, BT_OBEX_SERVICE_NAME, - "/", BT_OBEX_CLIENT_INTERFACE); - - retv_if(client_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + ret = g_dbus_proxy_call_sync(sending_info->transfer_info->proxy, + "Cancel", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &err); + if (ret == NULL) { + if (err != NULL) { + BT_ERR("Cancel Error: %s\n", err->message); + g_error_free(err); + } + } else { + g_variant_unref(ret); + } - dbus_g_proxy_cancel_call(client_proxy, - sending_info->sending_proxy); + param = g_variant_new("(issti)", result, + sending_info->address, + sending_info->transfer_info->file_name, + sending_info->transfer_info->size, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, + param); + + if (result == BLUETOOTH_ERROR_CANCEL_BY_USER) { + BT_ERR("result is not BLUETOOTH_ERROR_NONE"); + __bt_sending_release(); + file_offset = 0; + } + } else { g_idle_add(__bt_cancel_push_cb, NULL); } + BT_DBG("-"); + return BLUETOOTH_ERROR_NONE; } int _bt_opp_client_cancel_all_transfers(void) { + BT_DBG("+"); if (transfer_list) { g_slist_free_full(transfer_list, (GDestroyNotify)__bt_free_sending_data); @@ -606,15 +904,90 @@ int _bt_opp_client_cancel_all_transfers(void) } _bt_opp_client_cancel_push(); - + BT_DBG("-"); return BLUETOOTH_ERROR_NONE; } int _bt_opp_client_is_sending(gboolean *sending) { - BT_CHECK_PARAMETER(sending); + BT_CHECK_PARAMETER(sending, return); *sending = sending_info ? TRUE : FALSE; return BLUETOOTH_ERROR_NONE; } + +void _bt_opp_client_check_pending_transfer(const char *address) +{ + BT_DBG("+"); + + int result = BLUETOOTH_ERROR_CANCEL; + GVariant *param = NULL; + ret_if(sending_info == NULL); + ret_if(sending_info->transfer_info == NULL); + + if (g_strcmp0(sending_info->address, address) == 0) { + BT_INFO("Address Match.Cancel current transfer"); + sending_info->transfer_info->transfer_status = BT_TRANSFER_STATUS_COMPLETED; + sending_info->result = result; + + if (!sending_info->is_canceled) { + param = g_variant_new("(issti)", result, + sending_info->address, + sending_info->transfer_info->file_name, + sending_info->transfer_info->size, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_TRANSFER_COMPLETE, + param); + __bt_free_transfer_info(sending_info->transfer_info); + sending_info->transfer_info = NULL; + /* Reset the file offset as we will cancelled remaining files also */ + file_offset = 0; + } + param = g_variant_new("(isi)", sending_info->result, + sending_info->address, + sending_info->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, + BLUETOOTH_EVENT_OPC_DISCONNECTED, + param); + + __bt_sending_release(); + } + BT_DBG("-"); +} + +int _bt_opp_get_client_progress(guint8 *progress) +{ + if (sending_info == NULL || sending_info->transfer_info == NULL) { + BT_ERR("No Active Outbound transfer"); + return BLUETOOTH_ERROR_NOT_FOUND; + } + + *progress = (int)(((double)sending_info->transfer_info->progress / + sending_info->transfer_info->size) * 100); + + BT_DBG("Percentage: %d", *progress); + return BLUETOOTH_ERROR_NONE; +} + +void _bt_cancel_queued_transfers(void) +{ + bt_sending_data_t *data = NULL; + GVariant *param = NULL; + + BT_INFO("Cancel queued Transfers:: Length of transfer list is %d", + g_slist_length(transfer_list)); + + while (transfer_list) { + data = transfer_list->data; + param = g_variant_new("(isi)", BLUETOOTH_ERROR_INTERNAL, + data->address, data->request_id); + + BT_DBG("Address[%s] RequestID[%d]", data->address, data->request_id); + _bt_send_event(BT_OPP_CLIENT_EVENT, BLUETOOTH_EVENT_OPC_CONNECTED, + param); + + transfer_list = g_slist_remove(transfer_list, data); + } +}