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