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