fixed svace
[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
22 #include <sys/time.h>
23 #include <unistd.h>
24 #include <alarm.h>
25 #include <vconf.h>
26 #include <app.h>
27
28 #include "calendar.h"
29 #include "cal_typedef.h"
30 #include "cal_internal.h"
31 #include "cal_time.h"
32 #include "cal_inotify.h"
33 #include "cal_db_util.h"
34 #include "cal_db.h"
35 #include "cal_db_query.h"
36 #include "cal_server_dbus.h"
37
38 #define CAL_SEARCH_LOOP_MAX 4
39
40 struct _alarm_data_s {
41         int event_id;
42         long long int alert_utime; /* to compare */
43         int unit;
44         int tick;
45         int type; /* utime, localtime */
46         long long int time;
47         int record; /* todo, event */
48         char datetime[CAL_STR_SHORT_LEN32];
49         int system_type;
50 };
51
52 /* this api is necessary for repeat instance. */
53 static int _cal_server_alarm_unset_alerted_alarmmgr_id(int alarm_id)
54 {
55         char query[CAL_DB_SQL_MAX_LEN] = {0};
56         int ret = 0;
57
58         ret = cal_db_util_begin_trans();
59         if (CALENDAR_ERROR_NONE != ret) {
60                 ERR("cal_db_util_begin_trans() Fail");
61                 return CALENDAR_ERROR_DB_FAILED;
62         }
63
64         DBG("alarm_id(%d)", alarm_id);
65
66         snprintf(query, sizeof(query), "UPDATE %s SET alarm_id = 0 WHERE alarm_id =%d ",
67                         CAL_TABLE_ALARM, alarm_id);
68         ret = cal_db_util_query_exec(query);
69         if (CALENDAR_ERROR_NONE != ret) {
70                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
71                 SECURE("[%s]", query);
72                 cal_db_util_end_trans(false);
73                 return ret;
74         }
75         cal_db_util_end_trans(true);
76         return CALENDAR_ERROR_NONE;
77 }
78
79 static int _cal_server_alarm_clear_all_cb(alarm_id_t alarm_id, void *data)
80 {
81         int ret;
82
83         DBG("remove alarm id(%d)", alarm_id);
84         _cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
85         ret = alarmmgr_remove_alarm(alarm_id);
86         if (ret != ALARMMGR_RESULT_SUCCESS) {
87                 ERR("alarmmgr_remove_alarm() Fail(ret:%d)", ret);
88                 return ret;
89         }
90         return CALENDAR_ERROR_NONE;
91 }
92
93 static int _cal_server_alarm_update_alarm_id(int alarm_id, int event_id, int tick, int unit)
94 {
95         char query[CAL_DB_SQL_MAX_LEN] = {0};
96         int ret = 0;
97
98         ret = cal_db_util_begin_trans();
99         if (CALENDAR_ERROR_NONE != ret) {
100                 ERR("cal_db_util_begin_trans() Fail");
101                 return CALENDAR_ERROR_DB_FAILED;
102         }
103
104         DBG("Update alarm_id(%d) in alarm table", alarm_id);
105         snprintf(query, sizeof(query), "UPDATE %s SET alarm_id =%d "
106                         "WHERE event_id =%d AND remind_tick =%d AND remind_tick_unit =%d",
107                         CAL_TABLE_ALARM, alarm_id, event_id, tick, unit);
108         ret = cal_db_util_query_exec(query);
109         if (CALENDAR_ERROR_NONE != ret) {
110                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
111                 SECURE("[%s]", query);
112                 cal_db_util_end_trans(false);
113                 return ret;
114         }
115         cal_db_util_end_trans(true);
116         return CALENDAR_ERROR_NONE;
117 }
118
119 static long long int _cal_server_alarm_get_alert_utime(const char *field, int event_id, time_t current)
120 {
121         int ret = 0;
122         char query[CAL_DB_SQL_MAX_LEN] = {0};
123         snprintf(query, sizeof(query), "SELECT %s FROM %s "
124                         "WHERE event_id=%d AND %s>%ld ORDER BY %s LIMIT 1",
125                         field, CAL_TABLE_NORMAL_INSTANCE, event_id, field, current, field);
126
127         sqlite3_stmt *stmt = NULL;
128         ret = cal_db_util_query_prepare(query, &stmt);
129         if (CALENDAR_ERROR_NONE != ret) {
130                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
131                 SECURE("query[%s]", query);
132                 return ret;
133         }
134
135         long long int utime = 0;
136         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
137                 utime = sqlite3_column_int(stmt, 0);
138
139         sqlite3_finalize(stmt);
140         return utime;
141 }
142
143 static int _cal_server_alarm_get_alert_localtime(const char *field, int event_id, time_t current)
144 {
145         int ret = 0;
146         char query[CAL_DB_SQL_MAX_LEN] = {0};
147         struct tm st = {0};
148         tzset();
149         localtime_r(&current, &st);
150         time_t mod_current = timegm(&st);
151         snprintf(query, sizeof(query), "SELECT %s FROM %s "
152                         "WHERE event_id=%d AND strftime('%%s', %s)>%ld ORDER BY %s LIMIT 1",
153                         field, CAL_TABLE_ALLDAY_INSTANCE, event_id, field, mod_current, field);
154
155         sqlite3_stmt *stmt = NULL;
156         ret = cal_db_util_query_prepare(query, &stmt);
157         if (CALENDAR_ERROR_NONE != ret) {
158                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
159                 SECURE("query[%s]", query);
160                 return ret;
161         }
162
163         const char *datetime = NULL;
164         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
165                 datetime = (const char *)sqlite3_column_text(stmt, 0);
166
167         if (NULL == datetime || '\0' == *datetime) {
168                 ERR("Invalid datetime [%s]", datetime);
169                 sqlite3_finalize(stmt);
170                 return 0;
171         }
172
173         int y = 0, m = 0, d = 0;
174         int h = 0, n = 0, s = 0;
175         sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
176         sqlite3_finalize(stmt);
177
178         st.tm_year = y - 1900;
179         st.tm_mon = m - 1;
180         st.tm_mday = d;
181         st.tm_hour = h;
182         st.tm_min = n;
183         st.tm_sec = s;
184
185         return (long long int)mktime(&st);
186 }
187
188 /*
189  * to get aler time, time(NULL) is not accurate. 1 secs diff could be occured.
190  * so, searching DB is neccessary to find alert time.
191  */
192 int cal_server_alarm_get_alert_time(int alarm_id, time_t *tt_alert)
193 {
194         int ret = 0;
195         RETV_IF(NULL == tt_alert, CALENDAR_ERROR_INVALID_PARAMETER);
196
197         char query[CAL_DB_SQL_MAX_LEN] = {0};
198         snprintf(query, sizeof(query), "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, "
199                         "A.alarm_type, A.alarm_utime, A.alarm_datetime, B.type, B.dtstart_type, "
200                         "B.dtend_type FROM %s as A, %s as B ON A.event_id =B.id WHERE alarm_id =%d ",
201                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE, alarm_id);
202
203         sqlite3_stmt *stmt = NULL;
204         ret = cal_db_util_query_prepare(query, &stmt);
205         if (CALENDAR_ERROR_NONE != ret) {
206                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
207                 SECURE("query[%s]", query);
208                 return ret;
209         }
210
211         int event_id = 0;
212         int unit = 0;
213         int tick = 0;
214         int type = 0;
215         long long int utime = 0;
216         const char *datetime = NULL;
217         int record_type = 0;
218         int dtstart_type = 0;
219         int dtend_type = 0;
220         struct tm st = {0};
221
222         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
223                 event_id = sqlite3_column_int(stmt, 0);
224                 unit = sqlite3_column_int(stmt, 1);
225                 tick = sqlite3_column_int(stmt, 2);
226                 type = sqlite3_column_int(stmt, 3);
227                 utime = sqlite3_column_int64(stmt, 4);
228                 datetime = (const char *)sqlite3_column_text(stmt, 5);
229                 record_type = sqlite3_column_int(stmt, 6);
230                 dtstart_type = sqlite3_column_int(stmt, 7);
231                 dtend_type = sqlite3_column_int(stmt, 8);
232         }
233
234         if (NULL == tt_alert) {
235                 ERR("Invalid parameter: tt_alert is NULL");
236                 sqlite3_finalize(stmt);
237                 return CALENDAR_ERROR_INVALID_PARAMETER;
238         }
239
240         if (CALENDAR_ALARM_TIME_UNIT_SPECIFIC == unit) {
241                 if (CALENDAR_TIME_UTIME == type) {
242                         *tt_alert = utime;
243                 } else {
244                         int y = 0, m = 0, d = 0;
245                         int h = 0, n = 0, s = 0;
246                         if (datetime) {
247                                 sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
248
249                                 st.tm_year = y - 1900;
250                                 st.tm_mon = m - 1;
251                                 st.tm_mday = d;
252                                 st.tm_hour = h;
253                                 st.tm_min = n;
254                                 st.tm_sec = s;
255                                 *tt_alert = mktime(&st);
256                                 DBG("datetime[%s] to %02d:%02d:%02d (%d)", datetime, h, n, s, *tt_alert);
257                         }
258                 }
259                 sqlite3_finalize(stmt);
260                 return CALENDAR_ERROR_NONE;
261         }
262         sqlite3_finalize(stmt);
263
264         time_t current = time(NULL);
265         current += (tick * unit);
266         current -= 2; /* in case time passed */
267
268         switch (record_type) {
269         case CALENDAR_BOOK_TYPE_EVENT:
270                 switch (dtstart_type) {
271                 case CALENDAR_TIME_UTIME:
272                         utime = _cal_server_alarm_get_alert_utime("dtstart_utime", event_id, current);
273                         break;
274
275                 case CALENDAR_TIME_LOCALTIME:
276                         utime = _cal_server_alarm_get_alert_localtime("dtstart_datetime", event_id, current);
277                         break;
278                 }
279                 break;
280
281         case CALENDAR_BOOK_TYPE_TODO:
282                 switch (dtend_type) {
283                 case CALENDAR_TIME_UTIME:
284                         utime = _cal_server_alarm_get_alert_utime("dtend_utime", event_id, current);
285                         break;
286
287                 case CALENDAR_TIME_LOCALTIME:
288                         utime = _cal_server_alarm_get_alert_localtime("dtend_datetime", event_id, current);
289                         break;
290                 }
291                 break;
292         }
293         DBG("alert_time(%d) = utime(%lld) - (tick(%d) * unit(%d))", *tt_alert, utime, tick, unit);
294
295         *tt_alert = utime - (tick * unit);
296         return CALENDAR_ERROR_NONE;
297 }
298
299 /*
300  * bool get_all is
301  * true : to get all alarms including same time event.
302  * (ig. if 3 diffrent alarms exist at 06:30, list has 3 data)
303  * false : to get only one alarm to register in alarm-manager.
304  * (ig. if 3 diffrent alarms exist at 06:30, list has only one)
305  */
306 static void _cal_server_alarm_get_upcoming_specific_utime(time_t utime, bool get_all, GList **l)
307 {
308         int ret = 0;
309         char query[CAL_DB_SQL_MAX_LEN] = {0};
310         snprintf(query, sizeof(query), "SELECT event_id,remind_tick_unit,remind_tick,"
311                         "alarm_type,alarm_utime,alarm_datetime "
312                         "FROM %s WHERE remind_tick_unit =%d AND alarm_type =%d AND alarm_utime %s %ld %s",
313                         CAL_TABLE_ALARM, CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_UTIME,
314                         true == get_all ? "=" : ">", utime,
315                         true == get_all ? "" : "ORDER BY alarm_utime ASC LIMIT 1");
316
317         sqlite3_stmt *stmt = NULL;
318         ret = cal_db_util_query_prepare(query, &stmt);
319         if (CALENDAR_ERROR_NONE != ret) {
320                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
321                 SECURE("query[%s]", query);
322                 return;
323         }
324
325         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
326                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
327                 if (NULL == ad) {
328                         ERR("calloc() Fail");
329                         sqlite3_finalize(stmt);
330                         return;
331                 }
332
333                 ad->event_id = sqlite3_column_int(stmt, 0);
334                 ad->unit = sqlite3_column_int(stmt, 1);
335                 ad->tick = sqlite3_column_int(stmt, 2);
336                 ad->type = sqlite3_column_int(stmt, 3);
337                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
338                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
339                 *l = g_list_append(*l, ad);
340                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
341                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
342                 ad->alert_utime = ad->time;
343                 if (false == get_all) break;
344         }
345         sqlite3_finalize(stmt);
346 }
347
348 static void _cal_server_alarm_get_upcoming_specific_localtime(const char *datetime, bool get_all, GList **l)
349 {
350         int ret = 0;
351         char query[CAL_DB_SQL_MAX_LEN] = {0};
352 snprintf(query, sizeof(query), "SELECT event_id,remind_tick_unit,remind_tick,"
353                         "alarm_type,alarm_utime,alarm_datetime "
354                         "FROM %s WHERE remind_tick_unit=%d AND alarm_type=%d AND alarm_datetime %s '%s' %s",
355                         CAL_TABLE_ALARM, CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_LOCALTIME,
356                         true == get_all ? "=" : ">", datetime,
357                         true == get_all ? "" : "ORDER BY alarm_datetime ASC LIMIT 1");
358
359         sqlite3_stmt *stmt = NULL;
360         ret = cal_db_util_query_prepare(query, &stmt);
361         if (CALENDAR_ERROR_NONE != ret) {
362                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
363                 SECURE("query[%s]", query);
364                 return;
365         }
366
367         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
368                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
369                 if (NULL == ad) {
370                         ERR("calloc() Fail");
371                         sqlite3_finalize(stmt);
372                         return;
373                 }
374
375                 ad->event_id = sqlite3_column_int(stmt, 0);
376                 ad->unit = sqlite3_column_int(stmt, 1);
377                 ad->tick = sqlite3_column_int(stmt, 2);
378                 ad->type = sqlite3_column_int(stmt, 3);
379                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
380                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
381                 *l = g_list_append(*l, ad);
382                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
383                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
384
385                 int y = 0, m = 0, d = 0;
386                 int h = 0, n = 0, s = 0;
387                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
388
389                 struct tm st = {0};
390                 st.tm_year = y - 1900;
391                 st.tm_mon = m -1;
392                 st.tm_mday = d;
393                 st.tm_hour = h;
394                 st.tm_min = n;
395                 st.tm_sec = s;
396                 ad->alert_utime = (long long int)mktime(&st);
397                 if (false == get_all) break;
398         }
399         sqlite3_finalize(stmt);
400 }
401
402 static void _cal_server_alarm_get_upcoming_nonspecific_event_utime(time_t utime, bool get_all, GList **l)
403 {
404         int ret = 0;
405         /*
406          * A:alarm
407          * B:normal instance
408          */
409         char query[CAL_DB_SQL_MAX_LEN] = {0};
410         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick, "
411                         "A.alarm_type,B.dtstart_utime,A.alarm_datetime "
412                         "FROM %s as A, %s as B ON A.event_id = B.event_id "
413                         "WHERE A.remind_tick_unit >%d AND (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
414                         CAL_TABLE_ALARM, CAL_TABLE_NORMAL_INSTANCE, CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
415                         true == get_all ? "=" : ">", utime,
416                         true == get_all ? "" : "ORDER BY (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1");
417
418         sqlite3_stmt *stmt = NULL;
419         ret = cal_db_util_query_prepare(query, &stmt);
420         if (CALENDAR_ERROR_NONE != ret) {
421                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
422                 SECURE("query[%s]", query);
423                 return;
424         }
425
426         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
427                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
428                 if (NULL == ad) {
429                         ERR("calloc() Fail");
430                         sqlite3_finalize(stmt);
431                         return;
432                 }
433
434                 ad->event_id = sqlite3_column_int(stmt, 0);
435                 ad->unit = sqlite3_column_int(stmt, 1);
436                 ad->tick = sqlite3_column_int(stmt, 2);
437                 ad->type = sqlite3_column_int(stmt, 3);
438                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
439                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
440                 *l = g_list_append(*l, ad);
441                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
442                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
443
444                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
445                 if (false == get_all) break;
446         }
447         sqlite3_finalize(stmt);
448 }
449
450 static void _cal_server_alarm_get_upcoming_nonspecific_event_localtime(const char *datetime, bool get_all, GList **l)
451 {
452         int ret = 0;
453         /*
454          * A:alarm
455          * B:allday
456          */
457         char query[CAL_DB_SQL_MAX_LEN] = {0};
458         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick, "
459                         "A.alarm_type,A.alarm_utime,B.dtstart_datetime "
460                         "FROM %s as A, %s as B ON A.event_id = B.event_id "
461                         "WHERE A.remind_tick_unit >%d AND "
462                         "(strftime('%%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
463                         CAL_TABLE_ALARM, CAL_TABLE_ALLDAY_INSTANCE, CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
464                         datetime, true == get_all ? "=" : ">",
465                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
466         sqlite3_stmt *stmt = NULL;
467         ret = cal_db_util_query_prepare(query, &stmt);
468         if (CALENDAR_ERROR_NONE != ret) {
469                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
470                 SECURE("query[%s]", query);
471                 return;
472         }
473
474         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
475                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
476                 if (NULL == ad) {
477                         ERR("calloc() Fail");
478                         sqlite3_finalize(stmt);
479                         return;
480                 }
481
482                 ad->event_id = sqlite3_column_int(stmt, 0);
483                 ad->unit = sqlite3_column_int(stmt, 1);
484                 ad->tick = sqlite3_column_int(stmt, 2);
485                 ad->type = sqlite3_column_int(stmt, 3);
486                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
487                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
488                 *l = g_list_append(*l, ad);
489                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
490                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
491
492                 int y = 0, m = 0, d = 0;
493                 int h = 0, n = 0, s = 0;
494                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
495
496                 struct tm st = {0};
497                 st.tm_year = y - 1900;
498                 st.tm_mon = m -1;
499                 st.tm_mday = d;
500                 st.tm_hour = h;
501                 st.tm_min = n;
502                 st.tm_sec = s;
503                 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
504                 if (false == get_all) break;
505         }
506         sqlite3_finalize(stmt);
507 }
508
509 static void _cal_server_alarm_get_upcoming_nonspecific_todo_utime(time_t utime, bool get_all, GList **l)
510 {
511         int ret = 0;
512         /*
513          * A:alarm
514          * B:todo(normal)
515          */
516         char query[CAL_DB_SQL_MAX_LEN] = {0};
517         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick,"
518                         "A.alarm_type,B.dtend_utime,A.alarm_datetime "
519                         "FROM %s as A, %s as B ON A.event_id = B.id "
520                         "WHERE A.remind_tick_unit >%d AND B.type =%d "
521                         "AND (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
522                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
523                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
524                         true == get_all ? "=" : ">", utime,
525                         true == get_all ? "" : "ORDER BY (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
526
527         sqlite3_stmt *stmt = NULL;
528         ret = cal_db_util_query_prepare(query, &stmt);
529         if (CALENDAR_ERROR_NONE != ret) {
530                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
531                 SECURE("query[%s]", query);
532                 return;
533         }
534
535         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
536                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
537                 if (NULL == ad) {
538                         ERR("calloc() Fail");
539                         sqlite3_finalize(stmt);
540                         return;
541                 }
542
543                 ad->event_id = sqlite3_column_int(stmt, 0);
544                 ad->unit = sqlite3_column_int(stmt, 1);
545                 ad->tick = sqlite3_column_int(stmt, 2);
546                 ad->type = sqlite3_column_int(stmt, 3);
547                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
548                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
549                 *l = g_list_append(*l, ad);
550                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
551                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
552
553                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
554                 if (false == get_all) break;
555         }
556         sqlite3_finalize(stmt);
557 }
558
559 static void _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(const char *datetime, bool get_all, GList **l)
560 {
561         int ret = 0;
562         /*
563          * A:alarm
564          * B:todo(allday)
565          */
566         char query[CAL_DB_SQL_MAX_LEN] = {0};
567         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick,"
568                         "A.alarm_type,A.alarm_utime,B.dtend_datetime "
569                         "FROM %s as A, %s as B ON A.event_id = B.id "
570                         "WHERE A.remind_tick_unit >%d AND B.type =%d "
571                         "AND (strftime('%%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
572                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
573                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
574                         datetime, true == get_all ? "=" : ">",
575                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
576
577         sqlite3_stmt *stmt = NULL;
578         ret = cal_db_util_query_prepare(query, &stmt);
579         if (CALENDAR_ERROR_NONE != ret) {
580                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
581                 SECURE("query[%s]", query);
582                 return;
583         }
584
585         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
586                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
587                 if (NULL == ad) {
588                         ERR("calloc() Fail");
589                         sqlite3_finalize(stmt);
590                         return;
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                 int y = 0, m = 0, d = 0;
604                 int h = 0, n = 0, s = 0;
605                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
606
607                 struct tm st = {0};
608                 st.tm_year = y - 1900;
609                 st.tm_mon = m -1;
610                 st.tm_mday = d;
611                 st.tm_hour = h;
612                 st.tm_min = n;
613                 st.tm_sec = s;
614                 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
615                 if (false == get_all) break;
616         }
617         sqlite3_finalize(stmt);
618 }
619
620 static void _cal_server_alarm_get_latest(time_t utime, bool get_all, GList **out_l)
621 {
622         CAL_FN_CALL();
623         RET_IF(NULL == out_l);
624
625         tzset();
626         struct tm st_local = {0};
627         localtime_r(&utime, &st_local);
628
629         char datetime[CAL_STR_SHORT_LEN32] = {0};
630         snprintf(datetime, sizeof(datetime), CAL_FORMAT_LOCAL_DATETIME,
631                         st_local.tm_year +1900, st_local.tm_mon + 1, st_local.tm_mday,
632                         st_local.tm_hour, st_local.tm_min, st_local.tm_sec);
633         DBG("get alert to register with given time (%ld) datetime[%s]", utime, datetime);
634
635         GList *l = NULL;
636
637         _cal_server_alarm_get_upcoming_specific_utime(utime, get_all, &l);
638         _cal_server_alarm_get_upcoming_nonspecific_event_utime(utime, get_all, &l);
639         _cal_server_alarm_get_upcoming_nonspecific_todo_utime(utime, get_all, &l);
640
641         _cal_server_alarm_get_upcoming_specific_localtime(datetime, get_all, &l);
642         _cal_server_alarm_get_upcoming_nonspecific_event_localtime(datetime, get_all, &l);
643         _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(datetime, get_all, &l);
644
645         *out_l = l;
646 }
647
648 static gint _cal_server_alarm_sort_cb(gconstpointer a, gconstpointer b)
649 {
650         struct _alarm_data_s *p1 = (struct _alarm_data_s *)a;
651         struct _alarm_data_s *p2 = (struct _alarm_data_s *)b;
652         DBG("%lld) > (%lld)", p1->alert_utime, p2->alert_utime);
653
654         return p1->alert_utime < p2->alert_utime ? -1 : 1;
655 }
656
657 static GFunc _cal_server_alarm_print_cb(gpointer data, gpointer user_data)
658 {
659         struct _alarm_data_s *ad = (struct _alarm_data_s *)data;
660         DBG("id(%d) unit(%d) tick(%d) type(%d) time(%lld) datetime[%s]",
661                         ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
662         return 0;
663 }
664
665 static int _cal_server_alarm_register(GList *alarm_list)
666 {
667         CAL_FN_CALL();
668         RETV_IF(NULL == alarm_list, CALENDAR_ERROR_INVALID_PARAMETER);
669
670         int ret = CALENDAR_ERROR_NONE;
671         GList *l = g_list_first(alarm_list);
672         struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
673         RETVM_IF(NULL == ad, CALENDAR_ERROR_DB_FAILED, "No data");
674
675         /* clear all alarm which set by mine. */
676         ret = alarmmgr_enum_alarm_ids(_cal_server_alarm_clear_all_cb, NULL);
677         if (ret != ALARMMGR_RESULT_SUCCESS) {
678                 ERR("alarmmgr_enum_alarm_ids() Fail");
679                 return ret;
680         }
681
682         time_t mod_time = (time_t)ad->alert_utime;
683         alarm_entry_t *alarm_info = NULL;
684         alarm_info = alarmmgr_create_alarm();
685         if (NULL == alarm_info) {
686                 ERR("Failed to create alarm");
687                 return CALENDAR_ERROR_DB_FAILED;
688         }
689         tzset();
690         struct tm st_alarm = {0};
691
692         switch (ad->system_type) {
693         case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
694                 gmtime_r(&mod_time, &st_alarm);
695                 break;
696
697         default:
698                 tzset();
699                 localtime_r(&mod_time, &st_alarm);
700                 break;
701         }
702
703         alarm_date_t date = {0};
704         date.year = st_alarm.tm_year + 1900;
705         date.month = st_alarm.tm_mon + 1;
706         date.day = st_alarm.tm_mday;
707         date.hour = st_alarm.tm_hour;
708         date.min = st_alarm.tm_min;
709         date.sec = st_alarm.tm_sec;
710         alarmmgr_set_time(alarm_info, date);
711         DBG(COLOR_CYAN" >>> registered record id (%d) at %04d/%02d/%02d %02d:%02d:%02d "COLOR_END" (utime(%lld), datetime[%s], tick(%d) unit(%d))",
712                         ad->event_id, date.year, date.month, date.day, date.hour, date.min, date.sec,
713                         ad->time, ad->datetime, ad->tick, ad->unit);
714
715         int alarm_id = 0;
716         ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &alarm_id);
717         if (ret < 0) {
718                 ERR("alarmmgr_add_alarm_with_localtime Fail (%d)", ret);
719                 alarmmgr_free_alarm(alarm_info);
720                 return ret;
721         }
722         DBG("alarmmgr id (%d)", alarm_id);
723         _cal_server_alarm_update_alarm_id(alarm_id, ad->event_id, ad->tick, ad->unit);
724         alarmmgr_free_alarm(alarm_info);
725         return CALENDAR_ERROR_NONE;
726 }
727
728 struct alarm_ud {
729         GList *alarm_list;
730 };
731
732 static bool __app_matched_cb(app_control_h app_control, const char *package, void *user_data)
733 {
734         CAL_FN_CALL();
735
736         int ret = 0;
737
738         RETV_IF(NULL == user_data, true);
739
740         char *mime = NULL;
741         ret = app_control_get_mime(app_control, &mime);
742         RETVM_IF(APP_CONTROL_ERROR_NONE != ret, true, "app_control_get_mime() Fail(%d)", ret);
743
744         const char *reminder_mime = "application/x-tizen.calendar.reminder";
745         if (strncmp(mime, reminder_mime, strlen(reminder_mime))) { /* not same */
746                 DBG("get mime[%s] is not [%s]", mime, reminder_mime);
747                 free(mime);
748                 return true;
749         }
750         free(mime);
751
752         GList *alarm_list = (GList *)user_data;
753         int len = 0;
754         len = g_list_length(alarm_list);
755         if (0 == len) {
756                 DBG("len is 0, no alarm list");
757                 return true;
758         }
759
760         app_control_h b = NULL;
761         app_control_create(&b);
762         app_control_set_operation(b,  APP_CONTROL_OPERATION_DEFAULT);
763         app_control_set_app_id(b, package);
764
765         char **ids = NULL;
766         ids = calloc(len, sizeof(char *));
767         if (NULL == ids) {
768                 ERR("calloc() Fail");
769                 app_control_destroy(b);
770                 return CALENDAR_ERROR_OUT_OF_MEMORY;
771         }
772         GList *l = g_list_first(alarm_list);
773         int i;
774         for (i = 0; i < len; i++) {
775                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
776                 if (NULL == ad) {
777                         ERR("No data");
778                         l = g_list_next(l);
779                         continue;
780                 }
781                 DBG("pkg[%s] time[%lld] tick[%d] unit[%d] record_type[%d]",
782                                 package, ad->time, ad->tick, ad->unit, ad->record);
783
784                 int len = 0;
785                 char extra[CAL_STR_MIDDLE_LEN] = {0};
786                 len = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
787                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%lld", "time", ad->time);
788                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "tick", ad->tick);
789                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "unit", ad->unit);
790                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "type", ad->record);
791
792                 char buf_id[CAL_STR_MIDDLE_LEN] = {0};
793                 snprintf(buf_id, sizeof(buf_id), "%d", ad->event_id);
794                 app_control_add_extra_data(b, buf_id, extra); /* key: id, value: id=4&time=123123&.. */
795                 DBG("value[%s]", extra);
796
797                 /* append ids */
798                 ids[i] = strdup(buf_id);
799
800                 l = g_list_next(l);
801         }
802         app_control_add_extra_data_array(b, "ids", (const char **)ids, len);
803         app_control_send_launch_request(b, NULL, NULL);
804         app_control_destroy(b);
805
806         for (i = 0; i < len; i++) {
807                 free(ids[i]);
808                 ids[i] = NULL;
809         }
810         free(ids);
811
812         return true;
813 }
814
815 static void _cal_server_alarm_noti_with_control(GList *alarm_list)
816 {
817         CAL_FN_CALL();
818         RETM_IF(NULL == alarm_list, "No alarm list");
819
820         app_control_h app_control = NULL;
821         app_control_create(&app_control);
822         app_control_set_operation(app_control, APP_CONTROL_OPERATION_VIEW);
823         app_control_set_mime(app_control, "application/x-tizen.calendar.reminder");
824
825         struct alarm_ud *au = calloc(1, sizeof(struct alarm_ud));
826         if (NULL == au) {
827                 ERR("calloc() Fail");
828                 app_control_destroy(app_control);
829                 return;
830         }
831         au->alarm_list = alarm_list;
832         app_control_foreach_app_matched(app_control, __app_matched_cb, au);
833         app_control_destroy(app_control);
834 }
835
836 static void _cal_server_alarm_noti_with_callback(GList *alarm_list)
837 {
838         RETM_IF(NULL == alarm_list, "No alarm list");
839
840         GList *l = g_list_first(alarm_list);
841         while (l) {
842                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
843                 if (NULL == ad) {
844                         ERR("No data");
845                         l = g_list_next(l);
846                         continue;
847                 }
848                 DBG("callback time[%lld] tick[%d] unit[%d] record_type[%d]",
849                                 ad->time, ad->tick, ad->unit, ad->record);
850
851                 int len = 0;
852                 char extra[CAL_STR_MIDDLE_LEN] = {0};
853                 len = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
854                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%lld", "time", ad->time);
855                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "tick", ad->tick);
856                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "unit", ad->unit);
857                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "type", ad->record);
858                 cal_dbus_publish_reminder(len, extra);
859
860                 l = g_list_next(l);
861         }
862 }
863
864 int cal_server_alarm_register_next_alarm(time_t utime)
865 {
866         GList *l = NULL;
867         _cal_server_alarm_get_latest(utime, false, &l);
868         if (NULL == l)
869                 return CALENDAR_ERROR_NONE;
870
871         l = g_list_sort(l, _cal_server_alarm_sort_cb);
872         g_list_foreach(l, (GFunc)_cal_server_alarm_print_cb, NULL);
873         _cal_server_alarm_register(l);
874
875         g_list_free_full(l, free);
876         return CALENDAR_ERROR_NONE;
877 }
878
879 void cal_server_alarm_alert(time_t tt_alert)
880 {
881         GList *l = NULL;
882         _cal_server_alarm_get_latest(tt_alert, true, &l);
883         _cal_server_alarm_noti_with_callback(l);
884         _cal_server_alarm_noti_with_control(l);
885 }
886
887 static int _alert_cb(alarm_id_t alarm_id, void *data)
888 {
889         CAL_FN_CALL();
890         DBG("alarm_id (%ld)", alarm_id);
891
892         time_t tt_alert = 0;
893         cal_server_alarm_get_alert_time(alarm_id, &tt_alert);
894         cal_server_alarm_alert(tt_alert);
895         _cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
896         cal_server_alarm_register_next_alarm(tt_alert);
897         return 0;
898 }
899
900 static void _cal_server_alarm_timechange_cb(keynode_t *node, void *data)
901 {
902         time_t t = time(NULL);
903         cal_server_alarm_alert(t);
904         cal_server_alarm_register_next_alarm(t);
905 }
906
907 void _cal_server_alarm_set_timechange(void)
908 {
909         vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED,
910                         _cal_server_alarm_timechange_cb, NULL);
911
912         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_GMT,
913                         _cal_server_alarm_timechange_cb, NULL);
914         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_EVENT_GMT,
915                         _cal_server_alarm_timechange_cb, NULL);
916         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_ZONE,
917                         _cal_server_alarm_timechange_cb, NULL);
918 }
919
920 static void _changed_cb(const char* view_uri, void* data)
921 {
922         CAL_FN_CALL();
923         cal_server_alarm_register_next_alarm(time(NULL));
924 }
925
926 static int _cal_server_alarm_set_inotify(calendar_db_changed_cb callback)
927 {
928         cal_inotify_subscribe(CAL_NOTI_TYPE_EVENT, CAL_NOTI_EVENT_CHANGED, callback, NULL);
929         cal_inotify_subscribe(CAL_NOTI_TYPE_TODO, CAL_NOTI_TODO_CHANGED, callback, NULL);
930         return 0;
931 }
932
933 int cal_server_alarm_init(void)
934 {
935         CAL_FN_CALL();
936
937         int ret = 0;
938         _cal_server_alarm_set_timechange();
939         _cal_server_alarm_set_inotify(_changed_cb);
940
941         ret = alarmmgr_init("calendar-service");
942         if (ret < 0) {
943                 ERR("alarmmgr_init() Fail(%d)", ret);
944                 return CALENDAR_ERROR_SYSTEM;
945         }
946
947         ret = alarmmgr_set_cb(_alert_cb, NULL);
948         if (ret < 0) {
949                 ERR("alarmmgr_set_cb() Fail(%d)", ret);
950                 return CALENDAR_ERROR_SYSTEM;
951         }
952
953         cal_server_alarm_register_next_alarm(time(NULL));
954         return CALENDAR_ERROR_NONE;
955 }
956
957 void cal_server_alarm_deinit(void)
958 {
959         alarmmgr_fini();
960 }
961