modified define as upper char
[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
341                 int index = 0;
342                 ad->event_id = sqlite3_column_int(stmt, index++);
343                 ad->unit = sqlite3_column_int(stmt, index++);
344                 ad->tick = sqlite3_column_int(stmt, index++);
345                 ad->type = sqlite3_column_int(stmt, index++);
346                 ad->time = (long long int)sqlite3_column_int64(stmt, index++);
347                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, index++));
348                 *l = g_list_append(*l, ad);
349                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
350                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
351                 ad->alert_utime = ad->time;
352                 if (false == get_all) break;
353         }
354         sqlite3_finalize(stmt);
355 }
356
357 static void __cal_server_alarm_get_upcoming_specific_localtime(const char *datetime, bool get_all, GList **l)
358 {
359         char query_specific_localtime[CAL_DB_SQL_MAX_LEN] = {0};
360         snprintf(query_specific_localtime, sizeof(query_specific_localtime),
361                         "SELECT event_id, remind_tick_unit, remind_tick, "
362                         "alarm_type, alarm_utime, alarm_datetime "
363                         "FROM %s "
364                         "WHERE remind_tick_unit=%d AND alarm_type=%d AND alarm_datetime %s '%s' %s",
365                         CAL_TABLE_ALARM,
366                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_TIME_LOCALTIME,
367                         true == get_all ? "=" : ">",
368                         datetime,
369                         true == get_all ? "" : "ORDER BY alarm_datetime ASC LIMIT 1");
370
371         sqlite3_stmt *stmt = NULL;
372         stmt = _cal_db_util_query_prepare(query_specific_localtime);
373         if (NULL == stmt) {
374                 ERR("_cal_db_util_query_prepare() Failed");
375                 ERR("[%s]", query_specific_localtime);
376                 return;
377         }
378
379         while (CAL_DB_ROW == _cal_db_util_stmt_step(stmt)) {
380                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
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         snprintf(query_nonspecific_event_utime, sizeof(query_nonspecific_event_utime),
414                         // A:alarm B:normal instance
415                         "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, A.alarm_type, B.dtstart_utime, A.alarm_datetime "
416                         "FROM %s as A, %s as B ON A.event_id = B.event_id "
417                         "WHERE A.remind_tick_unit >%d AND (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
418                         CAL_TABLE_ALARM, CAL_TABLE_NORMAL_INSTANCE,
419                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
420                         true == get_all ? "=" : ">",
421                         utime,
422                         true == get_all ? "" : "ORDER BY (B.dtstart_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1");
423
424         sqlite3_stmt *stmt = NULL;
425         stmt = _cal_db_util_query_prepare(query_nonspecific_event_utime);
426         if (NULL == stmt) {
427                 ERR("_cal_db_util_query_prepare() Failed");
428                 ERR("[%s]", query_nonspecific_event_utime);
429                 return;
430         }
431
432         while (CAL_DB_ROW == _cal_db_util_stmt_step(stmt)) {
433                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
434
435                 int index = 0;
436                 ad->event_id = sqlite3_column_int(stmt, index++);
437                 ad->unit = sqlite3_column_int(stmt, index++);
438                 ad->tick = sqlite3_column_int(stmt, index++);
439                 ad->type = sqlite3_column_int(stmt, index++);
440                 ad->time = (long long int)sqlite3_column_int64(stmt, index++);
441                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, index++));
442                 *l = g_list_append(*l, ad);
443                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
444                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
445
446                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
447                 if (false == get_all) break;
448         }
449         sqlite3_finalize(stmt);
450 }
451
452 static void __cal_server_alarm_get_upcoming_nonspecific_event_localtime(const char *datetime, bool get_all, GList **l)
453 {
454         char query_nonspecific_event_localtime[CAL_DB_SQL_MAX_LEN] = {0};
455         snprintf(query_nonspecific_event_localtime, sizeof(query_nonspecific_event_localtime),
456                         // A:alarm B:allday
457                         "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, 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,
462                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
463                         datetime,
464                         true == get_all ? "=" : ">",
465                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtstart_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
466         sqlite3_stmt *stmt = NULL;
467         stmt = _cal_db_util_query_prepare(query_nonspecific_event_localtime);
468         if (NULL == stmt) {
469                 ERR("_cal_db_util_query_prepare() Failed");
470                 ERR("[%s]", query_nonspecific_event_localtime);
471                 return;
472         }
473
474         while (CAL_DB_ROW == _cal_db_util_stmt_step(stmt)) {
475                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
476
477                 int index = 0;
478                 ad->event_id = sqlite3_column_int(stmt, index++);
479                 ad->unit = sqlite3_column_int(stmt, index++);
480                 ad->tick = sqlite3_column_int(stmt, index++);
481                 ad->type = sqlite3_column_int(stmt, index++);
482                 ad->time = (long long int)sqlite3_column_int64(stmt, index++);
483                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, index++));
484                 *l = g_list_append(*l, ad);
485                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
486                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
487
488                 int y = 0, m = 0, d = 0;
489                 int h = 0, n = 0, s = 0;
490                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
491
492                 struct tm st = {0};
493                 st.tm_year = y - 1900;
494                 st.tm_mon = m -1;
495                 st.tm_mday = d;
496                 st.tm_hour = h;
497                 st.tm_min = n;
498                 st.tm_sec = s;
499                 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
500                 if (false == get_all) break;
501         }
502         sqlite3_finalize(stmt);
503 }
504
505 static void __cal_server_alarm_get_upcoming_nonspecific_todo_utime(time_t utime, bool get_all, GList **l)
506 {
507         char query_nonspecific_todo_utime[CAL_DB_SQL_MAX_LEN] = {0};
508         snprintf(query_nonspecific_todo_utime, sizeof(query_nonspecific_todo_utime),
509                         // A:alarm B:todo(normal)
510                         "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, A.alarm_type, B.dtend_utime, A.alarm_datetime "
511                         "FROM %s as A, %s as B ON A.event_id = B.id "
512                         "WHERE A.remind_tick_unit >%d AND B.type =%d "
513                         "AND (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) %s %ld %s",
514                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
515                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
516                         true == get_all ? "=" : ">",
517                         utime,
518                         true == get_all ? "" : "ORDER BY (B.dtend_utime - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
519
520         sqlite3_stmt *stmt = NULL;
521         stmt = _cal_db_util_query_prepare(query_nonspecific_todo_utime);
522         if (NULL == stmt) {
523                 ERR("_cal_db_util_query_prepare() Failed");
524                 ERR("[%s]", query_nonspecific_todo_utime);
525                 return;
526         }
527
528         while (CAL_DB_ROW == _cal_db_util_stmt_step(stmt)) {
529                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
530
531                 int index = 0;
532                 ad->event_id = sqlite3_column_int(stmt, index++);
533                 ad->unit = sqlite3_column_int(stmt, index++);
534                 ad->tick = sqlite3_column_int(stmt, index++);
535                 ad->type = sqlite3_column_int(stmt, index++);
536                 ad->time = (long long int)sqlite3_column_int64(stmt, index++);
537                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, index++));
538                 *l = g_list_append(*l, ad);
539                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
540                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
541
542                 ad->alert_utime = ad->time - (ad->tick * ad->unit);
543                 if (false == get_all) break;
544         }
545         sqlite3_finalize(stmt);
546 }
547
548 static void __cal_server_alarm_get_upcoming_nonspecific_todo_localtime(const char *datetime, bool get_all, GList **l)
549 {
550         char query_nonspecific_todo_localtime[CAL_DB_SQL_MAX_LEN] = {0};
551         snprintf(query_nonspecific_todo_localtime, sizeof(query_nonspecific_todo_localtime),
552                         // A:alarm B:todo(allday)
553                         "SELECT A.event_id, A.remind_tick_unit, A.remind_tick, A.alarm_type, A.alarm_utime, B.dtend_datetime "
554                         "FROM %s as A, %s as B ON A.event_id = B.id "
555                         "WHERE A.remind_tick_unit >%d AND B.type =%d "
556                         "AND (strftime('%%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick) - strftime('%%s', '%s') %s 0) %s",
557                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
558                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, CALENDAR_BOOK_TYPE_TODO,
559                         datetime,
560                         true == get_all ? "=" : ">",
561                         true == get_all ? "" : "ORDER BY (strftime('%s', B.dtend_datetime) - (A.remind_tick_unit * A.remind_tick)) LIMIT 1 ");
562
563         sqlite3_stmt *stmt = NULL;
564         stmt = _cal_db_util_query_prepare(query_nonspecific_todo_localtime);
565         if (NULL == stmt) {
566                 ERR("_cal_db_util_query_prepare() Failed");
567                 ERR("[%s]", query_nonspecific_todo_localtime);
568                 return;
569         }
570
571         while (CAL_DB_ROW == _cal_db_util_stmt_step(stmt)) {
572                 struct _alarm_data_s *ad = calloc(1, sizeof(struct _alarm_data_s));
573
574                 int index = 0;
575                 ad->event_id = sqlite3_column_int(stmt, index++);
576                 ad->unit = sqlite3_column_int(stmt, index++);
577                 ad->tick = sqlite3_column_int(stmt, index++);
578                 ad->type = sqlite3_column_int(stmt, index++);
579                 ad->time = (long long int)sqlite3_column_int64(stmt, index++);
580                 snprintf(ad->datetime, sizeof(ad->datetime), "%s", (const char *)sqlite3_column_text(stmt, index++));
581                 *l = g_list_append(*l, ad);
582                 DBG("found id(%d) unit(%d) tick(%d) type(%d) time(%lld) [%s]",
583                                 ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
584
585                 int y = 0, m = 0, d = 0;
586                 int h = 0, n = 0, s = 0;
587                 sscanf(ad->datetime, CAL_FORMAT_LOCAL_DATETIME, &y, &m, &d, &h, &n, &s);
588
589                 struct tm st = {0};
590                 st.tm_year = y - 1900;
591                 st.tm_mon = m -1;
592                 st.tm_mday = d;
593                 st.tm_hour = h;
594                 st.tm_min = n;
595                 st.tm_sec = s;
596                 ad->alert_utime = (long long int)mktime(&st) - (ad->tick * ad->unit);
597                 if (false == get_all) break;
598         }
599         sqlite3_finalize(stmt);
600 }
601
602 static int __cal_server_alarm_get_alert_list(time_t utime, GList **list)
603 {
604         CAL_FN_CALL();
605         RETV_IF(NULL == list, CALENDAR_ERROR_INVALID_PARAMETER);
606
607         tzset();
608         struct tm st_local = {0};
609         localtime_r(&utime, &st_local);
610         char datetime[32] = {0};
611         snprintf(datetime, sizeof(datetime), CAL_FORMAT_LOCAL_DATETIME,
612                         st_local.tm_year +1900, st_local.tm_mon + 1, st_local.tm_mday,
613                         st_local.tm_hour, st_local.tm_min, st_local.tm_sec);
614         DBG("get alert to register with given time (%ld) datetime[%s]", utime, datetime);
615
616         GList *l = NULL;
617
618         __cal_server_alarm_get_upcoming_specific_utime(utime, true, &l);
619         __cal_server_alarm_get_upcoming_nonspecific_event_utime(utime, true, &l);
620         __cal_server_alarm_get_upcoming_nonspecific_todo_utime(utime, true, &l);
621
622         __cal_server_alarm_get_upcoming_specific_localtime(datetime, true, &l);
623         __cal_server_alarm_get_upcoming_nonspecific_event_localtime(datetime, true, &l);
624         __cal_server_alarm_get_upcoming_nonspecific_todo_localtime(datetime, true, &l);
625
626         *list = l;
627
628         return CALENDAR_ERROR_NONE;
629 }
630
631 static gint __cal_server_alarm_sort_cb(gconstpointer a, gconstpointer b)
632 {
633         struct _alarm_data_s *p1 = (struct _alarm_data_s *)a;
634         struct _alarm_data_s *p2 = (struct _alarm_data_s *)b;
635         DBG("%lld) > (%lld)",p1->alert_utime, p2->alert_utime);
636
637         return p1->alert_utime > p2->alert_utime ? 1 : -1;
638 }
639
640 static GFunc __cal_server_alarm_print_cb(gpointer data, gpointer user_data)
641 {
642         struct _alarm_data_s *ad = (struct _alarm_data_s *)data;
643         DBG("id(%d) unit(%d) tick(%d) type(%d) time(%lld) datetime[%s]",
644                         ad->event_id, ad->unit, ad->tick, ad->type, ad->time, ad->datetime);
645         return 0;
646 }
647
648 static int __cal_server_alarm_register(GList *alarm_list)
649 {
650         CAL_FN_CALL();
651         RETV_IF(NULL == alarm_list, CALENDAR_ERROR_INVALID_PARAMETER);
652
653         int ret = CALENDAR_ERROR_NONE;
654         GList *l = g_list_first(alarm_list);
655         struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
656         RETVM_IF(NULL == ad, CALENDAR_ERROR_DB_FAILED, "No data");
657
658         // clear all alarm which set by mine.
659         ret = alarmmgr_enum_alarm_ids(__cal_server_alarm_clear_all_cb, NULL);
660         if (ret != ALARMMGR_RESULT_SUCCESS)
661         {
662                 ERR("alarmmgr_enum_alarm_ids() failed");
663                 return ret;
664         }
665
666         time_t mod_time = (time_t)ad->alert_utime;
667         alarm_entry_t *alarm_info = NULL;
668         alarm_info = alarmmgr_create_alarm();
669         if (NULL == alarm_info)
670         {
671                 ERR("Failed to create alarm");
672                 return CALENDAR_ERROR_DB_FAILED;
673         }
674         tzset();
675         struct tm st_alarm = {0};
676
677         switch (ad->system_type)
678         {
679         case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
680                 gmtime_r(&mod_time, &st_alarm);
681                 break;
682
683         default:
684                 tzset();
685                 localtime_r(&mod_time, &st_alarm);
686                 break;
687         }
688
689         alarm_date_t date = {0};
690         date.year = st_alarm.tm_year + 1900;
691         date.month = st_alarm.tm_mon + 1;
692         date.day = st_alarm.tm_mday;
693         date.hour = st_alarm.tm_hour;
694         date.min = st_alarm.tm_min;
695         date.sec = st_alarm.tm_sec;
696         alarmmgr_set_time(alarm_info, date);
697         DBG(COLOR_CYAN" >>> registered record id (%d) at %04d/%02d/%02d %02d:%02d:%02d "COLOR_END" (utime(%lld), datetime[%s], tick(%d) unit(%d))",
698                         ad->event_id, date.year, date.month, date.day, date.hour, date.min, date.sec,
699                         ad->time, ad->datetime, ad->tick, ad->unit);
700
701         int alarm_id = 0;
702         ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &alarm_id);
703         if (ret < 0)
704         {
705                 ERR("alarmmgr_add_alarm_with_localtime failed (%d)", ret);
706                 alarmmgr_free_alarm(alarm_info);
707                 return ret;
708         }
709         DBG("alarmmgr id (%d)", alarm_id);
710         __cal_server_alarm_update_alarm_id(alarm_id, ad->event_id, ad->tick, ad->unit);
711         alarmmgr_free_alarm(alarm_info);
712         return CALENDAR_ERROR_NONE;
713 }
714
715 static bool __app_matched_cb(app_control_h app_control, const char *package, void *user_data)
716 {
717         RETV_IF(NULL == user_data, true);
718
719         int ret = 0;
720         char *mime = NULL;
721         ret = app_control_get_mime(app_control, &mime);
722         RETVM_IF(APP_CONTROL_ERROR_NONE != ret, true, "app_control_get_mime() is failed(%d)", ret);
723
724         const char *reminder_mime = "application/x-tizen.calendar.reminder";
725         if (strncmp(mime, reminder_mime, strlen(reminder_mime))) { // not same
726                 DBG("get mime[%s] is not [%s]", mime, reminder_mime);
727                 free(mime);
728                 return true;
729         }
730         free(mime);
731
732         GList *alarm_list = (GList *)user_data;
733         int len = 0;
734         len = g_list_length(alarm_list);
735         if (0 == len) {
736                 DBG("len is 0, no alarm list");
737                 return true;
738         }
739
740         app_control_h b = NULL;
741         app_control_create(&b);
742         app_control_set_operation(b,  APP_CONTROL_OPERATION_DEFAULT);
743         app_control_set_app_id(b, package);
744
745         // data
746         char **ids = NULL;
747         ids = calloc(len, sizeof(char *));
748         if (NULL == ids) {
749                 ERR("calloc() is failed");
750                 app_control_destroy(b);
751                 return CALENDAR_ERROR_DB_FAILED;
752         }
753         GList *l = g_list_first(alarm_list);
754         int i;
755         for (i = 0; i < len; i++) {
756                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
757                 if (NULL == ad) {
758                         ERR("No data");
759                         l = g_list_next(l);
760                         continue;
761                 }
762                 DBG("pkg[%s] time[%lld] tick[%d] unit[%d] record_type[%d]",
763                                 package, ad->time, ad->tick, ad->unit, ad->record);
764
765                 char buf_event_id[128] = {0};
766                 char buf_time[128] = {0};
767                 char buf_tick[128] = {0};
768                 char buf_unit[128] = {0};
769                 char buf_record_type[128] = {0};
770                 snprintf(buf_event_id, sizeof(buf_event_id), "%d", ad->event_id);
771                 snprintf(buf_time, sizeof(buf_time), "%lld", ad->time);
772                 snprintf(buf_tick, sizeof(buf_tick), "%d", ad->tick);
773                 snprintf(buf_unit, sizeof(buf_unit), "%d", ad->unit);
774                 snprintf(buf_record_type, sizeof(buf_record_type), "%d", ad->record);
775
776                 char *p = NULL;
777                 _cal_server_reminder_add_callback_data(&p, "id", buf_event_id);
778                 _cal_server_reminder_add_callback_data(&p, "time", buf_time);
779                 _cal_server_reminder_add_callback_data(&p, "tick", buf_tick);
780                 _cal_server_reminder_add_callback_data(&p, "unit", buf_unit);
781                 _cal_server_reminder_add_callback_data(&p, "type", buf_record_type);
782
783                 app_control_add_extra_data(b, buf_event_id, p); // key: id, value: id=4&time=123123&..
784                 DBG("value[%s]", p);
785                 free(p);
786
787                 // append ids
788                 ids[i] = strdup(buf_event_id);
789
790                 l = g_list_next(l);
791         }
792         app_control_add_extra_data_array(b, "ids", (const char **)ids, len);
793         app_control_send_launch_request (b, NULL, NULL);
794         app_control_destroy(b);
795
796         // free ids
797         for (i = 0; i < len; i++) {
798                 free(ids[i]);
799                 ids[i] = NULL;
800         }
801         free(ids);
802
803         return true;
804 }
805
806 static void __cal_server_alarm_noti_with_control(GList *alarm_list)
807 {
808         RETM_IF(NULL == alarm_list, "No alarm list");
809
810         app_control_h app_control = NULL;
811         app_control_create(&app_control);
812         app_control_set_operation(app_control, APP_CONTROL_OPERATION_VIEW);
813         app_control_set_mime(app_control, "application/x-tizen.calendar.reminder");
814         app_control_foreach_app_matched(app_control, __app_matched_cb, alarm_list);
815         app_control_destroy(app_control);
816 }
817
818 static void __cal_server_alarm_noti_with_callback(GList *alarm_list)
819 {
820         RETM_IF(NULL == alarm_list, "No alarm list");
821
822         GList *l = g_list_first(alarm_list);
823         while (l) {
824                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
825                 if (NULL == ad) {
826                         ERR("No data");
827                         l = g_list_next(l);
828                         continue;
829                 }
830                 DBG("callback time[%lld] tick[%d] unit[%d] record_type[%d]",
831                                 ad->time, ad->tick, ad->unit, ad->record);
832
833                 char buf_event_id[128] = {0};
834                 char buf_time[128] = {0};
835                 char buf_tick[128] = {0};
836                 char buf_unit[128] = {0};
837                 char buf_record_type[128] = {0};
838                 snprintf(buf_event_id, sizeof(buf_event_id), "%d", ad->event_id);
839                 snprintf(buf_time, sizeof(buf_time), "%lld", ad->time);
840                 snprintf(buf_tick, sizeof(buf_tick), "%d", ad->tick);
841                 snprintf(buf_unit, sizeof(buf_unit), "%d", ad->unit);
842                 snprintf(buf_record_type, sizeof(buf_record_type), "%d", ad->record);
843
844                 char *p = NULL;
845                 _cal_server_reminder_add_callback_data(&p, "id", buf_event_id);
846                 _cal_server_reminder_add_callback_data(&p, "time", buf_time);
847                 _cal_server_reminder_add_callback_data(&p, "tick", buf_tick);
848                 _cal_server_reminder_add_callback_data(&p, "unit", buf_unit);
849                 _cal_server_reminder_add_callback_data(&p, "type", buf_record_type);
850                 _cal_server_reminder_publish(p);
851                 free(p);
852
853                 l = g_list_next(l);
854         }
855 }
856
857 static int __cal_server_alarm_register_with_alarmmgr(time_t utime)
858 {
859         tzset();
860         struct tm st_local = {0};
861         localtime_r(&utime, &st_local);
862         char datetime[32] = {0};
863         snprintf(datetime, sizeof(datetime), CAL_FORMAT_LOCAL_DATETIME,
864                         st_local.tm_year +1900, st_local.tm_mon + 1, st_local.tm_mday,
865                         st_local.tm_hour, st_local.tm_min, st_local.tm_sec);
866         DBG("search alarm to register with given time (%ld) datetime[%s]", utime, datetime);
867
868         GList *l = NULL;
869
870         __cal_server_alarm_get_upcoming_specific_utime(utime, false, &l);
871         __cal_server_alarm_get_upcoming_nonspecific_event_utime(utime, false, &l);
872         __cal_server_alarm_get_upcoming_nonspecific_todo_utime(utime, false, &l);
873
874         __cal_server_alarm_get_upcoming_specific_localtime(datetime, false, &l);
875         __cal_server_alarm_get_upcoming_nonspecific_event_localtime(datetime, false, &l);
876         __cal_server_alarm_get_upcoming_nonspecific_todo_localtime(datetime, false, &l);
877
878         if (NULL == l) {
879                 DBG("No alarm list");
880                 return CALENDAR_ERROR_NONE;
881         }
882
883         l = g_list_sort(l, __cal_server_alarm_sort_cb);
884         g_list_foreach(l, (GFunc)__cal_server_alarm_print_cb, NULL);
885         __cal_server_alarm_register(l);
886
887         // free list
888         l = g_list_first(l);
889         while(l) {
890                 struct _alarm_data_s *ad = (struct _alarm_data_s *)l->data;
891                 free(ad);
892                 l = g_list_next(l);
893         }
894         g_list_free(l);
895         return CALENDAR_ERROR_NONE;
896 }
897
898 static int _alert_cb(alarm_id_t alarm_id, void *data)
899 {
900         CAL_FN_CALL();
901         GList *l = NULL;
902
903         DBG("alarm_id (%ld)", alarm_id);
904         time_t tt_alert = 0;
905         __cal_server_alarm_get_alert_time(alarm_id, &tt_alert);
906         __cal_server_alarm_get_alert_list(tt_alert, &l);
907         __cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
908         __cal_server_alarm_noti_with_callback(l);
909         __cal_server_alarm_noti_with_control(l);
910         __cal_server_alarm_register_with_alarmmgr(tt_alert);
911         return 0;
912 }
913
914 ////////////////////////////////////////////////////////////////////
915 static void __cal_server_alarm_timechange_cb(keynode_t *node, void *data)
916 {
917         CAL_FN_CALL();
918         int t = 0;
919         int ret;
920
921         if (node) {
922                 t = vconf_keynode_get_int(node);
923         }
924         else
925         {
926                 ret = vconf_get_int(VCONFKEY_SYSTEM_TIMECHANGE, &t);
927                 WARN_IF(0 < ret, "vconf_get_int() Failed");
928         }
929
930         if (t < 0)
931         {
932                 __cal_server_alarm_register_with_alarmmgr(time(NULL));
933         }
934         else
935         {
936                 DBG("system changed time(%ld)", t);
937                 __cal_server_alarm_register_with_alarmmgr((time_t)t);
938         }
939 }
940
941 void __cal_server_alarm_set_timechange(void)
942 {
943         vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED,
944                         __cal_server_alarm_timechange_cb, NULL);
945
946         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_GMT,
947                         __cal_server_alarm_timechange_cb, NULL);
948         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_EVENT_GMT,
949                         __cal_server_alarm_timechange_cb, NULL);
950         vconf_notify_key_changed(VCONFKEY_TELEPHONY_NITZ_ZONE,
951                         __cal_server_alarm_timechange_cb, NULL);
952 }
953
954 static void __changed_cb(const char* view_uri, void* data)
955 {
956         CAL_FN_CALL();
957         __cal_server_alarm_register_with_alarmmgr(time(NULL));
958 }
959
960 static int __cal_server_alarm_set_inotify(calendar_db_changed_cb callback)
961 {
962         _cal_inotify_subscribe(CAL_NOTI_TYPE_EVENT, CAL_NOTI_EVENT_CHANGED, callback, NULL);
963         _cal_inotify_subscribe(CAL_NOTI_TYPE_TODO, CAL_NOTI_TODO_CHANGED, callback, NULL);
964         return 0;
965 }
966
967 int _cal_server_alarm(void)
968 {
969         CAL_FN_CALL();
970         int ret;
971
972         __cal_server_alarm_set_timechange();
973         __cal_server_alarm_set_inotify(__changed_cb);
974
975         ret = alarmmgr_init("calendar-service");
976         RETVM_IF(ret < 0, ret, "alarmmgr_init() failed");
977
978         ret = alarmmgr_set_cb(_alert_cb, NULL);
979         RETVM_IF(ret < 0, ret, "alarmmgr_set_cb() failed");
980
981         __cal_server_alarm_register_with_alarmmgr(time(NULL));
982
983         return CALENDAR_ERROR_NONE;
984 }
985