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