Fixed to compare after conversion to localtime in alert_localtime logic
[platform/core/pim/calendar-service.git] / server / cal_server_alarm.c
1 /*
2  * Calendar Service
3  *
4  * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
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 <stdlib.h>
21 #include <sys/time.h>
22 #include <unistd.h>
23 #include <alarm.h>
24 #include <vconf.h>
25 #include <app.h>
26
27 #include "calendar.h"
28 #include "cal_typedef.h"
29 #include "cal_internal.h"
30 #include "cal_time.h"
31 #include "cal_inotify.h"
32 #include "cal_db_util.h"
33 #include "cal_db.h"
34 #include "cal_db_query.h"
35 #include "cal_server_service.h"
36 #include "cal_server_ondemand.h"
37 #include "cal_server_dbus.h"
38 #include "cal_server_alarm.h"
39
40 #define CAL_SERVER_ALARM_THREAD_NAME "cal_server_alarm"
41
42 GThread *_cal_server_alarm_thread = NULL;
43 GCond _cal_server_alarm_cond;
44 GMutex _cal_server_alarm_mutex;
45 static bool server_killed = false;
46 static bool signal_called = false;
47
48 struct _alarm_data_s {
49         int event_id;
50         long long int alert_utime; /* to compare */
51         int unit;
52         int tick;
53         int type; /* utime, localtime */
54         long long int time;
55         int record; /* todo, event */
56         char datetime[CAL_STR_SHORT_LEN32];
57         int system_type;
58 };
59
60 struct alarm_ud {
61         GList *alarm_list;
62 };
63
64 /* this api is necessary for repeat instance. */
65 static int cal_server_alarm_unset_alerted_alarmmgr_id(int alarm_id)
66 {
67         char query[CAL_DB_SQL_MAX_LEN] = {0};
68         int ret = 0;
69
70         ret = cal_db_util_begin_trans();
71         if (CALENDAR_ERROR_NONE != ret) {
72                 /* LCOV_EXCL_START */
73                 ERR("cal_db_util_begin_trans() Fail");
74                 return CALENDAR_ERROR_DB_FAILED;
75                 /* LCOV_EXCL_STOP */
76         }
77
78         DBG("alarm_id(%d)", alarm_id);
79
80         snprintf(query, sizeof(query), "UPDATE %s SET alarm_id = 0 WHERE alarm_id =%d ",
81                         CAL_TABLE_ALARM, alarm_id);
82         ret = cal_db_util_query_exec(query);
83         if (CALENDAR_ERROR_NONE != ret) {
84                 /* LCOV_EXCL_START */
85                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
86                 SECURE("[%s]", query);
87                 cal_db_util_end_trans(false);
88                 return ret;
89                 /* LCOV_EXCL_STOP */
90         }
91         cal_db_util_end_trans(true);
92         return CALENDAR_ERROR_NONE;
93 }
94
95 static int _cal_server_alarm_clear_all_cb(alarm_id_t alarm_id, void *data)
96 {
97         int ret;
98
99         DBG("remove alarm id(%d)", alarm_id);
100         cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
101         ret = alarmmgr_remove_alarm(alarm_id);
102         if (ret != ALARMMGR_RESULT_SUCCESS) {
103                 /* LCOV_EXCL_START */
104                 ERR("alarmmgr_remove_alarm() Fail(ret:%d)", ret);
105                 return ret;
106                 /* LCOV_EXCL_STOP */
107         }
108         return CALENDAR_ERROR_NONE;
109 }
110
111 static int _cal_server_alarm_update_alarm_id(int alarm_id, int event_id, int tick, int unit)
112 {
113         char query[CAL_DB_SQL_MAX_LEN] = {0};
114         int ret = 0;
115
116         ret = cal_db_util_begin_trans();
117         if (CALENDAR_ERROR_NONE != ret) {
118                 /* LCOV_EXCL_START */
119                 ERR("cal_db_util_begin_trans() Fail");
120                 return CALENDAR_ERROR_DB_FAILED;
121                 /* LCOV_EXCL_STOP */
122         }
123
124         DBG("Update alarm_id(%d) in alarm table", alarm_id);
125         snprintf(query, sizeof(query), "UPDATE %s SET alarm_id =%d "
126                         "WHERE event_id =%d AND remind_tick =%d AND remind_tick_unit =%d",
127                         CAL_TABLE_ALARM, alarm_id, event_id, tick, unit);
128         ret = cal_db_util_query_exec(query);
129         if (CALENDAR_ERROR_NONE != ret) {
130                 /* LCOV_EXCL_START */
131                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
132                 SECURE("[%s]", query);
133                 cal_db_util_end_trans(false);
134                 return ret;
135                 /* LCOV_EXCL_STOP */
136         }
137         cal_db_util_end_trans(true);
138         return CALENDAR_ERROR_NONE;
139 }
140
141 static time_t _make_time(struct tm *time)
142 {
143         time_t utc = mktime(time);
144
145         /* If an error occurs when isdst is 1, retry it after chaning isdst is 0 */
146         if (utc < 0 && time->tm_isdst != 0 ) {
147                 time->tm_isdst = 0;
148                 utc = mktime(time);
149         }
150         return utc;
151 }
152
153 static long long int _get_event_alert_utime(const char *field, int event_id, time_t current)
154 {
155         int ret = 0;
156         char query[CAL_DB_SQL_MAX_LEN] = {0};
157         snprintf(query, sizeof(query), "SELECT %s FROM %s "
158                         "WHERE event_id=%d AND %s>%ld ORDER BY %s LIMIT 1",
159                         field, CAL_TABLE_UTIME_INSTANCE, event_id, field, current, field);
160
161         sqlite3_stmt *stmt = NULL;
162         ret = cal_db_util_query_prepare(query, &stmt);
163         if (CALENDAR_ERROR_NONE != ret) {
164                 /* LCOV_EXCL_START */
165                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
166                 SECURE("query[%s]", query);
167                 return ret;
168                 /* LCOV_EXCL_STOP */
169         }
170
171         long long int utime = 0;
172         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
173                 utime = sqlite3_column_int(stmt, 0);
174
175         sqlite3_finalize(stmt);
176         return utime;
177 }
178
179 static int _get_event_alert_localtime(const char *field, int event_id, time_t current)
180 {
181         int ret = 0;
182         char query[CAL_DB_SQL_MAX_LEN] = {0};
183         struct tm st = {0};
184         struct tm now_s = {0};
185         char buf[256] = {0};
186
187         localtime_r(&current, &now_s);
188         snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d", (int)(now_s.tm_year + 1900),
189                                 (int)(now_s.tm_mon + 1), (int)now_s.tm_mday, (int)now_s.tm_hour,
190                                 (int)now_s.tm_min, (int)now_s.tm_sec);
191         DBG("Current time : (%s)", buf);
192
193         snprintf(query, sizeof(query), "SELECT %s FROM %s "
194                         "WHERE event_id=%d AND (strftime('%%s', %s) - strftime('%%s', '%s') > 0) ORDER BY %s LIMIT 1",
195                         field, CAL_TABLE_LOCALTIME_INSTANCE, event_id, field, buf, field);
196
197         sqlite3_stmt *stmt = NULL;
198         ret = cal_db_util_query_prepare(query, &stmt);
199         if (CALENDAR_ERROR_NONE != ret) {
200                 /* LCOV_EXCL_START */
201                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
202                 SECURE("query[%s]", query);
203                 return ret;
204                 /* LCOV_EXCL_STOP */
205         }
206
207         const char *datetime = NULL;
208         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
209                 datetime = (const char *)sqlite3_column_text(stmt, 0);
210
211
212         if (NULL == datetime || '\0' == *datetime) {
213                 /* LCOV_EXCL_START */
214                 ERR("Invalid datetime [%s]", datetime);
215                 sqlite3_finalize(stmt);
216                 return 0;
217                 /* LCOV_EXCL_STOP */
218         }
219
220         int y = 0, m = 0, d = 0;
221         int h = 0, n = 0, s = 0;
222         sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
223         sqlite3_finalize(stmt);
224
225         st.tm_year = y - 1900;
226         st.tm_mon = m - 1;
227         st.tm_mday = d;
228         st.tm_hour = h;
229         st.tm_min = n;
230         st.tm_sec = s;
231         st.tm_isdst = cal_time_is_dst_savings();
232
233         return (long long int)_make_time(&st);
234 }
235
236 static int64_t _get_todo_alert_utime(const char *field, int id, time_t now_t)
237 {
238         int ret = 0;
239         char query[CAL_DB_SQL_MAX_LEN] = {0};
240         snprintf(query, sizeof(query), "SELECT %s FROM "CAL_TABLE_SCHEDULE" "
241                         "WHERE id=%d AND %s>%ld ORDER BY %s LIMIT 1", field, id, field, now_t, field);
242
243         sqlite3_stmt *stmt = NULL;
244         ret = cal_db_util_query_prepare(query, &stmt);
245         if (CALENDAR_ERROR_NONE != ret) {
246                 /* LCOV_EXCL_START */
247                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
248                 SECURE("query[%s]", query);
249                 return ret;
250                 /* LCOV_EXCL_STOP */
251         }
252
253         int64_t utime = 0;
254         ret = cal_db_util_stmt_step(stmt);
255         switch (ret) {
256         case CAL_SQLITE_ROW:
257                 utime = (int64_t)sqlite3_column_int64(stmt, 0);
258                 break;
259                 /* LCOV_EXCL_START
260         case SQLITE_DONE:
261                 ERR("No data");
262                 break;*/ //Svace:371986
263         default:
264                 ERR("Invalid return(%d)", ret);
265                 break;
266                 /* LCOV_EXCL_STOP */
267         }
268
269         sqlite3_finalize(stmt);
270         return utime;
271 }
272
273 static int _get_todo_alert_localtime(const char *field, int event_id, time_t current)
274 {
275         int ret = 0;
276         char query[CAL_DB_SQL_MAX_LEN] = {0};
277         struct tm st = {0};
278         struct tm now_s = {0};
279         char buf[256] = {0};
280
281         localtime_r(&current, &now_s);
282         snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d", (int)(now_s.tm_year + 1900),
283                                 (int)(now_s.tm_mon + 1), (int)now_s.tm_mday, (int)now_s.tm_hour,
284                                 (int)now_s.tm_min, (int)now_s.tm_sec);
285         DBG("Current time : (%s)", buf);
286
287         snprintf(query, sizeof(query), "SELECT %s FROM %s "
288                         "WHERE id=%d AND (strftime('%%s', %s) - strftime('%%s', '%s') > 0) ORDER BY %s LIMIT 1",
289                         field, CAL_TABLE_SCHEDULE, event_id, field, buf, field);
290
291         sqlite3_stmt *stmt = NULL;
292         ret = cal_db_util_query_prepare(query, &stmt);
293         if (CALENDAR_ERROR_NONE != ret) {
294                 /* LCOV_EXCL_START */
295                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
296                 SECURE("query[%s]", query);
297                 return ret;
298                 /* LCOV_EXCL_STOP */
299         }
300
301         const char *datetime = NULL;
302         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
303                 datetime = (const char *)sqlite3_column_text(stmt, 0);
304
305         if (NULL == datetime || '\0' == *datetime) {
306                 /* LCOV_EXCL_START */
307                 ERR("Invalid datetime [%s]", datetime);
308                 sqlite3_finalize(stmt);
309                 return 0;
310                 /* LCOV_EXCL_STOP */
311         }
312
313         int y = 0, m = 0, d = 0;
314         int h = 0, n = 0, s = 0;
315         sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
316         sqlite3_finalize(stmt);
317
318         st.tm_year = y - 1900;
319         st.tm_mon = m - 1;
320         st.tm_mday = d;
321         st.tm_hour = h;
322         st.tm_min = n;
323         st.tm_sec = s;
324         st.tm_isdst = cal_time_is_dst_savings();
325
326         return (long long int)_make_time(&st);
327 }
328 /*
329  * time(NULL) is not appropriate as parameter.
330  * 1 seconds could be flowed before calling function.(1 sec time diff)
331  * so, searching DB is neccessary to find alert time.
332  */
333 static int cal_server_alarm_get_alert_time(int alarm_id, time_t *tt_alert)
334 {
335         int ret = 0;
336         RETV_IF(NULL == tt_alert, CALENDAR_ERROR_INVALID_PARAMETER);
337
338         char query[CAL_DB_SQL_MAX_LEN] = {0};
339         snprintf(query, sizeof(query), "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, "
340                         "A.alarm_type, A.alarm_utime, A.alarm_datetime, B.type, B.dtstart_type, "
341                         "B.dtend_type FROM %s as A, %s as B ON A.event_id =B.id WHERE alarm_id =%d ",
342                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE, alarm_id);
343
344         sqlite3_stmt *stmt = NULL;
345         ret = cal_db_util_query_prepare(query, &stmt);
346         if (CALENDAR_ERROR_NONE != ret) {
347                 /* LCOV_EXCL_START */
348                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
349                 SECURE("query[%s]", query);
350                 return ret;
351                 /* LCOV_EXCL_STOP */
352         }
353
354         int event_id = 0;
355         int unit = 0;
356         int tick = 0;
357         int type = 0;
358         long long int utime = 0;
359         const char *datetime = NULL;
360         int record_type = 0;
361         int dtstart_type = 0;
362         int dtend_type = 0;
363         struct tm st = {0};
364
365         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
366                 event_id = sqlite3_column_int(stmt, 0);
367                 unit = sqlite3_column_int(stmt, 1);
368                 tick = sqlite3_column_int(stmt, 2);
369                 type = sqlite3_column_int(stmt, 3);
370                 utime = sqlite3_column_int64(stmt, 4);
371                 datetime = (const char *)sqlite3_column_text(stmt, 5);
372                 record_type = sqlite3_column_int(stmt, 6);
373                 dtstart_type = sqlite3_column_int(stmt, 7);
374                 dtend_type = sqlite3_column_int(stmt, 8);
375         }
376
377         if (CALENDAR_ALARM_TIME_UNIT_SPECIFIC == unit) {
378                 if (CALENDAR_TIME_UTIME == type) {
379                         *tt_alert = utime;
380                 } else {
381                         int y = 0, m = 0, d = 0;
382                         int h = 0, n = 0, s = 0;
383                         if (datetime) {
384                                 sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
385
386                                 st.tm_year = y - 1900;
387                                 st.tm_mon = m - 1;
388                                 st.tm_mday = d;
389                                 st.tm_hour = h;
390                                 st.tm_min = n;
391                                 st.tm_sec = s;
392                                 st.tm_isdst = cal_time_is_dst_savings();
393                                 *tt_alert = _make_time(&st);
394                                 DBG("datetime[%s] to %02d:%02d:%02d (%ld)", datetime, h, n, s, *tt_alert);
395                         }
396                 }
397                 sqlite3_finalize(stmt);
398                 return CALENDAR_ERROR_NONE;
399         }
400         sqlite3_finalize(stmt);
401
402         time_t current = time(NULL);
403
404         current += (tick * unit);
405         current -= 2; /* in case time passed */
406
407         switch (record_type) {
408         case CALENDAR_BOOK_TYPE_EVENT:
409                 switch (dtstart_type) {
410                 case CALENDAR_TIME_UTIME:
411                         utime = _get_event_alert_utime("dtstart_utime", event_id, current);
412                         break;
413
414                 case CALENDAR_TIME_LOCALTIME:
415                         utime = _get_event_alert_localtime("dtstart_datetime", event_id, current);
416                         break;
417                 }
418                 break;
419
420         case CALENDAR_BOOK_TYPE_TODO:
421                 switch (dtend_type) {
422                 case CALENDAR_TIME_UTIME:
423                         utime = _get_todo_alert_utime("dtend_utime", event_id, current);
424                         break;
425
426                 case CALENDAR_TIME_LOCALTIME:
427                         utime = _get_todo_alert_localtime("dtend_datetime", event_id, current);
428                         break;
429                 }
430                 break;
431         }
432         *tt_alert = utime - (tick * unit);
433
434         DBG("alert_time(%ld) = utime(%lld) - (tick(%d) * unit(%d))", *tt_alert, utime, tick, unit);
435
436         return CALENDAR_ERROR_NONE;
437 }
438
439 /*
440  * bool get_all is
441  * true : to get all alarms including same time event.
442  * (ig. if 3 diffrent alarms exist at 06:30, list has 3 data)
443  * false : to get only one alarm to register in alarm-manager.
444  * (ig. if 3 diffrent alarms exist at 06:30, list has only one)
445  */
446 static void _cal_server_alarm_get_upcoming_specific_utime(time_t utime, bool get_all, GList **l)
447 {
448         int ret = 0;
449         char query[CAL_DB_SQL_MAX_LEN] = {0};
450         snprintf(query, sizeof(query), "SELECT A.event_id, A.remind_tick_unit, A.remind_tick,"
451                         "A.alarm_type, A.alarm_utime, A.alarm_datetime "
452                         "FROM "CAL_TABLE_ALARM" as A, "CAL_TABLE_SCHEDULE" as S ON A.event_id = S.id "
453                         "WHERE S.link_base_id = 0 AND A.remind_tick_unit = %d AND A.alarm_type = %d "
454                         "AND A.alarm_utime %s %ld %s",
455                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_UTIME,
456                         true == get_all ? "=" : ">", utime,
457                         true == get_all ? "" : "ORDER BY alarm_utime ASC LIMIT 1");
458
459         sqlite3_stmt *stmt = NULL;
460         ret = cal_db_util_query_prepare(query, &stmt);
461         if (CALENDAR_ERROR_NONE != ret) {
462                 /* LCOV_EXCL_START */
463                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
464                 SECURE("query[%s]", query);
465                 return;
466                 /* LCOV_EXCL_STOP */
467         }
468
469         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
470                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
471                 if (NULL == ad) {
472                         /* LCOV_EXCL_START */
473                         ERR("calloc() Fail");
474                         sqlite3_finalize(stmt);
475                         return;
476                         /* LCOV_EXCL_STOP */
477                 }
478
479                 ad->event_id = sqlite3_column_int(stmt, 0);
480                 ad->unit = sqlite3_column_int(stmt, 1);
481                 ad->tick = sqlite3_column_int(stmt, 2);
482                 ad->type = sqlite3_column_int(stmt, 3);
483                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
484                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
485                 *l = g_list_append(*l, ad);
486                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
487                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
488                 ad->alert_utime = ad->time;
489                 if (false == get_all) break;
490         }
491         sqlite3_finalize(stmt);
492 }
493
494 static void _cal_server_alarm_get_upcoming_specific_localtime(const char *datetime, bool get_all, GList **l)
495 {
496         int ret = 0;
497         char query[CAL_DB_SQL_MAX_LEN] = {0};
498         snprintf(query, sizeof(query), "SELECT A.event_id, A.remind_tick_unit, A.remind_tick,"
499                         "A.alarm_type, A.alarm_utime, A.alarm_datetime "
500                         "FROM "CAL_TABLE_ALARM" as A, "CAL_TABLE_SCHEDULE" as S ON A.event_id = S.id "
501                         "WHERE S.link_base_id = 0 AND A.remind_tick_unit = %d AND A.alarm_type = %d "
502                         "AND A.alarm_datetime %s '%s' %s",
503                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_LOCALTIME,
504                         true == get_all ? "=" : ">", datetime,
505                         true == get_all ? "" : "ORDER BY alarm_datetime ASC LIMIT 1");
506
507         sqlite3_stmt *stmt = NULL;
508         ret = cal_db_util_query_prepare(query, &stmt);
509         if (CALENDAR_ERROR_NONE != ret) {
510                 /* LCOV_EXCL_START */
511                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
512                 SECURE("query[%s]", query);
513                 return;
514                 /* LCOV_EXCL_STOP */
515         }
516
517         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
518                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
519                 if (NULL == ad) {
520                         /* LCOV_EXCL_START */
521                         ERR("calloc() Fail");
522                         sqlite3_finalize(stmt);
523                         return;
524                         /* LCOV_EXCL_STOP */
525                 }
526
527                 ad->event_id = sqlite3_column_int(stmt, 0);
528                 ad->unit = sqlite3_column_int(stmt, 1);
529                 ad->tick = sqlite3_column_int(stmt, 2);
530                 ad->type = sqlite3_column_int(stmt, 3);
531                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
532                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
533                 *l = g_list_append(*l, ad);
534                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
535                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
536
537                 int y = 0, m = 0, d = 0;
538                 int h = 0, n = 0, s = 0;
539                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
540
541                 struct tm st = {0};
542                 st.tm_year = y - 1900;
543                 st.tm_mon = m -1;
544                 st.tm_mday = d;
545                 st.tm_hour = h;
546                 st.tm_min = n;
547                 st.tm_sec = s;
548                 st.tm_isdst = cal_time_is_dst_savings();
549                 ad->alert_utime = (long long int)_make_time(&st);
550                 if (false == get_all) break;
551         }
552         sqlite3_finalize(stmt);
553 }
554
555 static void _cal_server_alarm_get_upcoming_nonspecific_event_utime(time_t utime, bool get_all, GList **l)
556 {
557         int ret = 0;
558         /*
559          * A:alarm
560          * B:utime
561          */
562         char query[CAL_DB_SQL_MAX_LEN] = {0};
563         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick, "
564                         "A.alarm_type,B.dtstart_utime,A.alarm_datetime "
565                         "FROM "CAL_TABLE_ALARM" as A, "CAL_TABLE_UTIME_INSTANCE" as B, "CAL_TABLE_SCHEDULE" as S "
566                         "ON A.event_id = B.event_id AND B.event_id = S.id "
567                         "WHERE S.link_base_id = 0 AND A.remind_tick_unit > %d "
568                         "AND (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
569                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
570                         true == get_all ? "=" : ">", utime,
571                         true == get_all ? "" : "ORDER BY (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1");
572
573         sqlite3_stmt *stmt = NULL;
574         ret = cal_db_util_query_prepare(query, &stmt);
575         if (CALENDAR_ERROR_NONE != ret) {
576                 /* LCOV_EXCL_START */
577                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
578                 SECURE("query[%s]", query);
579                 return;
580                 /* LCOV_EXCL_STOP */
581         }
582
583         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
584                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
585                 if (NULL == ad) {
586                         /* LCOV_EXCL_START */
587                         ERR("calloc() Fail");
588                         sqlite3_finalize(stmt);
589                         return;
590                         /* LCOV_EXCL_STOP */
591                 }
592
593                 ad->event_id = sqlite3_column_int(stmt, 0);
594                 ad->unit = sqlite3_column_int(stmt, 1);
595                 ad->tick = sqlite3_column_int(stmt, 2);
596                 ad->type = sqlite3_column_int(stmt, 3);
597                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
598                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
599                 *l = g_list_append(*l, ad);
600                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
601                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
602
603                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
604                 if (false == get_all) break;
605         }
606         sqlite3_finalize(stmt);
607 }
608
609 static void _cal_server_alarm_get_upcoming_nonspecific_event_localtime(const char *datetime, bool get_all, GList **l)
610 {
611         int ret = 0;
612         /*
613          * A:alarm
614          * B:localtime
615          */
616         char query[CAL_DB_SQL_MAX_LEN] = {0};
617         snprintf(query, sizeof(query), "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, "
618                         "A.alarm_type, A.alarm_utime, B.dtstart_datetime "
619                         "FROM "CAL_TABLE_ALARM" as A, "CAL_TABLE_LOCALTIME_INSTANCE" as B, "CAL_TABLE_SCHEDULE" as S "
620                         "ON A.event_id = B.event_id AND B.event_id = S.id "
621                         "WHERE S.link_base_id = 0 AND A.remind_tick_unit >%d AND "
622                         "(strftime('%%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
623                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
624                         datetime, true == get_all ? "=" : ">",
625                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
626         sqlite3_stmt *stmt = NULL;
627         ret = cal_db_util_query_prepare(query, &stmt);
628         if (CALENDAR_ERROR_NONE != ret) {
629                 /* LCOV_EXCL_START */
630                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
631                 SECURE("query[%s]", query);
632                 return;
633                 /* LCOV_EXCL_STOP */
634         }
635
636         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
637                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
638                 if (NULL == ad) {
639                         /* LCOV_EXCL_START */
640                         ERR("calloc() Fail");
641                         sqlite3_finalize(stmt);
642                         return;
643                         /* LCOV_EXCL_STOP */
644                 }
645
646                 ad->event_id = sqlite3_column_int(stmt, 0);
647                 ad->unit = sqlite3_column_int(stmt, 1);
648                 ad->tick = sqlite3_column_int(stmt, 2);
649                 ad->type = sqlite3_column_int(stmt, 3);
650                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
651                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
652                 *l = g_list_append(*l, ad);
653                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
654                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
655
656                 int y = 0, m = 0, d = 0;
657                 int h = 0, n = 0, s = 0;
658                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
659
660                 struct tm st = {0};
661                 st.tm_year = y - 1900;
662                 st.tm_mon = m -1;
663                 st.tm_mday = d;
664                 st.tm_hour = h;
665                 st.tm_min = n;
666                 st.tm_sec = s;
667                 st.tm_isdst = cal_time_is_dst_savings();
668                 ad->alert_utime = (long long int)_make_time(&st) - (ad->tick * ad->unit);
669                 if (false == get_all) break;
670         }
671         sqlite3_finalize(stmt);
672 }
673
674 static void _cal_server_alarm_get_upcoming_nonspecific_todo_utime(time_t utime, bool get_all, GList **l)
675 {
676         int ret = 0;
677         /*
678          * A:alarm
679          * S:todo(utime)
680          */
681         char query[CAL_DB_SQL_MAX_LEN] = {0};
682         snprintf(query, sizeof(query), "SELECT A.event_id, A.remind_tick_unit, A.remind_tick,"
683                         "A.alarm_type, S.dtend_utime, A.alarm_datetime "
684                         "FROM "CAL_TABLE_ALARM" as A, "CAL_TABLE_SCHEDULE" as S ON A.event_id = S.id "
685                         "WHERE A.remind_tick_unit > %d AND S.type = %d "
686                         "AND (S.dtend_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
687                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
688                         true == get_all ? "=" : ">", utime,
689                         true == get_all ? "" : "ORDER BY (S.dtend_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
690
691         sqlite3_stmt *stmt = NULL;
692         ret = cal_db_util_query_prepare(query, &stmt);
693         if (CALENDAR_ERROR_NONE != ret) {
694                 /* LCOV_EXCL_START */
695                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
696                 SECURE("query[%s]", query);
697                 return;
698                 /* LCOV_EXCL_STOP */
699         }
700
701         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
702                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
703                 if (NULL == ad) {
704                         /* LCOV_EXCL_START */
705                         ERR("calloc() Fail");
706                         sqlite3_finalize(stmt);
707                         return;
708                         /* LCOV_EXCL_STOP */
709                 }
710
711                 ad->event_id = sqlite3_column_int(stmt, 0);
712                 ad->unit = sqlite3_column_int(stmt, 1);
713                 ad->tick = sqlite3_column_int(stmt, 2);
714                 ad->type = sqlite3_column_int(stmt, 3);
715                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
716                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
717                 *l = g_list_append(*l, ad);
718                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
719                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
720
721                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
722                 if (false == get_all) break;
723         }
724         sqlite3_finalize(stmt);
725 }
726
727 static void _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(const char *datetime, bool get_all, GList **l)
728 {
729         int ret = 0;
730         /*
731          * A:alarm
732          * B:todo(localtime)
733          */
734         char query[CAL_DB_SQL_MAX_LEN] = {0};
735         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick,"
736                         "A.alarm_type,A.alarm_utime,B.dtend_datetime "
737                         "FROM "CAL_TABLE_ALARM" as A, "CAL_TABLE_SCHEDULE" as B ON A.event_id = B.id "
738                         "WHERE A.remind_tick_unit >%d AND B.type =%d "
739                         "AND (strftime('%%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
740                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
741                         datetime, true == get_all ? "=" : ">",
742                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
743
744         sqlite3_stmt *stmt = NULL;
745         ret = cal_db_util_query_prepare(query, &stmt);
746         if (CALENDAR_ERROR_NONE != ret) {
747                 /* LCOV_EXCL_START */
748                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
749                 SECURE("query[%s]", query);
750                 return;
751                 /* LCOV_EXCL_STOP */
752         }
753
754         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
755                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
756                 if (NULL == ad) {
757                         /* LCOV_EXCL_START */
758                         ERR("calloc() Fail");
759                         sqlite3_finalize(stmt);
760                         return;
761                         /* LCOV_EXCL_STOP */
762                 }
763
764                 ad->event_id = sqlite3_column_int(stmt, 0);
765                 ad->unit = sqlite3_column_int(stmt, 1);
766                 ad->tick = sqlite3_column_int(stmt, 2);
767                 ad->type = sqlite3_column_int(stmt, 3);
768                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
769                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
770                 *l = g_list_append(*l, ad);
771                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
772                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
773
774                 int y = 0, m = 0, d = 0;
775                 int h = 0, n = 0, s = 0;
776                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
777
778                 struct tm st = {0};
779                 st.tm_year = y - 1900;
780                 st.tm_mon = m -1;
781                 st.tm_mday = d;
782                 st.tm_hour = h;
783                 st.tm_min = n;
784                 st.tm_sec = s;
785                 st.tm_isdst = cal_time_is_dst_savings();
786                 ad->alert_utime = (long long int)_make_time(&st) - (ad->tick * ad->unit);
787                 if (false == get_all) break;
788         }
789         sqlite3_finalize(stmt);
790 }
791
792 static void _cal_server_alarm_get_latest(time_t utime, bool get_all, GList **out_l)
793 {
794         int ret = 0;
795         CAL_FN_CALL();
796         RET_IF(NULL == out_l);
797
798         tzset();
799         struct tm st_local = {0};
800         localtime_r(&utime, &st_local);
801
802         char datetime[CAL_STR_SHORT_LEN32] = {0};
803         ret = snprintf(datetime, sizeof(datetime), CAL_FORMAT_LOCAL_DATETIME,
804                         st_local.tm_year +1900, st_local.tm_mon + 1, st_local.tm_mday,
805                         st_local.tm_hour, st_local.tm_min, st_local.tm_sec);
806
807         if(ret < 0){
808                 WARN("datetime is truncated (%s)",datetime);
809         }
810
811         DBG("get alert to register with given time (%ld) datetime[%s]", utime, datetime);
812
813         GList *l = NULL;
814
815         _cal_server_alarm_get_upcoming_specific_utime(utime, get_all, &l);
816         _cal_server_alarm_get_upcoming_nonspecific_event_utime(utime, get_all, &l);
817         _cal_server_alarm_get_upcoming_nonspecific_todo_utime(utime, get_all, &l);
818
819         _cal_server_alarm_get_upcoming_specific_localtime(datetime, get_all, &l);
820         _cal_server_alarm_get_upcoming_nonspecific_event_localtime(datetime, get_all, &l);
821         _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(datetime, get_all, &l);
822
823         *out_l = l;
824 }
825
826 static gint _cal_server_alarm_sort_cb(gconstpointer a, gconstpointer b)
827 {
828         struct _alarm_data_s *p1 = (struct _alarm_data_s *)a;
829         struct _alarm_data_s *p2 = (struct _alarm_data_s *)b;
830         DBG("%lld) > (%lld)", p1->alert_utime, p2->alert_utime);
831
832         return p1->alert_utime < p2->alert_utime ? -1 : 1;
833 }
834
835 static GFunc _cal_server_alarm_print_cb(gpointer data, gpointer user_data)
836 {
837         struct _alarm_data_s *ad = (struct _alarm_data_s *)data;
838         DBG("id(%d) unit(%d) tick(%d) type(%d) time(%lld) datetime[%s] alert_utime[%lld]",
839                         ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime, ad->alert_utime);
840         return 0;
841 }
842
843 static int _cal_server_alarm_register(GList *alarm_list)
844 {
845         CAL_FN_CALL();
846         RETV_IF(NULL == alarm_list, CALENDAR_ERROR_INVALID_PARAMETER);
847
848         int ret = CALENDAR_ERROR_NONE;
849         GList *l = g_list_first(alarm_list);
850         RETV_IF(NULL == l, CALENDAR_ERROR_INVALID_PARAMETER);
851
852         struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
853         RETVM_IF(NULL == ad, CALENDAR_ERROR_DB_FAILED, "No data");
854
855         /* clear all alarm which set by mine. */
856         ret = alarmmgr_enum_alarm_ids(_cal_server_alarm_clear_all_cb, NULL);
857         if (ret != ALARMMGR_RESULT_SUCCESS) {
858                 /* LCOV_EXCL_START */
859                 ERR("alarmmgr_enum_alarm_ids() Fail");
860                 return ret;
861                 /* LCOV_EXCL_STOP */
862         }
863
864         time_t mod_time = (time_t)ad->alert_utime;
865         alarm_entry_t *alarm_info = NULL;
866         alarm_info = alarmmgr_create_alarm();
867         if (NULL == alarm_info) {
868                 /* LCOV_EXCL_START */
869                 ERR("Failed to create alarm");
870                 return CALENDAR_ERROR_DB_FAILED;
871                 /* LCOV_EXCL_STOP */
872         }
873         tzset();
874         struct tm st_alarm = {0};
875
876         switch (ad->system_type) {
877         case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
878                 gmtime_r(&mod_time, &st_alarm);
879                 break;
880
881         default:
882                 tzset();
883                 localtime_r(&mod_time, &st_alarm);
884                 break;
885         }
886
887         alarm_date_t date = {0};
888         date.year = st_alarm.tm_year + 1900;
889         date.month = st_alarm.tm_mon + 1;
890         date.day = st_alarm.tm_mday;
891         date.hour = st_alarm.tm_hour;
892         date.min = st_alarm.tm_min;
893         date.sec = st_alarm.tm_sec;
894         alarmmgr_set_time(alarm_info, date);
895         DBG(COLOR_CYAN" >>> registered record id (%d) at %04d/%02d/%02d %02d:%02d:%02d "COLOR_END" (utime(%lld), datetime[%s], tick(%d) unit(%d))",
896                         ad->event_id, date.year, date.month, date.day, date.hour, date.min, date.sec,
897                         ad->time, ad->datetime, ad->tick, ad->unit);
898
899         int alarm_id = 0;
900         ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &alarm_id);
901         if (ret < 0) {
902                 /* LCOV_EXCL_START */
903                 ERR("alarmmgr_add_alarm_with_localtime Fail (%d)", ret);
904                 alarmmgr_free_alarm(alarm_info);
905                 return ret;
906                 /* LCOV_EXCL_STOP */
907         }
908         DBG("alarmmgr id (%d)", alarm_id);
909         _cal_server_alarm_update_alarm_id(alarm_id, ad->event_id, ad->tick, ad->unit);
910         alarmmgr_free_alarm(alarm_info);
911         return CALENDAR_ERROR_NONE;
912 }
913
914 static bool __app_matched_cb(app_control_h app_control, const char *package, void *user_data)
915 {
916         CAL_FN_CALL();
917
918         int ret = 0;
919         int i;
920
921         RETV_IF(NULL == user_data, true);
922
923         char *mime = NULL;
924         ret = app_control_get_mime(app_control, &mime);
925         RETVM_IF(APP_CONTROL_ERROR_NONE != ret, true, "app_control_get_mime() Fail(%d)", ret);
926
927         const char *reminder_mime = "application/x-tizen.calendar.reminder";
928         if (strncmp(mime, reminder_mime, strlen(reminder_mime))) { /* not same */
929                 DBG("get mime[%s] is not [%s]", mime, reminder_mime);
930                 free(mime);
931                 return true;
932         }
933         free(mime);
934
935         struct alarm_ud *au = (struct alarm_ud *)user_data;
936         GList *alarm_list = au->alarm_list;
937         if (NULL == alarm_list) {
938                 /* LCOV_EXCL_START */
939                 ERR("No list");
940                 return true;
941                 /* LCOV_EXCL_STOP */
942         }
943         int len = 0;
944         len = g_list_length(alarm_list);
945         if (0 == len) {
946                 DBG("len is 0, no alarm list");
947                 return true;
948         }
949
950         app_control_h ac = NULL;
951         ret = app_control_create(&ac);
952         if (APP_CONTROL_ERROR_NONE != ret) {
953                 /* LCOV_EXCL_START */
954                 ERR("app_control_create() Fail(%d)", ret);
955                 return true;
956                 /* LCOV_EXCL_STOP */
957         }
958         ret = app_control_set_operation(ac,  APP_CONTROL_OPERATION_DEFAULT);
959         if (APP_CONTROL_ERROR_NONE != ret) {
960                 /* LCOV_EXCL_START */
961                 ERR("app_control_create() Fail(%d)", ret);
962                 app_control_destroy(ac);
963                 return true;
964                 /* LCOV_EXCL_STOP */
965         }
966         ret = app_control_set_app_id(ac, package);
967         if (APP_CONTROL_ERROR_NONE != ret) {
968                 /* LCOV_EXCL_START */
969                 ERR("app_control_set_app_id() Fail(%d)", ret);
970                 app_control_destroy(ac);
971                 return true;
972                 /* LCOV_EXCL_STOP */
973         }
974
975         char **ids = NULL;
976         ids = calloc(len, sizeof(char *));
977         if (NULL == ids) {
978                 /* LCOV_EXCL_START */
979                 ERR("calloc() Fail");
980                 app_control_destroy(ac);
981                 return true;
982                 /* LCOV_EXCL_STOP */
983         }
984         GList *cursor = g_list_first(alarm_list);
985         for (i = 0; i < len; i++) {
986                 if (NULL == cursor) {
987                         ERR("cursor is NULL");
988                         break;
989                 }
990                 struct _alarm_data_s *ad = (struct _alarm_data_s *)cursor->data;
991                 if (NULL == ad) {
992                         WARN("No data");
993                         cursor = g_list_next(cursor);
994                         continue;
995                 }
996                 DBG("pkg[%s] time[%lld] tick[%d] unit[%d] record_type[%d]",
997                                 package, ad->time, ad->tick, ad->unit, ad->record);
998
999                 int slen = 0;
1000                 char extra[CAL_STR_MIDDLE_LEN] = {0};
1001                 slen = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
1002                 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%lld", "time", ad->time);
1003                 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%d", "tick", ad->tick);
1004                 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%d", "unit", ad->unit);
1005                 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%d", "type", ad->record);
1006
1007                 /*
1008                  * key: id, value: id=4&time=123123&..
1009                  */
1010                 char buf_id[CAL_STR_MIDDLE_LEN] = {0};
1011                 snprintf(buf_id, sizeof(buf_id), "%d", ad->event_id);
1012                 app_control_add_extra_data(ac, buf_id, extra);
1013                 DBG("value[%s] id[%s]", extra, buf_id);
1014
1015                 /* append ids */
1016                 ids[i] = strdup(buf_id);
1017
1018                 cursor = g_list_next(cursor);
1019         }
1020         app_control_add_extra_data_array(ac, "ids", (const char **)ids, len);
1021         app_control_send_launch_request(ac, NULL, NULL);
1022         app_control_destroy(ac);
1023
1024         for (i = 0; i < len; i++) {
1025                 free(ids[i]);
1026                 ids[i] = NULL;
1027         }
1028         free(ids);
1029
1030         return true;
1031 }
1032
1033 static void _cal_server_alarm_noti_with_control(GList *alarm_list)
1034 {
1035         CAL_FN_CALL();
1036
1037         int ret = 0;
1038         RETM_IF(NULL == alarm_list, "No alarm list");
1039
1040         app_control_h app_control = NULL;
1041         ret = app_control_create(&app_control);
1042         if (APP_CONTROL_ERROR_NONE != ret) {
1043                 /* LCOV_EXCL_START */
1044                 ERR("app_control_create() Fail(%d)", ret);
1045                 return;
1046                 /* LCOV_EXCL_STOP */
1047         }
1048         ret = app_control_set_operation(app_control, APP_CONTROL_OPERATION_VIEW);
1049         if (APP_CONTROL_ERROR_NONE != ret) {
1050                 /* LCOV_EXCL_START */
1051                 ERR("app_control_set_operation() Fail(%d)", ret);
1052                 app_control_destroy(app_control);
1053                 return;
1054                 /* LCOV_EXCL_STOP */
1055         }
1056         ret = app_control_set_mime(app_control, "application/x-tizen.calendar.reminder");
1057         if (APP_CONTROL_ERROR_NONE != ret) {
1058                 /* LCOV_EXCL_START */
1059                 ERR("app_control_set_mime() Fail(%d)", ret);
1060                 app_control_destroy(app_control);
1061                 return;
1062                 /* LCOV_EXCL_STOP */
1063         }
1064
1065         struct alarm_ud *au = calloc(1, sizeof(struct alarm_ud));
1066         if (NULL == au) {
1067                 /* LCOV_EXCL_START */
1068                 ERR("calloc() Fail");
1069                 app_control_destroy(app_control);
1070                 return;
1071                 /* LCOV_EXCL_STOP */
1072         }
1073         au->alarm_list = alarm_list;
1074         ret = app_control_foreach_app_matched(app_control, __app_matched_cb, au);
1075         if (APP_CONTROL_ERROR_NONE != ret) {
1076                 /* LCOV_EXCL_START */
1077                 ERR("app_control_foreach_app_matched() Fail(%d)", ret);
1078                 free(au);
1079                 app_control_destroy(app_control);
1080                 return;
1081                 /* LCOV_EXCL_STOP */
1082         }
1083         free(au);
1084         app_control_destroy(app_control);
1085 }
1086
1087 static void _cal_server_alarm_noti_with_callback(GList *alarm_list)
1088 {
1089         RETM_IF(NULL == alarm_list, "No alarm list");
1090
1091         GList *l = g_list_first(alarm_list);
1092         while (l) {
1093                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
1094                 if (NULL == ad) {
1095                         WARN("No data");
1096                         l = g_list_next(l);
1097                         continue;
1098                 }
1099                 DBG("callback time[%lld] tick[%d] unit[%d] record_type[%d]",
1100                                 ad->time, ad->tick, ad->unit, ad->record);
1101
1102                 int len = 0;
1103                 char extra[CAL_STR_MIDDLE_LEN] = {0};
1104                 len = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
1105                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%lld", "time", ad->time);
1106                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "tick", ad->tick);
1107                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "unit", ad->unit);
1108                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "type", ad->record);
1109                 cal_dbus_publish_reminder(len, extra);
1110
1111                 l = g_list_next(l);
1112         }
1113 }
1114
1115 static void cal_server_alarm_register_next_alarm(time_t utime)
1116 {
1117         CAL_FN_CALL();
1118
1119         GList *l = NULL;
1120         _cal_server_alarm_get_latest(utime, false, &l);
1121         if (NULL == l)
1122                 return;
1123
1124         l = g_list_sort(l, _cal_server_alarm_sort_cb);
1125         g_list_foreach(l, (GFunc)_cal_server_alarm_print_cb, NULL);
1126         _cal_server_alarm_register(l);
1127
1128         g_list_free_full(l, free);
1129 }
1130
1131 static void cal_server_alarm_alert(time_t tt_alert)
1132 {
1133         GList *l = NULL;
1134         _cal_server_alarm_get_latest(tt_alert, true, &l);
1135         if (NULL == l)
1136                 return;
1137
1138         _cal_server_alarm_noti_with_callback(l);
1139         _cal_server_alarm_noti_with_control(l);
1140         g_list_free_full(l, free);
1141 }
1142
1143 static int _alert_cb(alarm_id_t alarm_id, void *data)
1144 {
1145         CAL_FN_CALL();
1146         DBG("alarm_id (%d)", (int)alarm_id);
1147
1148         time_t tt_alert = 0;
1149         cal_server_alarm_get_alert_time(alarm_id, &tt_alert);
1150         cal_server_alarm_alert(tt_alert);
1151         cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
1152         cal_server_alarm_start();
1153         return 0;
1154 }
1155
1156 static void _timechanged_cb(keynode_t *node, void *data)
1157 {
1158         cal_server_alarm_alert(time(NULL));
1159         cal_server_alarm_start();
1160 }
1161
1162 static void _cal_server_alarm_set_timechange(void)
1163 {
1164         vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, _timechanged_cb, NULL);
1165         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_GMT, _timechanged_cb, NULL);
1166         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_ZONE, _timechanged_cb, NULL);
1167         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_EVENT_GMT, _timechanged_cb, NULL);
1168 }
1169
1170 static void _cal_server_alarm_unset_timechange(void)
1171 {
1172         vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, _timechanged_cb);
1173         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_NITZ_GMT, _timechanged_cb);
1174         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_NITZ_ZONE, _timechanged_cb);
1175         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_NITZ_EVENT_GMT, _timechanged_cb);
1176 }
1177
1178 static void _changed_cb(const char* view_uri, void* data)
1179 {
1180         DBG("Receive alarm change signal");
1181         cal_server_alarm_start();
1182 }
1183
1184 static int _cal_server_alarm_set_inotify(calendar_db_changed_cb callback)
1185 {
1186         cal_inotify_subscribe(CAL_NOTI_TYPE_EVENT, CAL_NOTI_FILE_EVENT, callback, NULL);
1187         cal_inotify_subscribe(CAL_NOTI_TYPE_TODO, CAL_NOTI_FILE_TODO, callback, NULL);
1188         return 0;
1189 }
1190
1191 static void _cal_server_alarm_unset_inotify(calendar_db_changed_cb callback)
1192 {
1193         cal_inotify_unsubscribe(CAL_NOTI_FILE_EVENT, callback, NULL);
1194         cal_inotify_unsubscribe(CAL_NOTI_FILE_TODO, callback, NULL);
1195 }
1196
1197 static int cal_server_alarm_init(void)
1198 {
1199         int ret = 0;
1200
1201         _cal_server_alarm_set_timechange();
1202         _cal_server_alarm_set_inotify(_changed_cb);
1203
1204         ret = alarmmgr_set_cb(_alert_cb, NULL);
1205         if (ret < 0) {
1206                 /* LCOV_EXCL_START */
1207                 ERR("alarmmgr_set_cb() Fail(%d)", ret);
1208                 return CALENDAR_ERROR_SYSTEM;
1209                 /* LCOV_EXCL_STOP */
1210         }
1211
1212         ret = alarmmgr_init("calendar-service");
1213         if (ret < 0) {
1214                 /* LCOV_EXCL_START */
1215                 ERR("alarmmgr_init() Fail(%d)", ret);
1216                 return CALENDAR_ERROR_SYSTEM;
1217                 /* LCOV_EXCL_STOP */
1218         }
1219
1220         return CALENDAR_ERROR_NONE;
1221 }
1222
1223 static gpointer _cal_server_alarm_main(gpointer user_data)
1224 {
1225         DBG("thread alarm: start");
1226
1227         int ret = 0;
1228         bool is_initialized = false;
1229
1230         while (1) {
1231                 g_mutex_lock(&_cal_server_alarm_mutex);
1232                 /*
1233                  * While syncing with contacts,
1234                  * because calendar-service could be stopped by on-demand,
1235                  * holding on-demand is needed.
1236                  */
1237                 cal_server_ondemand_hold();
1238
1239                 do {
1240                         if (false == is_initialized) {
1241                                 ret = cal_server_alarm_init();
1242                                 if (CALENDAR_ERROR_NONE != ret) {
1243                                         /* LCOV_EXCL_START */
1244                                         ERR("cal_server_alarm_init() Fail(%d)", ret);
1245                                         break;
1246                                         /* LCOV_EXCL_STOP */
1247                                 }
1248                                 DBG("thread alarm: init");
1249                                 is_initialized = true;
1250                         }
1251
1252                         ret = cal_connect();
1253                         if (CALENDAR_ERROR_NONE != ret) {
1254                                 /* LCOV_EXCL_START */
1255                                 ERR("cal_connect() Fail(%d)", ret);
1256                                 break;
1257                                 /* LCOV_EXCL_STOP */
1258                         }
1259
1260                         cal_server_alarm_register_next_alarm(time(NULL));
1261                         cal_disconnect();
1262
1263                 } while (0);
1264
1265                 cal_server_ondemand_release();
1266                 cal_server_ondemand_start();
1267
1268                 DBG("thread alarm: wait");
1269                 while (false == signal_called)
1270                         g_cond_wait(&_cal_server_alarm_cond, &_cal_server_alarm_mutex);
1271                 signal_called = false;
1272                 g_mutex_unlock(&_cal_server_alarm_mutex);
1273
1274                 if (server_killed)
1275                         break;
1276         }
1277         DBG("thread alarm: end");
1278         g_thread_exit(NULL);
1279
1280         return NULL;
1281 }
1282
1283 void cal_server_alarm_send_signal(void)
1284 {
1285         g_mutex_lock(&_cal_server_alarm_mutex);
1286         signal_called = true;
1287         g_cond_signal(&_cal_server_alarm_cond);
1288         g_mutex_unlock(&_cal_server_alarm_mutex);
1289 }
1290
1291 void cal_server_alarm_start(void)
1292 {
1293         CAL_FN_CALL();
1294
1295         if (NULL == _cal_server_alarm_thread) {
1296                 g_mutex_init(&_cal_server_alarm_mutex);
1297                 g_cond_init(&_cal_server_alarm_cond);
1298                 _cal_server_alarm_thread = g_thread_new(CAL_SERVER_ALARM_THREAD_NAME,
1299                                 _cal_server_alarm_main, NULL);
1300         }
1301         cal_server_alarm_send_signal();
1302 }
1303
1304 static void cal_server_alarm_deinit(void)
1305 {
1306         alarmmgr_fini();
1307         _cal_server_alarm_unset_inotify(_changed_cb);
1308         _cal_server_alarm_unset_timechange();
1309 }
1310
1311 void cal_server_alarm_end(void)
1312 {
1313         CAL_FN_CALL();
1314
1315         server_killed = true;
1316
1317         cal_server_alarm_deinit();
1318         cal_server_alarm_send_signal();
1319
1320         g_cond_clear(&_cal_server_alarm_cond);
1321         g_thread_join(_cal_server_alarm_thread);
1322         g_thread_unref(_cal_server_alarm_thread);
1323         _cal_server_alarm_thread = NULL;
1324 }