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