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