[cleanup] revise file location
[platform/core/connectivity/bluetooth-share.git] / app / bt-share-main.c
1 /*
2  * bluetooth-share
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #include <glib.h>
21 #include <glib-object.h>
22 #include <string.h>
23 #include <appcore-efl.h>
24 #include <vconf.h>
25 #include <Ecore_File.h>
26 #include <notification_internal.h>
27
28 /* For multi-user support */
29 #include <tzplatform_config.h>
30
31 #include "applog.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"
41
42 #include "bluetooth-share-api.h"
43
44 #define BLUETOOTH_SHARE_BUS             "org.projectx.bluetooth.share"
45
46 static gboolean terminated;
47 static GMainLoop *main_loop = NULL;
48 bt_appdata_t *app_state = NULL;
49 static guint owner_id;
50
51 /* LCOV_EXCL_START */
52 static void __lang_changed_cb(keynode_t *node, void *user_data)
53 {
54         FN_START;
55         /* init internationalization */
56         retm_if(appcore_set_i18n(BT_COMMON_PKG, BT_COMMON_RES) < 0,
57                         "appcore_set_i18n failed!");
58         FN_END;
59 }
60 /* LCOV_EXCL_STOP */
61
62 void _bt_terminate_bluetooth_share(void)
63 {
64         FN_START;
65
66         if (main_loop)
67                 g_main_loop_quit(main_loop); /* LCOV_EXCL_LINE */
68         else
69                 terminated = TRUE;
70
71         FN_END;
72 }
73
74 /* LCOV_EXCL_START */
75 static void __bt_release_service(bt_appdata_t *ad)
76 {
77         ret_if(ad == NULL);
78
79         _bt_deinit_vconf_notification();
80         _bt_delete_notification(ad->opc_noti);
81         _bt_clear_receive_noti_list();
82         ad->send_noti = NULL;
83         ad->receive_noti = NULL;
84         ad->opc_noti = NULL;
85
86         bluetooth_opc_deinit();
87         bluetooth_obex_server_deinit();
88         _bt_unregister_notification_cb(ad);
89
90         vconf_ignore_key_changed(VCONFKEY_LANGSET, __lang_changed_cb);
91
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;
96
97         if (ad->idler > 0) {
98                 DBG("Removing idler!!!");
99                 g_source_remove(ad->idler);
100         }
101         if (owner_id != 0)
102                 g_bus_unown_name(owner_id);
103
104         DBG("Terminating bluetooth-share daemon");
105 }
106 /* LCOV_EXCL_STOP */
107
108 /* LCOV_EXCL_START */
109 static void __bt_sigterm_handler(int signo)
110 {
111         FN_START;
112
113         if (main_loop)
114                 g_main_loop_quit(main_loop);
115         else
116                 terminated = TRUE;
117
118         FN_END;
119 }
120 /* LCOV_EXCL_STOP */
121
122 /* LCOV_EXCL_START */
123 static void __bt_update_transfer_status_values(void)
124 {
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;;
129         sqlite3 *db = NULL;
130
131 #if 0
132         /* Update notification status durning BT off */
133         retm_if(_bt_update_notification_status(ad) == FALSE,
134                         "Notification item is not existed.");
135 #endif
136
137         DBG("Initialize transfer information");
138
139         db = bt_share_open_db();
140         ret_if(!db);
141
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;
145
146                 while (list_iter != NULL) {
147                         info = list_iter->data;
148                         if (info == NULL)
149                                 break;
150
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);
161                         } else {
162                                 ERR("Invalid status");
163                         }
164
165                         list_iter = g_slist_next(list_iter);
166                 }
167
168                 bt_share_release_tr_data_list(tr_data_list);
169                 tr_data_list = NULL;
170                 list_iter = NULL;
171         }
172
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;
176
177                 while (list_iter != NULL) {
178                         info = list_iter->data;
179                         if (info == NULL)
180                                 break;
181
182                         if (info->tr_status == BT_TRANSFER_SUCCESS)
183                                 ad->recv_data.tr_success++;
184                         else
185                                 ad->recv_data.tr_fail++;
186
187                         list_iter = g_slist_next(list_iter);
188                 }
189                 bt_share_release_tr_data_list(tr_data_list);
190                 tr_data_list = NULL;
191                 list_iter = NULL;
192         }
193
194         bt_share_close_db(db);
195
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);
200 }
201 /* LCOV_EXCL_STOP */
202
203 /* LCOV_EXCL_START */
204 static GSList *__merge_sorted(GSList *inbound, GSList *outbound)
205 {
206         GSList *slist = NULL;
207         int *inbound_noti_id = NULL;
208         int *outbound_noti_id = NULL;
209
210         warn_if(inbound == NULL, "No inbound data!!!");
211         warn_if(outbound == NULL, "No outbound data!!!");
212
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  * ***************************************************************************/
219
220         while (inbound && outbound) {
221                 inbound_noti_id = (int *)inbound->data;
222                 outbound_noti_id = (int *)outbound->data;
223
224                 if (*inbound_noti_id > *outbound_noti_id) {
225                         slist = g_slist_prepend(slist, outbound_noti_id);
226                         outbound = g_slist_next(outbound);
227                 } else {
228                         slist = g_slist_prepend(slist, inbound_noti_id);
229                         inbound = g_slist_next(inbound);
230                 }
231         }
232
233         while (inbound) {
234                 inbound_noti_id = (int *)inbound->data;
235                 slist = g_slist_prepend(slist, inbound_noti_id);
236                 inbound = g_slist_next(inbound);
237         }
238
239         while (outbound) {
240                 outbound_noti_id = (int *)outbound->data;
241                 slist = g_slist_prepend(slist, outbound_noti_id);
242                 outbound = g_slist_next(outbound);
243         }
244
245         return slist;
246 }
247 /* LCOV_EXCL_STOP */
248
249 void _bt_remove_temporary_files_by_noti_id(sqlite3 *db, int noti_id)
250 {
251         FN_START;
252         GSList *file_list = bt_share_get_all_temporary_files_by_noti_id(db, noti_id, BT_TMP_DIR);
253
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);
260                 /* LCOV_EXCL_STOP */
261         }
262
263         bt_share_release_temporary_file_list(file_list);
264         FN_END;
265 }
266
267 /* LCOV_EXCL_START */
268 gboolean __bt_clean_database(gpointer user_data)
269 {
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;
275         sqlite3 *db = NULL;
276         GSList *inbound = NULL;
277         GSList *outbound = NULL;
278         GSList *slist = NULL;
279         GSList *current = NULL;
280         int group_id = 0;
281         int priv_id = 0;
282         int noti_id = 0;
283
284         FN_START;
285
286         if (ad->idler) {
287                 DBG("Removing g_idler!!!");
288                 g_source_remove(ad->idler);
289                 ad->idler = 0;
290         }
291
292         noti_err = notification_get_list(NOTIFICATION_TYPE_NOTI, -1, &noti_list);
293         if (noti_err != NOTIFICATION_ERROR_NONE) {
294                 ERR("Error in getting notification list. error(%d)", noti_err);
295                 return G_SOURCE_REMOVE;
296         }
297
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);
301
302         slist = __merge_sorted(inbound, outbound);
303         current = slist;
304         noti_list = notification_list_get_head(noti_list);
305         current_noti = noti_list;
306
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);
318
319                                 /* Remove all temporary files related to this noti_id */
320                                 _bt_remove_temporary_files_by_noti_id(db, noti_id);
321
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);
325                         } else {
326                                 current_noti = notification_list_get_next(current_noti);
327                         }
328                 } else {
329                         current_noti = notification_list_get_next(current_noti);
330                 }
331         }
332
333         /* Remove remaining records with remaining noti_id in slist */
334         while (current) {
335                 noti_id = *(int *)(current->data);
336                 DBG("Removing data by notification id: %d", noti_id);
337
338                 /* Remove all temporary files related to this noti_id */
339                 _bt_remove_temporary_files_by_noti_id(db, noti_id);
340
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);
344         }
345
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);
350         g_slist_free(slist);
351
352
353         FN_END
354         return G_SOURCE_REMOVE;
355 }
356 /* LCOV_EXCL_STOP */
357
358 /* LCOV_EXCL_START */
359 static gboolean __bt_dbus_request_name(void)
360 {
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);
363
364         return (owner_id != 0) ? TRUE : FALSE;
365 }
366 /* LCOV_EXCL_STOP */
367
368 int _bt_init_obex_server(void)
369 {
370         retvm_if(bluetooth_obex_server_init(BT_SHARE_DATA_DIR) != BLUETOOTH_ERROR_NONE,
371                         BT_SHARE_FAIL, "Fail to init obex server");
372
373         /* LCOV_EXCL_START */
374         bluetooth_obex_server_set_root(BT_SHARE_DATA_DIR);
375
376         return BT_SHARE_ERROR_NONE;
377         /* LCOV_EXCL_STOP */
378 }
379
380 /* LCOV_EXCL_START */
381 int main(void)
382 {
383         int ret = 0;
384         INFO("Starting bluetooth-share daemon");
385
386         signal(SIGTERM, __bt_sigterm_handler);
387
388         app_state = calloc(1, sizeof(bt_appdata_t));
389         if (!app_state)
390                 return -1;
391
392         if (__bt_dbus_request_name() == FALSE) {
393                 INFO("Aleady dbus instance existed");
394                 exit(0);
395         }
396
397         /* init internationalization */
398         retvm_if(appcore_set_i18n(BT_COMMON_PKG, BT_COMMON_RES) < 0,
399                         BT_SHARE_FAIL, "appcore_set_i18n failed!");
400
401         if (_bt_share_cynara_init()) {
402                 ERR("Failed to initialize Cynara.\n");
403                 return -1;
404         }
405
406         ret = vconf_notify_key_changed(VCONFKEY_LANGSET, __lang_changed_cb, NULL);
407         warn_if(ret != VCONF_OK, "vconf_notify_key_changed failed");
408
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");
412
413         ret = bluetooth_opc_init();
414         retvm_if(ret != BLUETOOTH_ERROR_NONE, BT_SHARE_FAIL, "bluetooth_opc_init failed");
415
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);
420
421         if (_bt_init_obex_server() == BT_SHARE_ERROR_NONE)
422                 app_state->obex_server_init = TRUE;
423
424         if (terminated == TRUE) {
425                 __bt_release_service(app_state);
426                 _bt_deinit_dbus_signal();
427                 bluetooth_unregister_callback();
428                 return BT_SHARE_FAIL;
429         }
430
431         app_state->idler = g_idle_add(__bt_clean_database, NULL);
432         warn_if(!app_state->idler, "Failed to create idler!!!");
433
434         main_loop = g_main_loop_new(NULL, FALSE);
435         g_main_loop_run(main_loop);
436
437         __bt_release_service(app_state);
438         _bt_deinit_dbus_signal();
439         bluetooth_unregister_callback();
440
441         return BT_SHARE_ERROR_NONE;
442 }
443 /* LCOV_EXCL_STOP */