4 * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
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.
28 #include "cal_typedef.h"
29 #include "cal_internal.h"
31 #include "cal_inotify.h"
32 #include "cal_db_util.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"
40 #define CAL_SERVER_ALARM_THREAD_NAME "cal_server_alarm"
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;
48 struct _alarm_data_s {
50 long long int alert_utime; /* to compare */
53 int type; /* utime, localtime */
55 int record; /* todo, event */
56 char datetime[CAL_STR_SHORT_LEN32];
64 /* this api is necessary for repeat instance. */
65 static int cal_server_alarm_unset_alerted_alarmmgr_id(int alarm_id)
67 char query[CAL_DB_SQL_MAX_LEN] = {0};
70 ret = cal_db_util_begin_trans();
71 if (CALENDAR_ERROR_NONE != ret) {
73 ERR("cal_db_util_begin_trans() Fail");
74 return CALENDAR_ERROR_DB_FAILED;
78 DBG("alarm_id(%d)", alarm_id);
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) {
85 ERR("cal_db_util_query_exec() Fail(%d)", ret);
86 SECURE("[%s]", query);
87 cal_db_util_end_trans(false);
91 cal_db_util_end_trans(true);
92 return CALENDAR_ERROR_NONE;
95 static int _cal_server_alarm_clear_all_cb(alarm_id_t alarm_id, void *data)
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);
108 return CALENDAR_ERROR_NONE;
111 static int _cal_server_alarm_update_alarm_id(int alarm_id, int event_id, int tick, int unit)
113 char query[CAL_DB_SQL_MAX_LEN] = {0};
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;
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);
137 cal_db_util_end_trans(true);
138 return CALENDAR_ERROR_NONE;
141 static long long int _get_event_alert_utime(const char *field, int event_id, time_t current)
144 char query[CAL_DB_SQL_MAX_LEN] = {0};
145 snprintf(query, sizeof(query), "SELECT %s FROM %s "
146 "WHERE event_id=%d AND %s>%ld ORDER BY %s LIMIT 1",
147 field, CAL_TABLE_UTIME_INSTANCE, event_id, field, current, field);
149 sqlite3_stmt *stmt = NULL;
150 ret = cal_db_util_query_prepare(query, &stmt);
151 if (CALENDAR_ERROR_NONE != ret) {
152 /* LCOV_EXCL_START */
153 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
154 SECURE("query[%s]", query);
159 long long int utime = 0;
160 if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
161 utime = sqlite3_column_int(stmt, 0);
163 sqlite3_finalize(stmt);
167 static int _get_event_alert_localtime(const char *field, int event_id, time_t current)
170 char query[CAL_DB_SQL_MAX_LEN] = {0};
173 localtime_r(¤t, &st);
174 time_t mod_current = timegm(&st);
175 snprintf(query, sizeof(query), "SELECT %s FROM %s "
176 "WHERE event_id=%d AND strftime('%%s', %s)>%ld ORDER BY %s LIMIT 1",
177 field, CAL_TABLE_LOCALTIME_INSTANCE, event_id, field, mod_current, field);
179 sqlite3_stmt *stmt = NULL;
180 ret = cal_db_util_query_prepare(query, &stmt);
181 if (CALENDAR_ERROR_NONE != ret) {
182 /* LCOV_EXCL_START */
183 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
184 SECURE("query[%s]", query);
189 const char *datetime = NULL;
190 if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
191 datetime = (const char *)sqlite3_column_text(stmt, 0);
193 if (NULL == datetime || '\0' == *datetime) {
194 /* LCOV_EXCL_START */
195 ERR("Invalid datetime [%s]", datetime);
196 sqlite3_finalize(stmt);
201 int y = 0, m = 0, d = 0;
202 int h = 0, n = 0, s = 0;
203 sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
204 sqlite3_finalize(stmt);
206 st.tm_year = y - 1900;
213 return (long long int)mktime(&st);
216 static int64_t _get_todo_alert_utime(const char *field, int id, time_t now_t)
219 char query[CAL_DB_SQL_MAX_LEN] = {0};
220 snprintf(query, sizeof(query), "SELECT %s FROM "CAL_TABLE_SCHEDULE" "
221 "WHERE id=%d AND %s>%ld ORDER BY %s LIMIT 1", field, id, field, now_t, field);
223 sqlite3_stmt *stmt = NULL;
224 ret = cal_db_util_query_prepare(query, &stmt);
225 if (CALENDAR_ERROR_NONE != ret) {
226 /* LCOV_EXCL_START */
227 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
228 SECURE("query[%s]", query);
234 ret = cal_db_util_stmt_step(stmt);
237 utime = (int64_t)sqlite3_column_int64(stmt, 0);
239 /* LCOV_EXCL_START */
244 ERR("Invalid return(%d)", ret);
249 sqlite3_finalize(stmt);
253 static int _get_todo_alert_localtime(const char *field, int event_id, time_t current)
256 char query[CAL_DB_SQL_MAX_LEN] = {0};
259 localtime_r(¤t, &st);
260 time_t mod_current = timegm(&st);
261 snprintf(query, sizeof(query), "SELECT %s FROM %s "
262 "WHERE id=%d AND strftime('%%s', %s)>%ld ORDER BY %s LIMIT 1",
263 field, CAL_TABLE_SCHEDULE, event_id, field, mod_current, field);
265 sqlite3_stmt *stmt = NULL;
266 ret = cal_db_util_query_prepare(query, &stmt);
267 if (CALENDAR_ERROR_NONE != ret) {
268 /* LCOV_EXCL_START */
269 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
270 SECURE("query[%s]", query);
275 const char *datetime = NULL;
276 if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
277 datetime = (const char *)sqlite3_column_text(stmt, 0);
279 if (NULL == datetime || '\0' == *datetime) {
280 /* LCOV_EXCL_START */
281 ERR("Invalid datetime [%s]", datetime);
282 sqlite3_finalize(stmt);
287 int y = 0, m = 0, d = 0;
288 int h = 0, n = 0, s = 0;
289 sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
290 sqlite3_finalize(stmt);
292 st.tm_year = y - 1900;
299 return (long long int)mktime(&st);
302 * time(NULL) is not appropriate as parameter.
303 * 1 seconds could be flowed before calling function.(1 sec time diff)
304 * so, searching DB is neccessary to find alert time.
306 static int cal_server_alarm_get_alert_time(int alarm_id, time_t *tt_alert)
309 RETV_IF(NULL == tt_alert, CALENDAR_ERROR_INVALID_PARAMETER);
311 char query[CAL_DB_SQL_MAX_LEN] = {0};
312 snprintf(query, sizeof(query), "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, "
313 "A.alarm_type, A.alarm_utime, A.alarm_datetime, B.type, B.dtstart_type, "
314 "B.dtend_type FROM %s as A, %s as B ON A.event_id =B.id WHERE alarm_id =%d ",
315 CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE, alarm_id);
317 sqlite3_stmt *stmt = NULL;
318 ret = cal_db_util_query_prepare(query, &stmt);
319 if (CALENDAR_ERROR_NONE != ret) {
320 /* LCOV_EXCL_START */
321 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
322 SECURE("query[%s]", query);
331 long long int utime = 0;
332 const char *datetime = NULL;
334 int dtstart_type = 0;
338 if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
339 event_id = sqlite3_column_int(stmt, 0);
340 unit = sqlite3_column_int(stmt, 1);
341 tick = sqlite3_column_int(stmt, 2);
342 type = sqlite3_column_int(stmt, 3);
343 utime = sqlite3_column_int64(stmt, 4);
344 datetime = (const char *)sqlite3_column_text(stmt, 5);
345 record_type = sqlite3_column_int(stmt, 6);
346 dtstart_type = sqlite3_column_int(stmt, 7);
347 dtend_type = sqlite3_column_int(stmt, 8);
350 if (NULL == tt_alert) {
351 /* LCOV_EXCL_START */
352 ERR("Invalid parameter: tt_alert is NULL");
353 sqlite3_finalize(stmt);
354 return CALENDAR_ERROR_INVALID_PARAMETER;
358 if (CALENDAR_ALARM_TIME_UNIT_SPECIFIC == unit) {
359 if (CALENDAR_TIME_UTIME == type) {
362 int y = 0, m = 0, d = 0;
363 int h = 0, n = 0, s = 0;
365 sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
367 st.tm_year = y - 1900;
373 *tt_alert = mktime(&st);
374 DBG("datetime[%s] to %02d:%02d:%02d (%d)", datetime, h, n, s, *tt_alert);
377 sqlite3_finalize(stmt);
378 return CALENDAR_ERROR_NONE;
380 sqlite3_finalize(stmt);
382 time_t current = time(NULL);
383 current += (tick * unit);
384 current -= 2; /* in case time passed */
386 switch (record_type) {
387 case CALENDAR_BOOK_TYPE_EVENT:
388 switch (dtstart_type) {
389 case CALENDAR_TIME_UTIME:
390 utime = _get_event_alert_utime("dtstart_utime", event_id, current);
393 case CALENDAR_TIME_LOCALTIME:
394 utime = _get_event_alert_localtime("dtstart_datetime", event_id, current);
399 case CALENDAR_BOOK_TYPE_TODO:
400 switch (dtend_type) {
401 case CALENDAR_TIME_UTIME:
402 utime = _get_todo_alert_utime("dtend_utime", event_id, current);
405 case CALENDAR_TIME_LOCALTIME:
406 utime = _get_todo_alert_localtime("dtend_datetime", event_id, current);
411 DBG("alert_time(%d) = utime(%lld) - (tick(%d) * unit(%d))", *tt_alert, utime, tick, unit);
413 *tt_alert = utime - (tick * unit);
414 return CALENDAR_ERROR_NONE;
419 * true : to get all alarms including same time event.
420 * (ig. if 3 diffrent alarms exist at 06:30, list has 3 data)
421 * false : to get only one alarm to register in alarm-manager.
422 * (ig. if 3 diffrent alarms exist at 06:30, list has only one)
424 static void _cal_server_alarm_get_upcoming_specific_utime(time_t utime, bool get_all, GList **l)
427 char query[CAL_DB_SQL_MAX_LEN] = {0};
428 snprintf(query, sizeof(query), "SELECT event_id,remind_tick_unit,remind_tick,"
429 "alarm_type,alarm_utime,alarm_datetime "
430 "FROM %s WHERE remind_tick_unit =%d AND alarm_type =%d AND alarm_utime %s %ld %s",
431 CAL_TABLE_ALARM, CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_UTIME,
432 true == get_all ? "=" : ">", utime,
433 true == get_all ? "" : "ORDER BY alarm_utime ASC LIMIT 1");
435 sqlite3_stmt *stmt = NULL;
436 ret = cal_db_util_query_prepare(query, &stmt);
437 if (CALENDAR_ERROR_NONE != ret) {
438 /* LCOV_EXCL_START */
439 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
440 SECURE("query[%s]", query);
445 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
446 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
448 /* LCOV_EXCL_START */
449 ERR("calloc() Fail");
450 sqlite3_finalize(stmt);
455 ad->event_id = sqlite3_column_int(stmt, 0);
456 ad->unit = sqlite3_column_int(stmt, 1);
457 ad->tick = sqlite3_column_int(stmt, 2);
458 ad->type = sqlite3_column_int(stmt, 3);
459 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
460 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
461 *l = g_list_append(*l, ad);
462 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
463 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
464 ad->alert_utime = ad->time;
465 if (false == get_all) break;
467 sqlite3_finalize(stmt);
470 static void _cal_server_alarm_get_upcoming_specific_localtime(const char *datetime, bool get_all, GList **l)
473 char query[CAL_DB_SQL_MAX_LEN] = {0};
474 snprintf(query, sizeof(query), "SELECT event_id,remind_tick_unit,remind_tick,"
475 "alarm_type,alarm_utime,alarm_datetime "
476 "FROM %s WHERE remind_tick_unit=%d AND alarm_type=%d AND alarm_datetime %s '%s' %s",
477 CAL_TABLE_ALARM, CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_LOCALTIME,
478 true == get_all ? "=" : ">", datetime,
479 true == get_all ? "" : "ORDER BY alarm_datetime ASC LIMIT 1");
481 sqlite3_stmt *stmt = NULL;
482 ret = cal_db_util_query_prepare(query, &stmt);
483 if (CALENDAR_ERROR_NONE != ret) {
484 /* LCOV_EXCL_START */
485 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
486 SECURE("query[%s]", query);
491 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
492 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
494 /* LCOV_EXCL_START */
495 ERR("calloc() Fail");
496 sqlite3_finalize(stmt);
501 ad->event_id = sqlite3_column_int(stmt, 0);
502 ad->unit = sqlite3_column_int(stmt, 1);
503 ad->tick = sqlite3_column_int(stmt, 2);
504 ad->type = sqlite3_column_int(stmt, 3);
505 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
506 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
507 *l = g_list_append(*l, ad);
508 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
509 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
511 int y = 0, m = 0, d = 0;
512 int h = 0, n = 0, s = 0;
513 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
516 st.tm_year = y - 1900;
522 ad->alert_utime = (long long int)mktime(&st);
523 if (false == get_all) break;
525 sqlite3_finalize(stmt);
528 static void _cal_server_alarm_get_upcoming_nonspecific_event_utime(time_t utime, bool get_all, GList **l)
535 char query[CAL_DB_SQL_MAX_LEN] = {0};
536 snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick, "
537 "A.alarm_type,B.dtstart_utime,A.alarm_datetime "
538 "FROM %s as A, %s as B ON A.event_id = B.event_id "
539 "WHERE A.remind_tick_unit >%d AND (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
540 CAL_TABLE_ALARM, CAL_TABLE_UTIME_INSTANCE, CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
541 true == get_all ? "=" : ">", utime,
542 true == get_all ? "" : "ORDER BY (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1");
544 sqlite3_stmt *stmt = NULL;
545 ret = cal_db_util_query_prepare(query, &stmt);
546 if (CALENDAR_ERROR_NONE != ret) {
547 /* LCOV_EXCL_START */
548 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
549 SECURE("query[%s]", query);
554 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
555 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
557 /* LCOV_EXCL_START */
558 ERR("calloc() Fail");
559 sqlite3_finalize(stmt);
564 ad->event_id = sqlite3_column_int(stmt, 0);
565 ad->unit = sqlite3_column_int(stmt, 1);
566 ad->tick = sqlite3_column_int(stmt, 2);
567 ad->type = sqlite3_column_int(stmt, 3);
568 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
569 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
570 *l = g_list_append(*l, ad);
571 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
572 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
574 ad->alert_utime = ad->time - (ad->tick * ad->unit);
575 if (false == get_all) break;
577 sqlite3_finalize(stmt);
580 static void _cal_server_alarm_get_upcoming_nonspecific_event_localtime(const char *datetime, bool get_all, GList **l)
587 char query[CAL_DB_SQL_MAX_LEN] = {0};
588 snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick, "
589 "A.alarm_type,A.alarm_utime,B.dtstart_datetime "
590 "FROM %s as A, %s as B ON A.event_id = B.event_id "
591 "WHERE A.remind_tick_unit >%d AND "
592 "(strftime('%%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
593 CAL_TABLE_ALARM, CAL_TABLE_LOCALTIME_INSTANCE, CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
594 datetime, true == get_all ? "=" : ">",
595 true == get_all ? "" : "ORDER BY (strftime('%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
596 sqlite3_stmt *stmt = NULL;
597 ret = cal_db_util_query_prepare(query, &stmt);
598 if (CALENDAR_ERROR_NONE != ret) {
599 /* LCOV_EXCL_START */
600 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
601 SECURE("query[%s]", query);
606 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
607 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
609 /* LCOV_EXCL_START */
610 ERR("calloc() Fail");
611 sqlite3_finalize(stmt);
616 ad->event_id = sqlite3_column_int(stmt, 0);
617 ad->unit = sqlite3_column_int(stmt, 1);
618 ad->tick = sqlite3_column_int(stmt, 2);
619 ad->type = sqlite3_column_int(stmt, 3);
620 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
621 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
622 *l = g_list_append(*l, ad);
623 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
624 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
626 int y = 0, m = 0, d = 0;
627 int h = 0, n = 0, s = 0;
628 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
631 st.tm_year = y - 1900;
637 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
638 if (false == get_all) break;
640 sqlite3_finalize(stmt);
643 static void _cal_server_alarm_get_upcoming_nonspecific_todo_utime(time_t utime, bool get_all, GList **l)
650 char query[CAL_DB_SQL_MAX_LEN] = {0};
651 snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick,"
652 "A.alarm_type,B.dtend_utime,A.alarm_datetime "
653 "FROM %s as A, %s as B ON A.event_id = B.id "
654 "WHERE A.remind_tick_unit >%d AND B.type =%d "
655 "AND (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
656 CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
657 CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
658 true == get_all ? "=" : ">", utime,
659 true == get_all ? "" : "ORDER BY (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
661 sqlite3_stmt *stmt = NULL;
662 ret = cal_db_util_query_prepare(query, &stmt);
663 if (CALENDAR_ERROR_NONE != ret) {
664 /* LCOV_EXCL_START */
665 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
666 SECURE("query[%s]", query);
671 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
672 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
674 /* LCOV_EXCL_START */
675 ERR("calloc() Fail");
676 sqlite3_finalize(stmt);
681 ad->event_id = sqlite3_column_int(stmt, 0);
682 ad->unit = sqlite3_column_int(stmt, 1);
683 ad->tick = sqlite3_column_int(stmt, 2);
684 ad->type = sqlite3_column_int(stmt, 3);
685 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
686 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
687 *l = g_list_append(*l, ad);
688 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
689 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
691 ad->alert_utime = ad->time - (ad->tick * ad->unit);
692 if (false == get_all) break;
694 sqlite3_finalize(stmt);
697 static void _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(const char *datetime, bool get_all, GList **l)
704 char query[CAL_DB_SQL_MAX_LEN] = {0};
705 snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick,"
706 "A.alarm_type,A.alarm_utime,B.dtend_datetime "
707 "FROM %s as A, %s as B ON A.event_id = B.id "
708 "WHERE A.remind_tick_unit >%d AND B.type =%d "
709 "AND (strftime('%%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
710 CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
711 CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
712 datetime, true == get_all ? "=" : ">",
713 true == get_all ? "" : "ORDER BY (strftime('%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
715 sqlite3_stmt *stmt = NULL;
716 ret = cal_db_util_query_prepare(query, &stmt);
717 if (CALENDAR_ERROR_NONE != ret) {
718 /* LCOV_EXCL_START */
719 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
720 SECURE("query[%s]", query);
725 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
726 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
728 /* LCOV_EXCL_START */
729 ERR("calloc() Fail");
730 sqlite3_finalize(stmt);
735 ad->event_id = sqlite3_column_int(stmt, 0);
736 ad->unit = sqlite3_column_int(stmt, 1);
737 ad->tick = sqlite3_column_int(stmt, 2);
738 ad->type = sqlite3_column_int(stmt, 3);
739 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
740 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
741 *l = g_list_append(*l, ad);
742 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
743 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
745 int y = 0, m = 0, d = 0;
746 int h = 0, n = 0, s = 0;
747 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
750 st.tm_year = y - 1900;
756 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
757 if (false == get_all) break;
759 sqlite3_finalize(stmt);
762 static void _cal_server_alarm_get_latest(time_t utime, bool get_all, GList **out_l)
765 RET_IF(NULL == out_l);
768 struct tm st_local = {0};
769 localtime_r(&utime, &st_local);
771 char datetime[CAL_STR_SHORT_LEN32] = {0};
772 snprintf(datetime, sizeof(datetime), CAL_FORMAT_LOCAL_DATETIME,
773 st_local.tm_year +1900, st_local.tm_mon + 1, st_local.tm_mday,
774 st_local.tm_hour, st_local.tm_min, st_local.tm_sec);
775 DBG("get alert to register with given time (%ld) datetime[%s]", utime, datetime);
779 _cal_server_alarm_get_upcoming_specific_utime(utime, get_all, &l);
780 _cal_server_alarm_get_upcoming_nonspecific_event_utime(utime, get_all, &l);
781 _cal_server_alarm_get_upcoming_nonspecific_todo_utime(utime, get_all, &l);
783 _cal_server_alarm_get_upcoming_specific_localtime(datetime, get_all, &l);
784 _cal_server_alarm_get_upcoming_nonspecific_event_localtime(datetime, get_all, &l);
785 _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(datetime, get_all, &l);
790 static gint _cal_server_alarm_sort_cb(gconstpointer a, gconstpointer b)
792 struct _alarm_data_s *p1 = (struct _alarm_data_s *)a;
793 struct _alarm_data_s *p2 = (struct _alarm_data_s *)b;
794 DBG("%lld) > (%lld)", p1->alert_utime, p2->alert_utime);
796 return p1->alert_utime < p2->alert_utime ? -1 : 1;
799 static GFunc _cal_server_alarm_print_cb(gpointer data, gpointer user_data)
801 struct _alarm_data_s *ad = (struct _alarm_data_s *)data;
802 DBG("id(%d) unit(%d) tick(%d) type(%d) time(%lld) datetime[%s]",
803 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
807 static int _cal_server_alarm_register(GList *alarm_list)
810 RETV_IF(NULL == alarm_list, CALENDAR_ERROR_INVALID_PARAMETER);
812 int ret = CALENDAR_ERROR_NONE;
813 GList *l = g_list_first(alarm_list);
814 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
815 RETVM_IF(NULL == ad, CALENDAR_ERROR_DB_FAILED, "No data");
817 /* clear all alarm which set by mine. */
818 ret = alarmmgr_enum_alarm_ids(_cal_server_alarm_clear_all_cb, NULL);
819 if (ret != ALARMMGR_RESULT_SUCCESS) {
820 /* LCOV_EXCL_START */
821 ERR("alarmmgr_enum_alarm_ids() Fail");
826 time_t mod_time = (time_t)ad->alert_utime;
827 alarm_entry_t *alarm_info = NULL;
828 alarm_info = alarmmgr_create_alarm();
829 if (NULL == alarm_info) {
830 /* LCOV_EXCL_START */
831 ERR("Failed to create alarm");
832 return CALENDAR_ERROR_DB_FAILED;
836 struct tm st_alarm = {0};
838 switch (ad->system_type) {
839 case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
840 gmtime_r(&mod_time, &st_alarm);
845 localtime_r(&mod_time, &st_alarm);
849 alarm_date_t date = {0};
850 date.year = st_alarm.tm_year + 1900;
851 date.month = st_alarm.tm_mon + 1;
852 date.day = st_alarm.tm_mday;
853 date.hour = st_alarm.tm_hour;
854 date.min = st_alarm.tm_min;
855 date.sec = st_alarm.tm_sec;
856 alarmmgr_set_time(alarm_info, date);
857 DBG(COLOR_CYAN" >>> registered record id (%d) at %04d/%02d/%02d %02d:%02d:%02d "COLOR_END" (utime(%lld), datetime[%s], tick(%d) unit(%d))",
858 ad->event_id, date.year, date.month, date.day, date.hour, date.min, date.sec,
859 ad->time, ad->datetime, ad->tick, ad->unit);
862 ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &alarm_id);
864 /* LCOV_EXCL_START */
865 ERR("alarmmgr_add_alarm_with_localtime Fail (%d)", ret);
866 alarmmgr_free_alarm(alarm_info);
870 DBG("alarmmgr id (%d)", alarm_id);
871 _cal_server_alarm_update_alarm_id(alarm_id, ad->event_id, ad->tick, ad->unit);
872 alarmmgr_free_alarm(alarm_info);
873 return CALENDAR_ERROR_NONE;
876 static bool __app_matched_cb(app_control_h app_control, const char *package, void *user_data)
883 RETV_IF(NULL == user_data, true);
886 ret = app_control_get_mime(app_control, &mime);
887 RETVM_IF(APP_CONTROL_ERROR_NONE != ret, true, "app_control_get_mime() Fail(%d)", ret);
889 const char *reminder_mime = "application/x-tizen.calendar.reminder";
890 if (strncmp(mime, reminder_mime, strlen(reminder_mime))) { /* not same */
891 DBG("get mime[%s] is not [%s]", mime, reminder_mime);
897 struct alarm_ud *au = (struct alarm_ud *)user_data;
898 GList *alarm_list = au->alarm_list;
899 if (NULL == alarm_list) {
900 /* LCOV_EXCL_START */
906 len = g_list_length(alarm_list);
908 DBG("len is 0, no alarm list");
912 app_control_h ac = NULL;
913 ret = app_control_create(&ac);
914 if (APP_CONTROL_ERROR_NONE != ret) {
915 /* LCOV_EXCL_START */
916 ERR("app_control_create() Fail(%d)", ret);
920 ret = app_control_set_operation(ac, APP_CONTROL_OPERATION_DEFAULT);
921 if (APP_CONTROL_ERROR_NONE != ret) {
922 /* LCOV_EXCL_START */
923 ERR("app_control_create() Fail(%d)", ret);
924 app_control_destroy(ac);
928 ret = app_control_set_app_id(ac, package);
929 if (APP_CONTROL_ERROR_NONE != ret) {
930 /* LCOV_EXCL_START */
931 ERR("app_control_set_app_id() Fail(%d)", ret);
932 app_control_destroy(ac);
938 ids = calloc(len, sizeof(char *));
940 /* LCOV_EXCL_START */
941 ERR("calloc() Fail");
942 app_control_destroy(ac);
946 GList *cursor = g_list_first(alarm_list);
947 for (i = 0; i < len; i++) {
948 struct _alarm_data_s *ad = (struct _alarm_data_s *)cursor->data;
951 cursor = g_list_next(cursor);
954 DBG("pkg[%s] time[%lld] tick[%d] unit[%d] record_type[%d]",
955 package, ad->time, ad->tick, ad->unit, ad->record);
958 char extra[CAL_STR_MIDDLE_LEN] = {0};
959 slen = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
960 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%lld", "time", ad->time);
961 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%d", "tick", ad->tick);
962 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%d", "unit", ad->unit);
963 slen += snprintf(extra+slen, sizeof(extra)-slen, "&%s=%d", "type", ad->record);
966 * key: id, value: id=4&time=123123&..
968 char buf_id[CAL_STR_MIDDLE_LEN] = {0};
969 snprintf(buf_id, sizeof(buf_id), "%d", ad->event_id);
970 app_control_add_extra_data(ac, buf_id, extra);
971 DBG("value[%s] id[%s]", extra, buf_id);
974 ids[i] = strdup(buf_id);
976 cursor = g_list_next(cursor);
978 app_control_add_extra_data_array(ac, "ids", (const char **)ids, len);
979 app_control_send_launch_request(ac, NULL, NULL);
980 app_control_destroy(ac);
982 g_list_free_full(alarm_list, free);
983 for (i = 0; i < len; i++) {
992 static void _cal_server_alarm_noti_with_control(GList *alarm_list)
997 RETM_IF(NULL == alarm_list, "No alarm list");
999 app_control_h app_control = NULL;
1000 ret = app_control_create(&app_control);
1001 if (APP_CONTROL_ERROR_NONE != ret) {
1002 /* LCOV_EXCL_START */
1003 ERR("app_control_create() Fail(%d)", ret);
1005 /* LCOV_EXCL_STOP */
1007 ret = app_control_set_operation(app_control, APP_CONTROL_OPERATION_VIEW);
1008 if (APP_CONTROL_ERROR_NONE != ret) {
1009 /* LCOV_EXCL_START */
1010 ERR("app_control_set_operation() Fail(%d)", ret);
1011 app_control_destroy(app_control);
1013 /* LCOV_EXCL_STOP */
1015 ret = app_control_set_mime(app_control, "application/x-tizen.calendar.reminder");
1016 if (APP_CONTROL_ERROR_NONE != ret) {
1017 /* LCOV_EXCL_START */
1018 ERR("app_control_set_mime() Fail(%d)", ret);
1019 app_control_destroy(app_control);
1021 /* LCOV_EXCL_STOP */
1024 struct alarm_ud *au = calloc(1, sizeof(struct alarm_ud));
1026 /* LCOV_EXCL_START */
1027 ERR("calloc() Fail");
1028 app_control_destroy(app_control);
1030 /* LCOV_EXCL_STOP */
1032 au->alarm_list = alarm_list;
1033 ret = app_control_foreach_app_matched(app_control, __app_matched_cb, au);
1034 if (APP_CONTROL_ERROR_NONE != ret) {
1035 /* LCOV_EXCL_START */
1036 ERR("app_control_foreach_app_matched() Fail(%d)", ret);
1038 app_control_destroy(app_control);
1040 /* LCOV_EXCL_STOP */
1043 app_control_destroy(app_control);
1046 static void _cal_server_alarm_noti_with_callback(GList *alarm_list)
1048 RETM_IF(NULL == alarm_list, "No alarm list");
1050 GList *l = g_list_first(alarm_list);
1052 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
1058 DBG("callback time[%lld] tick[%d] unit[%d] record_type[%d]",
1059 ad->time, ad->tick, ad->unit, ad->record);
1062 char extra[CAL_STR_MIDDLE_LEN] = {0};
1063 len = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
1064 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%lld", "time", ad->time);
1065 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "tick", ad->tick);
1066 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "unit", ad->unit);
1067 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "type", ad->record);
1068 cal_dbus_publish_reminder(len, extra);
1074 static void cal_server_alarm_register_next_alarm(time_t utime)
1079 _cal_server_alarm_get_latest(utime, false, &l);
1083 l = g_list_sort(l, _cal_server_alarm_sort_cb);
1084 g_list_foreach(l, (GFunc)_cal_server_alarm_print_cb, NULL);
1085 _cal_server_alarm_register(l);
1087 g_list_free_full(l, free);
1090 static void cal_server_alarm_alert(time_t tt_alert)
1093 _cal_server_alarm_get_latest(tt_alert, true, &l);
1097 _cal_server_alarm_noti_with_callback(l);
1098 _cal_server_alarm_noti_with_control(l);
1099 /* DO NOT FREE LIST, list is freed in callback */
1102 static int _alert_cb(alarm_id_t alarm_id, void *data)
1105 DBG("alarm_id (%ld)", alarm_id);
1107 time_t tt_alert = 0;
1108 cal_server_alarm_get_alert_time(alarm_id, &tt_alert);
1109 cal_server_alarm_alert(tt_alert);
1110 cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
1111 cal_server_alarm_start();
1115 static void _timechanged_cb(keynode_t *node, void *data)
1117 cal_server_alarm_alert(time(NULL));
1118 cal_server_alarm_start();
1121 static void _cal_server_alarm_set_timechange(void)
1123 vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, _timechanged_cb, NULL);
1124 vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_GMT, _timechanged_cb, NULL);
1125 vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_ZONE, _timechanged_cb, NULL);
1126 vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_EVENT_GMT, _timechanged_cb, NULL);
1129 static void _cal_server_alarm_unset_timechange(void)
1131 vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, _timechanged_cb);
1132 vconf_ignore_key_changed(VCONFKEY_TELEPHONY_NITZ_GMT, _timechanged_cb);
1133 vconf_ignore_key_changed(VCONFKEY_TELEPHONY_NITZ_ZONE, _timechanged_cb);
1134 vconf_ignore_key_changed(VCONFKEY_TELEPHONY_NITZ_EVENT_GMT, _timechanged_cb);
1137 static void _changed_cb(const char* view_uri, void* data)
1139 DBG("Receive alarm change signal");
1140 cal_server_alarm_start();
1143 static int _cal_server_alarm_set_inotify(calendar_db_changed_cb callback)
1145 cal_inotify_subscribe(CAL_NOTI_TYPE_EVENT, CAL_NOTI_FILE_EVENT, callback, NULL);
1146 cal_inotify_subscribe(CAL_NOTI_TYPE_TODO, CAL_NOTI_FILE_TODO, callback, NULL);
1150 static void _cal_server_alarm_unset_inotify(calendar_db_changed_cb callback)
1152 cal_inotify_unsubscribe(CAL_NOTI_FILE_EVENT, callback, NULL);
1153 cal_inotify_unsubscribe(CAL_NOTI_FILE_TODO, callback, NULL);
1156 static int cal_server_alarm_init(void)
1160 _cal_server_alarm_set_timechange();
1161 _cal_server_alarm_set_inotify(_changed_cb);
1163 ret = alarmmgr_init("calendar-service");
1165 /* LCOV_EXCL_START */
1166 ERR("alarmmgr_init() Fail(%d)", ret);
1167 return CALENDAR_ERROR_SYSTEM;
1168 /* LCOV_EXCL_STOP */
1171 ret = alarmmgr_set_cb(_alert_cb, NULL);
1173 /* LCOV_EXCL_START */
1174 ERR("alarmmgr_set_cb() Fail(%d)", ret);
1175 return CALENDAR_ERROR_SYSTEM;
1176 /* LCOV_EXCL_STOP */
1179 return CALENDAR_ERROR_NONE;
1182 static gpointer _cal_server_alarm_main(gpointer user_data)
1185 bool is_initialized = false;
1188 g_mutex_lock(&_cal_server_alarm_mutex);
1190 * While syncing with contacts,
1191 * because calendar-service could be stopped by on-demand,
1192 * holding on-demand is needed.
1194 cal_server_ondemand_hold();
1197 if (false == is_initialized) {
1198 ret = cal_server_alarm_init();
1199 if (CALENDAR_ERROR_NONE != ret) {
1200 /* LCOV_EXCL_START */
1201 ERR("cal_server_alarm_init() Fail(%d)", ret);
1203 /* LCOV_EXCL_STOP */
1206 is_initialized = true;
1209 ret = cal_connect();
1210 if (CALENDAR_ERROR_NONE != ret) {
1211 /* LCOV_EXCL_START */
1212 ERR("cal_connect() Fail(%d)", ret);
1214 /* LCOV_EXCL_STOP */
1217 cal_server_alarm_register_next_alarm(time(NULL));
1222 cal_server_ondemand_release();
1223 cal_server_ondemand_start();
1225 while (false == signal_called)
1226 g_cond_wait(&_cal_server_alarm_cond, &_cal_server_alarm_mutex);
1227 signal_called = false;
1228 g_mutex_unlock(&_cal_server_alarm_mutex);
1233 DBG("end alarm thread");
1234 g_thread_exit(NULL);
1239 void cal_server_alarm_send_signal(void)
1241 g_mutex_lock(&_cal_server_alarm_mutex);
1242 signal_called = true;
1243 g_cond_signal(&_cal_server_alarm_cond);
1244 g_mutex_unlock(&_cal_server_alarm_mutex);
1247 void cal_server_alarm_start(void)
1251 if (NULL == _cal_server_alarm_thread) {
1252 g_mutex_init(&_cal_server_alarm_mutex);
1253 g_cond_init(&_cal_server_alarm_cond);
1254 _cal_server_alarm_thread = g_thread_new(CAL_SERVER_ALARM_THREAD_NAME,
1255 _cal_server_alarm_main, NULL);
1257 cal_server_alarm_send_signal();
1260 static void cal_server_alarm_deinit(void)
1263 _cal_server_alarm_unset_inotify(_changed_cb);
1264 _cal_server_alarm_unset_timechange();
1267 void cal_server_alarm_end(void)
1271 server_killed = true;
1273 cal_server_alarm_deinit();
1274 cal_server_alarm_send_signal();
1276 g_cond_clear(&_cal_server_alarm_cond);
1277 g_thread_join(_cal_server_alarm_thread);
1278 g_thread_unref(_cal_server_alarm_thread);
1279 _cal_server_alarm_thread = NULL;