add comment LCOV_EXCL
[platform/core/pim/calendar-service.git] / server / db / cal_db_instance.c
1 /*
2  * Calendar Service
3  *
4  * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <string.h>
21 #include <stdlib.h>
22 #include <glib.h>
23 #include <unicode/ucal.h>
24 #include <unicode/ustring.h>
25 #include <unicode/ustdio.h>
26 #include <unicode/udat.h>
27 #include <sys/types.h>
28
29 #include "calendar_db.h"
30 #include "calendar_types.h"
31 #include "cal_internal.h"
32 #include "cal_typedef.h"
33 #include "cal_view.h"
34 #include "cal_time.h"
35 #include "cal_record.h"
36 #include "cal_db_instance_helper.h"
37 #include "cal_db.h"
38 #include "cal_db_util.h"
39 #include "cal_db_plugin_timezone_helper.h"
40
41 #define ms2sec(ms) (long long int)(ms / 1000.0)
42 #define sec2ms(s) (s * 1000.0)
43
44 /* input order
45  * UCAL_MONTH + UCAL_DAY_OF_MONTH
46  * UCAL_MONTH + UCAL_WEEK_OF_MONTH + UCAL_DAY_OF_WEEK
47  * UCAL_MONTH + UCAL_DAY_OF_WEEK_IN_MONTH + UCAL_DAY_OF_WEEK
48  * UCAL_DAY_OF_YEAR
49  * UCAL_DAY_OF_WEEK + UCAL_WEEK_OF_YEAR
50  */
51
52 struct day {
53         int uday;
54         const char *str;
55 };
56
57 #define CAL_LUNAR_CALENDAR_BASE_YEAR 2637
58 #define CAL_ENDLESS_LIMIT_YEAR 2036
59 #define CAL_ENDLESS_LIMIT_MONTH 12
60 #define CAL_ENDLESS_LIMIT_MDAY 31
61 #define CAL_ENDLESS_LIMIT_UTIME 2114380800 /* 2037/01/01 00:00:00 GMT */
62 #define CAL_ENDLESS_LIMIT_FULL_DAY (365 * 50)
63
64 static void __print_ucal(int calendar_system_type, UCalendar *ucal, const char *tzid, int wkst)
65 {
66         UErrorCode ec = U_ZERO_ERROR;
67         if (NULL == ucal) return;
68
69         UCalendar *s_ucal = NULL;
70
71         switch (calendar_system_type) {
72         case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
73                 s_ucal = cal_time_open_ucal(-1, tzid, wkst);
74                 if (NULL == s_ucal) {
75                         /* LCOV_EXCL_START */
76                         ERR("cal_time_open_ucal() Fail");
77                         return;
78                         /* LCOV_EXCL_STOP */
79                 }
80                 ucal_setMillis(s_ucal, ucal_getMillis(ucal, &ec), &ec);
81                 break;
82
83         default: /* CALENDAR_SYSTEM_NONE: CALENDAR_SYSTEM_GREGORIAN: */
84                 s_ucal = ucal;
85                 break;
86         }
87         DBG(COLOR_GREEN"[INSERTED] instance %04d-%02d-%02d %02d:%02d:%02d"COLOR_END,
88                         ucal_get(s_ucal, UCAL_YEAR, &ec),
89                         ucal_get(s_ucal, UCAL_MONTH, &ec) + 1,
90                         ucal_get(s_ucal, UCAL_DATE, &ec),
91                         ucal_get(s_ucal, UCAL_HOUR_OF_DAY, &ec),
92                         ucal_get(s_ucal, UCAL_MINUTE, &ec),
93                         ucal_get(s_ucal, UCAL_SECOND, &ec));
94
95         if (CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR == calendar_system_type)
96                 ucal_close(s_ucal);
97 }
98
99 static void __get_allday_date(cal_event_s *event, UCalendar *ucal, int *y, int *m, int *d, int *h, int *n, int *s)
100 {
101         UErrorCode ec = U_ZERO_ERROR;
102         if (NULL == ucal) return;
103
104         UCalendar *s_ucal = NULL;
105
106         switch (event->system_type) {
107         case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
108                 s_ucal = cal_time_open_ucal(-1, event->start_tzid, event->wkst);
109                 if (NULL == s_ucal) {
110                         /* LCOV_EXCL_START */
111                         ERR("cal_time_open_ucal() Fail");
112                         return;
113                         /* LCOV_EXCL_STOP */
114                 }
115                 ucal_setMillis(s_ucal, ucal_getMillis(ucal, &ec), &ec);
116                 break;
117
118         default:
119                 s_ucal = ucal;
120                 break;
121         }
122         if (y)
123                 *y = ucal_get(s_ucal, UCAL_YEAR, &ec);
124         if (m)
125                 *m = ucal_get(s_ucal, UCAL_MONTH, &ec) + 1;
126         if (d)
127                 *d = ucal_get(s_ucal, UCAL_DATE, &ec);
128         if (h)
129                 *h = ucal_get(s_ucal, UCAL_HOUR_OF_DAY, &ec);
130         if (n)
131                 *n = ucal_get(s_ucal, UCAL_MINUTE, &ec);
132         if (s)
133                 *s = ucal_get(s_ucal, UCAL_SECOND, &ec);
134
135         if (CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR == event->system_type)
136                 ucal_close(s_ucal);
137 }
138
139 static int _cal_db_instance_parse_byint(char *byint, int *by, int *len)
140 {
141         if (NULL == byint || '\0' == *byint)
142                 return CALENDAR_ERROR_NONE;
143
144         char **t = NULL;
145         t = g_strsplit_set(byint, " ,", -1);
146         RETVM_IF(NULL == t, CALENDAR_ERROR_OUT_OF_MEMORY, "g_strsplit_set() Fail");
147
148         int length = g_strv_length(t);
149         int i;
150         int index = 0;
151         for (i = 0 ; i < length; i++) {
152                 if (NULL == t[i] || 0 == strlen(t[i])) continue;
153                 by[index] = atoi(t[i]);
154                 index++;
155         }
156         g_strfreev(t);
157         if (len) *len = index;
158         return CALENDAR_ERROR_NONE;
159 }
160
161 static void __set_time_to_ucal(int calendar_system_type, UCalendar *ucal, calendar_time_s *t)
162 {
163         RET_IF(NULL == ucal);
164         RET_IF(NULL == t);
165
166         UErrorCode ec = U_ZERO_ERROR;
167
168         int y = 0, m = 0, d = 0;
169         int h = 0, n = 0, s = 0;
170         struct tm tm = {0};
171         switch (t->type) {
172         case CALENDAR_TIME_UTIME:
173                 ucal_setMillis(ucal, sec2ms(t->time.utime), &ec);
174                 break;
175
176         case CALENDAR_TIME_LOCALTIME:
177                 switch (calendar_system_type) {
178                 case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
179                         tm.tm_year = t->time.date.year - 1900;
180                         tm.tm_mon = t->time.date.month -1;
181                         tm.tm_mday = t->time.date.mday;
182                         tm.tm_hour = t->time.date.hour;
183                         tm.tm_min = t->time.date.minute;
184                         tm.tm_sec = t->time.date.second;
185                         ucal_setMillis(ucal, sec2ms(timegm(&tm)), &ec);
186
187                         y = ucal_get(ucal, UCAL_EXTENDED_YEAR, &ec) - CAL_LUNAR_CALENDAR_BASE_YEAR;
188                         m = ucal_get(ucal, UCAL_MONTH, &ec) + 1;
189                         d = ucal_get(ucal, UCAL_DATE, &ec);
190                         h = ucal_get(ucal, UCAL_HOUR_OF_DAY, &ec);
191                         n = ucal_get(ucal, UCAL_MINUTE, &ec);
192                         s = ucal_get(ucal, UCAL_SECOND, &ec);
193                         ucal_setDateTime(ucal, y, m - 1, d, h, n, s, &ec);
194                         ucal_set(ucal, UCAL_EXTENDED_YEAR, y + CAL_LUNAR_CALENDAR_BASE_YEAR);
195                         break;
196
197                 default:
198                         ucal_setDateTime(ucal, t->time.date.year,
199                                         t->time.date.month -1,
200                                         t->time.date.mday,
201                                         t->time.date.hour,
202                                         t->time.date.minute,
203                                         t->time.date.second, &ec);
204                         break;
205                 }
206                 break;
207         }
208 }
209
210 static int __get_exdate_list(UCalendar *ucal, cal_event_s *event, GList **list)
211 {
212         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
213         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
214
215         if (NULL == event->exdate || '\0' == *(event->exdate))
216                 return CALENDAR_ERROR_NONE;
217
218         char **t = NULL;
219         t = g_strsplit_set(event->exdate, " ,", -1);
220         RETVM_IF(NULL == t, CALENDAR_ERROR_OUT_OF_MEMORY, "g_strsplit_set() Fail");;
221
222         DBG("[%s]", event->exdate);
223         int len = 0;
224         len = g_strv_length(t);
225         DBG("exdate len (%d)", len);
226
227         int i;
228         for (i = 0; i < len; i++) {
229                 char *p = t[i];
230                 if (NULL == p)
231                         continue;
232
233                 int y = 0, m = 0, d = 0;
234                 int h = 0, n = 0, s = 0;
235                 long long int lli = 0;
236                 UCalendar *ucal2 = NULL;
237                 UErrorCode ec = U_ZERO_ERROR;
238                 switch (strlen(p)) {
239                 case 8:
240                         DBG("ALLDAY instance");
241                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDD, &y, &m, &d);
242
243                         ucal2 = ucal_clone(ucal, &ec);
244                         ucal_setDateTime(ucal2, y, m - 1, d, 0, 0, 0, &ec);
245                         lli = ms2sec(ucal_getMillis(ucal2, &ec));
246                         ucal_close(ucal2);
247                         break;
248
249                 case 15:
250                         DBG("ALLDAY instance");
251                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
252
253                         ucal2 = ucal_clone(ucal, &ec);
254                         ucal_setDateTime(ucal2, y, m - 1, d, h, n, s, &ec);
255                         lli = ms2sec(ucal_getMillis(ucal2, &ec));
256                         ucal_close(ucal2);
257                         break;
258
259                 case 16:
260                         DBG("NORMAL instance");
261                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ, &y, &m, &d, &h, &n, &s);
262                         lli = cal_time_convert_itol(NULL, y, m, d, h, n, s);
263                         break;
264                 }
265                 DBG("%lld", lli);
266
267                 long long int *lli_p = calloc(1, sizeof(long long int));
268                 if (NULL == lli_p)
269                         break;
270
271                 *lli_p = lli;
272
273                 *list = g_list_append(*list, lli_p);
274         }
275         g_strfreev(t);
276
277         return CALENDAR_ERROR_NONE;
278 }
279
280 static int _cal_db_instance_update_exdate_mod(int original_event_id, char *recurrence_id)
281 {
282         int ret = 0;
283         int i, j;
284         char **t = NULL;
285         char *p = NULL;
286         char query[CAL_DB_SQL_MAX_LEN] = {0};
287
288         if (original_event_id < 1 || NULL == recurrence_id) {
289                 DBG("Nothing to update exdate mod");
290                 return CALENDAR_ERROR_NONE;
291         }
292
293         DBG("recurrence_id[%s]", recurrence_id);
294         t = g_strsplit_set(recurrence_id, " ,", -1);
295         RETVM_IF(NULL == t, CALENDAR_ERROR_OUT_OF_MEMORY, "g_strsplit_set() Fail");;
296
297         for (i = 0; t[i]; i++) {
298                 p = t[i];
299
300                 /* remove space */
301                 j = 0;
302                 while (p[j] == ' ')
303                         j++;
304
305                 p = t[i] + j;
306                 DBG("%d[%s]", i + 1, p);
307
308                 int y = 0, m = 0, d = 0;
309                 int h = 0, n = 0, s = 0;
310                 char buf[CAL_STR_SHORT_LEN32] = {0};
311                 switch (strlen(p)) {
312                 case 8:
313                         DBG("ALLDAY instance");
314                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDD, &y, &m, &d);
315                         snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d", y, m, d, 0, 0, 0);
316                         snprintf(query, sizeof(query),
317                                         "DELETE FROM %s "
318                                         "WHERE event_id = %d AND dtstart_datetime = '%s' ",
319                                         CAL_TABLE_ALLDAY_INSTANCE,
320                                         original_event_id, buf);
321                         break;
322
323                 case 15:
324                         DBG("ALLDAY instance");
325                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
326                         snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d", y, m, d, h, n, s);
327                         snprintf(query, sizeof(query),
328                                         "DELETE FROM %s "
329                                         "WHERE event_id = %d AND dtstart_datetime = '%s' ",
330                                         CAL_TABLE_ALLDAY_INSTANCE,
331                                         original_event_id, buf);
332                         break;
333
334                 case 16:
335                         DBG("NORMAL instance");
336                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ, &y, &m, &d, &h, &n, &s);
337                         snprintf(query, sizeof(query), "DELETE FROM %s WHERE event_id=%d AND dtstart_utime=%lld ",
338                                         CAL_TABLE_NORMAL_INSTANCE, original_event_id, cal_time_convert_itol(NULL, y, m, d, h, n, s));
339                         DBG("(%lld)", cal_time_convert_itol(NULL, y, m, d, h, n, s));
340                         break;
341                 }
342                 ret = cal_db_util_query_exec(query);
343                 if (CALENDAR_ERROR_NONE != ret) {
344                         /* LCOV_EXCL_START */
345                         ERR("cal_db_util_query_exec() Fail(%d)", ret);
346                         SECURE("[%s]", query);
347                         g_strfreev(t);
348                         return ret;
349                         /* LCOV_EXCL_STOP */
350                 }
351         }
352         g_strfreev(t);
353         return CALENDAR_ERROR_NONE;
354 }
355
356 static inline int __cal_db_instance_has_after(calendar_time_s *t1, calendar_time_s *t2)
357 {
358         if (t1->type == CALENDAR_TIME_UTIME)
359                 return t1->time.utime < t2->time.utime ? 0 : 1;
360
361         DBG("%d %d %d /%d %d %d", t1->time.date.year, t1->time.date.month, t1->time.date.mday,
362                         t2->time.date.year, t2->time.date.month, t2->time.date.mday);
363
364         if (t1->time.date.year == t2->time.date.year) {
365                 if (t1->time.date.month == t2->time.date.month)
366                         return t1->time.date.mday < t2->time.date.mday ? 0 : 1;
367
368                 return t1->time.date.month < t2->time.date.month ? 0 : 1;
369         }
370         return t1->time.date.year < t2->time.date.year ? 0 : 1;
371 }
372
373 static inline int _cal_db_instance_convert_mday(const char *str, int *mday)
374 {
375         int d;
376
377         RETV_IF(!str, CALENDAR_ERROR_INVALID_PARAMETER);
378         RETV_IF(*str, CALENDAR_ERROR_INVALID_PARAMETER);
379
380         d = atoi(str);
381         RETVM_IF(d < 1 || 31 < d, CALENDAR_ERROR_INVALID_PARAMETER, "day(%d)", d);
382
383         DBG("get mday[%s] and convert to int(%d)", str, d);
384         *mday = d;
385         return CALENDAR_ERROR_NONE;
386 }
387
388 static int _cal_db_instance_del_inundant(int event_id, calendar_time_s *st, cal_event_s *event)
389 {
390         int ret = 0;
391         int cnt;
392         char query[CAL_DB_SQL_MAX_LEN];
393
394         if (event->range_type != CALENDAR_RANGE_COUNT)
395                 return CALENDAR_ERROR_NONE;
396
397         cnt = event->count;
398         DBG("get count(%d) and del after this", cnt);
399
400         if (st->type == CALENDAR_TIME_UTIME) {
401                 snprintf(query, sizeof(query), "DELETE FROM %s "
402                                 "WHERE event_id = %d "
403                                 "AND dtstart_utime > (SELECT dtstart_utime FROM %s "
404                                 "WHERE event_id = %d ORDER BY dtstart_utime LIMIT %d, 1) ",
405                                 CAL_TABLE_NORMAL_INSTANCE,
406                                 event_id,
407                                 CAL_TABLE_NORMAL_INSTANCE,
408                                 event_id, cnt -1);
409
410         } else if (st->type == CALENDAR_TIME_LOCALTIME) {
411                 snprintf(query, sizeof(query), "DELETE FROM %s WHERE event_id = %d "
412                                 "AND dtstart_datetime > (SELECT dtstart_datetime FROM %s "
413                                 "WHERE event_id = %d ORDER BY dtstart_datetime LIMIT %d, 1) ",
414                                 CAL_TABLE_ALLDAY_INSTANCE,
415                                 event_id,
416                                 CAL_TABLE_ALLDAY_INSTANCE,
417                                 event_id, cnt -1);
418         }
419
420         ret = cal_db_util_query_exec(query);
421         if (CALENDAR_ERROR_NONE != ret) {
422                 /* LCOV_EXCL_START */
423                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
424                 SECURE("[%s]", query);
425                 return ret;
426                 /* LCOV_EXCL_STOP */
427         }
428         return CALENDAR_ERROR_NONE;
429 }
430
431 /*
432  *      bit   |7 |6  |5  |4  |3  |2  |1  |0 |
433  *      value |0 |SA |FR |TH |WE |TU |MO |SU|
434  *
435  * UCAL_XXX = bit position + 1
436  * UCAL_SUNDAY = 1
437  * UCAL_MONDAY = 2...
438  */
439 static int __convert_week_to_bits(const char *byday, int *byday_len)
440 {
441         RETV_IF(NULL == byday, -1);
442
443         const char *week_text[7] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
444         int week = 0;
445         int i;
446         int len = 0;
447         for (i = 0; i < 7; i++) {
448                 if (strstr(byday, week_text[i])) {
449                         week |= (0x01 << i);
450                         len++;
451                 }
452         }
453         if (byday_len) *byday_len = len;
454         return week;
455 }
456
457 static int _cal_db_instance_get_duration(UCalendar *ucal, calendar_time_s *st, calendar_time_s *et, long long int *duration)
458 {
459         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
460         RETV_IF(NULL == st, CALENDAR_ERROR_INVALID_PARAMETER);
461         RETV_IF(NULL == et, CALENDAR_ERROR_INVALID_PARAMETER);
462
463         long long int _duration = -1;
464         UErrorCode ec = U_ZERO_ERROR;
465         UDate ud;
466
467         switch (st->type) {
468         case CALENDAR_TIME_UTIME:
469                 if (et->time.utime < st->time.utime) {
470                         /* LCOV_EXCL_START */
471                         ERR("check time: end(%lld < start(%lld)", et->time.utime, st->time.utime);
472                         return CALENDAR_ERROR_INVALID_PARAMETER;
473                         /* LCOV_EXCL_STOP */
474                 }
475                 _duration = et->time.utime - st->time.utime;
476                 break;
477
478         case CALENDAR_TIME_LOCALTIME:
479                 ucal_setDateTime(ucal, et->time.date.year, et->time.date.month -1, et->time.date.mday,
480                                 et->time.date.hour, et->time.date.minute, et->time.date.second, &ec);
481                 ud = ucal_getMillis(ucal, &ec);
482
483                 ucal_setDateTime(ucal, st->time.date.year, st->time.date.month -1, st->time.date.mday,
484                                 st->time.date.hour, st->time.date.minute, st->time.date.second, &ec);
485
486                 _duration = ucal_getFieldDifference(ucal, ud, UCAL_SECOND, &ec);
487                 if (U_FAILURE(ec)) {
488                         /* LCOV_EXCL_START */
489                         ERR("ucal_getFieldDifference() Fail[%s]", u_errorName(ec));
490                         return ec;
491                         /* LCOV_EXCL_STOP */
492                 }
493                 break;
494         }
495
496         if (duration) *duration = _duration;
497         return CALENDAR_ERROR_NONE;
498 }
499
500 static int _cal_db_instance_insert_record(UCalendar *ucal, long long int duration, cal_event_s *event)
501 {
502         int ret;
503         UErrorCode ec = U_ZERO_ERROR;
504         long long int lli_s = 0;
505         long long int lli_e = 0;
506         int y = 0, m = 0, d = 0;
507         int h = 0, n = 0, s = 0;
508         char buf_s[CAL_STR_MIDDLE_LEN] = {0};
509         char buf_e[CAL_STR_MIDDLE_LEN] = {0};
510
511         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
512
513         switch (event->start.type) {
514         case CALENDAR_TIME_UTIME:
515                 lli_s =  ms2sec(ucal_getMillis(ucal, &ec));
516                 lli_e = lli_s + duration;
517                 ret = cal_db_instance_helper_insert_utime_instance(event->index, lli_s, lli_e);
518                 RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "cal_db_instance_helper_insert_utime_instance() Fail(%d)", ret);
519                 break;
520
521         case CALENDAR_TIME_LOCALTIME:
522                 __get_allday_date(event, ucal, &y, &m, &d, &h, &n, &s);
523                 snprintf(buf_s, sizeof(buf_s), CAL_FORMAT_LOCAL_DATETIME, y, m, d, h, n, s);
524
525                 if (0 < duration) {
526                         UCalendar *ucal2 = NULL;
527                         ucal2 = ucal_clone(ucal, &ec);
528                         ucal_add(ucal2, UCAL_SECOND, duration, &ec);
529                         __get_allday_date(event, ucal2, &y, &m, &d, &h, &n, &s);
530                         ucal_close(ucal2);
531                 }
532                 snprintf(buf_e, sizeof(buf_e), CAL_FORMAT_LOCAL_DATETIME, y, m, d, h, n, s);
533                 ret = cal_db_instance_helper_insert_localtime_instance(event->index, buf_s, buf_e);
534                 RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "cal_db_instance_allday_insert_record() failed(%d)", ret);
535                 break;
536         }
537         __print_ucal(event->system_type, ucal, NULL, 1);
538         return CALENDAR_ERROR_NONE;
539 }
540
541 static int __convert_wday_to_int(const char *wday)
542 {
543         RETV_IF(NULL == wday, 0);
544
545         const char *week_text[7] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
546         int i;
547         for (i = 0; i < 7; i++) {
548                 if (strstr(wday, week_text[i]))
549                         return i + 1;
550         }
551         return 0;
552 }
553
554 static int __get_until_from_range(cal_event_s *event, calendar_time_s *until)
555 {
556         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
557         RETV_IF(NULL == until, CALENDAR_ERROR_INVALID_PARAMETER);
558
559         long long int range = 0;
560         switch (event->range_type) {
561         case CALENDAR_RANGE_COUNT:
562                 DBG("range count");
563                 break;
564
565         case CALENDAR_RANGE_UNTIL:
566                 DBG("range until");
567                 until->type = event->until.type;
568                 switch (until->type) {
569                 case CALENDAR_TIME_UTIME:
570                         range = cal_time_convert_itol(NULL, CAL_ENDLESS_LIMIT_YEAR,
571                                         CAL_ENDLESS_LIMIT_MONTH, CAL_ENDLESS_LIMIT_MDAY, 0, 0, 0);
572                         if (range < event->until.time.utime) {
573                                 DBG("range max < until time(%lld), so set max(%lld)", event->until.time.utime, range);
574                                 until->time.utime = range;
575                         } else {
576                                 until->time.utime = event->until.time.utime;
577                         }
578                         break;
579
580                 case CALENDAR_TIME_LOCALTIME:
581                         until->time.date.year = CAL_ENDLESS_LIMIT_YEAR < event->until.time.date.year ?
582                                 CAL_ENDLESS_LIMIT_YEAR : event->until.time.date.year;
583                         until->time.date.month = event->until.time.date.month;
584                         until->time.date.mday = event->until.time.date.mday;
585                         until->time.date.hour = event->until.time.date.hour;
586                         until->time.date.minute = event->until.time.date.minute;
587                         until->time.date.second = event->until.time.date.second;
588                         break;
589                 }
590                 break;
591
592         case CALENDAR_RANGE_NONE:
593                 DBG("range none");
594                 until->type = event->until.type;
595                 switch (until->type) {
596                 case CALENDAR_TIME_UTIME:
597                         until->time.utime = cal_time_convert_itol(event->start_tzid,
598                                         CAL_ENDLESS_LIMIT_YEAR,
599                                         CAL_ENDLESS_LIMIT_MONTH,
600                                         CAL_ENDLESS_LIMIT_MDAY,
601                                         0, 0, 0);
602                         break;
603                 case CALENDAR_TIME_LOCALTIME:
604                         until->time.date.year = CAL_ENDLESS_LIMIT_YEAR;
605                         until->time.date.month = CAL_ENDLESS_LIMIT_MONTH;
606                         until->time.date.mday = CAL_ENDLESS_LIMIT_MDAY;
607                         until->time.date.hour = 0;
608                         until->time.date.minute = 0;
609                         until->time.date.second = 0;
610                         break;
611                 }
612                 break;
613         }
614         return CALENDAR_ERROR_NONE;
615 }
616
617 /*
618  * Return true when index meets bysetpos value.
619  * ig. when bysetpos=2 and 3, index 1 returns true(skip), index 2 and 3 returns false(selected).
620  */
621 static bool __check_bysetpos_to_skip(int index, int *bysetpos, int bysetpos_len, int dates_len)
622 {
623         int i;
624         if (0 == bysetpos_len)
625                 return false;
626
627         for (i = 0; i < bysetpos_len; i++) {
628                 if (0 < bysetpos[i]) {
629                         if (bysetpos[i] == (index + 1))
630                                 return false;
631                 } else {
632                         if ((index - dates_len) == bysetpos[i])
633                                 return false;
634                 }
635         }
636         return true;
637 }
638
639 static bool __check_before_dtstart(long long int current_utime, long long int dtstart_utime)
640 {
641         if (current_utime < dtstart_utime) {
642                 DBG("get time(%lld) is earlier than start(%lld), so skip", current_utime, dtstart_utime);
643                 return true;
644         }
645         return false;
646 }
647
648 static bool __check_exdate_to_skip(long long int get_lli, GList **list)
649 {
650         GList *cursor = *list;
651         while (cursor) {
652                 long long int *lli_p = (long long int *)cursor->data;
653                 if (NULL == lli_p) {
654                         cursor = g_list_next(cursor);
655                         continue;
656                 }
657                 long long int lli = *lli_p;
658                 if (lli == get_lli) {
659                         DBG("found exdate(%lld)", get_lli);
660                         free(lli_p);
661                         *list = g_list_delete_link(*list, cursor);
662                         return true;
663                 }
664                 cursor = g_list_next(cursor);
665         }
666         return false;
667 }
668
669 static bool __check_to_stop_loop(long long int current_utime, long long int *last_utime, int loop)
670 {
671         if ((*last_utime == current_utime) || (CAL_ENDLESS_LIMIT_FULL_DAY == loop)) {
672                 DBG("current utime is same as last utime(%lld), so stoppted", current_utime);
673                 return true;
674         }
675         *last_utime = current_utime;
676         return false;
677 }
678
679 static bool __check_out_of_range(long long int current_utime, cal_event_s *event, long long int until_utime, int *count)
680 {
681         RETV_IF(NULL == event, true);
682
683         /* check range */
684         switch (event->range_type) {
685         case CALENDAR_RANGE_UNTIL:
686         case CALENDAR_RANGE_NONE:
687                 if (until_utime < current_utime) {
688                         DBG("(%lld) (%lld)", current_utime, until_utime);
689                         return true;
690                 }
691                 break;
692
693         case CALENDAR_RANGE_COUNT:
694                 (*count)++;
695                 if (event->count < *count) {
696                         DBG("(%d) (%d)", *count, event->count);
697                         return true;
698                 }
699
700                 if (CAL_ENDLESS_LIMIT_UTIME < current_utime) {
701                         /* event count is remained, it should not go over LIMIT */
702                         DBG("stopped because LIMIT UTIME(%lld) < dtstart(%lld)", (long long int)CAL_ENDLESS_LIMIT_UTIME, current_utime);
703                         return true;
704                 }
705                 break;
706         }
707         return false;
708 }
709
710 static bool __check_daily_bymonth_to_skip(UCalendar *ucal, int *bymonth, int bymonth_len, int *log_value)
711 {
712         if (0 == bymonth_len) return false;
713
714         UErrorCode ec = U_ZERO_ERROR;
715         int month = ucal_get(ucal, UCAL_MONTH, &ec) + 1;
716         int i;
717         for (i = 0; i < bymonth_len; i++) {
718                 if (month == bymonth[i])
719                         return false;
720         }
721         if (*log_value != month) {
722                 DBG("Get month(%d) Not in bymonth", month);
723                 *log_value = month;
724         }
725         return true;
726 }
727
728 static int __get_dates_in_month(UCalendar *ucal, int week_bits, int bymonth, int *dates_len)
729 {
730         UErrorCode ec = U_ZERO_ERROR;
731         int len = 0;
732
733         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
734
735         int i;
736         for (i = 0; i < 7; i++) {
737                 if (0 == (week_bits & (0x01 << i))) continue;
738                 int wday_int = i + 1;
739
740                 ucal_set(ucal, UCAL_MONTH, bymonth - 1);
741                 ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
742                 ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, 1);
743                 int weekno_start = ucal_get(ucal, UCAL_WEEK_OF_YEAR, &ec);
744
745                 ucal_set(ucal, UCAL_MONTH, bymonth - 1);
746                 ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
747                 ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, -1);
748                 int weekno_end = ucal_get(ucal, UCAL_WEEK_OF_YEAR, &ec);
749                 if (1 == weekno_end) {
750                         ucal_set(ucal, UCAL_MONTH, bymonth - 1);
751                         ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
752                         ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, -1);
753                         ucal_add(ucal, UCAL_DATE, -7, &ec);
754                         weekno_end = ucal_get(ucal, UCAL_WEEK_OF_YEAR, &ec) + 1;
755                 }
756                 int weekno_gap = weekno_end - weekno_start + 1;
757
758                 len += weekno_gap;
759         }
760         if (dates_len) *dates_len = len;
761         return CALENDAR_ERROR_NONE;
762 }
763
764 static int _cal_db_instance_publish_yearly_yday(UCalendar *ucal, cal_event_s *event, long long int duration)
765 {
766         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
767         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
768         RETV_IF(NULL == event->byyearday, CALENDAR_ERROR_INVALID_PARAMETER);
769         RETV_IF('\0' == event->byyearday[0], CALENDAR_ERROR_INVALID_PARAMETER);
770
771         UErrorCode ec = U_ZERO_ERROR;
772         calendar_time_s until = {0};
773         __get_until_from_range(event, &until);
774         __set_time_to_ucal(event->system_type, ucal, &until);
775         /* set until before dtstart_utime */
776         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
777
778         int byyearday[CAL_STR_MIDDLE_LEN] = {0};
779         int byyearday_len = 0;
780         _cal_db_instance_parse_byint(event->byyearday, byyearday, &byyearday_len);
781         DBG("byyearday len(%d)", byyearday_len);
782
783         int bysetpos[CAL_STR_MIDDLE_LEN] = {0};
784         int bysetpos_len = 0;
785         _cal_db_instance_parse_byint(event->bysetpos, bysetpos, &bysetpos_len);
786         DBG("bysetpos len(%d)", bysetpos_len);
787
788         GList *list = NULL;
789         __get_exdate_list(ucal, event, &list);
790
791         int loop = 0;
792         int count = 0;
793         bool is_exit = false;
794         long long int last_utime = 0;
795         long long int current_utime = 0;
796         while (false == is_exit) {
797                 calendar_time_s *st = &event->start;
798                 __set_time_to_ucal(event->system_type, ucal, st);
799                 long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
800                 ucal_add(ucal, UCAL_YEAR, event->interval * loop, &ec);
801
802                 int i;
803                 for (i = 0; i < byyearday_len; i++) {
804                         ucal_set(ucal, UCAL_DAY_OF_YEAR, byyearday[i]);
805                         if (true == __check_bysetpos_to_skip(i, bysetpos, bysetpos_len, byyearday_len))
806                                 continue;
807
808                         current_utime = ms2sec(ucal_getMillis(ucal, &ec));
809                         if (true == __check_before_dtstart(current_utime, dtstart_utime))
810                                 continue;
811
812                         if (true == __check_exdate_to_skip(current_utime, &list)) {
813                                 count++;
814                                 continue;
815                         }
816                         is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
817                         if (true == is_exit)
818                                 break;
819                         _cal_db_instance_insert_record(ucal, duration, event);
820                 }
821                 if (true == is_exit)
822                         break;
823                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
824                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
825                 loop++;
826         }
827         if (list)
828                 g_list_free_full(list, free);
829         return CALENDAR_ERROR_NONE;
830 }
831
832 /*
833  * weekno is different num+day
834  * weekno=10, byday=SU, is not always same as 10SU
835  * in 2014, Mar 2nd != Mar 9th
836  */
837 static int _cal_db_instance_publish_yearly_weekno(UCalendar *ucal, cal_event_s *event, long long int duration)
838 {
839         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
840         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
841         RETV_IF(NULL == event->byweekno || '\0' == event->byweekno[0], CALENDAR_ERROR_INVALID_PARAMETER);
842
843         UErrorCode ec = U_ZERO_ERROR;
844         calendar_time_s until = {0};
845         __get_until_from_range(event, &until);
846         __set_time_to_ucal(event->system_type, ucal, &until);
847         /* set until before dtstart_utime */
848         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
849
850         /* get byday */
851         int week_bits = 0;
852         int byday_len = 0;
853         if (NULL == event->byday || '\0' == event->byday[0]) {
854                 calendar_time_s *st = &event->start;
855                 __set_time_to_ucal(event->system_type, ucal, st);
856                 int dtstart_wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
857                 week_bits |= (0x01 << (dtstart_wday - 1));
858                 byday_len = 1;
859
860         } else {
861                 week_bits = __convert_week_to_bits(event->byday, &byday_len);
862         }
863         DBG("byday_len (%d) week integer(0x%x)", byday_len, week_bits);
864
865         int byweekno[CAL_STR_MIDDLE_LEN] = {0};
866         int byweekno_len = 0;
867         _cal_db_instance_parse_byint(event->byweekno, byweekno, &byweekno_len);
868         DBG("byweekno len(%d)", byweekno_len);
869
870         int bysetpos[CAL_STR_MIDDLE_LEN] = {0};
871         int bysetpos_len = 0;
872         _cal_db_instance_parse_byint(event->bysetpos, bysetpos, &bysetpos_len);
873         DBG("bysetpos len(%d)", bysetpos_len);
874
875         GList *list = NULL;
876         __get_exdate_list(ucal, event, &list);
877
878         int loop = 0;
879         int count = 0;
880         bool is_exit = false;
881         long long int last_utime = 0;
882         long long int current_utime = 0;
883         while (false == is_exit) {
884                 calendar_time_s *st = &event->start;
885                 __set_time_to_ucal(event->system_type, ucal, st);
886                 long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
887                 ucal_add(ucal, UCAL_YEAR, (event->interval * loop), &ec);
888                 long long int start_point = sec2ms(ucal_getMillis(ucal, &ec));
889
890                 /* extra_weekno : week-number converting value from iCalendar (RFC2445) to ICU:
891                  * - iCalendar W1 : first week containing at least 4 days of the year
892                  *                 (W0 when contains less than 4 days of the year)
893                  * - ICU W1 : week of 1,Jan
894                  */
895                 int extra_weekno = 0;
896                 ucal_set(ucal, UCAL_MONTH, 0);
897                 ucal_set(ucal, UCAL_DATE, 1);
898                 int wkst = ucal_getAttribute(ucal, UCAL_FIRST_DAY_OF_WEEK);
899                 int first_wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
900                 extra_weekno = 3 < ((first_wday+7-wkst)%7) ? 1 : 0;
901
902                 ucal_setMillis(ucal, ms2sec(start_point), &ec); /* set start point */
903
904                 int i;
905                 for (i = 0 ; i < byweekno_len; i++) {
906                         int j;
907                         int week_count = 0;
908                         for (j = 0; j < 7; j++) {
909                                 if (week_bits & (0x01 << j)) {
910                                         week_count++;
911                                         ucal_set(ucal, UCAL_WEEK_OF_YEAR, byweekno[i] + extra_weekno);
912                                         ucal_set(ucal, UCAL_DAY_OF_WEEK, j + 1);
913                                         if (true == __check_bysetpos_to_skip(i + week_count - 1, bysetpos, bysetpos_len, byweekno_len + byday_len - 1))
914                                                 continue;
915
916                                         current_utime = ms2sec(ucal_getMillis(ucal, &ec));
917                                         if (true == __check_before_dtstart(current_utime, dtstart_utime))
918                                                 continue;
919
920                                         if (true == __check_exdate_to_skip(current_utime, &list)) {
921                                                 count++;
922                                                 continue;
923                                         }
924                                         is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
925                                         if (true == is_exit)
926                                                 break;
927                                         _cal_db_instance_insert_record(ucal, duration, event);
928                                 }
929                         }
930                         if (true == is_exit)
931                                 break;
932                 }
933                 if (true == is_exit)
934                         break;
935                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
936                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
937                 loop++;
938         }
939         if (list)
940                 g_list_free_full(list, free);
941         return CALENDAR_ERROR_NONE;
942 }
943
944 static int _cal_db_instance_publish_yearly_wday(UCalendar *ucal, cal_event_s *event, long long int duration)
945 {
946         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
947         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
948
949         UErrorCode ec = U_ZERO_ERROR;
950         calendar_time_s until = {0};
951         __get_until_from_range(event, &until);
952         __set_time_to_ucal(event->system_type, ucal, &until);
953         /* set until before dtstart_utime */
954         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
955
956         /* get bymonth into array */
957         int bymonth[12] = {0};
958         int bymonth_len = 0;
959         bool has_bymonth = true;
960         _cal_db_instance_parse_byint(event->bymonth, bymonth, &bymonth_len);
961         if (0 == bymonth_len) {
962                 has_bymonth = false;
963                 calendar_time_s *st = &event->start;
964                 __set_time_to_ucal(event->system_type, ucal, st);
965                 int month = ucal_get(ucal, UCAL_MONTH, &ec) + 1;
966                 bymonth[0] = month;
967                 bymonth_len = 1;
968         }
969
970         /* get bymonthday into array */
971         int bymonthday[CAL_STR_MIDDLE_LEN] = {0};
972         int bymonthday_len = 0;
973         _cal_db_instance_parse_byint(event->bymonthday, bymonthday, &bymonthday_len);
974         DBG("bymonthday_len(%d)", bymonthday_len);
975
976         char **t = NULL;
977         int byday_len = 0;
978
979         /* if nowday in weekly */
980         if (NULL == event->byday || '\0' == event->byday[0]) {
981                 const char *week_text[7] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
982
983                 calendar_time_s *st = &event->start;
984                 __set_time_to_ucal(event->system_type, ucal, st);
985                 int nth = ucal_get(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, &ec);
986                 int dtstart_wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
987                 char buf[CAL_STR_SHORT_LEN32] = {0};
988                 snprintf(buf, sizeof(buf), "%d%s", nth, week_text[dtstart_wday -1]);
989                 DBG("set byday[%s]", buf);
990
991                 t = g_strsplit_set(buf, " ,", -1);
992                 byday_len = 1;
993
994         } else {
995                 t = g_strsplit_set(event->byday, " ,", -1);
996                 byday_len = g_strv_length(t);
997         }
998         DBG("[%s] byday_len(%d)", event->byday, byday_len);
999
1000         int bysetpos[CAL_STR_MIDDLE_LEN] = {0};
1001         int bysetpos_len = 0;
1002         _cal_db_instance_parse_byint(event->bysetpos, bysetpos, &bysetpos_len);
1003         DBG("bysetpos len(%d)", bysetpos_len);
1004
1005         GList *list = NULL;
1006         __get_exdate_list(ucal, event, &list);
1007
1008         int loop = 0;
1009         int count = 0;
1010         bool is_exit = false;
1011         long long int last_utime = 0;
1012         long long int current_utime = 0;
1013         while (false == is_exit) {
1014                 calendar_time_s *st = &event->start;
1015                 __set_time_to_ucal(event->system_type, ucal, st);
1016                 long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
1017                 ucal_add(ucal, UCAL_YEAR, event->interval * loop, &ec);
1018                 ucal_setMillis(ucal, ucal_getMillis(ucal, &ec), &ec); /* set start point */
1019
1020                 int i, j, k;
1021                 for (i = 0; i < bymonth_len; i++) {
1022
1023                         if (2 < strlen(t[0])) { /* -3SU, +2SA */
1024                                 for (j = 0; j < byday_len; j++) {
1025                                         if (0 == strlen(t[j])) continue;
1026                                         /* get nth, wday */
1027                                         int nth = 0;
1028                                         char wday[CAL_STR_SHORT_LEN32] = {0};
1029
1030                                         sscanf(t[j], "%d%s", &nth, wday); /* -3SU, +2SA */
1031                                         DBG("nth(%d) wday[%s]", nth, wday);
1032                                         int wday_int = __convert_wday_to_int(wday);
1033
1034                                         /* set nth, wday */
1035                                         if (0 < nth) {
1036                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1037                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, 1);
1038                                                 ucal_set(ucal, UCAL_MONTH, false == has_bymonth ? 0 : (bymonth[i] - 1));
1039                                                 ucal_add(ucal, UCAL_WEEK_OF_YEAR, nth - 1, &ec);
1040
1041                                         } else {
1042                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1043                                                 ucal_set(ucal, UCAL_MONTH, false == has_bymonth ? 0 : bymonth[i] - 1);
1044                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, nth);
1045                                         }
1046                                         if (true == __check_bysetpos_to_skip(j, bysetpos, bysetpos_len, bymonth_len + byday_len - 1))
1047                                                 continue;
1048
1049                                         current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1050                                         if (true == __check_before_dtstart(current_utime, dtstart_utime))
1051                                                 continue;
1052
1053                                         if (true == __check_exdate_to_skip(current_utime, &list)) {
1054                                                 count++;
1055                                                 continue;
1056                                         }
1057                                         is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1058                                         if (true == is_exit)
1059                                                 break;
1060                                         _cal_db_instance_insert_record(ucal, duration, event);
1061                                 }
1062
1063                         } else {
1064                                 /* SU, SA: no week num: means all week:1TH,2TH,3TH.., so needs another byevent->system_typex */
1065                                 int week_bits = 0;
1066                                 /* if nowday in weekly */
1067                                 if (NULL == event->byday || '\0' == event->byday[0]) {
1068                                         calendar_time_s *st = &event->start;
1069                                         __set_time_to_ucal(event->system_type, ucal, st);
1070                                         int dtstart_wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1071                                         week_bits |= (0x01 << (dtstart_wday - 1));
1072
1073                                 } else {
1074                                         week_bits = __convert_week_to_bits(event->byday, NULL);
1075                                 }
1076                                 DBG("week integer(0x%x)", week_bits);
1077
1078                                 if (bymonthday_len) { /* bymonthday */
1079                                         for (j = 0; j < bymonthday_len; j++) {
1080                                                 ucal_set(ucal, UCAL_MONTH, bymonth[i] - 1);
1081                                                 ucal_set(ucal, UCAL_DAY_OF_MONTH, bymonthday[j]);
1082                                                 bool is_match_wday = false;
1083                                                 int w = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1084                                                 for (k = 0; k < 7; k++) { /* check if this is one of wday */
1085                                                         if (week_bits & (0x01 << k)) {
1086                                                                 if ((k + 1) == w) {
1087                                                                         is_match_wday = true;
1088                                                                         break;
1089                                                                 }
1090                                                         }
1091                                                 }
1092                                                 if (false == is_match_wday) {
1093                                                         DBG("get wday(%d) != want wday(%d)", w, k + 1);
1094                                                         continue;
1095                                                 }
1096                                                 if (true == __check_bysetpos_to_skip(j, bysetpos, bysetpos_len, bymonthday_len))
1097                                                         continue;
1098
1099                                                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1100                                                 if (true == __check_before_dtstart(current_utime, dtstart_utime))
1101                                                         continue;
1102
1103                                                 if (true == __check_exdate_to_skip(current_utime, &list)) {
1104                                                         count++;
1105                                                         continue;
1106                                                 }
1107                                                 is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1108                                                 if (true == is_exit)
1109                                                         break;
1110                                                 _cal_db_instance_insert_record(ucal, duration, event);
1111                                         }
1112
1113                                 } else {
1114                                         int year = ucal_get(ucal, UCAL_YEAR, &ec);
1115
1116                                         ucal_set(ucal, UCAL_MONTH, bymonth[i] - 1);
1117                                         ucal_set(ucal, UCAL_DATE, 1);
1118                                         int byday_start = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1119
1120                                         int dates_len = 0;
1121                                         __get_dates_in_month(ucal, week_bits, bymonth[i], &dates_len);
1122                                         DBG("dates_len (%d)", dates_len);
1123
1124                                         int index = -1;
1125                                         for (j = 0; j < 6; j++) { /* check weekno in month: max 6 */
1126                                                 for (k = 0; k < 7; k++) {
1127                                                         if (0 == (week_bits & (0x01 << ((byday_start -1 +k)%7)))) continue;
1128                                                         index++;
1129
1130                                                         int wday_int = (byday_start -1 +k) %7 + 1;
1131                                                         ucal_set(ucal, UCAL_WEEK_OF_MONTH, (j + 1) + (byday_start -1 +k) / 7);
1132                                                         if (year != ucal_get(ucal, UCAL_YEAR, &ec))
1133                                                                 ucal_set(ucal, UCAL_YEAR, year); /* year is changed from 12/30 */
1134                                                         ucal_set(ucal, UCAL_MONTH, bymonth[i] - 1);
1135                                                         ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1136
1137                                                         int get_month = ucal_get(ucal, UCAL_MONTH, &ec) + 1;
1138                                                         if (bymonth[i] != get_month) { j = 6; break; }
1139
1140                                                         if (true == __check_bysetpos_to_skip(index, bysetpos, bysetpos_len, dates_len))
1141                                                                 continue;
1142
1143                                                         current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1144                                                         if (true == __check_before_dtstart(current_utime, dtstart_utime))
1145                                                                 continue;
1146
1147                                                         if (true == __check_exdate_to_skip(current_utime, &list)) {
1148                                                                 count++;
1149                                                                 continue;
1150                                                         }
1151                                                         is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1152                                                         if (true == is_exit)
1153                                                                 break;
1154                                                         _cal_db_instance_insert_record(ucal, duration, event);
1155                                                 }
1156                                                 if (true == is_exit)
1157                                                         break;
1158                                         }
1159                                 }
1160                         }
1161                         if (true == is_exit)
1162                                 break;
1163                 }
1164                 if (true == is_exit)
1165                         break;
1166                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1167                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
1168                 loop++;
1169         }
1170         g_strfreev(t);
1171         if (list)
1172                 g_list_free_full(list, free);
1173         return CALENDAR_ERROR_NONE;
1174 }
1175
1176 static int _cal_db_instance_publish_yearly_mday(UCalendar *ucal, cal_event_s *event, long long int duration)
1177 {
1178         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1179         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1180
1181         UErrorCode ec = U_ZERO_ERROR;
1182         calendar_time_s until = {0};
1183         __get_until_from_range(event, &until);
1184         __set_time_to_ucal(event->system_type, ucal, &until); /* set until before dtstart_utime */
1185         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
1186
1187         /* get bymonth into array */
1188         int bymonth[12] = {0};
1189         int bymonth_len = 0;
1190         _cal_db_instance_parse_byint(event->bymonth, bymonth, &bymonth_len);
1191         if (0 == bymonth_len) {
1192                 calendar_time_s *st = &event->start;
1193                 __set_time_to_ucal(event->system_type, ucal, st);
1194                 int month = ucal_get(ucal, UCAL_MONTH, &ec) + 1;
1195                 bymonth[0] = month;
1196                 bymonth_len = 1;
1197         }
1198         DBG("bymonth_len(%d)", bymonth_len);
1199
1200         /* get bymonthday into array */
1201         int bymonthday[CAL_STR_MIDDLE_LEN] = {0};
1202         int bymonthday_len = 0;
1203         _cal_db_instance_parse_byint(event->bymonthday, bymonthday, &bymonthday_len);
1204         if (0 == bymonthday_len) {
1205                 calendar_time_s *st = &event->start;
1206                 __set_time_to_ucal(event->system_type, ucal, st);
1207                 int dtstart_mday = ucal_get(ucal, UCAL_DATE, &ec);
1208                 bymonthday[0] = dtstart_mday;
1209                 bymonthday_len = 1;
1210         }
1211         DBG("bymonthday len(%d)", bymonthday_len);
1212
1213         int bysetpos[CAL_STR_MIDDLE_LEN] = {0};
1214         int bysetpos_len = 0;
1215         _cal_db_instance_parse_byint(event->bysetpos, bysetpos, &bysetpos_len);
1216         DBG("bysetpos len(%d)", bysetpos_len);
1217
1218         GList *list = NULL;
1219         __get_exdate_list(ucal, event, &list);
1220
1221         int loop = 0;
1222         int count = 0;
1223         bool is_exit = false;
1224         long long int last_utime = 0;
1225         long long int current_utime = 0;
1226         while (false == is_exit) {
1227                 calendar_time_s *st = &event->start;
1228                 __set_time_to_ucal(event->system_type, ucal, st);
1229                 long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
1230                 ucal_add(ucal, UCAL_YEAR, event->interval *loop, &ec);
1231                 ucal_setMillis(ucal, ucal_getMillis(ucal, &ec), &ec); /* set start point */
1232
1233                 int i, j;
1234                 for (j = 0; j < bymonth_len; j++) {
1235                         for (i = 0 ; i < bymonthday_len; i++) {
1236                                 if (0 < bymonthday[i]) {
1237                                         ucal_set(ucal, UCAL_MONTH, bymonth[j] - 1);
1238                                         ucal_set(ucal, UCAL_DATE, bymonthday[i]);
1239                                         int get_mday = ucal_get(ucal, UCAL_DATE, &ec);
1240                                         if (get_mday != bymonthday[i]) {
1241                                                 DBG("bymonthday(%d) but get (%d) from icu", bymonthday[i], get_mday);
1242                                                 continue;
1243                                         }
1244                                 } else if (bymonthday[i] < 0) {
1245                                         ucal_set(ucal, UCAL_MONTH, bymonth[j] - 1);
1246                                         ucal_set(ucal, UCAL_DATE, 1);
1247                                         ucal_add(ucal, UCAL_MONTH, 1, &ec);
1248                                         ucal_add(ucal, UCAL_DAY_OF_YEAR, bymonthday[i], &ec);
1249
1250                                 } else { /* 0 is invalid */
1251                                         DBG("Invalid bymonthday(%d)", bymonthday[i]);
1252                                         continue;
1253                                 }
1254                                 if (true == __check_bysetpos_to_skip(i, bysetpos, bysetpos_len, bymonthday_len)) {
1255                                         DBG("no bysetpos");
1256                                         continue;
1257                                 }
1258                                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1259                                 if (true == __check_before_dtstart(current_utime, dtstart_utime))
1260                                         continue;
1261
1262                                 if (true == __check_exdate_to_skip(current_utime, &list)) {
1263                                         count++;
1264                                         continue;
1265                                 }
1266                                 is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1267                                 if (true == is_exit)
1268                                         break;
1269                                 _cal_db_instance_insert_record(ucal, duration, event);
1270                         }
1271                 }
1272                 if (true == is_exit)
1273                         break;
1274                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1275                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
1276                 loop++;
1277         }
1278         if (list)
1279                 g_list_free_full(list, free);
1280         return CALENDAR_ERROR_NONE;
1281 }
1282
1283 static int _cal_db_instance_publish_record_yearly(UCalendar *ucal, cal_event_s *event, long long int duration)
1284 {
1285         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1286         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1287
1288         if (event->byyearday && 0 < strlen(event->byyearday)) {
1289                 _cal_db_instance_publish_yearly_yday(ucal, event, duration);
1290         } else if (event->byweekno && 0 < strlen(event->byweekno)) {
1291                 _cal_db_instance_publish_yearly_weekno(ucal, event, duration);
1292         } else {
1293                 if (event->byday && *event->byday)
1294                         _cal_db_instance_publish_yearly_wday(ucal, event, duration);
1295                 else
1296                         _cal_db_instance_publish_yearly_mday(ucal, event, duration);
1297         }
1298         return CALENDAR_ERROR_NONE;
1299 }
1300
1301 static int _cal_db_instance_publish_monthly_wday(UCalendar *ucal, cal_event_s *event, long long int duration)
1302 {
1303         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1304         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1305
1306         UErrorCode ec = U_ZERO_ERROR;
1307         calendar_time_s until = {0};
1308         __get_until_from_range(event, &until);
1309         __set_time_to_ucal(event->system_type, ucal, &until); /* set until before dtstart_utime */
1310         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
1311
1312         /* get bymonthday into array */
1313         int bymonthday[CAL_STR_MIDDLE_LEN] = {0};
1314         int bymonthday_len = 0;
1315         _cal_db_instance_parse_byint(event->bymonthday, bymonthday, &bymonthday_len);
1316
1317         char **t = NULL;
1318         int byday_len = 0;
1319
1320         /* if nowday in weekly */
1321         if (NULL == event->byday || '\0' == event->byday[0]) {
1322                 const char *week_text[7] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
1323
1324                 calendar_time_s *st = &event->start;
1325                 __set_time_to_ucal(event->system_type, ucal, st);
1326                 int week_nth = ucal_get(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, &ec);
1327                 int dtstart_wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1328                 char buf[CAL_STR_SHORT_LEN32] = {0};
1329                 snprintf(buf, sizeof(buf), "%d%s", week_nth, week_text[dtstart_wday -1]);
1330                 DBG("set byday[%s]", buf);
1331
1332                 t = g_strsplit_set(buf, " ,", -1);
1333                 byday_len = 1;
1334
1335         } else {
1336                 t = g_strsplit_set(event->byday, " ,", -1);
1337                 byday_len = g_strv_length(t);
1338         }
1339         DBG("[%s] byday_len(%d)", event->byday, byday_len);
1340
1341         int bysetpos[CAL_STR_MIDDLE_LEN] = {0};
1342         int bysetpos_len = 0;
1343         _cal_db_instance_parse_byint(event->bysetpos, bysetpos, &bysetpos_len);
1344         DBG("bysetpos len(%d)", bysetpos_len);
1345
1346         GList *list = NULL;
1347         __get_exdate_list(ucal, event, &list);
1348
1349         int loop = 0;
1350         int count = 0;
1351         bool is_exit = false;
1352         long long int last_utime = 0;
1353         long long int current_utime = 0;
1354         while (false == is_exit) {
1355                 calendar_time_s *st = &event->start;
1356                 __set_time_to_ucal(event->system_type, ucal, st);
1357                 long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
1358                 ucal_add(ucal, UCAL_MONTH, event->interval * loop, &ec);
1359                 ucal_setMillis(ucal, ucal_getMillis(ucal, &ec), &ec); /* set start point */
1360
1361                 int i, j, k;
1362                 if (2 < strlen(t[0])) { /* -3SU, +2SA */
1363                         for (i = 0; i < byday_len; i++) {
1364                                 if (0 == strlen(t[i]))
1365                                         continue;
1366                                 /* get nth, wday */
1367                                 int nth = 0;
1368                                 char wday[CAL_STR_SHORT_LEN32] = {0};
1369
1370                                 sscanf(t[i], "%d%s", &nth, wday); /* -3SU, +2SA */
1371                                 DBG("nth(%d) wday[%s]", nth, wday);
1372                                 int wday_int = __convert_wday_to_int(wday);
1373
1374                                 /* set nth, wday */
1375                                 if (0 < nth) {
1376                                         if (4 < nth) {
1377                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1378                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, -1);
1379
1380                                         } else {
1381                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1382                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, 1);
1383                                                 ucal_add(ucal, UCAL_WEEK_OF_YEAR, nth - 1, &ec);
1384                                         }
1385                                 } else {
1386                                         ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1387                                         ucal_set(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, nth);
1388                                 }
1389                                 if (true == __check_bysetpos_to_skip(i, bysetpos, bysetpos_len, byday_len))
1390                                         continue;
1391
1392                                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1393                                 if (true == __check_before_dtstart(current_utime, dtstart_utime))
1394                                         continue;
1395
1396                                 if (true == __check_exdate_to_skip(current_utime, &list)) {
1397                                         count++;
1398                                         continue;
1399                                 }
1400                                 is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1401                                 if (true == is_exit)
1402                                         break;
1403                                 _cal_db_instance_insert_record(ucal, duration, event);
1404                         }
1405
1406                 } else { /* SU, SA: no week num: means all week:1TH,2TH,3TH.., so needs another byevent->system_type */
1407                         int week_bits = 0;
1408                         /* if nowday in weekly */
1409                         if (NULL == event->byday || '\0' == event->byday[0]) {
1410                                 calendar_time_s *st = &event->start;
1411                                 __set_time_to_ucal(event->system_type, ucal, st);
1412                                 int dtstart_wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1413                                 week_bits |= (0x01 << (dtstart_wday - 1));
1414
1415                         } else {
1416                                 week_bits = __convert_week_to_bits(event->byday, NULL);
1417                         }
1418                         DBG("week integer(0x%x)", week_bits);
1419
1420                         if (bymonthday_len) { /* bymonthday */
1421                                 for (j = 0; j < bymonthday_len; j++) {
1422                                         ucal_set(ucal, UCAL_DATE, bymonthday[j]);
1423                                         bool is_match_wday = false;
1424                                         int w = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1425                                         for (k = 0; k < 7; k++) { /* check if this is one of wday */
1426                                                 if (week_bits & (0x01 << k)) {
1427                                                         if ((k + 1) == w) {
1428                                                                 is_match_wday = true;
1429                                                                 break;
1430                                                         }
1431                                                 }
1432                                         }
1433                                         if (false == is_match_wday) {
1434                                                 DBG("get wday(%d) != want wday(%d)", w, k + 1);
1435                                                 continue;
1436                                         }
1437                                         if (true == __check_bysetpos_to_skip(j, bysetpos, bysetpos_len, bymonthday_len))
1438                                                 continue;
1439
1440                                         current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1441                                         if (true == __check_before_dtstart(current_utime, dtstart_utime))
1442                                                 continue;
1443
1444                                         if (true == __check_exdate_to_skip(current_utime, &list)) {
1445                                                 count++;
1446                                                 continue;
1447                                         }
1448                                         is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1449                                         if (true == is_exit)
1450                                                 break;
1451                                         _cal_db_instance_insert_record(ucal, duration, event);
1452                                 }
1453
1454                         } else {
1455                                 int year = ucal_get(ucal, UCAL_YEAR, &ec);
1456                                 int month = ucal_get(ucal, UCAL_MONTH, &ec) + 1;
1457
1458                                 ucal_set(ucal, UCAL_MONTH, month - 1);
1459                                 ucal_set(ucal, UCAL_DATE, 1);
1460                                 int byday_start = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1461
1462                                 int dates_len = 0;
1463                                 __get_dates_in_month(ucal, week_bits, month, &dates_len);
1464                                 DBG("month(%d) dates_len (%d)", month, dates_len);
1465
1466                                 int index = -1;
1467                                 for (j = 0; j < 6; j++) { /* check weekno in month: max 6 */
1468                                         for (k = 0; k < 7; k++) {
1469                                                 if (0 == (week_bits & (0x01 << ((byday_start -1 +k)%7)))) continue;
1470                                                 index++;
1471
1472                                                 int wday_int = (byday_start -1 +k) %7 + 1;
1473                                                 ucal_set(ucal, UCAL_WEEK_OF_MONTH, (j + 1) + (byday_start -1 +k) / 7);
1474                                                 if (year != ucal_get(ucal, UCAL_YEAR, &ec)) ucal_set(ucal, UCAL_YEAR, year);
1475                                                 ucal_set(ucal, UCAL_MONTH, month - 1);
1476                                                 ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1477
1478                                                 int get_month = ucal_get(ucal, UCAL_MONTH, &ec) + 1;
1479                                                 if (month != get_month) { j = 6; break; }
1480
1481                                                 if (true == __check_bysetpos_to_skip(index, bysetpos, bysetpos_len, dates_len))
1482                                                         continue;
1483
1484                                                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1485                                                 if (true == __check_before_dtstart(current_utime, dtstart_utime))
1486                                                         continue;
1487
1488                                                 if (true == __check_exdate_to_skip(current_utime, &list)) {
1489                                                         count++;
1490                                                         continue;
1491                                                 }
1492                                                 is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1493                                                 if (true == is_exit)
1494                                                         break;
1495                                                 _cal_db_instance_insert_record(ucal, duration, event);
1496                                         }
1497                                         if (true == is_exit)
1498                                                 break;
1499                                 }
1500                         }
1501                 }
1502                 if (true == is_exit)
1503                         break;
1504                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1505                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
1506                 loop++;
1507         }
1508         g_strfreev(t);
1509         if (list)
1510                 g_list_free_full(list, free);
1511         return CALENDAR_ERROR_NONE;
1512 }
1513
1514 static int _cal_db_instance_publish_monthly_mday(UCalendar *ucal, cal_event_s *event, long long int duration)
1515 {
1516         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1517         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1518
1519         UErrorCode ec = U_ZERO_ERROR;
1520         calendar_time_s until = {0};
1521         __get_until_from_range(event, &until);
1522         __set_time_to_ucal(event->system_type, ucal, &until); /* set until before dtstart_utime */
1523         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
1524
1525         /* get bymonthday into array */
1526         int bymonthday[CAL_STR_MIDDLE_LEN] = {0};
1527         int bymonthday_len = 0;
1528         _cal_db_instance_parse_byint(event->bymonthday, bymonthday, &bymonthday_len);
1529         if (0 == bymonthday_len) {
1530                 calendar_time_s *st = &event->start;
1531                 __set_time_to_ucal(event->system_type, ucal, st);
1532                 int dtstart_mday = ucal_get(ucal, UCAL_DATE, &ec);
1533                 bymonthday[0] = dtstart_mday;
1534                 bymonthday_len = 1;
1535         }
1536         DBG("bymonthday_len(%d) [%s]", bymonthday_len, event->bymonthday);
1537
1538         int bysetpos[CAL_STR_MIDDLE_LEN] = {0};
1539         int bysetpos_len = 0;
1540         _cal_db_instance_parse_byint(event->bysetpos, bysetpos, &bysetpos_len);
1541         DBG("bysetpos_len(%d)", bysetpos_len);
1542
1543         GList *list = NULL;
1544         __get_exdate_list(ucal, event, &list);
1545
1546         int loop = 0;
1547         int count = 0;
1548         bool is_exit = false;
1549         long long int last_utime = 0;
1550         long long int current_utime = 0;
1551         while (false == is_exit) {
1552                 calendar_time_s *st = &event->start;
1553                 __set_time_to_ucal(event->system_type, ucal, st);
1554                 long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
1555                 ucal_add(ucal, UCAL_MONTH, event->interval * loop, &ec);
1556                 ucal_setMillis(ucal, ucal_getMillis(ucal, &ec), &ec); /* set start point */
1557
1558                 int i;
1559                 for (i = 0 ; i < bymonthday_len; i++) {
1560                         if (0 < bymonthday[i]) {
1561                                 ucal_set(ucal, UCAL_MONTH, ucal_get(ucal, UCAL_MONTH, &ec));
1562                                 ucal_set(ucal, UCAL_DATE, bymonthday[i]);
1563                                 int get_mday = ucal_get(ucal, UCAL_DATE, &ec);
1564                                 if (get_mday != bymonthday[i]) {
1565                                         DBG("bymonthday(%d) but get (%d) from icu", bymonthday[i], get_mday);
1566                                         continue;
1567                                 }
1568                         } else if (bymonthday[i] < 0) {
1569                                 ucal_set(ucal, UCAL_DATE, 1);
1570                                 ucal_add(ucal, UCAL_MONTH, 1, &ec);
1571                                 ucal_add(ucal, UCAL_DAY_OF_YEAR, bymonthday[i], &ec);
1572
1573                         } else { /* 0 is invalid */
1574                                 DBG("Invalid bymonthday(%d)", bymonthday[i]);
1575                                 continue;
1576                         }
1577                         if (true == __check_bysetpos_to_skip(i, bysetpos, bysetpos_len, bymonthday_len))
1578                                 continue;
1579
1580                         current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1581                         if (true == __check_before_dtstart(current_utime, dtstart_utime))
1582                                 continue;
1583
1584                         if (true == __check_exdate_to_skip(current_utime, &list)) {
1585                                 count++;
1586                                 continue;
1587                         }
1588                         is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1589                         if (true == is_exit)
1590                                 break;
1591                         _cal_db_instance_insert_record(ucal, duration, event);
1592                 }
1593                 if (true == is_exit)
1594                         break;
1595                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1596                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
1597                 loop++;
1598         }
1599         if (list)
1600                 g_list_free_full(list, free);
1601         return CALENDAR_ERROR_NONE;
1602 }
1603
1604 static int _cal_db_instance_publish_record_monthly(UCalendar *ucal, cal_event_s *event, long long int duration)
1605 {
1606         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1607         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1608
1609         if (event->byday && 0 < strlen(event->byday))
1610                 _cal_db_instance_publish_monthly_wday(ucal, event, duration);
1611         else
1612                 _cal_db_instance_publish_monthly_mday(ucal, event, duration);
1613
1614         return CALENDAR_ERROR_NONE;
1615 }
1616
1617 static int _cal_db_instance_publish_weekly_wday(UCalendar *ucal, cal_event_s *event, long long int duration)
1618 {
1619         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1620         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1621
1622         UErrorCode ec = U_ZERO_ERROR;
1623         calendar_time_s until = {0};
1624         __get_until_from_range(event, &until);
1625         __set_time_to_ucal(event->system_type, ucal, &until); /* set until before dtstart_utime */
1626         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
1627
1628         int week_bits = 0;
1629         int byday_len = 0;
1630         /* if nowday in weekly */
1631         if (NULL == event->byday || '\0' == event->byday[0]) {
1632                 calendar_time_s *st = &event->start;
1633                 __set_time_to_ucal(event->system_type, ucal, st);
1634                 int dtstart_wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &ec);
1635                 week_bits |= (0x01 << (dtstart_wday - 1));
1636
1637         } else {
1638                 week_bits = __convert_week_to_bits(event->byday, &byday_len);
1639         }
1640         DBG("week integer(0x%x)", week_bits);
1641
1642         int bysetpos[CAL_STR_MIDDLE_LEN] = {0};
1643         int bysetpos_len = 0;
1644         _cal_db_instance_parse_byint(event->bysetpos, bysetpos, &bysetpos_len);
1645         DBG("bysetpos len(%d)", bysetpos_len);
1646
1647         GList *list = NULL;
1648         __get_exdate_list(ucal, event, &list);
1649
1650         int byday_start = ucal_getAttribute(ucal, UCAL_FIRST_DAY_OF_WEEK);
1651         DBG("get first day of week(%d)", byday_start);
1652
1653         int loop = 0;
1654         int count = 0;
1655         bool is_exit = false;
1656         long long int last_utime = 0;
1657         long long int current_utime = 0;
1658         while (false == is_exit) {
1659                 calendar_time_s *st = &event->start;
1660                 __set_time_to_ucal(event->system_type, ucal, st);
1661                 long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
1662                 ucal_add(ucal, UCAL_WEEK_OF_YEAR, event->interval *loop, &ec);
1663                 ucal_setMillis(ucal, ucal_getMillis(ucal, &ec), &ec); /* set start point */
1664
1665                 int i;
1666                 int index = -1;
1667                 for (i = 0; i < 7; i++) {
1668                         if (0 == (week_bits & (0x01 << ((byday_start -1 +i)%7))))
1669                                 continue;
1670                         index++;
1671
1672                         int wday_int = (byday_start -1 +i) %7 + 1;
1673                         ucal_set(ucal, UCAL_DAY_OF_WEEK, wday_int);
1674
1675                         if (true == __check_bysetpos_to_skip(index, bysetpos, bysetpos_len, byday_len))
1676                                 continue;
1677
1678                         current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1679                         if (true == __check_before_dtstart(current_utime, dtstart_utime))
1680                                 continue;
1681
1682                         if (true == __check_exdate_to_skip(current_utime, &list)) {
1683                                 count++;
1684                                 continue;
1685                         }
1686                         is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1687                         if (true == is_exit)
1688                                 break;
1689                         _cal_db_instance_insert_record(ucal, duration, event);
1690                 }
1691                 if (true == is_exit)
1692                         break;
1693                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1694                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
1695                 loop++;
1696         }
1697         if (list)
1698                 g_list_free_full(list, free);
1699         return CALENDAR_ERROR_NONE;
1700 }
1701
1702 static int _cal_db_instance_publish_record_weekly(UCalendar *ucal, cal_event_s *event, long long int duration)
1703 {
1704         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1705         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1706
1707         _cal_db_instance_publish_weekly_wday(ucal, event, duration);
1708         return CALENDAR_ERROR_NONE;
1709 }
1710
1711 static int _cal_db_instance_publish_daily_mday(UCalendar *ucal, cal_event_s *event, long long int duration)
1712 {
1713         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1714         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1715
1716         UErrorCode ec = U_ZERO_ERROR;
1717         calendar_time_s until = {0};
1718         __get_until_from_range(event, &until);
1719         __set_time_to_ucal(event->system_type, ucal, &until); /* set until before dtstart_utime */
1720         long long int until_utime = ms2sec(ucal_getMillis(ucal, &ec));
1721
1722         /* get bymonth into array */
1723         int bymonth[12] = {0};
1724         int bymonth_len = 0;
1725         _cal_db_instance_parse_byint(event->bymonth, bymonth, &bymonth_len);
1726
1727         GList *list = NULL;
1728         __get_exdate_list(ucal, event, &list);
1729
1730         calendar_time_s *st = &event->start;
1731         __set_time_to_ucal(event->system_type, ucal, st);
1732         long long int dtstart_utime = ms2sec(ucal_getMillis(ucal, &ec));
1733         DBG("(%lld)", ms2sec(ucal_getMillis(ucal, &ec)));
1734
1735         int loop = 0;
1736         int count = 0;
1737         bool is_exit = false;
1738         long long int last_utime = 0;
1739         long long int current_utime = 0;
1740         int log_value = 0;
1741         while (false == is_exit) {
1742                 if (loop) ucal_add(ucal, UCAL_DAY_OF_YEAR, event->interval, &ec);
1743
1744                 if (true == __check_daily_bymonth_to_skip(ucal, bymonth, bymonth_len, &log_value)) {
1745                         if (0 == loop) loop = 1;
1746                         continue;
1747                 }
1748                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1749                 if (true == __check_before_dtstart(current_utime, dtstart_utime)) {
1750                         if (0 == loop) loop = 1;
1751                         continue;
1752                 }
1753                 if (true == __check_exdate_to_skip(current_utime, &list)) {
1754                         if (0 == loop) loop = 1;
1755                         count++;
1756                         continue;
1757                 }
1758                 is_exit = __check_out_of_range(current_utime, event, until_utime, &count);
1759                 if (true == is_exit) break;
1760                 _cal_db_instance_insert_record(ucal, duration, event);
1761
1762                 current_utime = ms2sec(ucal_getMillis(ucal, &ec));
1763                 is_exit = __check_to_stop_loop(current_utime, &last_utime, loop);
1764                 loop++;
1765         }
1766         if (list)
1767                 g_list_free_full(list, free);
1768         return CALENDAR_ERROR_NONE;
1769 }
1770
1771 static int _cal_db_instance_publish_record_daily(UCalendar *ucal, cal_event_s *event, long long int duration)
1772 {
1773         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1774         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1775
1776         _cal_db_instance_publish_daily_mday(ucal, event, duration);
1777         return CALENDAR_ERROR_NONE;
1778 }
1779
1780 static int _cal_db_instance_publish_record_once(UCalendar *ucal, cal_event_s *event, long long int duration)
1781 {
1782         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1783         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1784
1785         calendar_time_s *st = &event->start;
1786         __set_time_to_ucal(event->system_type, ucal, st);
1787         _cal_db_instance_insert_record(ucal, duration, event);
1788         return CALENDAR_ERROR_NONE;
1789 }
1790
1791 static int _cal_db_instance_publish_record_details(UCalendar *ucal, cal_event_s *event)
1792 {
1793         RETV_IF(NULL == ucal, CALENDAR_ERROR_INVALID_PARAMETER);
1794         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
1795
1796         long long int duration = -1;
1797         int exception_freq = 0; /* for exception */
1798
1799         _cal_db_instance_get_duration(ucal, &event->start, &event->end, &duration);
1800         WARN_IF(duration < 0, "Invalid duration (%lld)", duration);
1801
1802         if (0 < event->original_event_id) {
1803                 DBG("this is exception event so publish only one instance");
1804                 exception_freq = event->freq;
1805                 event->freq = CALENDAR_RECURRENCE_NONE;
1806         }
1807
1808         DBG("event interval(%d)", event->interval);
1809         if (event->interval < 1) {
1810                 DBG("Invalid interval, so set 1");
1811                 event->interval = 1;
1812         }
1813
1814         switch (event->freq) {
1815         case CALENDAR_RECURRENCE_YEARLY:
1816                 _cal_db_instance_publish_record_yearly(ucal, event, duration);
1817                 break;
1818
1819         case CALENDAR_RECURRENCE_MONTHLY:
1820                 _cal_db_instance_publish_record_monthly(ucal, event, duration);
1821                 break;
1822
1823         case CALENDAR_RECURRENCE_WEEKLY:
1824                 _cal_db_instance_publish_record_weekly(ucal, event, duration);
1825                 break;
1826
1827         case CALENDAR_RECURRENCE_DAILY:
1828                 _cal_db_instance_publish_record_daily(ucal, event, duration);
1829                 break;
1830
1831         case CALENDAR_RECURRENCE_NONE:
1832         default:
1833                 _cal_db_instance_publish_record_once(ucal, event, duration);
1834                 break;
1835         }
1836
1837         if (0 < event->original_event_id) {
1838                 DBG("return freq for exception event");
1839                 event->freq = exception_freq;
1840         }
1841
1842         return CALENDAR_ERROR_NONE;
1843 }
1844
1845 int cal_db_instance_update_exdate_del(int id, char *exdate)
1846 {
1847         int ret = 0;
1848         char query[CAL_DB_SQL_MAX_LEN] = {0};
1849         char **t = NULL;
1850         char *p = NULL;
1851
1852         if (NULL == exdate || '\0' == *exdate) {
1853                 DBG("Nothing to update exdate del");
1854                 return CALENDAR_ERROR_NONE;
1855         }
1856
1857         DBG("exdate[%s]", exdate);
1858         t = g_strsplit_set(exdate, " ,", -1);
1859         if (NULL == t) {
1860                 /* LCOV_EXCL_START */
1861                 ERR("g_strsplit_set() Fail");
1862                 return CALENDAR_ERROR_OUT_OF_MEMORY;
1863                 /* LCOV_EXCL_STOP */
1864         }
1865
1866         int i;
1867         for (i = 0; t[i]; i++) {
1868                 if (NULL == t[i] || '\0' == *t[i]) continue;
1869
1870                 int y = 0, m = 0, d = 0;
1871                 int h = 0, n = 0, s = 0;
1872
1873                 p = t[i];
1874                 DBG("exdate[%s]", p);
1875                 int len = strlen(p);
1876                 switch (len) {
1877                 case 8: /* 20141212 */
1878                         DBG("ALLDAY instance");
1879                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDD, &y, &m, &d);
1880                         snprintf(query, sizeof(query), "DELETE FROM %s "
1881                                         "WHERE event_id = %d AND dtstart_datetime = '%04d-%02d-%02dT%02d:%02d:%02d' ",
1882                                         CAL_TABLE_ALLDAY_INSTANCE, id, y, m, d, h, n, s);
1883                         break;
1884
1885                 case 15: /* 20141212T000000 */
1886                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
1887                         snprintf(query, sizeof(query), "DELETE FROM %s "
1888                                         "WHERE event_id = %d AND dtstart_datetime = '%04d-%02d-%02dT%02d:%02d:%02d' ",
1889                                         CAL_TABLE_ALLDAY_INSTANCE, id, y, m, d, h, n, s);
1890                         DBG("localtime instance");
1891                         break;
1892
1893                 case 16: /* 20141212T000000Z */
1894                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ, &y, &m, &d, &h, &n, &s);
1895                         snprintf(query, sizeof(query), "DELETE FROM %s "
1896                                         "WHERE event_id = %d AND dtstart_utime = %lld ",
1897                                         CAL_TABLE_NORMAL_INSTANCE, id, cal_time_convert_itol(NULL, y, m, d, h, n, s));
1898                         DBG("normal instance (%lld)", cal_time_convert_itol(NULL, y, m, d, h, n, s));
1899                         break;
1900                 }
1901
1902                 ret = cal_db_util_query_exec(query);
1903                 if (CALENDAR_ERROR_NONE != ret) {
1904                         /* LCOV_EXCL_START */
1905                         ERR("cal_db_util_query_exec() Fail(%d)", ret);
1906                         SECURE("[%s]", query);
1907                         g_strfreev(t);
1908                         return ret;
1909                         /* LCOV_EXCL_STOP */
1910                 }
1911         }
1912         g_strfreev(t);
1913         return CALENDAR_ERROR_NONE;
1914 }
1915
1916 int cal_db_instance_publish_record(calendar_record_h record)
1917 {
1918         RETV_IF(NULL == record, CALENDAR_ERROR_INVALID_PARAMETER);
1919
1920         cal_event_s *event = NULL;
1921         event = (cal_event_s *)(record);
1922
1923         char *tzid = NULL;
1924         int offset = 0;
1925         int sign = 0;
1926         char buf[CAL_STR_SHORT_LEN32] = {0};
1927         switch (event->start.type) {
1928         case CALENDAR_TIME_UTIME:
1929                 if (NULL == event->start_tzid) {
1930                         tzid = NULL;
1931                         break;
1932                 }
1933                 if (true == cal_time_is_available_tzid(event->start_tzid)) {
1934                         tzid = event->start_tzid;
1935                         break;
1936                 }
1937                 cal_db_timezone_get_offset(event->calendar_id, event->start_tzid, &offset);
1938                 if (0 == offset) {
1939                         tzid = NULL;
1940                         break;
1941                 }
1942                 DBG("offset(%d)", offset);
1943                 sign = offset < 0 ? -1 : 1;
1944                 offset /= 60;
1945                 offset *= sign;
1946                 snprintf(buf, sizeof(buf), "Etc/GMT%c%d", sign < 0 ? '-' : '+', offset);
1947                 tzid = buf;
1948                 DBG("set tzid[%s]", buf);
1949                 break;
1950
1951         case CALENDAR_TIME_LOCALTIME:
1952                 tzid = NULL;
1953                 break;
1954         }
1955
1956         UCalendar *ucal = cal_time_open_ucal(event->system_type, tzid, event->wkst);
1957
1958         _cal_db_instance_publish_record_details(ucal, event);
1959         _cal_db_instance_del_inundant(event->index, &event->start, event);
1960         _cal_db_instance_update_exdate_mod(event->original_event_id, event->recurrence_id);
1961
1962         ucal_close(ucal);
1963
1964         return CALENDAR_ERROR_NONE;
1965 }
1966
1967 int cal_db_instance_get_now(long long int *current)
1968 {
1969         *current = ms2sec(ucal_getNow());
1970         return CALENDAR_ERROR_NONE;
1971 }
1972
1973 int cal_db_instance_discard_record(int index)
1974 {
1975         char query[CAL_DB_SQL_MAX_LEN] = {0};
1976         int ret = 0;
1977
1978         DBG("delete normal");
1979         snprintf(query, sizeof(query), "DELETE FROM %s WHERE event_id = %d ",
1980                         CAL_TABLE_NORMAL_INSTANCE, index);
1981
1982         ret = cal_db_util_query_exec(query);
1983         if (CALENDAR_ERROR_NONE != ret) {
1984                 /* LCOV_EXCL_START */
1985                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
1986                 SECURE("[%s]", query);
1987                 return ret;
1988                 /* LCOV_EXCL_STOP */
1989         }
1990
1991         DBG("delete allday");
1992         snprintf(query, sizeof(query), "DELETE FROM %s WHERE event_id = %d ",
1993                         CAL_TABLE_ALLDAY_INSTANCE, index);
1994
1995         ret = cal_db_util_query_exec(query);
1996         if (CALENDAR_ERROR_NONE != ret) {
1997                 /* LCOV_EXCL_START */
1998                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
1999                 SECURE("[%s]", query);
2000                 return ret;
2001                 /* LCOV_EXCL_STOP */
2002         }
2003         return CALENDAR_ERROR_NONE;
2004 }
2005