apply coding rule
[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                         sscanf(datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
247
248                         st.tm_year = y - 1900;
249                         st.tm_mon = m - 1;
250                         st.tm_mday = d;
251                         st.tm_hour = h;
252                         st.tm_min = n;
253                         st.tm_sec = s;
254                         *tt_alert = mktime(&st);
255                         DBG("datetime[%s] to %02d:%02d:%02d (%d)", datetime, h, n, s, *tt_alert);
256                 }
257                 sqlite3_finalize(stmt);
258                 return CALENDAR_ERROR_NONE;
259         }
260         sqlite3_finalize(stmt);
261
262         time_t current = time(NULL);
263         current += (tick * unit);
264         current -= 2; /* in case time passed */
265
266         switch (record_type) {
267         case CALENDAR_BOOK_TYPE_EVENT:
268                 switch (dtstart_type) {
269                 case CALENDAR_TIME_UTIME:
270                         utime = _cal_server_alarm_get_alert_utime("dtstart_utime", event_id, current);
271                         break;
272
273                 case CALENDAR_TIME_LOCALTIME:
274                         utime = _cal_server_alarm_get_alert_localtime("dtstart_datetime", event_id, current);
275                         break;
276                 }
277                 break;
278
279         case CALENDAR_BOOK_TYPE_TODO:
280                 switch (dtend_type) {
281                 case CALENDAR_TIME_UTIME:
282                         utime = _cal_server_alarm_get_alert_utime("dtend_utime", event_id, current);
283                         break;
284
285                 case CALENDAR_TIME_LOCALTIME:
286                         utime = _cal_server_alarm_get_alert_localtime("dtend_datetime", event_id, current);
287                         break;
288                 }
289                 break;
290         }
291         DBG("alert_time(%d) = utime(%lld) - (tick(%d) * unit(%d))", *tt_alert, utime, tick, unit);
292
293         *tt_alert = utime - (tick * unit);
294         return CALENDAR_ERROR_NONE;
295 }
296
297 /*
298  * bool get_all is
299  * true : to get all alarms including same time event.
300  * (ig. if 3 diffrent alarms exist at 06:30, list has 3 data)
301  * false : to get only one alarm to register in alarm-manager.
302  * (ig. if 3 diffrent alarms exist at 06:30, list has only one)
303  */
304 static void _cal_server_alarm_get_upcoming_specific_utime(time_t utime, bool get_all, GList **l)
305 {
306         int ret = 0;
307         char query[CAL_DB_SQL_MAX_LEN] = {0};
308         snprintf(query, sizeof(query), "SELECT event_id,remind_tick_unit,remind_tick,"
309                         "alarm_type,alarm_utime,alarm_datetime "
310                         "FROM %s WHERE remind_tick_unit =%d AND alarm_type =%d AND alarm_utime %s %ld %s",
311                         CAL_TABLE_ALARM, CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_UTIME,
312                         true == get_all ? "=" : ">", utime,
313                         true == get_all ? "" : "ORDER BY alarm_utime ASC LIMIT 1");
314
315         sqlite3_stmt *stmt = NULL;
316         ret = cal_db_util_query_prepare(query, &stmt);
317         if (CALENDAR_ERROR_NONE != ret) {
318                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
319                 SECURE("query[%s]", query);
320                 return;
321         }
322
323         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
324                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
325                 if (NULL == ad) {
326                         ERR("calloc() Fail");
327                         sqlite3_finalize(stmt);
328                         return;
329                 }
330
331                 ad->event_id = sqlite3_column_int(stmt, 0);
332                 ad->unit = sqlite3_column_int(stmt, 1);
333                 ad->tick = sqlite3_column_int(stmt, 2);
334                 ad->type = sqlite3_column_int(stmt, 3);
335                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
336                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
337                 *l = g_list_append(*l, ad);
338                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
339                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
340                 ad->alert_utime = ad->time;
341                 if (false == get_all) break;
342         }
343         sqlite3_finalize(stmt);
344 }
345
346 static void _cal_server_alarm_get_upcoming_specific_localtime(const char *datetime, bool get_all, GList **l)
347 {
348         int ret = 0;
349         char query[CAL_DB_SQL_MAX_LEN] = {0};
350 snprintf(query, sizeof(query), "SELECT event_id,remind_tick_unit,remind_tick,"
351                         "alarm_type,alarm_utime,alarm_datetime "
352                         "FROM %s WHERE remind_tick_unit=%d AND alarm_type=%d AND alarm_datetime %s '%s' %s",
353                         CAL_TABLE_ALARM, CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_LOCALTIME,
354                         true == get_all ? "=" : ">", datetime,
355                         true == get_all ? "" : "ORDER BY alarm_datetime ASC LIMIT 1");
356
357         sqlite3_stmt *stmt = NULL;
358         ret = cal_db_util_query_prepare(query, &stmt);
359         if (CALENDAR_ERROR_NONE != ret) {
360                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
361                 SECURE("query[%s]", query);
362                 return;
363         }
364
365         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
366                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
367                 if (NULL == ad) {
368                         ERR("calloc() Fail");
369                         sqlite3_finalize(stmt);
370                         return;
371                 }
372
373                 ad->event_id = sqlite3_column_int(stmt, 0);
374                 ad->unit = sqlite3_column_int(stmt, 1);
375                 ad->tick = sqlite3_column_int(stmt, 2);
376                 ad->type = sqlite3_column_int(stmt, 3);
377                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
378                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
379                 *l = g_list_append(*l, ad);
380                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
381                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
382
383                 int y = 0, m = 0, d = 0;
384                 int h = 0, n = 0, s = 0;
385                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
386
387                 struct tm st = {0};
388                 st.tm_year = y - 1900;
389                 st.tm_mon = m -1;
390                 st.tm_mday = d;
391                 st.tm_hour = h;
392                 st.tm_min = n;
393                 st.tm_sec = s;
394                 ad->alert_utime = (long long int)mktime(&st);
395                 if (false == get_all) break;
396         }
397         sqlite3_finalize(stmt);
398 }
399
400 static void _cal_server_alarm_get_upcoming_nonspecific_event_utime(time_t utime, bool get_all, GList **l)
401 {
402         int ret = 0;
403         /*
404          * A:alarm
405          * B:normal instance
406          */
407         char query[CAL_DB_SQL_MAX_LEN] = {0};
408         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick, "
409                         "A.alarm_type,B.dtstart_utime,A.alarm_datetime "
410                         "FROM %s as A, %s as B ON A.event_id = B.event_id "
411                         "WHERE A.remind_tick_unit >%d AND (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
412                         CAL_TABLE_ALARM, CAL_TABLE_NORMAL_INSTANCE, CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
413                         true == get_all ? "=" : ">", utime,
414                         true == get_all ? "" : "ORDER BY (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1");
415
416         sqlite3_stmt *stmt = NULL;
417         ret = cal_db_util_query_prepare(query, &stmt);
418         if (CALENDAR_ERROR_NONE != ret) {
419                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
420                 SECURE("query[%s]", query);
421                 return;
422         }
423
424         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
425                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
426                 if (NULL == ad) {
427                         ERR("calloc() Fail");
428                         sqlite3_finalize(stmt);
429                         return;
430                 }
431
432                 ad->event_id = sqlite3_column_int(stmt, 0);
433                 ad->unit = sqlite3_column_int(stmt, 1);
434                 ad->tick = sqlite3_column_int(stmt, 2);
435                 ad->type = sqlite3_column_int(stmt, 3);
436                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
437                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
438                 *l = g_list_append(*l, ad);
439                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
440                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
441
442                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
443                 if (false == get_all) break;
444         }
445         sqlite3_finalize(stmt);
446 }
447
448 static void _cal_server_alarm_get_upcoming_nonspecific_event_localtime(const char *datetime, bool get_all, GList **l)
449 {
450         int ret = 0;
451         /*
452          * A:alarm
453          * B:allday
454          */
455         char query[CAL_DB_SQL_MAX_LEN] = {0};
456         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick, "
457                         "A.alarm_type,A.alarm_utime,B.dtstart_datetime "
458                         "FROM %s as A, %s as B ON A.event_id = B.event_id "
459                         "WHERE A.remind_tick_unit >%d AND "
460                         "(strftime('%%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
461                         CAL_TABLE_ALARM, CAL_TABLE_ALLDAY_INSTANCE, CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
462                         datetime, true == get_all ? "=" : ">",
463                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
464         sqlite3_stmt *stmt = NULL;
465         ret = cal_db_util_query_prepare(query, &stmt);
466         if (CALENDAR_ERROR_NONE != ret) {
467                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
468                 SECURE("query[%s]", query);
469                 return;
470         }
471
472         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
473                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
474                 if (NULL == ad) {
475                         ERR("calloc() Fail");
476                         sqlite3_finalize(stmt);
477                         return;
478                 }
479
480                 ad->event_id = sqlite3_column_int(stmt, 0);
481                 ad->unit = sqlite3_column_int(stmt, 1);
482                 ad->tick = sqlite3_column_int(stmt, 2);
483                 ad->type = sqlite3_column_int(stmt, 3);
484                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
485                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
486                 *l = g_list_append(*l, ad);
487                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
488                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
489
490                 int y = 0, m = 0, d = 0;
491                 int h = 0, n = 0, s = 0;
492                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
493
494                 struct tm st = {0};
495                 st.tm_year = y - 1900;
496                 st.tm_mon = m -1;
497                 st.tm_mday = d;
498                 st.tm_hour = h;
499                 st.tm_min = n;
500                 st.tm_sec = s;
501                 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
502                 if (false == get_all) break;
503         }
504         sqlite3_finalize(stmt);
505 }
506
507 static void _cal_server_alarm_get_upcoming_nonspecific_todo_utime(time_t utime, bool get_all, GList **l)
508 {
509         int ret = 0;
510         /*
511          * A:alarm
512          * B:todo(normal)
513          */
514         char query[CAL_DB_SQL_MAX_LEN] = {0};
515         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick,"
516                         "A.alarm_type,B.dtend_utime,A.alarm_datetime "
517                         "FROM %s as A, %s as B ON A.event_id = B.id "
518                         "WHERE A.remind_tick_unit >%d AND B.type =%d "
519                         "AND (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
520                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
521                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
522                         true == get_all ? "=" : ">", utime,
523                         true == get_all ? "" : "ORDER BY (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
524
525         sqlite3_stmt *stmt = NULL;
526         ret = cal_db_util_query_prepare(query, &stmt);
527         if (CALENDAR_ERROR_NONE != ret) {
528                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
529                 SECURE("query[%s]", query);
530                 return;
531         }
532
533         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
534                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
535                 if (NULL == ad) {
536                         ERR("calloc() Fail");
537                         sqlite3_finalize(stmt);
538                         return;
539                 }
540
541                 ad->event_id = sqlite3_column_int(stmt, 0);
542                 ad->unit = sqlite3_column_int(stmt, 1);
543                 ad->tick = sqlite3_column_int(stmt, 2);
544                 ad->type = sqlite3_column_int(stmt, 3);
545                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
546                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
547                 *l = g_list_append(*l, ad);
548                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
549                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
550
551                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
552                 if (false == get_all) break;
553         }
554         sqlite3_finalize(stmt);
555 }
556
557 static void _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(const char *datetime, bool get_all, GList **l)
558 {
559         int ret = 0;
560         /*
561          * A:alarm
562          * B:todo(allday)
563          */
564         char query[CAL_DB_SQL_MAX_LEN] = {0};
565         snprintf(query, sizeof(query), "SELECT A.event_id,A.remind_tick_unit,A.remind_tick,"
566                         "A.alarm_type,A.alarm_utime,B.dtend_datetime "
567                         "FROM %s as A, %s as B ON A.event_id = B.id "
568                         "WHERE A.remind_tick_unit >%d AND B.type =%d "
569                         "AND (strftime('%%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
570                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
571                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
572                         datetime, true == get_all ? "=" : ">",
573                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
574
575         sqlite3_stmt *stmt = NULL;
576         ret = cal_db_util_query_prepare(query, &stmt);
577         if (CALENDAR_ERROR_NONE != ret) {
578                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
579                 SECURE("query[%s]", query);
580                 return;
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                         ERR("calloc() Fail");
587                         sqlite3_finalize(stmt);
588                         return;
589                 }
590
591                 ad->event_id = sqlite3_column_int(stmt, 0);
592                 ad->unit = sqlite3_column_int(stmt, 1);
593                 ad->tick = sqlite3_column_int(stmt, 2);
594                 ad->type = sqlite3_column_int(stmt, 3);
595                 ad->time = (long long int)sqlite3_column_int64(stmt, 4);
596                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, 5));
597                 *l = g_list_append(*l, ad);
598                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
599                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
600
601                 int y = 0, m = 0, d = 0;
602                 int h = 0, n = 0, s = 0;
603                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
604
605                 struct tm st = {0};
606                 st.tm_year = y - 1900;
607                 st.tm_mon = m -1;
608                 st.tm_mday = d;
609                 st.tm_hour = h;
610                 st.tm_min = n;
611                 st.tm_sec = s;
612                 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
613                 if (false == get_all) break;
614         }
615         sqlite3_finalize(stmt);
616 }
617
618 static void _cal_server_alarm_get_latest(time_t utime, bool get_all, GList **out_l)
619 {
620         CAL_FN_CALL();
621         RET_IF(NULL == out_l);
622
623         tzset();
624         struct tm st_local = {0};
625         localtime_r(&utime, &st_local);
626
627         char datetime[CAL_STR_SHORT_LEN32] = {0};
628         snprintf(datetime, sizeof(datetime), CAL_FORMAT_LOCAL_DATETIME,
629                         st_local.tm_year +1900, st_local.tm_mon + 1, st_local.tm_mday,
630                         st_local.tm_hour, st_local.tm_min, st_local.tm_sec);
631         DBG("get alert to register with given time (%ld) datetime[%s]", utime, datetime);
632
633         GList *l = NULL;
634
635         _cal_server_alarm_get_upcoming_specific_utime(utime, get_all, &l);
636         _cal_server_alarm_get_upcoming_nonspecific_event_utime(utime, get_all, &l);
637         _cal_server_alarm_get_upcoming_nonspecific_todo_utime(utime, get_all, &l);
638
639         _cal_server_alarm_get_upcoming_specific_localtime(datetime, get_all, &l);
640         _cal_server_alarm_get_upcoming_nonspecific_event_localtime(datetime, get_all, &l);
641         _cal_server_alarm_get_upcoming_nonspecific_todo_localtime(datetime, get_all, &l);
642
643         *out_l = l;
644 }
645
646 static gint _cal_server_alarm_sort_cb(gconstpointer a, gconstpointer b)
647 {
648         struct _alarm_data_s *p1 = (struct _alarm_data_s *)a;
649         struct _alarm_data_s *p2 = (struct _alarm_data_s *)b;
650         DBG("%lld) > (%lld)", p1->alert_utime, p2->alert_utime);
651
652         return p1->alert_utime < p2->alert_utime ? -1 : 1;
653 }
654
655 static GFunc _cal_server_alarm_print_cb(gpointer data, gpointer user_data)
656 {
657         struct _alarm_data_s *ad = (struct _alarm_data_s *)data;
658         DBG("id(%d) unit(%d) tick(%d) type(%d) time(%lld) datetime[%s]",
659                         ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
660         return 0;
661 }
662
663 static int _cal_server_alarm_register(GList *alarm_list)
664 {
665         CAL_FN_CALL();
666         RETV_IF(NULL == alarm_list, CALENDAR_ERROR_INVALID_PARAMETER);
667
668         int ret = CALENDAR_ERROR_NONE;
669         GList *l = g_list_first(alarm_list);
670         struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
671         RETVM_IF(NULL == ad, CALENDAR_ERROR_DB_FAILED, "No data");
672
673         /* clear all alarm which set by mine. */
674         ret = alarmmgr_enum_alarm_ids(_cal_server_alarm_clear_all_cb, NULL);
675         if (ret != ALARMMGR_RESULT_SUCCESS) {
676                 ERR("alarmmgr_enum_alarm_ids() Fail");
677                 return ret;
678         }
679
680         time_t mod_time = (time_t)ad->alert_utime;
681         alarm_entry_t *alarm_info = NULL;
682         alarm_info = alarmmgr_create_alarm();
683         if (NULL == alarm_info) {
684                 ERR("Failed to create alarm");
685                 return CALENDAR_ERROR_DB_FAILED;
686         }
687         tzset();
688         struct tm st_alarm = {0};
689
690         switch (ad->system_type) {
691         case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
692                 gmtime_r(&mod_time, &st_alarm);
693                 break;
694
695         default:
696                 tzset();
697                 localtime_r(&mod_time, &st_alarm);
698                 break;
699         }
700
701         alarm_date_t date = {0};
702         date.year = st_alarm.tm_year + 1900;
703         date.month = st_alarm.tm_mon + 1;
704         date.day = st_alarm.tm_mday;
705         date.hour = st_alarm.tm_hour;
706         date.min = st_alarm.tm_min;
707         date.sec = st_alarm.tm_sec;
708         alarmmgr_set_time(alarm_info, date);
709         DBG(COLOR_CYAN" >>> registered record id (%d) at %04d/%02d/%02d %02d:%02d:%02d "COLOR_END" (utime(%lld), datetime[%s], tick(%d) unit(%d))",
710                         ad->event_id, date.year, date.month, date.day, date.hour, date.min, date.sec,
711                         ad->time, ad->datetime, ad->tick, ad->unit);
712
713         int alarm_id = 0;
714         ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &alarm_id);
715         if (ret < 0) {
716                 ERR("alarmmgr_add_alarm_with_localtime Fail (%d)", ret);
717                 alarmmgr_free_alarm(alarm_info);
718                 return ret;
719         }
720         DBG("alarmmgr id (%d)", alarm_id);
721         _cal_server_alarm_update_alarm_id(alarm_id, ad->event_id, ad->tick, ad->unit);
722         alarmmgr_free_alarm(alarm_info);
723         return CALENDAR_ERROR_NONE;
724 }
725
726 struct alarm_ud {
727         GList *alarm_list;
728 };
729
730 static bool __app_matched_cb(app_control_h app_control, const char *package, void *user_data)
731 {
732         CAL_FN_CALL();
733
734         int ret = 0;
735         struct alarm_ud *au = (struct alarm_ud *)user_data;
736
737         RETV_IF(NULL == user_data, true);
738
739         char *mime = NULL;
740         ret = app_control_get_mime(app_control, &mime);
741         RETVM_IF(APP_CONTROL_ERROR_NONE != ret, true, "app_control_get_mime() Fail(%d)", ret);
742
743         const char *reminder_mime = "application/x-tizen.calendar.reminder";
744         if (strncmp(mime, reminder_mime, strlen(reminder_mime))) { /* not same */
745                 DBG("get mime[%s] is not [%s]", mime, reminder_mime);
746                 free(mime);
747                 return true;
748         }
749         free(mime);
750
751         GList *alarm_list = (GList *)user_data;
752         int len = 0;
753         len = g_list_length(alarm_list);
754         if (0 == len) {
755                 DBG("len is 0, no alarm list");
756                 return true;
757         }
758
759         app_control_h b = NULL;
760         app_control_create(&b);
761         app_control_set_operation(b,  APP_CONTROL_OPERATION_DEFAULT);
762         app_control_set_app_id(b, package);
763
764         char **ids = NULL;
765         ids = calloc(len, sizeof(char *));
766         if (NULL == ids) {
767                 ERR("calloc() Fail");
768                 app_control_destroy(b);
769                 return CALENDAR_ERROR_OUT_OF_MEMORY;
770         }
771         GList *l = g_list_first(alarm_list);
772         int i;
773         for (i = 0; i < len; i++) {
774                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
775                 if (NULL == ad) {
776                         ERR("No data");
777                         l = g_list_next(l);
778                         continue;
779                 }
780                 DBG("pkg[%s] time[%lld] tick[%d] unit[%d] record_type[%d]",
781                                 package, ad->time, ad->tick, ad->unit, ad->record);
782
783                 int len = 0;
784                 char extra[CAL_STR_MIDDLE_LEN] = {0};
785                 len = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
786                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%lld", "time", ad->time);
787                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "tick", ad->tick);
788                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "unit", ad->unit);
789                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "type", ad->record);
790
791                 char buf_id[CAL_STR_MIDDLE_LEN] = {0};
792                 snprintf(buf_id, sizeof(buf_id), "%d", ad->event_id);
793                 app_control_add_extra_data(b, buf_id, extra); /* key: id, value: id=4&time=123123&.. */
794                 DBG("value[%s]", extra);
795
796                 /* append ids */
797                 ids[i] = strdup(buf_id);
798
799                 l = g_list_next(l);
800         }
801         app_control_add_extra_data_array(b, "ids", (const char **)ids, len);
802         app_control_send_launch_request(b, NULL, NULL);
803         app_control_destroy(b);
804
805         for (i = 0; i < len; i++) {
806                 free(ids[i]);
807                 ids[i] = NULL;
808         }
809         free(ids);
810
811         return true;
812 }
813
814 static void _cal_server_alarm_noti_with_control(GList *alarm_list)
815 {
816         CAL_FN_CALL();
817         RETM_IF(NULL == alarm_list, "No alarm list");
818
819         app_control_h app_control = NULL;
820         app_control_create(&app_control);
821         app_control_set_operation(app_control, APP_CONTROL_OPERATION_VIEW);
822         app_control_set_mime(app_control, "application/x-tizen.calendar.reminder");
823
824         struct alarm_ud *au = calloc(1, sizeof(struct alarm_ud));
825         if (NULL == au) {
826                 ERR("calloc() Fail");
827                 app_control_destroy(app_control);
828                 return;
829         }
830         au->alarm_list = alarm_list;
831         app_control_foreach_app_matched(app_control, __app_matched_cb, au);
832         app_control_destroy(app_control);
833 }
834
835 static void _cal_server_alarm_noti_with_callback(GList *alarm_list)
836 {
837         RETM_IF(NULL == alarm_list, "No alarm list");
838
839         GList *l = g_list_first(alarm_list);
840         while (l) {
841                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
842                 if (NULL == ad) {
843                         ERR("No data");
844                         l = g_list_next(l);
845                         continue;
846                 }
847                 DBG("callback time[%lld] tick[%d] unit[%d] record_type[%d]",
848                                 ad->time, ad->tick, ad->unit, ad->record);
849
850                 int len = 0;
851                 char extra[CAL_STR_MIDDLE_LEN] = {0};
852                 len = snprintf(extra, sizeof(extra), "%s=%d", "id", ad->event_id);
853                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%lld", "time", ad->time);
854                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "tick", ad->tick);
855                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "unit", ad->unit);
856                 len += snprintf(extra+len, sizeof(extra)-len, "&%s=%d", "type", ad->record);
857                 cal_dbus_publish_reminder(len, extra);
858
859                 l = g_list_next(l);
860         }
861 }
862
863 int cal_server_alarm_register_next_alarm(time_t utime)
864 {
865         GList *l = NULL;
866         _cal_server_alarm_get_latest(utime, false, &l);
867         if (NULL == l)
868                 return CALENDAR_ERROR_NONE;
869
870         l = g_list_sort(l, _cal_server_alarm_sort_cb);
871         g_list_foreach(l, (GFunc)_cal_server_alarm_print_cb, NULL);
872         _cal_server_alarm_register(l);
873
874         g_list_free_full(l, free);
875         return CALENDAR_ERROR_NONE;
876 }
877
878 void cal_server_alarm_alert(time_t tt_alert)
879 {
880         GList *l = NULL;
881         _cal_server_alarm_get_latest(tt_alert, true, &l);
882         _cal_server_alarm_noti_with_callback(l);
883         _cal_server_alarm_noti_with_control(l);
884 }
885
886 static int _alert_cb(alarm_id_t alarm_id, void *data)
887 {
888         CAL_FN_CALL();
889         DBG("alarm_id (%ld)", alarm_id);
890
891         time_t tt_alert = 0;
892         cal_server_alarm_get_alert_time(alarm_id, &tt_alert);
893         cal_server_alarm_alert(tt_alert);
894         _cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
895         cal_server_alarm_register_next_alarm(tt_alert);
896         return 0;
897 }
898
899 static void _cal_server_alarm_timechange_cb(keynode_t *node, void *data)
900 {
901         time_t t = time(NULL);
902         cal_server_alarm_alert(t);
903         cal_server_alarm_register_next_alarm(t);
904 }
905
906 void _cal_server_alarm_set_timechange(void)
907 {
908         vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED,
909                         _cal_server_alarm_timechange_cb, NULL);
910
911         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_GMT,
912                         _cal_server_alarm_timechange_cb, NULL);
913         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_EVENT_GMT,
914                         _cal_server_alarm_timechange_cb, NULL);
915         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_ZONE,
916                         _cal_server_alarm_timechange_cb, NULL);
917 }
918
919 static void _changed_cb(const char* view_uri, void* data)
920 {
921         CAL_FN_CALL();
922         cal_server_alarm_register_next_alarm(time(NULL));
923 }
924
925 static int _cal_server_alarm_set_inotify(calendar_db_changed_cb callback)
926 {
927         cal_inotify_subscribe(CAL_NOTI_TYPE_EVENT, CAL_NOTI_EVENT_CHANGED, callback, NULL);
928         cal_inotify_subscribe(CAL_NOTI_TYPE_TODO, CAL_NOTI_TODO_CHANGED, callback, NULL);
929         return 0;
930 }
931
932 int cal_server_alarm_init(void)
933 {
934         CAL_FN_CALL();
935
936         int ret = 0;
937         _cal_server_alarm_set_timechange();
938         _cal_server_alarm_set_inotify(_changed_cb);
939
940         ret = alarmmgr_init("calendar-service");
941         if (ret < 0) {
942                 ERR("alarmmgr_init() Fail(%d)", ret);
943                 return CALENDAR_ERROR_SYSTEM;
944         }
945
946         ret = alarmmgr_set_cb(_alert_cb, NULL);
947         if (ret < 0) {
948                 ERR("alarmmgr_set_cb() Fail(%d)", ret);
949                 return CALENDAR_ERROR_SYSTEM;
950         }
951
952         cal_server_alarm_register_next_alarm(time(NULL));
953         return CALENDAR_ERROR_NONE;
954 }
955
956 void cal_server_alarm_deinit(void)
957 {
958         alarmmgr_fini();
959 }
960