Tizen 2.1 base
[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 <appsvc.h>
23 #include <alarm.h>
24 #include <vconf.h>
25
26 #include "cal_internal.h"
27 #include "calendar2.h"
28 #include "cal_time.h"
29 #include "cal_typedef.h"
30 #include "cal_inotify.h"
31
32 #include "cal_db_util.h"
33 #include "cal_db.h"
34 #include "cal_db_query.h"
35
36 static struct timeval stv; // check time
37 static struct timeval etv; // check time
38
39 static int __cal_server_alarm_unset_alerted_alarmmgr_id(int alarm_id);
40
41 static int __cal_server_alarm_clear_all_cb(alarm_id_t alarm_id, void *data)
42 {
43         int ret;
44
45         DBG("remove alarm id(%d)", alarm_id);
46         __cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
47         ret = alarmmgr_remove_alarm(alarm_id);
48         if (ret != ALARMMGR_RESULT_SUCCESS)
49         {
50                 ERR("alarmmgr_remove_alarm() failed(ret:%d)", ret);
51                 return ret;
52         }
53         return CALENDAR_ERROR_NONE;
54 }
55
56 struct _normal_data_s
57 {
58         int id;
59         long long int alarm_utime;
60         int tick;
61         int unit;
62         int alarm_id;
63 };
64
65 struct _allday_data_s
66 {
67         int id;
68         int alarm_datetime;
69         int tick;
70         int unit;
71         int alarm_id;
72 };
73
74 static int __cal_server_alarm_get_next_list_normal_event(long long int from_utime, long long int to_utime, GList **list, int *count)
75 {
76         int index;
77     char query[CAL_DB_SQL_MAX_LEN] = {0};
78     sqlite3_stmt *stmt = NULL;
79
80         DBG("searching normal event (%lld) ~ (%lld)", from_utime, to_utime);
81
82         snprintf(query, sizeof(query),
83                         "SELECT A.event_id, B.alarm_time, "
84                         "B.remind_tick, B.remind_tick_unit, B.alarm_id "
85                         "FROM %s as A, "                       // A is normal instance
86                         "%s as B ON A.event_id = B.event_id, " // B is alarm
87                         "%s as C ON B.event_id = C.id "        // c is schedule
88                         "WHERE C.has_alarm == 1 AND C.type = %d "
89                         "AND B.remind_tick_unit = %d AND B.alarm_time = %lld "
90                         "UNION "
91                         "SELECT A.event_id, A.dtstart_utime - (B.remind_tick * B.remind_tick_unit), "
92                         "B.remind_tick, B.remind_tick_unit, B.alarm_id "
93                         "FROM %s as A, "                       // A is normal instance
94                         "%s as B ON A.event_id = B.event_id, " // B is alarm
95                         "%s as C ON B.event_id = C.id "        // c is schedule
96                         "WHERE C.has_alarm = 1 AND C.type = %d "
97                         "AND B.remind_tick_unit > %d "
98                         "AND (A.dtstart_utime - (B.remind_tick * B.remind_tick_unit)) >= %lld "
99                         "AND (A.dtstart_utime - (B.remind_tick * B.remind_tick_unit)) < %lld "
100                         "ORDER BY (A.dtstart_utime - (B.remind_tick * B.remind_tick_unit))",
101                         CAL_TABLE_NORMAL_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
102                         CALENDAR_BOOK_TYPE_EVENT,
103                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, from_utime,
104                         CAL_TABLE_NORMAL_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
105                         CALENDAR_BOOK_TYPE_EVENT,
106                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
107                         from_utime, to_utime);
108
109         stmt = _cal_db_util_query_prepare(query);
110         if (NULL == stmt)
111         {
112                 DBG("query[%s]", query);
113                 ERR("_cal_db_util_query_prepare() Failed");
114                 return CALENDAR_ERROR_DB_FAILED;
115         }
116
117         *count = 0;
118         while (CAL_DB_ROW  == _cal_db_util_stmt_step(stmt))
119         {
120                 struct _normal_data_s *nd = calloc(1, sizeof(struct _normal_data_s));
121
122                 index = 0;
123                 nd->id = sqlite3_column_int(stmt, index++);
124                 nd->alarm_utime = sqlite3_column_int64(stmt, index++);
125                 nd->tick = sqlite3_column_int(stmt, index++);
126                 nd->unit = sqlite3_column_int(stmt, index++);
127                 nd->alarm_id = sqlite3_column_int(stmt, index++);
128
129                 *list = g_list_append(*list, nd);
130                 (*count)++;
131         }
132         sqlite3_finalize(stmt);
133         return CALENDAR_ERROR_NONE;
134 }
135
136 static int __cal_server_alarm_get_next_list_normal_todo(long long int from_utime, long long int to_utime, GList **list, int *count)
137 {
138         int index;
139     char query[CAL_DB_SQL_MAX_LEN] = {0};
140     sqlite3_stmt *stmt = NULL;
141
142         DBG("searching normal todo (%lld) ~ (%lld)", from_utime, to_utime);
143
144         snprintf(query, sizeof(query),
145                         "SELECT B.id, A.alarm_time, "
146                         "A.remind_tick, A.remind_tick_unit, A.alarm_id "
147                         "FROM %s as A, "                          // A is alarm
148                         "%s as B ON A.event_id = B.id "           // B is schedule
149                         "WHERE B.has_alarm == 1 AND B.type = %d "
150                         "AND A.remind_tick_unit = %d AND A.alarm_time = %lld "
151                         "UNION "
152                         "SELECT B.id, B.dtend_utime - (A.remind_tick * A.remind_tick_unit), "
153                         "A.remind_tick, A.remind_tick_unit, A.alarm_id "
154                         "FROM %s as A, "                          // A is alarm
155                         "%s as B ON A.event_id = B.id "           // B is schedule
156                         "WHERE B.has_alarm = 1 AND B.type = %d "
157                         "AND A.remind_tick_unit > %d "
158                         "AND (B.dtend_utime - (A.remind_tick * A.remind_tick_unit)) >= %lld "
159                         "AND (B.dtend_utime - (A.remind_tick * A.remind_tick_unit)) < %lld "
160                         "ORDER BY (B.dtend_utime - (A.remind_tick * A.remind_tick_unit))",
161                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
162                         CALENDAR_BOOK_TYPE_TODO,
163                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, from_utime,
164                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
165                         CALENDAR_BOOK_TYPE_TODO,
166                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
167                         from_utime, to_utime);
168
169         stmt = _cal_db_util_query_prepare(query);
170         if (NULL == stmt)
171         {
172                 DBG("query[%s]", query);
173                 ERR("_cal_db_util_query_prepare() Failed");
174                 return CALENDAR_ERROR_DB_FAILED;
175         }
176
177         *count = 0;
178         while (CAL_DB_ROW  == _cal_db_util_stmt_step(stmt))
179         {
180                 struct _normal_data_s *nd = calloc(1, sizeof(struct _normal_data_s));
181
182                 index = 0;
183                 nd->id = sqlite3_column_int(stmt, index++);
184                 nd->alarm_utime = sqlite3_column_int64(stmt, index++);
185                 nd->tick = sqlite3_column_int(stmt, index++);
186                 nd->unit = sqlite3_column_int(stmt, index++);
187                 nd->alarm_id = sqlite3_column_int(stmt, index++);
188
189                 *list = g_list_append(*list, nd);
190                 (*count)++;
191         }
192         sqlite3_finalize(stmt);
193         return CALENDAR_ERROR_NONE;
194 }
195
196 static int __cal_server_alarm_get_next_list_allday_event(int from_datetime, int to_datetime, GList **list, int *count)
197 {
198         int index;
199     char query[CAL_DB_SQL_MAX_LEN] = {0};
200     sqlite3_stmt *stmt = NULL;
201
202         DBG("searching allday (%d) ~ (%d)", from_datetime, to_datetime);
203
204         snprintf(query, sizeof(query),
205                         "SELECT A.event_id, B.alarm_time, "
206                         "B.remind_tick, B.remind_tick_unit, B.alarm_id "
207                         "FROM %s as A, "                       // A is allday instance
208                         "%s as B ON A.event_id = B.event_id, " // B is alarm
209                         "%s as C ON B.event_id = C.id "        // C is schedule
210                         "WHERE C.has_alarm == 1 AND C.type = %d "
211                         "AND B.remind_tick_unit = %d AND B.alarm_time = %d "
212                         "UNION "
213                         "SELECT A.event_id, A.dtstart_datetime, "
214                         "B.remind_tick, B.remind_tick_unit, B.alarm_id "
215                         "FROM %s as A, "                       // A is allday instance
216                         "%s as B ON A.event_id = B.event_id, " // B is alarm
217                         "%s as C ON B.event_id = C.id "        // C is schedule
218                         "WHERE C.has_alarm = 1 AND C.type = %d "
219                         "AND B.remind_tick_unit > %d "
220                         "AND A.dtstart_datetime - (B.remind_tick * B.remind_tick_unit)/86400 > %d "
221                         "AND A.dtstart_datetime - (B.remind_tick * B.remind_tick_unit)/86400 <= %d ",
222                         CAL_TABLE_ALLDAY_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
223                         CALENDAR_BOOK_TYPE_EVENT,
224                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, from_datetime,
225                         CAL_TABLE_ALLDAY_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
226                         CALENDAR_BOOK_TYPE_EVENT,
227                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
228                         from_datetime, to_datetime);
229
230         stmt = _cal_db_util_query_prepare(query);
231         if (NULL == stmt)
232         {
233                 DBG("query[%s]", query);
234                 ERR("_cal_db_util_query_prepare() Failed");
235                 return CALENDAR_ERROR_DB_FAILED;
236         }
237
238         *count = 0;
239         while (CAL_DB_ROW  == _cal_db_util_stmt_step(stmt))
240         {
241                 struct _allday_data_s *ad = calloc(1, sizeof(struct _allday_data_s));
242
243                 index = 0;
244                 ad->id = sqlite3_column_int(stmt, index++);
245                 ad->alarm_datetime = sqlite3_column_int(stmt, index++);
246                 ad->tick = sqlite3_column_int(stmt, index++);
247                 ad->unit = sqlite3_column_int(stmt, index++);
248                 ad->alarm_id = sqlite3_column_int(stmt, index++);
249
250                 *list = g_list_append(*list, ad);
251                 (*count)++;
252         }
253         sqlite3_finalize(stmt);
254         return CALENDAR_ERROR_NONE;
255 }
256
257 static int __cal_server_alarm_get_next_list_allday_todo(int from_datetime, int to_datetime, GList **list, int *count)
258 {
259         int index;
260     char query[CAL_DB_SQL_MAX_LEN] = {0};
261     sqlite3_stmt *stmt = NULL;
262
263         DBG("searching allday todo(%d) ~ (%d)", from_datetime, to_datetime);
264
265         snprintf(query, sizeof(query),
266                         "SELECT A.event_id, A.alarm_time, "
267                         "A.remind_tick, A.remind_tick_unit, A.alarm_id "
268                         "FROM %s as A, "                // A is alarm
269                         "%s as B ON A.event_id = B.id " // B is schedule
270                         "WHERE B.has_alarm == 1 AND B.type = %d "
271                         "AND A.remind_tick_unit = %d AND A.alarm_time = %d "
272                         "UNION "
273                         "SELECT A.event_id, B.dtend_datetime, "
274                         "A.remind_tick, A.remind_tick_unit, A.alarm_id "
275                         "FROM %s as A, "                // A is alarm
276                         "%s as B ON A.event_id = B.id " // B is schedule
277                         "WHERE B.has_alarm = 1 AND B.type = %d "
278                         "AND A.remind_tick_unit > %d "
279                         "AND B.dtend_datetime - (A.remind_tick * A.remind_tick_unit)/86400 > %d "
280                         "AND B.dtend_datetime - (A.remind_tick * A.remind_tick_unit)/86400 <= %d ",
281                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
282                         CALENDAR_BOOK_TYPE_TODO,
283                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC, from_datetime,
284                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
285                         CALENDAR_BOOK_TYPE_TODO,
286                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
287                         from_datetime, to_datetime);
288
289         stmt = _cal_db_util_query_prepare(query);
290         if (NULL == stmt)
291         {
292                 DBG("query[%s]", query);
293                 ERR("_cal_db_util_query_prepare() Failed");
294                 return CALENDAR_ERROR_DB_FAILED;
295         }
296
297         *count = 0;
298         while (CAL_DB_ROW  == _cal_db_util_stmt_step(stmt))
299         {
300                 struct _allday_data_s *ad = calloc(1, sizeof(struct _allday_data_s));
301
302                 index = 0;
303                 ad->id = sqlite3_column_int(stmt, index++);
304                 ad->alarm_datetime = sqlite3_column_int(stmt, index++);
305                 ad->tick = sqlite3_column_int(stmt, index++);
306                 ad->unit = sqlite3_column_int(stmt, index++);
307                 ad->alarm_id = sqlite3_column_int(stmt, index++);
308
309                 *list = g_list_append(*list, ad);
310                 (*count)++;
311         }
312         sqlite3_finalize(stmt);
313         return CALENDAR_ERROR_NONE;
314 }
315
316 static int __cal_server_alarm_update_alarm_id(int alarm_id, int event_id, int tick, int unit)
317 {
318     char query[CAL_DB_SQL_MAX_LEN] = {0};
319     cal_db_util_error_e dbret = CAL_DB_OK;
320
321         DBG("Update alarm_id(%d) in alarm table", alarm_id);
322         snprintf(query, sizeof(query), "UPDATE %s SET "
323                         "alarm_id = %d "
324                         "WHERE event_id = %d AND remind_tick = %d AND remind_tick_unit = %d",
325                         CAL_TABLE_ALARM,
326                         alarm_id,
327                         event_id, tick, unit);
328
329         dbret = _cal_db_util_query_exec(query);
330         if (CAL_DB_OK != dbret)
331         {
332                 ERR("_cal_db_util_query_exec() Failed(%d)", dbret);
333                 switch (dbret)
334                 {
335                 case CAL_DB_ERROR_NO_SPACE:
336                         return CALENDAR_ERROR_FILE_NO_SPACE;
337                 default:
338                         return CALENDAR_ERROR_DB_FAILED;
339                 }
340         }
341
342         return CALENDAR_ERROR_NONE;
343 }
344
345 static GFunc __cal_server_alarm_print_list_normal(gpointer data, gpointer user_data)
346 {
347         struct _normal_data_s *normal = (struct _normal_data_s *)data;
348         DBG("%02d:%lld", normal->id, normal->alarm_utime);
349         return 0;
350 }
351
352 static GFunc __cal_server_alarm_print_list_allday_todo(gpointer data, gpointer user_data)
353 {
354         struct _allday_data_s *allday = (struct _allday_data_s *)data;
355         DBG("%02d:%d", allday->id, allday->alarm_datetime);
356         return 0;
357 }
358
359 static int __cal_server_alarm_get_list_with_alarmmgr_id(int alarm_id, GList **normal_list, GList **allday_list)
360 {
361         int index;
362     char query[CAL_DB_SQL_MAX_LEN] = {0};
363     sqlite3_stmt *stmt = NULL;
364         struct _normal_data_s *nd;
365         struct _allday_data_s *ad;
366
367         snprintf(query, sizeof(query),
368                         "SELECT A.type, A.dtstart_type, A.dtend_type, B.remind_tick, B.remind_tick_unit "
369                         "FROM %s as A, "                // schedule
370                         "%s as B ON A.id = B.event_id " // alarm
371                         "WHERE B.alarm_id = %d",
372                         CAL_TABLE_SCHEDULE,
373                         CAL_TABLE_ALARM,
374                         alarm_id);
375
376         stmt = _cal_db_util_query_prepare(query);
377         if (NULL == stmt)
378         {
379                 DBG("query[%s]", query);
380                 ERR("_cal_db_util_query_prepare() Failed");
381                 return CALENDAR_ERROR_DB_FAILED;
382         }
383
384         int type = 0;
385         int dtstart_type = 0;
386         int dtend_type = 0;
387         int tick = 0;
388         int unit = 0;
389         if (CAL_DB_ROW  == _cal_db_util_stmt_step(stmt))
390         {
391                 index = 0;
392                 type = sqlite3_column_int(stmt, index++);
393                 dtstart_type = sqlite3_column_int(stmt, index++);
394                 dtend_type = sqlite3_column_int(stmt, index++);
395                 tick = sqlite3_column_int(stmt, index++);
396                 unit = sqlite3_column_int(stmt, index++);
397         }
398         else
399         {
400                 ERR("No record");
401         }
402         sqlite3_finalize(stmt);
403         stmt = NULL;
404
405         if ((type == CALENDAR_BOOK_TYPE_EVENT && dtstart_type == CALENDAR_TIME_UTIME)
406                         || (type == CALENDAR_BOOK_TYPE_TODO && dtend_type == CALENDAR_TIME_UTIME))
407         {
408                 long long int now_utime;
409                 now_utime = _cal_time_get_now();
410                 now_utime -= now_utime % 60;
411
412                 snprintf(query, sizeof(query),
413                                 "SELECT A.event_id, A.dtstart_utime, "
414                                 "B.remind_tick, B.remind_tick_unit "
415                                 "FROM %s as A, "                       // A is normal instance
416                                 "%s as B ON A.event_id = B.event_id, " // B is alarm
417                                 "%s as C ON B.event_id = C.id "        // c is schedule
418                                 "WHERE C.has_alarm == 1 AND C.type = %d "
419                                 "AND B.remind_tick_unit = %d "
420                                 "AND B.alarm_time = %lld "
421                                 "UNION "
422                                 "SELECT A.event_id, A.dtstart_utime, "
423                                 "B.remind_tick, B.remind_tick_unit "
424                                 "FROM %s as A, "                       // A is normal instance
425                                 "%s as B ON A.event_id = B.event_id, " // B is alarm
426                                 "%s as C ON B.event_id = C.id "        // c is schedule
427                                 "WHERE C.has_alarm = 1 AND C.type = %d "
428                                 "AND B.remind_tick_unit > %d "
429                                 "AND (A.dtstart_utime - (B.remind_tick * B.remind_tick_unit)) >= %lld "
430                                 "AND (A.dtstart_utime - (B.remind_tick * B.remind_tick_unit)) < %lld "
431                                 "UNION "
432                                 "SELECT B.id, B.dtend_utime, "
433                                 "A.remind_tick, A.remind_tick_unit "
434                                 "FROM %s as A, "                          // A is alarm
435                                 "%s as B ON A.event_id = B.id "           // B is schedule
436                                 "WHERE B.has_alarm == 1 AND B.type = %d "
437                                 "AND A.remind_tick_unit = %d "
438                                 "AND A.alarm_time = %lld "
439                                 "UNION "
440                                 "SELECT B.id, B.dtend_utime, "
441                                 "A.remind_tick, A.remind_tick_unit "
442                                 "FROM %s as A, "                          // A is alarm
443                                 "%s as B ON A.event_id = B.id "           // B is schedule
444                                 "WHERE B.has_alarm = 1 AND B.type = %d "
445                                 "AND A.remind_tick_unit > %d "
446                                 "AND (B.dtend_utime - (A.remind_tick * A.remind_tick_unit)) >= %lld "
447                                 "AND (B.dtend_utime - (A.remind_tick * A.remind_tick_unit)) < %lld ",
448                         CAL_TABLE_NORMAL_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
449                         CALENDAR_BOOK_TYPE_EVENT,
450                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
451                         now_utime,
452                         CAL_TABLE_NORMAL_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
453                         CALENDAR_BOOK_TYPE_EVENT,
454                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
455                         now_utime, now_utime + 60,
456                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
457                         CALENDAR_BOOK_TYPE_TODO,
458                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
459                         now_utime,
460                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
461                         CALENDAR_BOOK_TYPE_TODO,
462                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
463                         now_utime, now_utime + 60);
464
465                 stmt = _cal_db_util_query_prepare(query);
466                 if (NULL == stmt)
467                 {
468                         DBG("query[%s]", query);
469                         ERR("_cal_db_util_query_prepare() Failed");
470                         return CALENDAR_ERROR_DB_FAILED;
471                 }
472
473                 while (CAL_DB_ROW == _cal_db_util_stmt_step(stmt))
474                 {
475                         index = 0;
476                         nd = calloc(1, sizeof(struct _normal_data_s));
477                         nd->id = sqlite3_column_int(stmt, index++);
478                         nd->alarm_utime = sqlite3_column_int64(stmt, index++); // dtstart, dtend
479                         nd->tick = sqlite3_column_int(stmt, index++);
480                         nd->unit = sqlite3_column_int(stmt, index++);
481                         *normal_list = g_list_append(*normal_list, nd);
482                         DBG("(%d)", nd->id);
483                 }
484         }
485         else
486         {
487                 int now_datetime;
488                 time_t now_timet = time(NULL);
489                 struct tm start_tm = {0};
490                 now_timet -= now_timet % 60;
491                 gmtime_r(&now_timet, &start_tm);
492                 now_datetime = (start_tm.tm_year + 1900) * 10000
493                         + (start_tm.tm_mon + 1) * 100
494                         + (start_tm.tm_mday);
495
496                 snprintf(query, sizeof(query),
497                                 "SELECT A.event_id, A.dtstart_datetime, "
498                                 "B.remind_tick, B.remind_tick_unit "
499                                 "FROM %s as A, "                       // A is allday instance
500                                 "%s as B ON A.event_id = B.event_id, " // B is alarm
501                                 "%s as C ON B.event_id = C.id "        // C is schedule
502                                 "WHERE C.has_alarm == 1 AND C.type = %d "
503                                 "AND B.remind_tick_unit = %d "
504                                 "AND B.alarm_time = %d "
505                                 "UNION "
506                                 "SELECT A.event_id, A.dtstart_datetime, "
507                                 "B.remind_tick, B.remind_tick_unit "
508                                 "FROM %s as A, "                       // A is allday instance
509                                 "%s as B ON A.event_id = B.event_id, " // B is alarm
510                                 "%s as C ON B.event_id = C.id "        // C is schedule
511                                 "WHERE C.has_alarm = 1 AND C.type = %d "
512                                 "AND B.remind_tick_unit > %d "
513                                 "AND A.dtstart_datetime - (B.remind_tick * B.remind_tick_unit)/86400 = %d "
514                                 "UNION "
515                                 "SELECT A.event_id, B.dtend_datetime, "
516                                 "A.remind_tick, A.remind_tick_unit "
517                                 "FROM %s as A, "                // A is alarm
518                                 "%s as B ON A.event_id = B.id " // B is schedule
519                                 "WHERE B.has_alarm == 1 AND B.type = %d "
520                                 "AND A.remind_tick_unit = %d AND A.alarm_time = %d "
521                                 "UNION "
522                                 "SELECT A.event_id, B.dtend_datetime, "
523                                 "A.remind_tick, A.remind_tick_unit "
524                                 "FROM %s as A, "                // A is alarm
525                                 "%s as B ON A.event_id = B.id " // B is schedule
526                                 "WHERE B.has_alarm = 1 AND B.type = %d "
527                                 "AND A.remind_tick_unit > %d "
528                                 "AND B.dtend_datetime - (A.remind_tick * A.remind_tick_unit)/86400 = %d ",
529                         CAL_TABLE_ALLDAY_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
530                         CALENDAR_BOOK_TYPE_EVENT,
531                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
532                         now_datetime,
533                         CAL_TABLE_ALLDAY_INSTANCE, CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
534                         CALENDAR_BOOK_TYPE_EVENT,
535                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
536                         now_datetime,
537                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
538                         CALENDAR_BOOK_TYPE_TODO,
539                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
540                         now_datetime,
541                         CAL_TABLE_ALARM, CAL_TABLE_SCHEDULE,
542                         CALENDAR_BOOK_TYPE_TODO,
543                         CALENDAR_ALARM_TIME_UNIT_SPECIFIC,
544                         now_datetime);
545
546                 stmt = _cal_db_util_query_prepare(query);
547                 if (NULL == stmt)
548                 {
549                         DBG("query[%s]", query);
550                         ERR("_cal_db_util_query_prepare() Failed");
551                         return CALENDAR_ERROR_DB_FAILED;
552                 }
553
554                 const unsigned char *temp;
555                 while (CAL_DB_ROW == _cal_db_util_stmt_step(stmt))
556                 {
557                         index = 0;
558                         ad = calloc(1, sizeof(struct _allday_data_s));
559                         ad->id = sqlite3_column_int(stmt, index++);
560                         temp = sqlite3_column_text(stmt, index++); // dtstart, dtend
561                         ad->alarm_datetime = atoi((const char *)temp);
562                         ad->tick = sqlite3_column_int(stmt, index++);
563                         ad->unit = sqlite3_column_int(stmt, index++);
564                         *allday_list = g_list_append(*allday_list, ad);
565                 }
566         }
567         sqlite3_finalize(stmt);
568         return CALENDAR_ERROR_NONE;
569 }
570
571 // this api is necessary for repeat instance.
572 static int __cal_server_alarm_unset_alerted_alarmmgr_id(int alarm_id)
573 {
574     char query[CAL_DB_SQL_MAX_LEN] = {0};
575     cal_db_util_error_e dbret = CAL_DB_OK;
576
577         DBG("alarm_id(%d)", alarm_id);
578
579         snprintf(query, sizeof(query),
580                         "UPDATE %s SET alarm_id = 0 WHERE alarm_id = %d ",
581                         CAL_TABLE_ALARM, alarm_id);
582
583         dbret = _cal_db_util_query_exec(query);
584         if (CAL_DB_OK != dbret)
585         {
586                 ERR("_cal_db_util_query_exec() Failed(%d)", dbret);
587                 switch (dbret)
588                 {
589                 case CAL_DB_ERROR_NO_SPACE:
590                         return CALENDAR_ERROR_FILE_NO_SPACE;
591                 default:
592                         return CALENDAR_ERROR_DB_FAILED;
593                 }
594         }
595
596         return CALENDAR_ERROR_NONE;
597 }
598
599 static int __cal_server_alarm_alert_with_pkgname(const char *pkgname, char *id, char *time, char *tick, char *unit)
600 {
601         int ret = CALENDAR_ERROR_NONE;
602         int index;
603     char query[CAL_DB_SQL_MAX_LEN] = {0};
604         const char *key;
605         const char *value;
606     sqlite3_stmt *stmt = NULL;
607     cal_db_util_error_e dbret = CAL_DB_OK;
608
609         if (NULL == pkgname)
610         {
611                 ERR("Invalid parameter: pkgname is NULL");
612                 return CALENDAR_ERROR_INVALID_PARAMETER;
613         }
614
615         // get user key, value
616         snprintf(query, sizeof(query), "SELECT key, value FROM %s WHERE pkgname = '%s' ",
617                         CAL_REMINDER_ALERT, pkgname);
618     stmt = _cal_db_util_query_prepare(query);
619     if (NULL == stmt)
620     {
621         ERR("_cal_db_util_query_prepare() Failed");
622         return CALENDAR_ERROR_DB_FAILED;
623     }
624
625     while(CAL_DB_ROW == _cal_db_util_stmt_step(stmt))
626     {
627                 index = 0;
628                 key = (const char *)sqlite3_column_text(stmt, index++);
629                 value = (const char *)sqlite3_column_text(stmt, index++);
630         }
631
632         // run appsvc
633         DBG("[%s][%s][%s][%s]", id, time, tick, unit);
634
635         bundle *b;
636         b = bundle_create();
637         appsvc_set_pkgname(b, pkgname);
638         appsvc_set_operation(b, APPSVC_OPERATION_DEFAULT);
639         if (key && value) appsvc_add_data(b, key, value);
640         appsvc_add_data(b, "calendar-service/id", id);
641         appsvc_add_data(b, "calendar-service/time", time);
642         appsvc_add_data(b, "calendar-service/tick", tick);
643         appsvc_add_data(b, "calendar-service/unit", unit);
644         ret = appsvc_run_service(b, 0, NULL, NULL);
645         bundle_free(b);
646
647         sqlite3_finalize(stmt);
648
649         // if no app, delete from the table
650         if (APPSVC_RET_ELAUNCH == ret)
651         {
652                 DBG("Deleted no responce pkg[%s]", pkgname);
653                 snprintf(query, sizeof(query), "DELETE FROM %s WHERE pkgname = '%s' ",
654                                 CAL_REMINDER_ALERT, pkgname);
655                 dbret = _cal_db_util_query_exec(query);
656                 if (CAL_DB_OK != dbret)
657                 {
658                         ERR("_cal_db_util_query_exec() failed(ret:%d)", ret);
659                         switch (dbret)
660                         {
661                         case CAL_DB_ERROR_NO_SPACE:
662                                 return CALENDAR_ERROR_FILE_NO_SPACE;
663                         default:
664                                 return CALENDAR_ERROR_DB_FAILED;
665                         }
666                 }
667
668         }
669         return CALENDAR_ERROR_NONE;
670 }
671
672 static int __cal_server_alarm_alert(char *id, char *time, char *tick, char *unit)
673 {
674         int index;
675     char query[CAL_DB_SQL_MAX_LEN] = {0};
676     sqlite3_stmt *stmt = NULL;
677
678         snprintf(query, sizeof(query), "SELECT pkgname FROM %s WHERE onoff = 1 ",
679                         CAL_REMINDER_ALERT);
680     stmt = _cal_db_util_query_prepare(query);
681     if (NULL == stmt)
682     {
683         ERR("_cal_db_util_query_prepare() Failed");
684         return CALENDAR_ERROR_DB_FAILED;
685     }
686
687     while(CAL_DB_ROW == _cal_db_util_stmt_step(stmt))
688     {
689                 index = 0;
690                 const char *pkgname = (const char *)sqlite3_column_text(stmt, index++);
691                 DBG("pkgname[%s]", pkgname);
692                 __cal_server_alarm_alert_with_pkgname(pkgname, id, time, tick, unit);
693         }
694         sqlite3_finalize(stmt);
695
696         return CALENDAR_ERROR_NONE;
697 }
698
699 static int __cal_server_alarm_noti_with_appsvc(int alarm_id, GList *normal_list, GList *allday_list)
700 {
701         char buf_id[128] = {0};
702         char buf_time[128] = {0};
703         char buf_tick[128] = {0};
704         char buf_unit[128] = {0};
705         GList *l = NULL;
706
707         l = g_list_first(normal_list);
708         if (NULL == l) DBG("normal list is NULL");
709         while (l)
710         {
711                 struct _normal_data_s *nd = (struct _normal_data_s *)l->data;
712                 snprintf(buf_id, sizeof(buf_id), "%d", nd->id);
713                 snprintf(buf_time, sizeof(buf_time), "%lld", nd->alarm_utime);
714                 snprintf(buf_tick, sizeof(buf_tick), "%d", nd->tick);
715                 snprintf(buf_unit, sizeof(buf_unit), "%d", nd->unit);
716
717                 __cal_server_alarm_alert(buf_id, buf_time, buf_tick, buf_unit);
718                 l = g_list_next(l);
719         }
720
721         l = NULL;
722         l = g_list_first(allday_list);
723         if (NULL == l) DBG("allday list is NULL");
724         while (l)
725         {
726                 struct _allday_data_s *ad = (struct _allday_data_s *)l->data;
727                 snprintf(buf_id, sizeof(buf_id), "%d",  ad->id);
728                 snprintf(buf_time, sizeof(buf_time), "%d", ad->alarm_datetime);
729                 snprintf(buf_tick, sizeof(buf_tick), "%d", ad->tick);
730                 snprintf(buf_unit, sizeof(buf_unit), "%d", ad->unit);
731
732                 __cal_server_alarm_alert(buf_id, buf_time, buf_tick, buf_unit);
733                 l = g_list_next(l);
734         }
735         return 0;
736 }
737
738 static int __cal_server_alarm_register_next_normal(long long int now_utime, GList *normal_list)
739 {
740         int ret;
741         int alarm_id;
742         struct _normal_data_s *nd;
743
744         GList *l = g_list_first(normal_list);
745
746         // try to save the first record.
747         // if alarm id exists, it means updated record is not earilier than already registerd one.
748         nd = (struct _normal_data_s *)l->data;
749         if (NULL == nd)
750         {
751                 ERR("No data");
752                 return CALENDAR_ERROR_DB_FAILED;
753         }
754
755         if (nd->alarm_id > 0)
756         {
757                 DBG("Already registered this id");
758                 return CALENDAR_ERROR_NONE;
759         }
760
761         DBG("new is earilier than registered.");
762
763         // clear all alarm which set by mine.
764         ret = alarmmgr_enum_alarm_ids(__cal_server_alarm_clear_all_cb, NULL);
765         if (ret != ALARMMGR_RESULT_SUCCESS)
766         {
767                 ERR("alarmmgr_enum_alarm_ids() failed");
768                 return ret;
769         }
770
771         // register new list
772         long long int mod_alarm_utime; // del seconds
773         mod_alarm_utime = nd->alarm_utime - (nd->alarm_utime % 60);
774         ret = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE,
775                         (time_t)(mod_alarm_utime - now_utime),
776                         0, NULL, &alarm_id);
777         if (ret < 0)
778         {
779                 ERR("alarmmgr_add_alarm_appsvc failed (%d)", ret);
780                 return ret;
781         }
782         DBG("Get normal alarmmgr id (%d)", alarm_id);
783         __cal_server_alarm_update_alarm_id(alarm_id, nd->id, nd->tick, nd->unit);
784
785         return CALENDAR_ERROR_NONE;
786 }
787
788 static int __cal_server_alarm_register_next_allday(time_t now_timet, GList *allday_list)
789 {
790         int ret;
791         int alarm_id;
792         struct _allday_data_s *ad;
793         time_t alarm_timet;
794
795         GList *l = g_list_first(allday_list);
796         alarm_id = 0;
797         ad = (struct _allday_data_s *)l->data;
798         if (NULL == ad)
799         {
800                 ERR("No data");
801                 return CALENDAR_ERROR_DB_FAILED;
802         }
803
804         if (ad->alarm_id > 0)
805         {
806                 DBG("Already registered this id");
807                 return CALENDAR_ERROR_NONE;
808         }
809
810         DBG("new is earilier than registered.");
811
812         // clear all alarm which set by mine.
813         ret = alarmmgr_enum_alarm_ids(__cal_server_alarm_clear_all_cb, NULL);
814         if (ret != ALARMMGR_RESULT_SUCCESS)
815         {
816                 ERR("alarmmgr_enum_alarm_ids() failed");
817                 return ret;
818         }
819
820         // register new list
821         ret = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE,
822                         (time_t)(alarm_timet - (ad->tick * ad->unit) - now_timet),
823                         0, NULL, &alarm_id);
824         if (ret < 0)
825         {
826                 ERR("alarmmgr_add_alarm_appsvc failed (%d)", ret);
827                 return ret;
828         }
829         DBG("Get allday alarmmgr id (%d)", alarm_id);
830         __cal_server_alarm_update_alarm_id(alarm_id, ad->id, ad->tick, ad->unit);
831
832         return CALENDAR_ERROR_NONE;
833 }
834
835 static gint __cal_server_alarm_normal_sort_cb(gconstpointer a, gconstpointer b)
836 {
837         struct _normal_data_s *p1 = (struct _normal_data_s *)a;
838         struct _normal_data_s *p2 = (struct _normal_data_s *)b;
839
840         return p1->alarm_utime - p2->alarm_utime > 0 ? 1 : -1;
841 }
842
843 static gint __cal_server_alarm_allday_sort_cb(gconstpointer a, gconstpointer b)
844 {
845         struct _allday_data_s *p1 = (struct _allday_data_s *)a;
846         struct _allday_data_s *p2 = (struct _allday_data_s *)b;
847
848         return p1->alarm_datetime - p2->alarm_datetime > 0 ? 1 : -1;
849 }
850
851 static int __cal_server_alarm_register_with_alarmmgr(void)
852 {
853         GList *normal_list = NULL;
854         GList *allday_list = NULL;
855         int event_count;
856         int todo_count;
857         int loop_count;
858
859         gettimeofday(&stv, NULL); // check time
860
861         // for normal
862         long long int now_utime;
863         long long int from_utime, to_utime;
864         now_utime = _cal_time_get_now();
865
866         event_count = 0;
867         todo_count = 0;
868         to_utime = now_utime - (now_utime %  60) + 60;
869
870         // searching 3months, next 6months, next 12months
871         for (loop_count = 1; loop_count < 4; loop_count++)
872         {
873                 from_utime = to_utime;
874                 to_utime = from_utime + (60 * 60 * 24 * 30 * 3 * loop_count);
875                 __cal_server_alarm_get_next_list_normal_event(from_utime, to_utime, &normal_list, &event_count);
876                 __cal_server_alarm_get_next_list_normal_todo(from_utime, to_utime, &normal_list, &todo_count);
877                 if (event_count + todo_count > 0)
878                 {
879                         break;
880                 }
881         }
882         DBG("event count(%d) todo count(%d)", event_count, todo_count);
883
884         if (event_count + todo_count > 0)
885         {
886                 normal_list = g_list_sort(normal_list, __cal_server_alarm_normal_sort_cb);
887                 DBG("after sorting");
888                 g_list_foreach(normal_list, (GFunc)__cal_server_alarm_print_list_normal, NULL);
889                 __cal_server_alarm_register_next_normal(now_utime, normal_list);
890
891         }
892         if (normal_list)
893         {
894                 g_list_free_full(normal_list, free);
895                 normal_list = NULL;
896         }
897
898         // for allday
899         DBG("allday");
900         time_t now_timet;
901         time_t from_timet, to_timet;
902         int from_datetime, to_datetime;
903         struct tm datetime_tm;
904         now_timet = time(NULL);
905
906         event_count = 0;
907         todo_count = 0;
908         to_timet = now_timet;
909
910         // searching 3months, next 6months, next 12months
911         for (loop_count = 1; loop_count < 4; loop_count++)
912         {
913                 from_timet = to_timet;
914                 gmtime_r(&from_timet, &datetime_tm);
915                 from_datetime = (1900 + datetime_tm.tm_year) * 10000 + (datetime_tm.tm_mon + 1) * 100 + datetime_tm.tm_mday;
916
917                 to_timet = from_timet + (60 * 60 * 24 * 30 * 3 * loop_count);
918                 gmtime_r(&to_timet, &datetime_tm);
919                 to_datetime = (1900 + datetime_tm.tm_year) * 10000 + (datetime_tm.tm_mon + 1) * 100 + datetime_tm.tm_mday;
920
921                 __cal_server_alarm_get_next_list_allday_event(from_datetime, to_datetime, &allday_list, &event_count);
922                 __cal_server_alarm_get_next_list_allday_todo(from_datetime, to_datetime, &allday_list, &todo_count);
923
924                 if (event_count + todo_count > 0)
925                 {
926                         break;
927                 }
928         }
929         DBG("event count(%d) todo count(%d)", event_count, todo_count);
930
931         if (event_count + todo_count > 0)
932         {
933                 allday_list = g_list_sort(allday_list, __cal_server_alarm_allday_sort_cb);
934                 DBG("after sorting");
935                 g_list_foreach(allday_list, (GFunc)__cal_server_alarm_print_list_allday_todo, NULL);
936                 __cal_server_alarm_register_next_allday(now_timet, allday_list);
937         }
938         if (allday_list)
939         {
940                 g_list_free_full(allday_list, free);
941                 allday_list = NULL;
942         }
943
944         int diff;
945         gettimeofday(&etv, NULL);
946         diff = ((int)etv.tv_sec *1000 + (int)etv.tv_usec/1000)
947                 -((int)stv.tv_sec *1000 + (int)stv.tv_usec/1000);
948         DBG("registering time diff %ld(%d.%d)",diff, diff/1000, diff%1000); // time check
949         return 0;
950 }
951
952 static int _alert_cb(alarm_id_t alarm_id, void *data)
953 {
954         GList *normal_list = NULL;
955         GList *allday_list = NULL;
956
957         __cal_server_alarm_get_list_with_alarmmgr_id(alarm_id, &normal_list, &allday_list);
958         __cal_server_alarm_unset_alerted_alarmmgr_id(alarm_id);
959         __cal_server_alarm_noti_with_appsvc(alarm_id, normal_list, allday_list);
960         if (normal_list)
961         {
962                 g_list_free_full(normal_list, free);
963                 normal_list = NULL;
964         }
965         if (allday_list)
966         {
967                 g_list_free_full(allday_list, free);
968                 allday_list = NULL;
969         }
970
971         __cal_server_alarm_register_with_alarmmgr();
972         return 0;
973 }
974
975 ////////////////////////////////////////////////////////////////////
976 static void __cal_server_alarm_timechange_cb(keynode_t *node, void *data)
977 {
978         __cal_server_alarm_register_with_alarmmgr();
979 }
980
981 int __cal_server_alarm_set_timechange(void)
982 {
983         int ret;
984
985         ret = vconf_notify_key_changed(VCONFKEY_SYSTEM_TIMECHANGE,
986                         __cal_server_alarm_timechange_cb, NULL);
987         if (ret < 0)
988         {
989                 ERR("vconf_ignore_key_changed() failed");
990                 return ret;
991         }
992         return CALENDAR_ERROR_NONE;
993 }
994
995 static void __changed_cb(const char* view_uri, void* data)
996 {
997         __cal_server_alarm_register_with_alarmmgr();
998 }
999
1000 static int __cal_server_alarm_set_inotify(calendar_db_changed_cb callback)
1001 {
1002         _cal_inotify_subscribe(CAL_NOTI_TYPE_EVENT, CAL_NOTI_EVENT_CHANGED, callback, NULL);
1003         _cal_inotify_subscribe(CAL_NOTI_TYPE_TODO, CAL_NOTI_TODO_CHANGED, callback, NULL);
1004         return 0;
1005 }
1006
1007 int _cal_server_alarm(void)
1008 {
1009         int ret;
1010
1011         __cal_server_alarm_set_timechange();
1012         __cal_server_alarm_set_inotify(__changed_cb);
1013
1014         ret = alarmmgr_init("calendar-service");
1015         retvm_if(ret < 0, ret, "alarmmgr_init() failed");
1016
1017         ret = alarmmgr_set_cb(_alert_cb, NULL);
1018         retvm_if(ret < 0, ret, "alarmmgr_set_cb() failed");
1019
1020         __cal_server_alarm_register_with_alarmmgr();
1021
1022         return CALENDAR_ERROR_NONE;
1023 }
1024