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