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.
21 #include <glib-object.h>
23 #include <appcore-efl.h>
25 #include <Ecore_File.h>
26 #include <notification_internal.h>
28 /* For multi-user support */
29 #include <tzplatform_config.h>
32 #include "bt-share-main.h"
33 #include "bluetooth-api.h"
34 #include "obex-event-handler.h"
35 #include "bt-share-ipc.h"
36 #include "bt-share-noti-handler.h"
37 #include "bt-share-resource.h"
38 #include "bt-share-notification.h"
39 #include "bt-share-common.h"
40 #include "bt-share-cynara.h"
42 #include "bluetooth-share-api.h"
44 #define BLUETOOTH_SHARE_BUS "org.projectx.bluetooth.share"
46 static gboolean terminated;
47 static GMainLoop *main_loop = NULL;
48 bt_appdata_t *app_state = NULL;
49 static guint owner_id;
52 static void __lang_changed_cb(keynode_t *node, void *user_data)
55 /* init internationalization */
56 retm_if(appcore_set_i18n(BT_COMMON_PKG, BT_COMMON_RES) < 0,
57 "appcore_set_i18n failed!");
62 void _bt_terminate_bluetooth_share(void)
67 g_main_loop_quit(main_loop); /* LCOV_EXCL_LINE */
75 static void __bt_release_service(bt_appdata_t *ad)
79 _bt_deinit_vconf_notification();
80 _bt_delete_notification(ad->opc_noti);
81 _bt_clear_receive_noti_list();
83 ad->receive_noti = NULL;
86 bluetooth_opc_deinit();
87 bluetooth_obex_server_deinit();
88 _bt_unregister_notification_cb(ad);
90 vconf_ignore_key_changed(VCONFKEY_LANGSET, __lang_changed_cb);
92 g_free(server_auth_info.filename);
93 g_free(server_auth_info.name);
94 server_auth_info.filename = NULL;
95 server_auth_info.name = NULL;
98 DBG("Removing idler!!!");
99 g_source_remove(ad->idler);
102 g_bus_unown_name(owner_id);
104 DBG("Terminating bluetooth-share daemon");
108 /* LCOV_EXCL_START */
109 static void __bt_sigterm_handler(int signo)
114 g_main_loop_quit(main_loop);
122 /* LCOV_EXCL_START */
123 static void __bt_update_transfer_status_values(void)
125 bt_appdata_t *ad = app_state;
126 GSList *tr_data_list = NULL;
127 GSList *list_iter = NULL;
128 bt_tr_data_t *info = NULL;;
132 /* Update notification status durning BT off */
133 retm_if(_bt_update_notification_status(ad) == FALSE,
134 "Notification item is not existed.");
137 DBG("Initialize transfer information");
139 db = bt_share_open_db();
142 tr_data_list = bt_share_get_all_tr_data_list(db, BT_DB_OUTBOUND);
143 if (tr_data_list != NULL) {
144 list_iter = tr_data_list;
146 while (list_iter != NULL) {
147 info = list_iter->data;
151 if (info->tr_status == BT_TRANSFER_SUCCESS) {
152 ad->send_data.tr_success++;
153 } else if (info->tr_status == BT_TRANSFER_FAIL) {
154 ad->send_data.tr_fail++;
155 } else if (info->tr_status == BT_TRANSFER_ONGOING) {
156 /* In case of ongoing file transfer if bluetooth is switched off
157 we need to update the status to fail for these transaction */
158 ad->send_data.tr_fail++;
159 info->tr_status = BT_TR_FAIL;
160 bt_share_update_tr_data(db, BT_DB_OUTBOUND, info->id, info);
162 ERR("Invalid status");
165 list_iter = g_slist_next(list_iter);
168 bt_share_release_tr_data_list(tr_data_list);
173 tr_data_list = bt_share_get_all_tr_data_list(db, BT_DB_INBOUND);
174 if (tr_data_list != NULL) {
175 list_iter = tr_data_list;
177 while (list_iter != NULL) {
178 info = list_iter->data;
182 if (info->tr_status == BT_TRANSFER_SUCCESS)
183 ad->recv_data.tr_success++;
185 ad->recv_data.tr_fail++;
187 list_iter = g_slist_next(list_iter);
189 bt_share_release_tr_data_list(tr_data_list);
194 bt_share_close_db(db);
196 DBG("[Send] success %d, fail %d", ad->send_data.tr_success,
197 ad->send_data.tr_fail);
198 DBG("[Receive] success %d, fail %d", ad->recv_data.tr_success,
199 ad->recv_data.tr_fail);
203 /* LCOV_EXCL_START */
204 static GSList *__merge_sorted(GSList *inbound, GSList *outbound)
206 GSList *slist = NULL;
207 int *inbound_noti_id = NULL;
208 int *outbound_noti_id = NULL;
210 warn_if(inbound == NULL, "No inbound data!!!");
211 warn_if(outbound == NULL, "No outbound data!!!");
213 /* **********************Note from glib documentation**************************
214 * g_slist_append() has to traverse the entire list to find the end, which
215 * is inefficient when adding multiple elements. A common idiom to avoid the
216 * inefficiency is to use g_slist_prepend() and reverse the list with
217 * g_slist_reverse() when all elements have been added.
218 * ***************************************************************************/
220 while (inbound && outbound) {
221 inbound_noti_id = (int *)inbound->data;
222 outbound_noti_id = (int *)outbound->data;
224 if (*inbound_noti_id > *outbound_noti_id) {
225 slist = g_slist_prepend(slist, outbound_noti_id);
226 outbound = g_slist_next(outbound);
228 slist = g_slist_prepend(slist, inbound_noti_id);
229 inbound = g_slist_next(inbound);
234 inbound_noti_id = (int *)inbound->data;
235 slist = g_slist_prepend(slist, inbound_noti_id);
236 inbound = g_slist_next(inbound);
240 outbound_noti_id = (int *)outbound->data;
241 slist = g_slist_prepend(slist, outbound_noti_id);
242 outbound = g_slist_next(outbound);
249 void _bt_remove_temporary_files_by_noti_id(sqlite3 *db, int noti_id)
252 GSList *file_list = bt_share_get_all_temporary_files_by_noti_id(db, noti_id, BT_TMP_DIR);
254 GSList *current_file = file_list;
255 while (current_file) {
256 /* LCOV_EXCL_START */
257 DBG("Removing [%s]", (char *)(current_file->data));
258 ecore_file_remove((char *)(current_file->data));
259 current_file = g_slist_next(current_file);
263 bt_share_release_temporary_file_list(file_list);
267 /* LCOV_EXCL_START */
268 gboolean __bt_clean_database(gpointer user_data)
270 bt_appdata_t *ad = app_state;
271 notification_h noti = NULL;
272 notification_list_h noti_list = NULL;
273 notification_list_h current_noti = NULL;
274 notification_error_e noti_err = NOTIFICATION_ERROR_NONE;
276 GSList *inbound = NULL;
277 GSList *outbound = NULL;
278 GSList *slist = NULL;
279 GSList *current = NULL;
287 DBG("Removing g_idler!!!");
288 g_source_remove(ad->idler);
292 noti_err = notification_get_list(NOTIFICATION_TYPE_NOTI, -1, ¬i_list);
293 if (noti_err != NOTIFICATION_ERROR_NONE) {
294 ERR("Error in getting notification list. error(%d)", noti_err);
295 return G_SOURCE_REMOVE;
298 db = bt_share_open_db();
299 inbound = bt_share_get_noti_list(db, BT_DB_INBOUND);
300 outbound = bt_share_get_noti_list(db, BT_DB_OUTBOUND);
302 slist = __merge_sorted(inbound, outbound);
304 noti_list = notification_list_get_head(noti_list);
305 current_noti = noti_list;
307 while (current_noti && current) {
308 noti = notification_list_get_data(current_noti);
309 noti_err = notification_get_id(noti, &group_id, &priv_id);
310 noti_id = *(int *)(current->data);
311 DBG("priv_id: %d | noti_id: %d", priv_id, noti_id);
312 if (noti_err == NOTIFICATION_ERROR_NONE) {
313 if (priv_id == noti_id) {
314 current = g_slist_next(current);
315 current_noti = notification_list_get_next(current_noti);
316 } else if (noti_id > priv_id) {
317 DBG("Removing data by notification id: %d", noti_id);
319 /* Remove all temporary files related to this noti_id */
320 _bt_remove_temporary_files_by_noti_id(db, noti_id);
322 bt_share_remove_tr_data_by_notification(db, BT_DB_INBOUND, noti_id);
323 bt_share_remove_tr_data_by_notification(db, BT_DB_OUTBOUND, noti_id);
324 current = g_slist_next(current);
326 current_noti = notification_list_get_next(current_noti);
329 current_noti = notification_list_get_next(current_noti);
333 /* Remove remaining records with remaining noti_id in slist */
335 noti_id = *(int *)(current->data);
336 DBG("Removing data by notification id: %d", noti_id);
338 /* Remove all temporary files related to this noti_id */
339 _bt_remove_temporary_files_by_noti_id(db, noti_id);
341 bt_share_remove_tr_data_by_notification(db, BT_DB_INBOUND, noti_id);
342 bt_share_remove_tr_data_by_notification(db, BT_DB_OUTBOUND, noti_id);
343 current = g_slist_next(current);
346 bt_share_close_db(db);
347 notification_free_list(noti_list);
348 bt_share_release_noti_list(inbound);
349 bt_share_release_noti_list(outbound);
354 return G_SOURCE_REMOVE;
358 /* LCOV_EXCL_START */
359 static gboolean __bt_dbus_request_name(void)
361 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, BLUETOOTH_SHARE_BUS,
362 G_DBUS_CALL_FLAGS_NONE, NULL, NULL, NULL, NULL, NULL);
364 return (owner_id != 0) ? TRUE : FALSE;
368 int _bt_init_obex_server(void)
370 retvm_if(bluetooth_obex_server_init(BT_SHARE_DATA_DIR) != BLUETOOTH_ERROR_NONE,
371 BT_SHARE_FAIL, "Fail to init obex server");
373 /* LCOV_EXCL_START */
374 bluetooth_obex_server_set_root(BT_SHARE_DATA_DIR);
376 return BT_SHARE_ERROR_NONE;
380 /* LCOV_EXCL_START */
384 INFO("Starting bluetooth-share daemon");
386 signal(SIGTERM, __bt_sigterm_handler);
388 app_state = calloc(1, sizeof(bt_appdata_t));
392 if (__bt_dbus_request_name() == FALSE) {
393 INFO("Aleady dbus instance existed");
397 /* init internationalization */
398 retvm_if(appcore_set_i18n(BT_COMMON_PKG, BT_COMMON_RES) < 0,
399 BT_SHARE_FAIL, "appcore_set_i18n failed!");
401 if (_bt_share_cynara_init()) {
402 ERR("Failed to initialize Cynara.\n");
406 ret = vconf_notify_key_changed(VCONFKEY_LANGSET, __lang_changed_cb, NULL);
407 warn_if(ret != VCONF_OK, "vconf_notify_key_changed failed");
409 ret = bluetooth_register_callback(_bt_share_event_handler, NULL);
410 warn_if(ret != BLUETOOTH_ERROR_NONE && ret != BLUETOOTH_ERROR_ALREADY_INITIALIZED,
411 "bluetooth_register callback failed");
413 ret = bluetooth_opc_init();
414 retvm_if(ret != BLUETOOTH_ERROR_NONE, BT_SHARE_FAIL, "bluetooth_opc_init failed");
416 _bt_init_dbus_signal();
417 _bt_init_vconf_notification((void *)app_state);
418 __bt_update_transfer_status_values();
419 _bt_register_notification_cb(app_state);
421 if (_bt_init_obex_server() == BT_SHARE_ERROR_NONE)
422 app_state->obex_server_init = TRUE;
424 if (terminated == TRUE) {
425 __bt_release_service(app_state);
426 _bt_deinit_dbus_signal();
427 bluetooth_unregister_callback();
428 return BT_SHARE_FAIL;
431 app_state->idler = g_idle_add(__bt_clean_database, NULL);
432 warn_if(!app_state->idler, "Failed to create idler!!!");
434 main_loop = g_main_loop_new(NULL, FALSE);
435 g_main_loop_run(main_loop);
437 __bt_release_service(app_state);
438 _bt_deinit_dbus_signal();
439 bluetooth_unregister_callback();
441 return BT_SHARE_ERROR_NONE;