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