add comment LCOV_EXCL
[platform/core/pim/calendar-service.git] / common / cal_vcalendar_parse.c
1 /*
2  * Calendar Service
3  *
4  * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdlib.h>
21 #include <ctype.h>
22
23 #include "calendar_list.h"
24 #include "cal_internal.h"
25 #include "cal_typedef.h"
26 #include "cal_record.h"
27 #include "cal_view.h"
28 #include "cal_time.h"
29 #include "cal_vcalendar.h"
30 #include "cal_vcalendar_parse.h"
31 #include "cal_utils.h"
32
33 /*
34  * LF | \n | 0x0A
35  * CR | \r | 0x0D
36  */
37 #define VCAL_LF 0x0A
38 #define VCAL_CR 0x0D
39
40 struct user_data {
41         char *timezone_tzid; /* TZ(ver1) VTIMEZONE(ver2) */
42         char *datetime_tzid; /* in vevent, vtodo as param: TZID=US-Eastern */
43         int version;
44         int type; /* event, todo */
45         bool is_allday;
46         bool has_rrule;
47 };
48
49 enum {
50         VCAL_RELATED_NONE,
51         VCAL_RELATED_START,
52         VCAL_RELATED_END,
53 };
54
55 enum {
56         VCAL_RECURRENCE_NONE,
57         VCAL_RECURRENCE_YEARLY_BYYEARDAY,
58         VCAL_RECURRENCE_YEARLY_BYWEEKLY,
59         VCAL_RECURRENCE_YEARLY_BYMONTH,
60         VCAL_RECURRENCE_YEARLY_BYMONTHDAY,
61         VCAL_RECURRENCE_YEARLY_BYDAY,
62         VCAL_RECURRENCE_MONTHLY_BYMONTHDAY,
63         VCAL_RECURRENCE_MONTHLY_BYDAY,
64         VCAL_RECURRENCE_WEEKLY,
65         VCAL_RECURRENCE_DAILY,
66 };
67
68 enum {
69         VCAL_VER_1 = 1,
70         VCAL_VER_2 = 2,
71 };
72
73 enum {
74         VCAL_DATETIME_LENGTH_YYYYMMDD = 8,
75         VCAL_DATETIME_LENGTH_YYYYMMDDTHHMMSS = 15,
76         VCAL_DATETIME_LENGTH_YYYYMMDDTHHMMSSZ = 16,
77 };
78
79 enum {
80         VCAL_COMPONENT_NONE,
81         VCAL_COMPONENT_VEVENT,
82         VCAL_COMPONENT_VTODO,
83         VCAL_COMPONENT_VJOURNAL,
84         VCAL_COMPONENT_VFREEBUSY,
85         VCAL_COMPONENT_VTIMEZONE,
86         VCAL_COMPONENT_MAX,
87 };
88
89 enum {
90         VCAL_PROPERTY_NONE,
91         VCAL_PROPERTY_VERSION,
92         VCAL_PROPERTY_TZ,
93         VCAL_PROPERTY_BEGIN,
94         VCAL_PROPERTY_END,
95         VCAL_PROPERTY_MAX,
96 };
97
98 enum {
99         VCAL_COMPONENT_PROPERTY_NONE,
100         VCAL_COMPONENT_PROPERTY_DTSTAMP,
101         VCAL_COMPONENT_PROPERTY_UID,
102         VCAL_COMPONENT_PROPERTY_RECURRENCE_ID,
103         VCAL_COMPONENT_PROPERTY_DTSTART,
104         VCAL_COMPONENT_PROPERTY_CREATED,        /* for ver 2: created */
105         VCAL_COMPONENT_PROPERTY_DCREATED,       /* for ver 1: created */
106         VCAL_COMPONENT_PROPERTY_DESCRIPTION,
107         VCAL_COMPONENT_PROPERTY_LAST_MODIFIED,
108         VCAL_COMPONENT_PROPERTY_LOCATION,
109         VCAL_COMPONENT_PROPERTY_PRIORITY,
110         VCAL_COMPONENT_PROPERTY_STATUS,
111         VCAL_COMPONENT_PROPERTY_SUMMARY,
112         VCAL_COMPONENT_PROPERTY_RRULE,
113         VCAL_COMPONENT_PROPERTY_DTEND,
114         VCAL_COMPONENT_PROPERTY_DUE,
115         VCAL_COMPONENT_PROPERTY_ATTENDEE,
116         VCAL_COMPONENT_PROPERTY_CATEGORIES,
117         VCAL_COMPONENT_PROPERTY_DALARM,         /* for ver 1: display alarm */
118         VCAL_COMPONENT_PROPERTY_MALARM,         /* for ver 1: mail alarm */
119         VCAL_COMPONENT_PROPERTY_AALARM,         /* for ver 1: audio alarm */
120         VCAL_COMPONENT_PROPERTY_EXDATE,
121         VCAL_COMPONENT_PROPERTY_X_ALLDAY,
122         VCAL_COMPONENT_PROPERTY_X_LUNAR,
123         VCAL_COMPONENT_PROPERTY_BEGIN,
124         VCAL_COMPONENT_PROPERTY_END,
125         VCAL_COMPONENT_PROPERTY_EXTENDED,
126         VCAL_COMPONENT_PROPERTY_MAX,
127 };
128
129 enum {
130         VCAL_COMPONENT_PROPERTY_VALARM_NONE,
131         VCAL_COMPONENT_PROPERTY_VALARM_ACTION,
132         VCAL_COMPONENT_PROPERTY_VALARM_TRIGGER,
133         VCAL_COMPONENT_PROPERTY_VALARM_REPEAT,
134         VCAL_COMPONENT_PROPERTY_VALARM_ATTACH,
135         VCAL_COMPONENT_PROPERTY_VALARM_DESCRIPTION,
136         VCAL_COMPONENT_PROPERTY_VALARM_SUMMARY,
137         VCAL_COMPONENT_PROPERTY_VALARM_DURATION,
138         VCAL_COMPONENT_PROPERTY_VALARM_END,
139         VCAL_COMPONENT_PROPERTY_VALARM_MAX,
140 };
141
142 enum {
143         VCAL_ENCODING_NONE,
144         VCAL_ENCODING_BASE64,
145         VCAL_ENCODING_QUOTED_PRINTABLE,
146         VCAL_ENCODING_MAX,
147 };
148
149 enum {
150         VCAL_CHARSET_NONE,
151         VCAL_CHARSET_UTF_8,
152         VCAL_CHARSET_UTF_16,
153         VCAL_CHARSET_ISO_8859_1,
154         VCAL_CHARSET_UTF_MAX,
155 };
156
157 enum {
158         VCAL_COMPONENT_PROPERTY_VTIMEZONE_NONE,
159         VCAL_COMPONENT_PROPERTY_VTIMEZONE_DTSTART,
160         VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETFROM,
161         VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETTO,
162         VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZNAME,
163         VCAL_COMPONENT_PROPERTY_VTIMEZONE_RDATE,
164         VCAL_COMPONENT_PROPERTY_VTIMEZONE_END,
165         VCAL_COMPONENT_PROPERTY_VTIMEZONE_MAX,
166 };
167
168 enum {
169         VCAL_VER_10_DALARM_NONE = 0,
170         VCAL_VER_10_DALARM_RUN_TIME,
171         VCAL_VER_10_DALARM_SNOOZE_TIME,
172         VCAL_VER_10_DALARM_REPEAT_COUNT,
173         VCAL_VER_10_DALARM_DISPLAY_STRING,
174 };
175
176 enum {
177         VCAL_VER_10_MALARM_NONE = 0,
178         VCAL_VER_10_MALARM_RUN_TIME,
179         VCAL_VER_10_MALARM_SNOOZE_TIME,
180         VCAL_VER_10_MALARM_REPEAT_COUNT,
181         VCAL_VER_10_MALARM_ADDRESS_STRING,
182         VCAL_VER_10_MALARM_NOTE_STRING,
183 };
184
185 enum {
186         VCAL_VER_10_AALARM_NONE = 0,
187         VCAL_VER_10_AALARM_RUN_TIME,
188         VCAL_VER_10_AALARM_SNOOZE_TIME,
189         VCAL_VER_10_AALARM_REPEAT_COUNT,
190         VCAL_VER_10_AALARM_AUDIO_CONTENT,
191 };
192
193 static const char *vcal_component[VCAL_COMPONENT_MAX] = {0};
194 static void __init_component(void)
195 {
196         if (NULL == *vcal_component) {
197                 vcal_component[VCAL_COMPONENT_VEVENT] = "VEVENT";
198                 vcal_component[VCAL_COMPONENT_VTODO] = "VTODO";
199                 vcal_component[VCAL_COMPONENT_VJOURNAL] = "VJOURNAL";
200                 vcal_component[VCAL_COMPONENT_VFREEBUSY] = "VFREEBUSY";
201                 vcal_component[VCAL_COMPONENT_VTIMEZONE] = "VTIMEZONE";
202         }
203 }
204
205 static const char *vcal_property[VCAL_PROPERTY_MAX] = {0};
206 static void __init_property(void)
207 {
208         if (NULL == *vcal_property) {
209                 vcal_property[VCAL_PROPERTY_VERSION] = "VERSION";
210                 vcal_property[VCAL_PROPERTY_TZ] = "TZ";
211                 vcal_property[VCAL_PROPERTY_BEGIN] = "BEGIN";
212                 vcal_property[VCAL_PROPERTY_END] = "END";
213         }
214 }
215
216 static const char *component_property[VCAL_COMPONENT_PROPERTY_MAX] = {0};
217 static void __init_component_property(void)
218 {
219         if (NULL == *component_property) {
220                 component_property[VCAL_COMPONENT_PROPERTY_DTSTAMP] = "DTSTAMP";
221                 component_property[VCAL_COMPONENT_PROPERTY_UID] = "UID";
222                 component_property[VCAL_COMPONENT_PROPERTY_RECURRENCE_ID] = "RECURRENCE-ID";
223                 component_property[VCAL_COMPONENT_PROPERTY_DTSTART] = "DTSTART";
224                 component_property[VCAL_COMPONENT_PROPERTY_CREATED] = "CREATED";        /* for ver 2: created */
225                 component_property[VCAL_COMPONENT_PROPERTY_DCREATED] = "DCREATED";      /* for ver 1: created */
226                 component_property[VCAL_COMPONENT_PROPERTY_DESCRIPTION] = "DESCRIPTION";
227                 component_property[VCAL_COMPONENT_PROPERTY_LAST_MODIFIED] = "LAST-MODIFIED";
228                 component_property[VCAL_COMPONENT_PROPERTY_LOCATION] = "LOCATION";
229                 component_property[VCAL_COMPONENT_PROPERTY_PRIORITY] = "PRIORITY";
230                 component_property[VCAL_COMPONENT_PROPERTY_STATUS] = "STATUS";
231                 component_property[VCAL_COMPONENT_PROPERTY_SUMMARY] = "SUMMARY";
232                 component_property[VCAL_COMPONENT_PROPERTY_RRULE] = "RRULE";
233                 component_property[VCAL_COMPONENT_PROPERTY_DTEND] = "DTEND";
234                 component_property[VCAL_COMPONENT_PROPERTY_DUE] = "DUE";
235                 component_property[VCAL_COMPONENT_PROPERTY_ATTENDEE] = "ATTENDEE";
236                 component_property[VCAL_COMPONENT_PROPERTY_CATEGORIES] = "CATEGORIES";
237                 component_property[VCAL_COMPONENT_PROPERTY_DALARM] = "DALARM";
238                 component_property[VCAL_COMPONENT_PROPERTY_MALARM] = "MALARM";
239                 component_property[VCAL_COMPONENT_PROPERTY_AALARM] = "AALARM";
240                 component_property[VCAL_COMPONENT_PROPERTY_EXDATE] = "EXDATE";
241                 component_property[VCAL_COMPONENT_PROPERTY_X_ALLDAY] = "X-ALLDAY";
242                 component_property[VCAL_COMPONENT_PROPERTY_X_LUNAR] = "X-LUNAR";
243                 component_property[VCAL_COMPONENT_PROPERTY_BEGIN] = "BEGIN";    /* start alarm component */
244                 component_property[VCAL_COMPONENT_PROPERTY_END] = "END";                /* exit record component */
245                 component_property[VCAL_COMPONENT_PROPERTY_EXTENDED] = "X-";
246         }
247 };
248
249 static const char *component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_MAX] = {0};
250 static void __init_component_property_valarm(void)
251 {
252         if (NULL == *component_property_valarm) {
253                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_ACTION] = "ACTION";
254                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_TRIGGER] = "TRIGGER";
255                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_REPEAT] = "REPEAT";
256                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_ATTACH] = "ATTACH";
257                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_DESCRIPTION] = "DESCRIPTION";
258                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_SUMMARY] = "SUMMARY";
259                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_DURATION] = "DURATION";
260                 component_property_valarm[VCAL_COMPONENT_PROPERTY_VALARM_END] = "END";
261         }
262 }
263
264 static const char *component_property_vtimezone[VCAL_COMPONENT_PROPERTY_VTIMEZONE_MAX] = {0};
265 static void __init_component_property_vtimezone(void)
266 {
267         if (NULL == *component_property_vtimezone) {
268                 component_property_vtimezone[VCAL_COMPONENT_PROPERTY_VTIMEZONE_DTSTART] = "DTSTART";
269                 component_property_vtimezone[VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETFROM] = "TZOFFSETFROM";
270                 component_property_vtimezone[VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETTO] = "TZOFFSETTO";
271                 component_property_vtimezone[VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZNAME] = "TZNAME";
272                 component_property_vtimezone[VCAL_COMPONENT_PROPERTY_VTIMEZONE_RDATE] = "RDATE";
273                 component_property_vtimezone[VCAL_COMPONENT_PROPERTY_VTIMEZONE_END] = "END";
274         }
275 };
276
277 static inline void __print_cursor(char *cursor, int line)
278 {
279         int i;
280         DBG("(%d)", line);
281         for (i = 0; i < 5; i++) {
282                 if (VCAL_CR == *(cursor + i) || VCAL_LF == *(cursor + i)) break;
283                 DBG("[%c]", *(cursor + i));
284         }
285 }
286
287 static inline void __free_user_data(struct user_data *ud)
288 {
289         if (ud) {
290                 if (ud->timezone_tzid) free(ud->timezone_tzid);
291                 if (ud->datetime_tzid) free(ud->datetime_tzid);
292                 free(ud);
293         }
294 }
295
296 static inline char* __remove_empty_line(char *src)
297 {
298         while (*src) {
299                 if ('\n' != *src && '\r' != *src)
300                         break;
301                 src++;
302         }
303         return src;
304 }
305
306 static inline char* __remove_invalid_space(char *src)
307 {
308         bool start = false;
309         while (*src) {
310                 switch (*src) {
311                 case ' ':
312                 case ':':
313                 case ';':
314                         src++;
315                         break;
316                 default:
317                         start = true;
318                         break;
319                 }
320                 if (start) break;
321         }
322         return src;
323 }
324
325 static inline char* __crlf(char *p)
326 {
327         RETV_IF(NULL == p, NULL);
328         while (VCAL_LF != *p) {
329                 if ('\0' == *p)
330                         return NULL;
331
332                 p++;
333         }
334         return p +1;
335 }
336
337 static bool __check_has_rrule(char *stream)
338 {
339         RETV_IF(NULL == stream, false);
340
341         bool ret = false;
342         char *cursor = stream;
343         while (*cursor) {
344                 if (*(cursor++) == VCAL_LF) {
345                         if (*(cursor++) == 'R' &&
346                                         *(cursor++) == 'R' &&
347                                         *(cursor++) == 'U' &&
348                                         *(cursor++) == 'L' &&
349                                         *(cursor++) == 'E' &&
350                                         *(cursor++) == ':') {
351                                 return true;
352                         } else if (*(cursor-1) == 'E' &&
353                                         *(cursor++) == 'N' &&
354                                         *(cursor++) == 'D' &&
355                                         *(cursor++) == ':' &&
356                                         *(cursor++) == 'V' &&
357                                         *(cursor++) == 'E' &&
358                                         *(cursor++) == 'V' &&
359                                         *(cursor++) == 'E' &&
360                                         *(cursor++) == 'N' &&
361                                         *(cursor++) == 'T') {
362                                 break;
363                         }
364                 }
365         }
366         return ret;
367 }
368
369 static int _sub_caltime(struct user_data *ud, calendar_time_s *s, calendar_time_s *a, int *diff)
370 {
371         RETV_IF(NULL == s, CALENDAR_ERROR_INVALID_PARAMETER);
372         RETV_IF(NULL == a, CALENDAR_ERROR_INVALID_PARAMETER);
373         RETV_IF(NULL == diff, CALENDAR_ERROR_INVALID_PARAMETER);
374
375         if (s->type != a->type) {
376                 WARN("This is strange. start type(%d) alarm type(%d)", s->type, a->type);
377                 char *tz = NULL;
378                 if (ud->timezone_tzid)
379                         tz = ud->timezone_tzid;
380                 else if (ud->datetime_tzid)
381                         tz = ud->datetime_tzid;
382                 else
383                         tz = NULL;
384
385                 long long int lli = 0;
386                 if (CALENDAR_TIME_LOCALTIME == s->type) {
387                         lli = cal_time_convert_itol(tz, s->time.date.year, s->time.date.month,
388                                         s->time.date.mday, s->time.date.hour, s->time.date.minute,
389                                         s->time.date.second);
390                         *diff = lli - a->time.utime;
391                         DBG("Convert start localtime with tz[%s] and get(%lld)", tz, lli);
392                 } else {
393                         lli = cal_time_convert_itol(tz, a->time.date.year, a->time.date.month,
394                                         a->time.date.mday, a->time.date.hour, a->time.date.minute,
395                                         a->time.date.second);
396                         *diff = s->time.utime - lli;
397                         DBG("Convert alarm localtime with tz[%s] and get(%lld)", tz, lli);
398                 }
399                 return CALENDAR_ERROR_NONE;
400         }
401         switch (s->type) {
402         case CALENDAR_TIME_UTIME:
403                 *diff = s->time.utime - a->time.utime;
404                 break;
405         case CALENDAR_TIME_LOCALTIME:
406                 *diff = cal_time_convert_itol(NULL, s->time.date.year, s->time.date.month,
407                                 s->time.date.mday, s->time.date.hour, s->time.date.minute, s->time.date.second) -
408                         cal_time_convert_itol(NULL, a->time.date.year, a->time.date.month,
409                                         a->time.date.mday, a->time.date.hour, a->time.date.minute, a->time.date.second);
410                 break;
411         }
412         return CALENDAR_ERROR_NONE;
413 }
414
415 static void _get_tick_unit(int t, int *tick, int *unit)
416 {
417         if (0 == t)
418                 return;
419
420         if (0 == (t % CALENDAR_ALARM_TIME_UNIT_WEEK)) {
421                 *tick = t / CALENDAR_ALARM_TIME_UNIT_WEEK;
422                 *unit = CALENDAR_ALARM_TIME_UNIT_WEEK;
423         } else if (0 == (t % CALENDAR_ALARM_TIME_UNIT_DAY)) {
424                 *tick = t / CALENDAR_ALARM_TIME_UNIT_DAY;
425                 *unit = CALENDAR_ALARM_TIME_UNIT_DAY;
426         } else if (0 == (t % CALENDAR_ALARM_TIME_UNIT_HOUR)) {
427                 *tick = t / CALENDAR_ALARM_TIME_UNIT_HOUR;
428                 *unit = CALENDAR_ALARM_TIME_UNIT_HOUR;
429         } else if (0 == (t % CALENDAR_ALARM_TIME_UNIT_MINUTE)) {
430                 *tick = t / CALENDAR_ALARM_TIME_UNIT_MINUTE;
431                 *unit = CALENDAR_ALARM_TIME_UNIT_MINUTE;
432         } else {
433                 *tick = t;
434                 *unit = CALENDAR_ALARM_TIME_UNIT_SPECIFIC;
435         }
436         DBG("tick(%d), unit(%d)", *tick, *unit);
437 }
438
439 static char* __get_value(char *cursor, char **value)
440 {
441         RETV_IF(NULL == cursor, NULL);
442         RETV_IF(NULL == value, NULL);
443
444         /* offset: length until ';' or ':' */
445         int offset = 0;
446         while (':' != *(cursor + offset) && ';' != *(cursor + offset))
447                 offset++;
448
449         int i = 0;
450         while (VCAL_LF != *(cursor + offset + i)) {
451                 if ('\0' == *(cursor + offset + i))
452                         return NULL;
453
454                 i++;
455         }
456
457         char *p = calloc(i + 1, sizeof(char));
458         RETVM_IF(NULL == p, NULL, "calloc() Fail");
459
460         if (VCAL_CR == *(cursor + offset + i -1))
461                 memcpy(p, cursor + offset, i -1);
462         else
463                 memcpy(p, cursor + offset, i);
464
465         *value = p;
466         DBG("offset(%d) len(%d) value[%s]", offset, i, *value);
467
468         return cursor + offset + i +1;
469 }
470
471 static char* __check_word(char *src, const char *word)
472 {
473         RETV_IF(NULL == src, NULL);
474
475         src = __remove_empty_line(src);
476         src = __remove_invalid_space(src);
477
478         while (*src == *word) {
479                 src++;
480                 word++;
481
482                 if ('\0' == *src || '\0' == *word)
483                         break;
484         }
485
486         if ('\0' == *word)
487                 return src;
488         else
489                 return NULL;
490 }
491
492 /*
493  * Change '-' to '/' as icu format to be recognized in icu library.
494  * ig. US-Easten -> US/Eastern
495  */
496 static inline void __adjust_tzid(char *p)
497 {
498         RET_IF(NULL == p);
499
500         DBG("Before [%s]", p);
501         int i = 0;
502         while (*(p +i)) {
503                 if ('-' == *(p +i)) {
504                         if ('1' <= *(p +i +1) && *(p +i +1) <= '9')
505                                 i++;
506                         else
507                                 *(p +i) = '/';
508                 }
509                 i++;
510         }
511         DBG("After [%s]", p);
512 }
513
514 static void __unfolding(char *p)
515 {
516         RET_IF(NULL == p);
517         RET_IF('\0' == *p);
518
519         char *q = p;
520         while ('\0' != *p) {
521                 switch (*p) {
522                 case '=':
523                         if (VCAL_LF == *(p +1) && ' ' == *(p +2)) /* ver1.0:out of spec, but allowed exceptional case */
524                                 p += 3;
525                         else if (VCAL_CR == *(p +1) && VCAL_LF == *(p +2) && ' ' == *(p +3)) /* ver1.0:in spec case */
526                                 p += 4;
527                         else if (VCAL_CR == *(p +1) && VCAL_LF == *(p +2)) /* galaxy wants this format */
528                                 p += 3;
529                         else ;
530                         break;
531
532                 case VCAL_LF:
533                         if (' ' == *(p + 1)) /* ver2.0:out of spec, but allowed exceptional case */
534                                 p += 2;
535                         else if ('\t' == *(p + 1)) /* ver2.0:out of spec, but allowed exceptional case */
536                                 p += 2;
537                         else ;
538                         break;
539
540                 case VCAL_CR:
541                         if ('\n' == *(p + 1) && ' ' == *(p + 2)) /* ver2.0:in spec case */
542                                 p += 3;
543                         else if ('\n' == *(p + 1) && '\t' == *(p + 2)) /* ver2.0:out of spec, but allowed exceptional case */
544                                 p += 3;
545                         else ;
546                         break;
547                 }
548
549                 *q = *p;
550                 p++;
551                 q++;
552         }
553 }
554
555 static void __decode_escaped_char(char *p)
556 {
557         RET_IF(NULL == p);
558         RET_IF('\0' == *p);
559
560         char *q = p;
561         while ('\0' != *p) {
562                 if ('\\' == *p && *(p +1)) {
563                         switch (*(p +1)) {
564                         case '\\':
565                                 *q = '\\';
566                                 p++;
567                                 break;
568                         case 'n':
569                         case 'N':
570                                 *q = '\n';
571                                 p++;
572                                 break;
573                         case ';':
574                                 *q = ';';
575                                 p++;
576                                 break;
577                         case ',':
578                                 *q = ',';
579                                 p++;
580                                 break;
581                         }
582                 } else {
583                         *q = *p;
584                 }
585                 q++;
586                 p++;
587         }
588         *q = '\0';
589 }
590
591 static void __decode_base64(char *p)
592 {
593         RET_IF(NULL == p);
594         RET_IF('\0' == *p);
595
596         DBG("Before [%s]", p);
597         guchar *buf = NULL;
598         gsize size = 0;
599         buf = g_base64_decode(p, &size);
600         if (0 == size) {
601                 free(buf);
602                 return;
603         }
604         if (strlen(p) < size) {
605                 /* LCOV_EXCL_START */
606                 ERR("out of size");
607                 return;
608                 /* LCOV_EXCL_STOP */
609         }
610
611         snprintf(p, size + 1, "%s%c", buf, '\0');
612         free(buf);
613         DBG("After [%s]", p);
614 }
615
616 static char __decode_hexa(char *p)
617 {
618         int i;
619         char decoded[2] = {0x00, 0x00};
620
621         for (i = 0; i < 2; i++) {
622                 switch (p[i]) {
623                 case '0' ... '9':
624                         decoded[i] = p[i] - '0';
625                         break;
626                 case 'a' ... 'f':
627                         decoded[i] = p[i] - 'a' + 10;
628                         break;
629                 case 'A' ... 'F':
630                         decoded[i] = p[i] - 'A' + 10;
631                         break;
632                 }
633         }
634         return (char)((decoded[0] << 4) + decoded[1]);
635 }
636
637 static void __decode_quoted_printable(char *p)
638 {
639         RET_IF(NULL == p);
640         RET_IF('\0' == *p);
641
642         int i = 0, j = 0;
643         char ch;
644
645         DBG("Before[%s]", p);
646         while (p[i]) {
647                 if (p[i] == '=') {
648                         if (p[i+1] == 0x09 || p[i+1] == 0x20) {
649                                 i += 3;
650                         } else if (p[i+1] == '\r' || p[i+1] == '\n') {
651                                 i += 3;
652                         } else {
653                                 if (p[i+1] == '0' && tolower(p[i+2]) == 'd' &&
654                                                 p[i+3] == '=' && p[i+4] == '0' && tolower(p[i+5]) == 'a') {
655                                         p[j] = '\n';
656                                         j++;
657                                         i += 6;
658                                 } else {
659                                         ch = __decode_hexa(p +i +1);
660                                         p[j] = ch;
661                                         j++;
662                                         i += 3;
663                                 }
664                         }
665                 } else {
666                         p[j] = p[i];
667                         j++;
668                         i++;
669                 }
670         }
671         p[j] = '\0';
672         DBG("After[%s]", p);
673 }
674
675 static char* __decode_iso8859_1_to_utf8(char *p)
676 {
677         RETV_IF(NULL == p, NULL);
678
679         char *src = NULL;
680         char *dst = NULL;
681
682         DBG("Before [%s]", p);
683         int len = strlen(p);
684         len *= 2;
685
686         char *out_p = NULL;
687         out_p = realloc(p, len);
688         if (NULL == out_p) {
689                 /* LCOV_EXCL_START */
690                 ERR("realloc() Fail");
691                 return NULL;
692                 /* LCOV_EXCL_STOP */
693         }
694
695         /* check enough space */
696         for (src = dst = out_p; *src; src++, dst++) {
697                 if (*src & 0x80)
698                         ++dst;
699         }
700
701         while (dst > src) {
702                 if (*src & 0x80) {
703                         *dst-- = 0x80 | (*src & 0x3f);
704                         *dst-- = 0xc0 | (*((unsigned char *)src--) >> 6);
705                 } else {
706                         *dst-- = *src--;
707                 }
708         }
709         DBG("After [%s]", out_p);
710         return out_p;
711 }
712
713 static char* __decode_charset(char *p)
714 {
715         char **t = NULL;
716         t =  g_strsplit(p, ":", 2);
717         RETVM_IF(NULL == t, NULL, "g_strsplit() Fail");
718
719         if ('\0' == *t[0]) { /* no param */
720                 g_strfreev(t);
721                 return cal_strdup(p + 1);
722         }
723
724         char **s = NULL;
725         s = g_strsplit(t[0], ";", -1);
726         if (NULL == s) {
727                 /* LCOV_EXCL_START */
728                 ERR("g_strsplit() Fail");
729                 g_strfreev(t);
730                 return NULL;
731                 /* LCOV_EXCL_STOP */
732         }
733         int count_param = g_strv_length(s);
734         DBG("count_param(%d)", count_param);
735
736         int charset = VCAL_CHARSET_NONE;
737         int encoding = VCAL_ENCODING_NONE;
738
739         int i;
740         for (i = 0; i < count_param; i++) {
741                 if (NULL == s[i] || '\0' == *s[i])
742                         continue;
743
744                 if (CAL_STRING_EQUAL == strncmp(s[i], "CHARSET=", strlen("CHARSET="))) {
745                         int key_len = strlen("CHARSET=");
746                         if (CAL_STRING_EQUAL == strcmp(s[i] + key_len, "UTF-8"))
747                                 charset = VCAL_CHARSET_UTF_8;
748                         else if (CAL_STRING_EQUAL == strcmp(s[i] + key_len, "ISO-8859-1"))
749                                 charset = VCAL_CHARSET_ISO_8859_1;
750                         else
751                                 WARN("Not support charset[%s]", s[i] + key_len);
752                 } else if (CAL_STRING_EQUAL == strncmp(s[i], "ENCODING=", strlen("ENCODING="))) {
753                         int key_len = strlen("ENCODING=");
754                         if (CAL_STRING_EQUAL == strcmp(s[i] + key_len, "BASE64"))
755                                 encoding = VCAL_ENCODING_BASE64;
756                         else if (CAL_STRING_EQUAL == strcmp(s[i] + key_len, "QUOTED-PRINTABLE"))
757                                 encoding = VCAL_ENCODING_QUOTED_PRINTABLE;
758                         else
759                                 WARN("Not support encoding[%s]", s[i] + key_len);
760                 } else {
761                         WARN("[%s]", s[i]);
762                 }
763         }
764         g_strfreev(s);
765         /* param end */
766
767         char *ret_str = strdup(t[1]);
768         g_strfreev(t);
769
770         switch (encoding) {
771         case VCAL_ENCODING_BASE64:
772                 __decode_base64(ret_str);
773                 break;
774         case VCAL_ENCODING_QUOTED_PRINTABLE:
775                 __decode_quoted_printable(ret_str);
776                 break;
777         }
778
779         switch (charset) {
780         case VCAL_CHARSET_UTF_8:
781                 break;
782         case VCAL_CHARSET_ISO_8859_1:
783                 ret_str = __decode_iso8859_1_to_utf8(ret_str);
784                 break;
785         }
786
787         return ret_str;
788 }
789
790 static char* __decode_datetime(char *p, struct user_data *ud)
791 {
792         char **t = NULL;
793         t =  g_strsplit(p, ":", -1);
794         RETVM_IF(NULL == t, NULL, "g_strsplit() Fail");
795
796         if ('\0' == *t[0]) { /* no param */
797                 g_strfreev(t);
798                 return p + 1;
799         }
800         int count = g_strv_length(t);
801         int len_param = strlen(t[count -1]);
802         *(p + strlen(p) - len_param -1) = '\0';
803         g_strfreev(t);
804
805         /* param start */
806         char **s = NULL;
807         s = g_strsplit(p, ";", -1);
808         RETVM_IF(NULL == s, p + strlen(p) - len_param, "g_strsplit() Fail");
809
810         int count_param = g_strv_length(s);
811         DBG("count_param(%d)", count_param);
812         int i;
813         for (i = 0; i < count_param; i++) {
814                 if (NULL == s[i] || '\0' == *s[i])
815                         continue;
816
817                 if (CAL_STRING_EQUAL != strncmp(s[i], "TZID=", strlen("TZID=")))
818                         continue;
819
820                 if (ud->datetime_tzid)
821                         break;
822
823                 char *tzid = NULL;
824                 tzid = strdup(s[i] + strlen("TZID="));
825                 if (NULL == tzid) {
826                         /* LCOV_EXCL_START */
827                         ERR("strdup() Fail");
828                         break;
829                         /* LCOV_EXCL_STOP */
830                 }
831                 __adjust_tzid(tzid);
832                 DBG("modified tzid[%s]", tzid);
833
834                 if (true == cal_time_is_available_tzid(tzid)) {
835                         DBG("VALID tzid");
836                         ud->datetime_tzid = tzid;
837                         break;
838                 }
839                 free(tzid);
840
841                 if (ud->timezone_tzid && *ud->timezone_tzid) {
842                         ud->datetime_tzid = strdup(ud->timezone_tzid);
843                         if (NULL == ud->datetime_tzid) {
844                                 /* LCOV_EXCL_START */
845                                 ERR("strdup() Fail");
846                                 break;
847                                 /* LCOV_EXCL_STOP */
848                         }
849                         DBG("set datetime_tzid[%s] as timezone_tzid", ud->datetime_tzid);
850                 } else {
851                         /* LCOV_EXCL_START */
852                         ERR("INVALID tzid");
853                         /* LCOV_EXCL_STOP */
854                 }
855                 break;
856         }
857         g_strfreev(s);
858         /* param end */
859
860         DBG("(%d) (%d) [%s]", strlen(p), len_param, p + strlen(p) +1);
861         return p + strlen(p) +1;
862 }
863
864 static void __decode_duration(char *cursor, int len, int *tick, int *unit)
865 {
866         RET_IF(NULL == cursor);
867         RET_IF('\0' == *cursor);
868         RET_IF(NULL == tick);
869         RET_IF(NULL == unit);
870
871         char buf[8] = {0};
872         int sign = 1;
873         int digit = 0;
874         int t = 0, u = 0;
875         int i;
876         for (i = 0; i < len; i++) {
877                 switch (*(cursor + i)) {
878                 case '0':
879                 case '1':
880                 case '2':
881                 case '3':
882                 case '4':
883                 case '5':
884                 case '6':
885                 case '7':
886                 case '8':
887                 case '9':
888                         digit++;
889                         break;
890                 case '+':
891                         break;
892                 case '-':
893                         sign = -1;
894                         break;
895                 case 'P':
896                         break;
897                 case 'T':
898                         break;
899                 case 'W':
900                         u = CALENDAR_ALARM_TIME_UNIT_WEEK;
901                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
902                         t = atoi(buf) * u;
903                         DBG("[%s] (%d)", buf, t);
904                         digit = 0;
905                         break;
906                 case 'D':
907                         u = CALENDAR_ALARM_TIME_UNIT_DAY;
908                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
909                         t += atoi(buf) * u;
910                         DBG("[%s] (%d)", buf, t);
911                         digit = 0;
912                         break;
913                 case 'H':
914                         u = CALENDAR_ALARM_TIME_UNIT_HOUR;
915                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
916                         t += atoi(buf) * u;
917                         DBG("[%s] (%d)", buf, t);
918                         digit = 0;
919                         break;
920                 case 'M':
921                         u = CALENDAR_ALARM_TIME_UNIT_MINUTE;
922                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
923                         t += atoi(buf) * u;
924                         DBG("[%s] (%d)", buf, t);
925                         digit = 0;
926                         break;
927                 case 'S':
928                         u = CALENDAR_ALARM_TIME_UNIT_SPECIFIC;
929                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
930                         t += atoi(buf) * u;
931                         DBG("[%s] (%d)", buf, t);
932                         digit = 0;
933                         break;
934                 default:
935                         /* LCOV_EXCL_START */
936                         ERR("Invalid value");
937                         break;
938                         /* LCOV_EXCL_STOP */
939                 }
940         }
941
942         t *= sign;
943         _get_tick_unit(t, tick, unit);
944 }
945
946 static bool __is_digit(char *p)
947 {
948         while (*p) {
949                 if ((*p < '0' || '9' < *p) && '+' != *p && '-' != *p)
950                         return false;
951                 p++;
952         }
953         return true;
954 }
955
956 static char* __get_index(char *cursor, const char **array, int len, int *index)
957 {
958         RETV_IF(NULL == index, NULL);
959
960         int i;
961         char *new = NULL;
962         for (i = 1; i < len; i++) {
963                 new = __check_word(cursor, array[i]);
964                 if (new) break;
965         }
966         if (len == i) {
967                 *index = 0;
968                 return cursor;
969         }
970
971         *index = i;
972         DBG("index(%d) [%s]", i, array[i]);
973         return cursor + strlen(array[i]);
974 }
975
976 static void __get_version(char *value, int *version)
977 {
978         CAL_FN_CALL();
979
980         RET_IF(NULL == value);
981         RET_IF(NULL == version);
982
983         if (CAL_STRING_EQUAL == strncmp(value, ":1.0", strlen(":1.0")))
984                 *version = 1;
985         else
986                 *version = 2;
987
988         DBG("version(%d)", *version);
989 }
990
991 static int _get_caltime(char *p, calendar_time_s *caltime, struct user_data *ud)
992 {
993         RETV_IF(NULL == p, CALENDAR_ERROR_INVALID_PARAMETER);
994         RETV_IF('\0' == *p, CALENDAR_ERROR_INVALID_PARAMETER);
995         RETV_IF(NULL == caltime, CALENDAR_ERROR_INVALID_PARAMETER);
996         RETV_IF(NULL == ud, CALENDAR_ERROR_INVALID_PARAMETER);
997
998         int ret = CALENDAR_ERROR_NONE;
999
1000         switch (strlen(p)) {
1001         case VCAL_DATETIME_LENGTH_YYYYMMDD:
1002                 caltime->type = CALENDAR_TIME_LOCALTIME;
1003                 sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDD,
1004                                 &(caltime->time.date.year), &(caltime->time.date.month), &(caltime->time.date.mday));
1005                 caltime->time.date.hour = 0;
1006                 caltime->time.date.minute = 0;
1007                 caltime->time.date.second = 0;
1008                 DBG(CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS,
1009                                 caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1010                                 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1011                 break;
1012         case VCAL_DATETIME_LENGTH_YYYYMMDDTHHMMSS:
1013                 sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS,
1014                                 &(caltime->time.date.year), &(caltime->time.date.month), &(caltime->time.date.mday),
1015                                 &(caltime->time.date.hour), &(caltime->time.date.minute), &(caltime->time.date.second));
1016
1017                 if (VCAL_VER_1 == ud->version) {
1018                         caltime->type = CALENDAR_TIME_LOCALTIME;
1019                 } else {
1020                         if (NULL == ud->datetime_tzid || '\0' == *ud->datetime_tzid) {
1021                                 if (NULL == ud->timezone_tzid || '\0' == *ud->timezone_tzid) {
1022                                         /* Without tzid is localtime */
1023                                         caltime->type = CALENDAR_TIME_LOCALTIME;
1024                                         DBG(CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS,
1025                                                         caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1026                                                         caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1027                                 } else {
1028                                         /* No 'Z' with tzid means utime */
1029                                         caltime->type = CALENDAR_TIME_UTIME;
1030                                         caltime->time.utime = cal_time_convert_itol(ud->timezone_tzid,
1031                                                         caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1032                                                         caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1033                                         DBG("timezone_tzid[%s] (%lld)", ud->timezone_tzid, caltime->time.utime);
1034                                 }
1035                         } else {
1036                                 /* No 'Z' with tzid means utime */
1037                                 caltime->type = CALENDAR_TIME_UTIME;
1038                                 caltime->time.utime = cal_time_convert_itol(ud->datetime_tzid,
1039                                                 caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1040                                                 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1041                                 DBG("datetime_tzid[%s] (%lld)", ud->datetime_tzid, caltime->time.utime);
1042                         }
1043                 }
1044                 break;
1045         case VCAL_DATETIME_LENGTH_YYYYMMDDTHHMMSSZ:
1046                 if (ud->is_allday) {
1047                         caltime->type = CALENDAR_TIME_LOCALTIME;
1048                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ,
1049                                         &(caltime->time.date.year), &(caltime->time.date.month), &(caltime->time.date.mday),
1050                                         &(caltime->time.date.hour), &(caltime->time.date.minute), &(caltime->time.date.second));
1051                         caltime->time.date.hour = 0;
1052                         caltime->time.date.minute = 0;
1053                         caltime->time.date.second = 0;
1054                         DBG(CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS,
1055                                         caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1056                                         caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1057                 } else {
1058                         caltime->type = CALENDAR_TIME_UTIME;
1059                         caltime->time.utime = cal_time_convert_lli(p);
1060                         DBG("(%lld)", caltime->time.utime);
1061                 }
1062                 break;
1063         default:
1064                 /* LCOV_EXCL_START */
1065                 ERR("Invalid time format[%s]", p);
1066                 ret = CALENDAR_ERROR_INVALID_PARAMETER;
1067                 break;
1068                 /* LCOV_EXCL_STOP */
1069         }
1070         return ret;
1071 }
1072
1073 /*
1074  * TZ:+05
1075  * TZ:
1076  * TZ:+5
1077  * TZ:5:30
1078  * TZ:+05:30
1079  */
1080 static void __parse_tz(const char *tz, int *h, int *m)
1081 {
1082         RET_IF(NULL == tz);
1083
1084         char **t = g_strsplit(tz, ":", -1);
1085         RETM_IF(NULL == t, "g_strsplit() is NULL");
1086
1087         int sign = 0;
1088         if ('-' == *t[0])
1089                 sign = -1;
1090         else if ('+' == *t[0])
1091                 sign = 1;
1092         else
1093                 sign = 0;
1094
1095         if (0 == strlen(t[0])) {
1096                 /* LCOV_EXCL_START */
1097                 ERR("No hour");
1098                 g_strfreev(t);
1099                 return;
1100                 /* LCOV_EXCL_STOP */
1101         }
1102
1103         char buf[8] = {0};
1104         if (sign) {
1105                 snprintf(buf, strlen(t[0]), "%s", t[0] + 1);
1106         } else {
1107                 sign = 1;
1108                 snprintf(buf, strlen(t[0]) + 1, "%s", t[0]);
1109         }
1110         if (h) *h = sign * atoi(buf);
1111
1112         if (1 == g_strv_length(t)) {
1113                 if (m) *m = 0;
1114                 g_strfreev(t);
1115                 return;
1116         }
1117
1118         snprintf(buf, strlen(t[1]) + 1, "%s", t[1]);
1119         if (m) *m = atoi(buf);
1120
1121         g_strfreev(t);
1122 }
1123
1124 static void __get_tz(char *value, char **tz)
1125 {
1126         RET_IF(NULL == value);
1127         RET_IF(NULL == tz);
1128
1129         int h = 0, m = 0;
1130         __parse_tz(value +1, &h, &m); /* +1 to skip ':' */
1131
1132         char buf[CAL_STR_SHORT_LEN32] = {0};
1133         if (0 == m)
1134                 snprintf(buf, sizeof(buf), "Etc/GMT%c%d", h < 0 ? '+' : '-', h);
1135         else
1136                 cal_time_get_registered_tzid_with_offset(h * 3600 + m * 60, buf, sizeof(buf));
1137
1138         DBG("set tzid [%s]", buf);
1139
1140         *tz = strdup(buf);
1141 }
1142
1143 static void __work_component_property_dtstamp(char *value, calendar_record_h record, struct user_data *ud)
1144 {
1145         return;
1146 }
1147
1148 static void __work_component_property_uid(char *value, calendar_record_h record, struct user_data *ud)
1149 {
1150         RET_IF(NULL == value);
1151         RET_IF('\0' == *value);
1152         RET_IF(NULL == record);
1153         RET_IF(NULL == ud);
1154
1155         int ret = 0;
1156         char *s = __decode_charset(value);
1157         __decode_escaped_char(s);
1158         switch (ud->type) {
1159         case CALENDAR_BOOK_TYPE_EVENT:
1160                 ret = cal_record_set_str(record, _calendar_event.uid, s);
1161                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1162                 break;
1163         case CALENDAR_BOOK_TYPE_TODO:
1164                 ret = cal_record_set_str(record, _calendar_todo.uid, s);
1165                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1166                 break;
1167         }
1168         free(s);
1169 }
1170
1171 static void __work_component_property_recurrence_id(char *value, calendar_record_h record, struct user_data *ud)
1172 {
1173         RET_IF(NULL == value);
1174         RET_IF('\0' == *value);
1175         RET_IF(NULL == record);
1176         RET_IF(NULL == ud);
1177
1178         int ret = 0;
1179         switch (ud->type) {
1180         case CALENDAR_BOOK_TYPE_EVENT:
1181                 ret = cal_record_set_str(record, _calendar_event.recurrence_id, value +1);
1182                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1183                 break;
1184         case CALENDAR_BOOK_TYPE_TODO:
1185                 DBG("Not supported in todo");
1186                 break;
1187         }
1188 }
1189
1190 static void __work_component_property_dtstart(char *value, calendar_record_h record, struct user_data *ud)
1191 {
1192         RET_IF(NULL == value);
1193         RET_IF('\0' == *value);
1194         RET_IF(NULL == record);
1195         RET_IF(NULL == ud);
1196
1197         int ret = 0;
1198
1199         value = __decode_datetime(value, ud);
1200         calendar_time_s dtstart = {0};
1201         ret = _get_caltime(value, &dtstart, ud);
1202         if (CALENDAR_ERROR_NONE != ret) {
1203                 /* LCOV_EXCL_START */
1204                 ERR("_get_caltime() Fail(%d)", ret);
1205                 return;
1206                 /* LCOV_EXCL_STOP */
1207         }
1208
1209         char *tzid = NULL;
1210         tzid = ud->datetime_tzid ? ud->datetime_tzid : (ud->timezone_tzid ? ud->timezone_tzid : NULL);
1211
1212         switch (ud->type) {
1213         case CALENDAR_BOOK_TYPE_EVENT:
1214                 if (tzid && *tzid) {
1215                         ret = cal_record_set_str(record, _calendar_event.start_tzid, tzid);
1216                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1217                 }
1218                 ret = cal_record_set_caltime(record, _calendar_event.start_time, dtstart);
1219                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1220                 break;
1221         case CALENDAR_BOOK_TYPE_TODO:
1222                 if (tzid && *tzid) {
1223                         ret = cal_record_set_str(record, _calendar_todo.start_tzid, tzid);
1224                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1225                 }
1226                 ret = cal_record_set_caltime(record, _calendar_todo.start_time, dtstart);
1227                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1228                 break;
1229         }
1230
1231         /* check if dtend is earlier than dtstart. */
1232         if (CALENDAR_BOOK_TYPE_TODO == ud->type) /* skip in todo */
1233                 return;
1234
1235         calendar_time_s dtend = {0};
1236         ret = calendar_record_get_caltime(record, _calendar_event.end_time, &dtend);
1237         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
1238
1239         if (0 == dtend.time.utime) /* not set yet */
1240                 return;
1241
1242         int diff = 0;
1243         _sub_caltime(ud, &dtstart, &dtend, &diff);
1244         if (diff <= 0) /* proper data */
1245                 return;
1246
1247         WARN("dtend < dtstart so set end time to start");
1248         dtend = dtstart;
1249 }
1250
1251 static void __work_component_property_created(char *value, calendar_record_h record, struct user_data *ud)
1252 {
1253         RET_IF(NULL == value);
1254         RET_IF('\0' == *value);
1255         RET_IF(NULL == record);
1256         RET_IF(NULL == ud);
1257
1258         int ret = 0;
1259         switch (ud->type) {
1260         case CALENDAR_BOOK_TYPE_EVENT:
1261                 ret = cal_record_set_lli(record, _calendar_event.created_time, cal_time_convert_lli(value));
1262                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_lli() Fail(%d)", ret);
1263                 break;
1264
1265         case CALENDAR_BOOK_TYPE_TODO:
1266                 ret = cal_record_set_lli(record, _calendar_todo.created_time, cal_time_convert_lli(value));
1267                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_lli() Fail(%d)", ret);
1268                 break;
1269         }
1270 }
1271
1272 static void __work_component_property_description(char *value, calendar_record_h record, struct user_data *ud)
1273 {
1274         RET_IF(NULL == value);
1275         RET_IF('\0' == *value);
1276         RET_IF(NULL == record);
1277         RET_IF(NULL == ud);
1278
1279         int ret = 0;
1280         char *s = __decode_charset(value);
1281         __decode_escaped_char(s);
1282         switch (ud->type) {
1283         case CALENDAR_BOOK_TYPE_EVENT:
1284                 ret = cal_record_set_str(record, _calendar_event.description, s);
1285                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1286                 break;
1287         case CALENDAR_BOOK_TYPE_TODO:
1288                 ret = cal_record_set_str(record, _calendar_todo.description, s);
1289                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1290                 break;
1291         }
1292         free(s);
1293 }
1294
1295 static void __work_component_property_last_modified(char *value, calendar_record_h record, struct user_data *ud)
1296 {
1297         RET_IF(NULL == value);
1298         RET_IF('\0' == *value);
1299         RET_IF(NULL == record);
1300         RET_IF(NULL == ud);
1301
1302         int ret = 0;
1303         switch (ud->type) {
1304         case CALENDAR_BOOK_TYPE_EVENT:
1305                 ret = cal_record_set_lli(record, _calendar_event.last_modified_time, cal_time_convert_lli(value));
1306                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_lli() Fail(%d)", ret);
1307                 break;
1308         case CALENDAR_BOOK_TYPE_TODO:
1309                 ret = cal_record_set_lli(record, _calendar_todo.last_modified_time, cal_time_convert_lli(value));
1310                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_lli() Fail(%d)", ret);
1311                 break;
1312         }
1313 }
1314
1315 static void __work_component_property_location(char *value, calendar_record_h record, struct user_data *ud)
1316 {
1317         RET_IF(NULL == value);
1318         RET_IF('\0' == *value);
1319         RET_IF(NULL == record);
1320         RET_IF(NULL == ud);
1321
1322         int ret = 0;
1323         char *s = __decode_charset(value);
1324         __decode_escaped_char(s);
1325         switch (ud->type) {
1326         case CALENDAR_BOOK_TYPE_EVENT:
1327                 ret = cal_record_set_str(record, _calendar_event.location, s);
1328                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1329                 break;
1330         case CALENDAR_BOOK_TYPE_TODO:
1331                 ret = cal_record_set_str(record, _calendar_todo.location, s);
1332                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1333                 break;
1334         }
1335         free(s);
1336 }
1337
1338 static int __decode_priority(char *value, struct user_data *ud)
1339 {
1340         int original_priority = atoi(value);
1341         int modified_priority = 0;
1342
1343         switch (ud->version) {
1344         case VCAL_VER_1:
1345                 switch (original_priority) {
1346                 case 0:
1347                         modified_priority = CALENDAR_TODO_PRIORITY_LOW;
1348                         break;
1349                 case 1:
1350                         modified_priority = CALENDAR_TODO_PRIORITY_NORMAL;
1351                         break;
1352                 case 2:
1353                         modified_priority = CALENDAR_TODO_PRIORITY_HIGH;
1354                         break;
1355                 default:
1356                         DBG("Unable to parse [%s]", value);
1357                         modified_priority = CALENDAR_TODO_PRIORITY_NONE;
1358                         break;
1359                 }
1360                 break;
1361
1362         case VCAL_VER_2:
1363         default:
1364                 switch (original_priority) {
1365                 case 1 ... 4:
1366                         modified_priority = CALENDAR_TODO_PRIORITY_HIGH;
1367                         break;
1368                 case 5:
1369                         modified_priority = CALENDAR_TODO_PRIORITY_NORMAL;
1370                         break;
1371                 case 6 ... 9:
1372                         modified_priority = CALENDAR_TODO_PRIORITY_LOW;
1373                         break;
1374                 default:
1375                         DBG("Unable to parse [%s]", value);
1376                         modified_priority = CALENDAR_TODO_PRIORITY_NONE;
1377                         break;
1378                 }
1379                 break;
1380         }
1381         DBG("convert priority(%d) -> (%d)", original_priority, modified_priority);
1382         return modified_priority;
1383 }
1384
1385 static void __work_component_property_priority(char *value, calendar_record_h record, struct user_data *ud)
1386 {
1387         RET_IF(NULL == value);
1388         RET_IF('\0' == *value);
1389         RET_IF(NULL == record);
1390         RET_IF(NULL == ud);
1391         RETM_IF(*value < '0' || '9' < *value, "out of range[%s]", value);
1392
1393         int ret = 0;
1394         int modified_priority = __decode_priority(value, ud);
1395         switch (ud->type) {
1396         case CALENDAR_BOOK_TYPE_EVENT:
1397                 ret = cal_record_set_int(record, _calendar_event.priority, modified_priority);
1398                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1399                 break;
1400         case CALENDAR_BOOK_TYPE_TODO:
1401                 ret = cal_record_set_int(record, _calendar_todo.priority, modified_priority);
1402                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1403                 break;
1404         }
1405 }
1406
1407 static void __work_component_property_status(char *value, calendar_record_h record, struct user_data *ud)
1408 {
1409         RET_IF(NULL == value);
1410         RET_IF('\0' == *value);
1411         RET_IF(NULL == record);
1412         RET_IF(NULL == ud);
1413
1414         int ret = 0;
1415         int status = 0;
1416         switch (ud->type) {
1417         case CALENDAR_BOOK_TYPE_EVENT:
1418                 if (CAL_STRING_EQUAL == strncmp(value, ":TENTATIVE", strlen(":TENTATIVE")))
1419                         status = CALENDAR_EVENT_STATUS_TENTATIVE;
1420                 else if (CAL_STRING_EQUAL == strncmp(value, ":CONFIRMED", strlen(":CONFIRMED")))
1421                         status = CALENDAR_EVENT_STATUS_CONFIRMED;
1422                 else if (CAL_STRING_EQUAL == strncmp(value, ":CANCELLED", strlen(":CANCELLED")))
1423                         status = CALENDAR_EVENT_STATUS_CANCELLED;
1424                 else
1425                         status = CALENDAR_EVENT_STATUS_NONE;
1426
1427                 ret = cal_record_set_int(record, _calendar_event.event_status, status);
1428                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1429                 break;
1430         case CALENDAR_BOOK_TYPE_TODO:
1431                 if (CAL_STRING_EQUAL == strncmp(value, ":NEEDS-ACTION", strlen(":NEEDS-ACTION")))
1432                         status = CALENDAR_TODO_STATUS_NEEDS_ACTION;
1433                 else if (CAL_STRING_EQUAL == strncmp(value, ":NEEDS ACTION", strlen(":NEEDS ACTION")))
1434                         status = CALENDAR_TODO_STATUS_NEEDS_ACTION;
1435                 else if (CAL_STRING_EQUAL == strncmp(value, ":COMPLETED", strlen(":COMPLETED")))
1436                         status = CALENDAR_TODO_STATUS_COMPLETED;
1437                 else if (CAL_STRING_EQUAL == strncmp(value, ":IN-PROCESS", strlen(":IN-PROCESS")))
1438                         status = CALENDAR_TODO_STATUS_IN_PROCESS;
1439                 else if (CAL_STRING_EQUAL == strncmp(value, ":CANCELLED", strlen(":CANCELLED")))
1440                         status = CALENDAR_TODO_STATUS_CANCELED;
1441                 else
1442                         status = CALENDAR_TODO_STATUS_NONE;
1443
1444                 ret = cal_record_set_int(record, _calendar_todo.todo_status, status);
1445                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1446                 break;
1447         }
1448 }
1449
1450 static void __work_component_property_summary(char *value, calendar_record_h record, struct user_data *ud)
1451 {
1452         RET_IF(NULL == value);
1453         RET_IF('\0' == *value);
1454         RET_IF(NULL == record);
1455         RET_IF(NULL == ud);
1456
1457         int ret = 0;
1458         char *s = __decode_charset(value);
1459         __decode_escaped_char(s);
1460         switch (ud->type) {
1461         case CALENDAR_BOOK_TYPE_EVENT:
1462                 ret = cal_record_set_str(record, _calendar_event.summary, s);
1463                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1464                 break;
1465         case CALENDAR_BOOK_TYPE_TODO:
1466                 ret = cal_record_set_str(record, _calendar_todo.summary, s);
1467                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1468                 break;
1469         }
1470         free(s);
1471 }
1472
1473 static bool __is_wday_string(char *p)
1474 {
1475         RETV_IF(NULL == p, false);
1476         RETV_IF('0' == *p, false);
1477
1478         if ('S' == *p && 'U' == *(p +1))
1479                 return true;
1480         else if ('M' == *p && 'O' == *(p +1))
1481                 return true;
1482         else if ('T' == *p && 'U' == *(p +1))
1483                 return true;
1484         else if ('W' == *p && 'E' == *(p +1))
1485                 return true;
1486         else if ('T' == *p && 'H' == *(p +1))
1487                 return true;
1488         else if ('F' == *p && 'R' == *(p +1))
1489                 return true;
1490         else if ('S' == *p && 'A' == *(p +1))
1491                 return true;
1492         else
1493                 return false;
1494
1495 }
1496
1497 static int __get_frequency(char *p)
1498 {
1499         if ('Y' == *p && 'M' == *(p +1))
1500                 return VCAL_RECURRENCE_YEARLY_BYMONTH;
1501         else if ('Y' == *p && 'D' == *(p +1))
1502                 return VCAL_RECURRENCE_YEARLY_BYYEARDAY;
1503         else if ('M' == *p && 'P' == *(p +1))
1504                 return VCAL_RECURRENCE_MONTHLY_BYDAY;
1505         else if ('M' == *p && 'D' == *(p +1))
1506                 return VCAL_RECURRENCE_MONTHLY_BYMONTHDAY;
1507         else if ('W' == *p && 'E' != *(p +1))  /* check 'E' for WE(Wednesday) */
1508                 return VCAL_RECURRENCE_WEEKLY;
1509         else if ('D' == *p)
1510                 return VCAL_RECURRENCE_DAILY;
1511         else
1512                 return VCAL_RECURRENCE_NONE;
1513 }
1514
1515 static void __set_bystr(int freq_mode, calendar_record_h record, char *bystr)
1516 {
1517         RET_IF(NULL == record);
1518         RET_IF(NULL == bystr);
1519         RET_IF('\0' == *bystr);
1520
1521         DBG("bystr[%s]", bystr);
1522         bystr[strlen(bystr) -1] = '\0'; /* to remove ',' */
1523         int ret = 0;
1524         switch (freq_mode) {
1525         case VCAL_RECURRENCE_YEARLY_BYMONTH:
1526                 ret = cal_record_set_str(record, _calendar_event.bymonth, bystr);
1527                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1528                 break;
1529         case VCAL_RECURRENCE_YEARLY_BYYEARDAY:
1530                 ret = cal_record_set_str(record, _calendar_event.byyearday, bystr);
1531                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1532                 break;
1533         case VCAL_RECURRENCE_MONTHLY_BYMONTHDAY:
1534                 ret = cal_record_set_str(record, _calendar_event.bymonthday, bystr);
1535                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1536                 break;
1537         case VCAL_RECURRENCE_MONTHLY_BYDAY:
1538                 ret = cal_record_set_str(record, _calendar_event.byday, bystr);
1539                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1540                 break;
1541         case VCAL_RECURRENCE_WEEKLY:
1542                 ret = cal_record_set_str(record, _calendar_event.byday, bystr);
1543                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1544                 break;
1545         case VCAL_RECURRENCE_DAILY:
1546                 break;
1547         }
1548 }
1549
1550 /*
1551  * Yearly |bymonth   |YM1 6 7 #10
1552  *                   |YM1 1 6 12 #5 MP1 1+ MO 1- FR
1553  * Yearly |byyearday |YD3 1 100 200 #10
1554  * Monthly|byposition|MP2 1+ SU 1- SU #10
1555  * Monthly|byday     |MD1 1 1- #10
1556  * Weekly |          |W2 MO WE FR 19941224T000000Z
1557  * Daly   |          |D2 #0
1558  */
1559 static void __work_component_property_rrule_ver_1(char *value, calendar_record_h record, struct user_data *ud)
1560 {
1561         CAL_FN_CALL();
1562
1563         RET_IF(NULL == value);
1564         RET_IF('\0' == *value);
1565         RET_IF(NULL == record);
1566         RET_IF(NULL == ud);
1567
1568         int ret = 0;
1569         char **t = NULL;
1570         t =  g_strsplit_set(value, ": ", -1);
1571         RETM_IF(NULL == t, "g_strsplit_set() Fail");
1572
1573         /* start */
1574         int len = g_strv_length(t);
1575
1576         int frequency = 0;
1577         int freq_mode = 0;
1578         bool has_by = false;
1579
1580         char bystr[CAL_STR_MIDDLE_LEN] = {0};
1581         int len_str = 0;
1582
1583         int week[5] = {0};
1584         int week_index = 0;
1585
1586         int i;
1587         for (i = 0; i < len; i++) {
1588                 if (NULL == t[i] || '\0' == *t[i])
1589                         continue;
1590
1591                 DBG("[%s]", t[i]);
1592
1593                 if (true == __is_wday_string(t[i])) {
1594                         has_by = true;
1595                         if (week_index) {
1596                                 int j = 0;
1597                                 for (j = 0; j < week_index; j++)
1598                                         len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%d%s,", week[j], t[i]);
1599
1600                         } else {
1601                                 len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%s,", t[i]);
1602                         }
1603                         DBG("[%s] week_index(%d)", bystr, week_index);
1604                 } else if ('L' == *t[i] && 'D' == *(t[i] +1)) {  /* last day */
1605                         has_by = true;
1606                         len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%s,", "-1");
1607
1608                 } else if ('W' == *t[i] && 'K' == *(t[i] +1) && 'S' == *(t[i] +2) && 'T' == *(t[i] +3)) { /* +4 is '=' */
1609                         if ('S' == *(t[i] +5) && 'U' == *(t[i] +6))
1610                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SUNDAY);
1611                         else if ('M' == *(t[i] +5))
1612                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_MONDAY);
1613                         else if ('T' == *(t[i] +5) && 'U' == *(t[i] +6))
1614                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_TUESDAY);
1615                         else if ('W' == *(t[i] +5))
1616                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_WEDNESDAY);
1617                         else if ('T' == *(t[i] +5) && 'H' == *(t[i] +6))
1618                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_THURSDAY);
1619                         else if ('F' == *(t[i] +5))
1620                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_FRIDAY);
1621                         else if ('S' == *(t[i] +5) && 'A' == *(t[i] +6))
1622                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SATURDAY);
1623                         else
1624                                 ERR("Invalid parameter[%s]", t[i]);
1625
1626                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1627                 } else if (true == __is_digit(t[i])) {
1628
1629                         char buf[8] = {0};
1630                         bool exit_loop = false;
1631                         int sign = 1;
1632                         int j = 0;
1633                         switch (freq_mode) {
1634                         case VCAL_RECURRENCE_MONTHLY_BYDAY:
1635                         case VCAL_RECURRENCE_WEEKLY:
1636                                 if (true == has_by)
1637                                         week_index = 0;
1638
1639                                 while (*(t[i] +j)) {
1640                                         switch (*(t[i] +j)) {
1641                                         case '+':
1642                                                 exit_loop = true;
1643                                                 sign = 1;
1644                                                 break;
1645                                         case '-':
1646                                                 exit_loop = true;
1647                                                 sign = -1;
1648                                                 break;
1649                                         default:
1650                                                 break;
1651                                         }
1652                                         if (true == exit_loop) break;
1653                                         j++;
1654                                 }
1655                                 snprintf(buf, j +1, "%s", t[i]);
1656                                 week[week_index] = atoi(buf) * sign;
1657                                 week_index++;
1658                                 break;
1659                         default:
1660                                 has_by = true;
1661                                 while (*(t[i] +j)) {
1662                                         switch (*(t[i] +j)) {
1663                                         case '+':
1664                                                 exit_loop = true;
1665                                                 sign = 1;
1666                                                 break;
1667                                         case '-':
1668                                                 exit_loop = true;
1669                                                 sign = -1;
1670                                                 break;
1671                                         default:
1672                                                 break;
1673                                         }
1674                                         if (true == exit_loop) break;
1675                                         j++;
1676                                 }
1677                                 snprintf(buf, j +1, "%s", t[i]);
1678                                 len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%d,", (atoi(buf) * sign));
1679                                 break;
1680                         }
1681                 } else {
1682                         if (true == has_by) {
1683                                 __set_bystr(freq_mode, record, bystr);
1684                                 week_index = 0;
1685                                 memset(bystr, 0x0, strlen(bystr));
1686                                 len_str = 0;
1687                                 has_by = false;
1688                         }
1689                         if (VCAL_RECURRENCE_NONE != (freq_mode = __get_frequency(t[i]))) {
1690                                 if (0 == frequency) {
1691                                         int interval = 0;
1692                                         switch (freq_mode) {
1693                                         case VCAL_RECURRENCE_YEARLY_BYMONTH:
1694                                                 frequency = CALENDAR_RECURRENCE_YEARLY;
1695                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1696                                                 break;
1697                                         case VCAL_RECURRENCE_YEARLY_BYYEARDAY:
1698                                                 frequency = CALENDAR_RECURRENCE_YEARLY;
1699                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1700                                                 break;
1701                                         case VCAL_RECURRENCE_MONTHLY_BYDAY:
1702                                                 frequency = CALENDAR_RECURRENCE_MONTHLY;
1703                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1704                                                 break;
1705                                         case VCAL_RECURRENCE_MONTHLY_BYMONTHDAY:
1706                                                 frequency = CALENDAR_RECURRENCE_MONTHLY;
1707                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1708                                                 break;
1709                                         case VCAL_RECURRENCE_WEEKLY:
1710                                                 frequency = CALENDAR_RECURRENCE_WEEKLY;
1711                                                 interval = ('\0' == *(t[i] +1)) ? 1 : atoi(t[i] +1);
1712                                                 break;
1713                                         case VCAL_RECURRENCE_DAILY:
1714                                                 frequency = CALENDAR_RECURRENCE_DAILY;
1715                                                 interval = ('\0' == *(t[i] +1)) ? 1 : atoi(t[i] +1);
1716                                                 break;
1717                                         }
1718                                         ret = cal_record_set_int(record, _calendar_event.freq, frequency);
1719                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1720                                         ret = cal_record_set_int(record, _calendar_event.interval, interval);
1721                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1722                                         DBG("frequency[%d] interval(%d)", frequency, interval);
1723                                 }
1724                         } else {
1725                                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("YYYYMMDDTHHMMSS") <= strlen(t[i])) {
1726                                         DBG("until");
1727                                         calendar_time_s caltime = {0};
1728                                         _get_caltime(t[i], &caltime, ud);
1729                                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_UNTIL);
1730                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1731                                         ret = cal_record_set_caltime(record, _calendar_event.until_time, caltime);
1732                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1733
1734                                 } else if ('#' == *t[i]) {
1735                                         /* count */
1736                                         if (true == __is_digit(t[i] +1)) {
1737                                                 if (0 == atoi(t[i] +1)) {
1738                                                         DBG("endless");
1739                                                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_NONE);
1740                                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1741                                                 } else {
1742                                                         DBG("count (%d)", atoi(t[i] +1));
1743                                                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_COUNT);
1744                                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1745                                                         ret = cal_record_set_int(record, _calendar_event.count, atoi(t[i] +1));
1746                                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1747                                                 }
1748                                         } else {
1749                                                 ERR("Unable to parse count[%s]", t[i]);
1750                                         }
1751                                 } else {
1752                                         DBG("Invalid");
1753                                 }
1754                         }
1755                 }
1756         }
1757         if (true == has_by)
1758                 __set_bystr(freq_mode, record, bystr);
1759
1760         g_strfreev(t);
1761 }
1762
1763 static void __work_component_property_rrule_ver_2(char *value, calendar_record_h record, struct user_data *ud)
1764 {
1765         int ret = 0;
1766         char **t = NULL;
1767
1768         RET_IF(NULL == value);
1769         RET_IF('\0' == *value);
1770         RET_IF(NULL == record);
1771         RET_IF(NULL == ud);
1772
1773         t =  g_strsplit_set(value, ";:", -1);
1774         RETM_IF(NULL == t, "g_strsplit_set() Fail");
1775
1776         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_NONE);
1777         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1778
1779         int len = g_strv_length(t);
1780         int i;
1781         for (i = 0; i < len; i++) {
1782                 if (NULL == t[i] || '\0' == *t[i]) continue;
1783
1784                 if (CAL_STRING_EQUAL == strncmp(t[i], "FREQ=", strlen("FREQ="))) {
1785                         int frequency = 0;
1786                         if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=YEARLY", strlen("=YEARLY")))
1787                                 frequency = CALENDAR_RECURRENCE_YEARLY;
1788                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=MONTHLY", strlen("=MONTHLY")))
1789                                 frequency = CALENDAR_RECURRENCE_MONTHLY;
1790                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=WEEKLY", strlen("=WEEKLY")))
1791                                 frequency = CALENDAR_RECURRENCE_WEEKLY;
1792                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=DAILY", strlen("=DAILY")))
1793                                 frequency = CALENDAR_RECURRENCE_DAILY;
1794                         else
1795                                 frequency = CALENDAR_RECURRENCE_NONE;
1796
1797                         DBG("frequency(%d) [%s]", frequency, t[i] + strlen("FREQ") + 1);
1798                         ret = cal_record_set_int(record, _calendar_event.freq, frequency);
1799                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1800
1801                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "UNTIL=", strlen("UNTIL="))) {
1802                         calendar_time_s caltime = {0};
1803                         _get_caltime(t[i] + strlen("UNTIL="), &caltime, ud);
1804                         ret = cal_record_set_caltime(record, _calendar_event.until_time, caltime);
1805                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1806                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_UNTIL);
1807                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1808                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "COUNT=", strlen("COUNT="))) {
1809                         int count = atoi(t[i] + strlen("COUNT="));
1810                         if (count < 1) count = 1;
1811                         ret = cal_record_set_int(record,  _calendar_event.count, count);
1812                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1813                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_COUNT);
1814                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1815                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "INTERVAL=", strlen("INTERVAL="))) {
1816                         int interval = atoi(t[i] + strlen("INTERVAL="));
1817                         if (interval < 1) interval = 1;
1818                         ret = cal_record_set_int(record, _calendar_event.interval, interval);
1819                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1820                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYYEARDAY=", strlen("BYYEARDAY="))) {
1821                         ret = cal_record_set_str(record, _calendar_event.byyearday, t[i] + strlen("BYYEARDAY="));
1822                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1823                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYWEEKNO=", strlen("BYWEEKNO="))) {
1824                         ret = cal_record_set_str(record, _calendar_event.byweekno, t[i] + strlen("BYWEEKNO="));
1825                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1826                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYMONTH=", strlen("BYMONTH="))) {
1827                         ret = cal_record_set_str(record, _calendar_event.bymonth, t[i] + strlen("BYMONTH="));
1828                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1829                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYMONTHDAY=", strlen("BYMONTHDAY="))) {
1830                         ret = cal_record_set_str(record, _calendar_event.bymonthday, t[i] + strlen("BYMONTHDAY="));
1831                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1832                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYDAY=", strlen("BYDAY="))) {
1833                         ret = cal_record_set_str(record, _calendar_event.byday, t[i] + strlen("BYDAY="));
1834                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1835                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYSETPOS=", strlen("BYSETPOS="))) {
1836                         ret = cal_record_set_str(record, _calendar_event.bysetpos, t[i] + strlen("BYSETPOS="));
1837                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1838                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "WKST=", strlen("WKST="))) {
1839                         if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "SU", strlen("SU")))
1840                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SUNDAY);
1841                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "MO", strlen("MO")))
1842                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_MONDAY);
1843                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "TU", strlen("TU")))
1844                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_TUESDAY);
1845                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "WE", strlen("WE")))
1846                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_WEDNESDAY);
1847                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "TH", strlen("TH")))
1848                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_THURSDAY);
1849                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "FR", strlen("FR")))
1850                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_FRIDAY);
1851                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "SA", strlen("SA")))
1852                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SATURDAY);
1853                         else
1854                                 DBG("Unable to parse[%s]", t[i]);
1855
1856                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1857                 } else {
1858                         DBG("Unable to parse[%s]", t[i]);
1859                 }
1860         }
1861
1862         g_strfreev(t);
1863 }
1864
1865 static void __work_component_property_rrule(char *value, calendar_record_h record, struct user_data *ud)
1866 {
1867         CAL_FN_CALL();
1868
1869         RET_IF(NULL == value);
1870         RET_IF('\0' == *value);
1871         RET_IF(NULL == record);
1872         RET_IF(NULL == ud);
1873
1874         int version = ud->version;
1875         /* check if this field has different version content */
1876         if (CAL_STRING_EQUAL == strncmp(value, ":FREQ=", strlen(":FREQ=")))
1877                 version = VCAL_VER_2;
1878         else
1879                 version = VCAL_VER_1;
1880
1881         switch (ud->type) {
1882         case CALENDAR_BOOK_TYPE_EVENT:
1883                 switch (version) {
1884                 case VCAL_VER_1:
1885                         __work_component_property_rrule_ver_1(value, record, ud);
1886                         break;
1887                 case VCAL_VER_2:
1888                         __work_component_property_rrule_ver_2(value, record, ud);
1889                         break;
1890                 }
1891                 break;
1892         case CALENDAR_BOOK_TYPE_TODO:
1893                 DBG("Not support rrule in todo");
1894                 break;
1895         }
1896 }
1897
1898 static void __work_component_property_dtend(char *value, calendar_record_h record, struct user_data *ud)
1899 {
1900         RET_IF(NULL == value);
1901         RET_IF('\0' == *value);
1902         RET_IF(NULL == record);
1903         RET_IF(NULL == ud);
1904
1905         int ret = 0;
1906
1907         value = __decode_datetime(value, ud);
1908         calendar_time_s dtend = {0};
1909         ret = _get_caltime(value, &dtend, ud);
1910         if (CALENDAR_ERROR_NONE != ret) {
1911                 /* LCOV_EXCL_START */
1912                 ERR("_get_caltime() Fail(%d)", ret);
1913                 return;
1914                 /* LCOV_EXCL_STOP */
1915         }
1916
1917         char *tzid = NULL;
1918         tzid = ud->datetime_tzid ? ud->datetime_tzid : (ud->timezone_tzid ? ud->timezone_tzid : NULL);
1919
1920         /* check if dtend is earlier than dtstart. */
1921         do {
1922                 if (CALENDAR_BOOK_TYPE_TODO == ud->type) /* skip in todo */
1923                         break;
1924
1925                 calendar_time_s dtstart = {0};
1926                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &dtstart);
1927                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
1928
1929                 if (0 == dtstart.time.utime) /* not set yet */
1930                         break;
1931
1932                 int diff = 0;
1933                 _sub_caltime(ud, &dtstart, &dtend, &diff);
1934                 if (diff <= 0) /* proper data */
1935                         break;
1936
1937                 WARN("dtend < dtstart so set end time to start");
1938                 dtend = dtstart;
1939         } while (0);
1940
1941         switch (ud->type) {
1942         case CALENDAR_BOOK_TYPE_EVENT:
1943                 if (tzid && *tzid) {
1944                         ret = cal_record_set_str(record, _calendar_event.end_tzid, tzid);
1945                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1946                 }
1947                 ret = cal_record_set_caltime(record, _calendar_event.end_time, dtend);
1948                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1949                 break;
1950         case CALENDAR_BOOK_TYPE_TODO:
1951                 if (tzid && *tzid) {
1952                         ret = cal_record_set_str(record, _calendar_todo.due_tzid, tzid);
1953                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1954                 }
1955                 ret = cal_record_set_caltime(record, _calendar_todo.due_time, dtend);
1956                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1957                 break;
1958         }
1959 }
1960
1961 static void __work_component_property_attendee_mailto(calendar_record_h attendee, char *value)
1962 {
1963         RET_IF(NULL == value);
1964         RET_IF('\0' == *value);
1965         RET_IF(NULL == attendee);
1966
1967         int ret = 0;
1968         char *mailto = NULL;
1969         ret = calendar_record_get_str(attendee, _calendar_attendee.email, &mailto);
1970         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_str() Fail");
1971         if (mailto)
1972                 return;
1973
1974         ret = cal_record_set_str(attendee, _calendar_attendee.email, value);
1975         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
1976 }
1977 static void __work_component_property_attendee_cutype(calendar_record_h attendee, char *value)
1978 {
1979         int ret = 0;
1980
1981         RET_IF(NULL == value);
1982         RET_IF('\0' == *value);
1983         RET_IF(NULL == attendee);
1984
1985         const char *prop = NULL;
1986         if (CAL_STRING_EQUAL == strncmp(value, "INDIVIDUAL", strlen("INDIVIDUAL"))) {
1987                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_INDIVIDUAL);
1988                 if (strlen(value) > strlen("INDIVIDUAL"))
1989                         prop = "INDIVIDUAL";
1990
1991         } else if (CAL_STRING_EQUAL == strncmp(value, "GROUP", strlen("GROUP"))) {
1992                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_GROUP);
1993                 if (strlen(value) > strlen("GROUP"))
1994                         prop = "GROUP";
1995
1996         } else if (CAL_STRING_EQUAL == strncmp(value, "RESOURCE", strlen("RESOURCE"))) {
1997                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_RESOURCE);
1998                 if (strlen(value) > strlen("RESOURCE"))
1999                         prop = "RESOURCE";
2000
2001         } else if (CAL_STRING_EQUAL == strncmp(value, "ROOM", strlen("ROOM"))) {
2002                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_ROOM);
2003                 if (strlen(value) > strlen("ROOM"))
2004                         prop = "ROOM";
2005
2006         } else if (CAL_STRING_EQUAL == strncmp(value, "UNKNOWN", strlen("UNKNOWN"))) {
2007                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_UNKNOWN);
2008                 if (strlen(value) > strlen("UNKNOWN"))
2009                         prop = "UNKNOWN";
2010
2011         } else {
2012                 /* LCOV_EXCL_START */
2013                 ERR("Invalid value[%s]", value);
2014                 /* LCOV_EXCL_STOP */
2015         }
2016         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2017
2018         /* check mailto */
2019         if (prop && CAL_STRING_EQUAL == strncmp(value + strlen(prop), ":MAILTO", strlen(":MAILTO")))
2020                 __work_component_property_attendee_mailto(attendee, value + strlen(prop) + strlen(":MAILTO") +1);
2021 }
2022 static void __work_component_property_attendee_member(calendar_record_h attendee, char *value)
2023 {
2024         RET_IF(NULL == value);
2025         RET_IF('\0' == *value);
2026         RET_IF(NULL == attendee);
2027
2028         int ret = cal_record_set_str(attendee, _calendar_attendee.member, value);
2029         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2030 }
2031 static void __work_component_property_attendee_role(calendar_record_h attendee, char *value)
2032 {
2033         int ret = 0;
2034
2035         RET_IF(NULL == value);
2036         RET_IF('\0' == *value);
2037         RET_IF(NULL == attendee);
2038
2039         const char *prop = NULL;
2040         if (CAL_STRING_EQUAL == strncmp(value, "REQ-PARTICIPANT", strlen("REQ-PARTICIPANT"))) {
2041                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_REQ_PARTICIPANT);
2042                 if (strlen(value) > strlen("REQ-PARTICIPANT"))
2043                         prop = "REQ-PARTICIPANT";
2044         } else if (CAL_STRING_EQUAL == strncmp(value, "OPT-PARTICIPANT", strlen("OPT-PARTICIPANT"))) {
2045                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_OPT_PARTICIPANT);
2046                 if (strlen(value) > strlen("OPT-PARTICIPANT"))
2047                         prop = "OPT-PARTICIPANT";
2048         } else if (CAL_STRING_EQUAL == strncmp(value, "NON-PARTICIPANT", strlen("NON-PARTICIPANT"))) {
2049                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_NON_PARTICIPANT);
2050                 if (strlen(value) > strlen("NON-PARTICIPANT"))
2051                         prop = "NON-PARTICIPANT";
2052         } else if (CAL_STRING_EQUAL == strncmp(value, "CHAIR", strlen("CHAIR"))) {
2053                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_CHAIR);
2054                 if (strlen(value) > strlen("CHAIR"))
2055                         prop = "CHAIR";
2056         } else {
2057                 /* LCOV_EXCL_START */
2058                 ERR("Invalid value[%s]", value);
2059                 /* LCOV_EXCL_STOP */
2060         }
2061         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2062
2063         /* check mailto */
2064         if (prop && CAL_STRING_EQUAL == strncmp(value + strlen(prop), ":MAILTO", strlen(":MAILTO")))
2065                 __work_component_property_attendee_mailto(attendee, value + strlen(prop) + strlen(":MAILTO") +1);
2066 }
2067 static void __work_component_property_attendee_partstat(calendar_record_h attendee, char *value)
2068 {
2069         int ret = 0;
2070
2071         RET_IF(NULL == value);
2072         RET_IF('\0' == *value);
2073         RET_IF(NULL == attendee);
2074
2075         const char *prop = NULL;
2076         if (CAL_STRING_EQUAL == strncmp(value, "NEEDS-ACTION", strlen("NEEDS-ACTION"))) {
2077                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_PENDING);
2078                 if (strlen(value) > strlen("NEEDS-ACTION"))
2079                         prop = "NEEDS-ACTION";
2080
2081         } else if (CAL_STRING_EQUAL == strncmp(value, "ACCEPTED", strlen("ACCEPTED"))) {
2082                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_ACCEPTED);
2083                 if (strlen(value) > strlen("ACCEPTED"))
2084                         prop = "ACCEPTED";
2085
2086         } else if (CAL_STRING_EQUAL == strncmp(value, "DECLINED", strlen("DECLINED"))) {
2087                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_DECLINED);
2088                 if (strlen(value) > strlen("DECLINED"))
2089                         prop = "DECLINED";
2090
2091         } else if (CAL_STRING_EQUAL == strncmp(value, "TENTATIVE", strlen("TENTATIVE"))) {
2092                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_TENTATIVE);
2093                 if (strlen(value) > strlen("TENTATIVE"))
2094                         prop = "TENTATIVE";
2095
2096         } else if (CAL_STRING_EQUAL == strncmp(value, "DELEGATED", strlen("DELEGATED"))) {
2097                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_DELEGATED);
2098                 if (strlen(value) > strlen("DELEGATED"))
2099                         prop = "DELEGATED";
2100
2101         } else if (CAL_STRING_EQUAL == strncmp(value, "COMPLETED", strlen("COMPLETED"))) {
2102                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_COMPLETED);
2103                 if (strlen(value) > strlen("COMPLETED"))
2104                         prop = "COMPLETED";
2105
2106         } else if (CAL_STRING_EQUAL == strncmp(value, "IN-PROCESS", strlen("IN-PROCESS"))) {
2107                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_IN_PROCESS);
2108                 if (strlen(value) > strlen("IN-PROCESS"))
2109                         prop = "IN-PROCESS";
2110
2111         } else {
2112                 /* LCOV_EXCL_START */
2113                 ERR("Invalid value[%s]", value);
2114                 /* LCOV_EXCL_STOP */
2115         }
2116         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2117
2118         /* check mailto */
2119         if (prop && CAL_STRING_EQUAL == strncmp(value + strlen(prop), ":MAILTO", strlen(":MAILTO")))
2120                 __work_component_property_attendee_mailto(attendee, value + strlen(prop) + strlen(":MAILTO") +1);
2121 }
2122 static void __work_component_property_attendee_rsvp(calendar_record_h attendee, char *value)
2123 {
2124         RET_IF(NULL == value);
2125         RET_IF('\0' == *value);
2126         RET_IF(NULL == attendee);
2127
2128         int ret = 0;
2129         if (CAL_STRING_EQUAL == strncmp(value, "TRUE", strlen("TRUE")))
2130                 ret = cal_record_set_int(attendee, _calendar_attendee.rsvp, 1);
2131         else
2132                 ret = cal_record_set_int(attendee, _calendar_attendee.rsvp, 0);
2133
2134         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2135 }
2136 static void __work_component_property_attendee_delegated_to(calendar_record_h attendee, char *value)
2137 {
2138         RET_IF(NULL == value);
2139         RET_IF('\0' == *value);
2140         RET_IF(NULL == attendee);
2141
2142         int ret = 0;
2143         ret = cal_record_set_str(attendee, _calendar_attendee.delegatee_uri, value);
2144         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
2145 }
2146 static void __work_component_property_attendee_delegated_from(calendar_record_h attendee, char *value)
2147 {
2148         RET_IF(NULL == value);
2149         RET_IF('\0' == *value);
2150         RET_IF(NULL == attendee);
2151
2152         int ret = 0;
2153         ret = cal_record_set_str(attendee, _calendar_attendee.delegator_uri, value);
2154         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
2155 }
2156 static void __work_component_property_attendee_sent_by(calendar_record_h attendee, char *value)
2157 {
2158         return;
2159 }
2160 static void __work_component_property_attendee_cn(calendar_record_h attendee, char *value)
2161 {
2162         RET_IF(NULL == value);
2163         RET_IF('\0' == *value);
2164         RET_IF(NULL == attendee);
2165
2166         int ret = 0;
2167         ret = cal_record_set_str(attendee, _calendar_attendee.name, value);
2168         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
2169 }
2170 static void __work_component_property_attendee_dir(calendar_record_h attendee, char *value)
2171 {
2172         return;
2173 }
2174
2175 /*
2176  * example
2177  * ATTENDEE;ROLE=REQ-PARTICIPANT;DELEGATED-FROM="MAILTO:bob@host.com";PARTSTAT=ACCEPTED;CN=Jane Doe:MAILTO:jdoe@host1.com
2178  * ATTENDEE;CN=John Smith;DIR="ldap://host.com:6666/o=eDABC%20Industries,c=3DUS??(cn=3DBJim%20Dolittle)":MAILTO:jimdo@host1.com
2179  * ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP:MAILTO:employee-A@host.com
2180  * ATTENDEE;CN=MAILTO:MAILTO:MAILTO@host.com
2181  */
2182 static void __work_component_property_attendee(char *value, calendar_record_h record, struct user_data *ud)
2183 {
2184         RET_IF(NULL == value);
2185         RET_IF('\0' == *value);
2186         RET_IF(NULL == record);
2187         RET_IF(NULL == ud);
2188
2189         int ret = 0;
2190         calendar_record_h attendee = NULL;
2191         ret = calendar_record_create(_calendar_attendee._uri, &attendee);
2192         RETM_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_create() Fail(%d)", ret);
2193
2194         char **t = NULL;
2195         t =  g_strsplit(value, ";", -1);
2196         RETM_IF(NULL == t, "g_strsplit() Fail");
2197
2198         int len = g_strv_length(t);
2199         int i;
2200         for (i = 0; i < len; i++) {
2201                 if (NULL == t[i] || '\0' == *t[i]) continue;
2202
2203                 if (CAL_STRING_EQUAL == strncmp(t[i], "CUTYPE", strlen("CUTYPE")))
2204                         __work_component_property_attendee_cutype(attendee, t[i] + strlen("CUTYPE") +1);
2205                 else if (CAL_STRING_EQUAL == strncmp(t[i], "MEMBER", strlen("MEMBER")))
2206                         __work_component_property_attendee_member(attendee, t[i] + strlen("MEMBER") +1);
2207                 else if (CAL_STRING_EQUAL == strncmp(t[i], "ROLE", strlen("ROLE")))
2208                         __work_component_property_attendee_role(attendee, t[i] + strlen("ROLE") +1);
2209                 else if (CAL_STRING_EQUAL == strncmp(t[i], "PARTSTAT", strlen("PARTSTAT")))
2210                         __work_component_property_attendee_partstat(attendee, t[i] + strlen("PARTSTAT") +1);
2211                 else if (CAL_STRING_EQUAL == strncmp(t[i], "RSVP", strlen("RSVP")))
2212                         __work_component_property_attendee_rsvp(attendee, t[i] + strlen("RSVP") +1);
2213                 else if (CAL_STRING_EQUAL == strncmp(t[i], "DELEGATED-TO", strlen("DELEGATED-TO")))
2214                         __work_component_property_attendee_delegated_to(attendee, t[i] + strlen("DELEGATED-TO") +1);
2215                 else if (CAL_STRING_EQUAL == strncmp(t[i], "DELEGATED-FROM", strlen("DELEGATED-FROM")))
2216                         __work_component_property_attendee_delegated_from(attendee, t[i] + strlen("DELEGATED-FROM") +1);
2217                 else if (CAL_STRING_EQUAL == strncmp(t[i], "SENT_BY", strlen("SENT_BY")))
2218                         __work_component_property_attendee_sent_by(attendee, t[i] + strlen("SENT_BY") +1);
2219                 else if (CAL_STRING_EQUAL == strncmp(t[i], "CN", strlen("CN")))
2220                         __work_component_property_attendee_cn(attendee, t[i] + strlen("CN") +1);
2221                 else if (CAL_STRING_EQUAL == strncmp(t[i], "DIR", strlen("DIR")))
2222                         __work_component_property_attendee_dir(attendee, t[i] + strlen("DIR") +1);
2223                 else if (CAL_STRING_EQUAL == strncmp(t[i], ":MAILTO", strlen(":MAILTO")))
2224                         __work_component_property_attendee_mailto(attendee, t[i] + strlen(":MAILTO") +1);
2225                 else
2226                         ERR("Invalid value[%s]", t[i]);
2227
2228         }
2229         g_strfreev(t);
2230
2231         switch (ud->type) {
2232         case CALENDAR_BOOK_TYPE_EVENT:
2233                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_attendee, attendee);
2234                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2235                 break;
2236         case CALENDAR_BOOK_TYPE_TODO:
2237                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_attendee, attendee);
2238                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2239                 break;
2240         }
2241 }
2242
2243 static void __work_component_property_categories(char *value, calendar_record_h record, struct user_data *ud)
2244 {
2245         RET_IF(NULL == value);
2246         RET_IF('\0' == *value);
2247         RET_IF(NULL == record);
2248         RET_IF(NULL == ud);
2249
2250         int ret = 0;
2251         char *s = __decode_charset(value);
2252         __decode_escaped_char(s);
2253         switch (ud->type) {
2254         case CALENDAR_BOOK_TYPE_EVENT:
2255                 ret = cal_record_set_str(record, _calendar_event.categories, s);
2256                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2257                 break;
2258         case CALENDAR_BOOK_TYPE_TODO:
2259                 ret = cal_record_set_str(record, _calendar_todo.categories, s);
2260                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2261                 break;
2262         }
2263         free(s);
2264 }
2265
2266 static void _set_alarm_tick_unit(calendar_record_h alarm, calendar_time_s alarm_time, int diff)
2267 {
2268         int ret = 0;
2269
2270         RET_IF(NULL == alarm);
2271
2272         if (diff < 0) {
2273                 DBG("set specific alarm");
2274                 ret = cal_record_set_caltime(alarm, _calendar_alarm.alarm_time, alarm_time);
2275                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
2276                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_SPECIFIC);
2277                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2278         } else if (0 == diff) {
2279                 DBG("set alarm in start time");
2280                 ret = cal_record_set_int(alarm, _calendar_alarm.tick, 0);
2281                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2282                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_HOUR);
2283                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2284         } else {
2285                 int tick = 0;
2286                 int unit = 0;
2287                 _get_tick_unit(diff, &tick, &unit);
2288                 ret = cal_record_set_int(alarm, _calendar_alarm.tick, tick);
2289                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2290                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, unit);
2291                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2292         }
2293 }
2294
2295 /*
2296  * for ver 1.0
2297  * dalarmparts  = 0*3(strnosemi ";") strnosemi; runTime, snoozeTime, repeatCount, displayString
2298  * DALARM:19960415T235000;PT5M;2;Your Taxes Are Due !!!
2299  */
2300 static void __work_component_property_dalarm(char *value, calendar_record_h record, struct user_data *ud)
2301 {
2302         RET_IF(NULL == value);
2303         RET_IF('\0' == *value);
2304         RET_IF(NULL == record);
2305         RET_IF(NULL == ud);
2306
2307         int ret = 0;
2308         char **t = NULL;
2309         t =  g_strsplit_set(value, ";:", -1);
2310         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2311
2312         calendar_record_h alarm = NULL;
2313         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2314         if (CALENDAR_ERROR_NONE != ret) {
2315                 /* LCOV_EXCL_START */
2316                 ERR("calendar_record_create() Fail(%d)", ret);
2317                 g_strfreev(t);
2318                 return;
2319                 /* LCOV_EXCL_STOP */
2320         }
2321         ret = cal_record_set_int(alarm, _calendar_alarm.action, CALENDAR_ALARM_ACTION_DISPLAY);
2322         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2323
2324         int len = g_strv_length(t);
2325         int i;
2326         int index = VCAL_VER_10_DALARM_NONE;
2327         for (i = 0; i < len; i++) {
2328                 if (index)
2329                         index++;
2330                 if (NULL == t[i] || '\0' == *t[i])
2331                         continue;
2332
2333                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("PTM") < strlen(t[i])) {
2334                         /* runTime */
2335                         index = VCAL_VER_10_DALARM_RUN_TIME;
2336                         calendar_time_s alarm_time = {0};
2337                         ret = _get_caltime(t[i], &alarm_time, ud);
2338                         if (CALENDAR_ERROR_NONE != ret) {
2339                                 /* LCOV_EXCL_START */
2340                                 ERR("_get_caltime() Fail(%d)", ret);
2341                                 index = VCAL_VER_10_AALARM_NONE;
2342                                 break;
2343                                 /* LCOV_EXCL_STOP */
2344                         }
2345
2346                         if (true == ud->has_rrule) {
2347                                 calendar_time_s start_time = {0};
2348                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &start_time);
2349
2350                                 int diff = 0;
2351                                 ret = _sub_caltime(ud, &start_time, &alarm_time, &diff);
2352                                 if (CALENDAR_ERROR_NONE != ret) {
2353                                         /* LCOV_EXCL_START */
2354                                         ERR("_sub_caltime() Fail(%d)", ret);
2355                                         index = VCAL_VER_10_DALARM_NONE;
2356                                         break;
2357                                         /* LCOV_EXCL_STOP */
2358                                 }
2359                                 _set_alarm_tick_unit(alarm, alarm_time, diff);
2360
2361                         } else {
2362                                 _set_alarm_tick_unit(alarm, alarm_time, -1); /* -1 goes to specific time */
2363                         }
2364                 } else if (VCAL_VER_10_DALARM_DISPLAY_STRING == index) { /* displayString */
2365                         DBG("displayString [%s]", t[i]);
2366                         ret = cal_record_set_str(alarm, _calendar_alarm.summary, t[i]);
2367                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2368
2369                 } else {
2370                         /* TYPE, VALUE */
2371                 }
2372         }
2373
2374         if (VCAL_VER_10_DALARM_NONE == index) {
2375                 DBG("No alarm");
2376                 calendar_record_destroy(alarm, true);
2377                 g_strfreev(t);
2378                 return;
2379         }
2380
2381         switch (ud->type) {
2382         case VCALENDAR_TYPE_VEVENT:
2383                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2384                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2385                 break;
2386         case VCALENDAR_TYPE_VTODO:
2387                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2388                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2389                 break;
2390         }
2391         g_strfreev(t);
2392 }
2393
2394 /*
2395  * for ver 1.0
2396  * malarmparts  = 0*4(strnosemi ";") strnosemi; runTime, snoozeTime, repeatCount, addressString, noteString
2397  */
2398 static void __work_component_property_malarm(char *value, calendar_record_h record, struct user_data *ud)
2399 {
2400         /* diff with aalarm: action */
2401         RET_IF(NULL == value);
2402         RET_IF('\0' == *value);
2403         RET_IF(NULL == record);
2404         RET_IF(NULL == ud);
2405
2406         int ret = 0;
2407         char **t = NULL;
2408         t =  g_strsplit_set(value, ";:", -1);
2409         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2410
2411         calendar_record_h alarm = NULL;
2412         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2413         if (CALENDAR_ERROR_NONE != ret) {
2414                 /* LCOV_EXCL_START */
2415                 ERR("calendar_record_create() Fail(%d)", ret);
2416                 g_strfreev(t);
2417                 return;
2418                 /* LCOV_EXCL_STOP */
2419         }
2420         ret = cal_record_set_int(alarm, _calendar_alarm.action, CALENDAR_ALARM_ACTION_EMAIL);
2421         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2422
2423         int len = g_strv_length(t);
2424         int i;
2425         int index = VCAL_VER_10_MALARM_NONE;
2426         for (i = 0; i < len; i++) {
2427                 if (index)
2428                         index++;
2429                 if (NULL == t[i] || '\0' == *t[i])
2430                         continue;
2431
2432                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("PTM") < strlen(t[i])) {
2433                         /* runTime */
2434                         index = VCAL_VER_10_MALARM_RUN_TIME;
2435                         calendar_time_s alarm_time = {0};
2436                         ret = _get_caltime(t[i], &alarm_time, ud);
2437                         if (CALENDAR_ERROR_NONE != ret) {
2438                                 /* LCOV_EXCL_START */
2439                                 ERR("_get_caltime() Fail(%d)", ret);
2440                                 index = VCAL_VER_10_AALARM_NONE;
2441                                 break;
2442                                 /* LCOV_EXCL_STOP */
2443                         }
2444
2445                         if (true == ud->has_rrule) {
2446                                 calendar_time_s start_time = {0};
2447                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &start_time);
2448                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
2449
2450                                 int diff = 0;
2451                                 ret = _sub_caltime(ud, &start_time, &alarm_time, &diff);
2452                                 if (CALENDAR_ERROR_NONE != ret) {
2453                                         /* LCOV_EXCL_START */
2454                                         ERR("_sub_caltime() Fail(%d)", ret);
2455                                         index = VCAL_VER_10_MALARM_NONE;
2456                                         break;
2457                                         /* LCOV_EXCL_STOP */
2458                                 }
2459                                 _set_alarm_tick_unit(alarm, alarm_time, diff);
2460
2461                         } else {
2462                                 _set_alarm_tick_unit(alarm, alarm_time, -1); /* -1 goes to specific time */
2463                         }
2464                 } else if (VCAL_VER_10_MALARM_ADDRESS_STRING == index) { /* addressString */
2465                         DBG("addressString [%s]", t[i]);
2466                         ret = cal_record_set_str(alarm, _calendar_alarm.attach, t[i]);
2467                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2468
2469                 } else if (VCAL_VER_10_MALARM_NOTE_STRING == index) { /* noteString */
2470                         DBG("noteString [%s]", t[i]);
2471                         ret = cal_record_set_str(alarm, _calendar_alarm.description, t[i]);
2472                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2473
2474                 } else {
2475                         /* TYPE, VALUE */
2476                 }
2477         }
2478
2479         if (VCAL_VER_10_MALARM_NONE == index) {
2480                 DBG("No alarm");
2481                 calendar_record_destroy(alarm, true);
2482                 g_strfreev(t);
2483                 return;
2484         }
2485
2486         switch (ud->type) {
2487         case VCALENDAR_TYPE_VEVENT:
2488                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2489                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2490                 break;
2491         case VCALENDAR_TYPE_VTODO:
2492                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2493                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2494                 break;
2495         }
2496         g_strfreev(t);
2497 }
2498 /*
2499  * for ver 1.0
2500  * aalarmparts  = 0*3(strnosemi ";") strnosemi; runTime, snoozeTime, repeatCount, audioContent
2501  * AALARM;TYPE=WAVE;VALUE=URL:19960415T235959; ; ; file:///mmedia/taps.wav
2502  * AALARM;TYPE=WAVE;VALUE=CONTENT-ID:19960903T060000;PT15M;4;<jsmith.part2.=960901T083000.xyzMail@host1.com>
2503  */
2504 static void __work_component_property_aalarm(char *value, calendar_record_h record, struct user_data *ud)
2505 {
2506         CAL_FN_CALL();
2507
2508         RET_IF(NULL == value);
2509         RET_IF('\0' == *value);
2510         RET_IF(NULL == record);
2511         RET_IF(NULL == ud);
2512
2513         int ret = 0;
2514         char **t = NULL;
2515         t =  g_strsplit_set(value, ";:", -1);
2516         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2517
2518         calendar_record_h alarm = NULL;
2519         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2520         if (CALENDAR_ERROR_NONE != ret) {
2521                 /* LCOV_EXCL_START */
2522                 ERR("calendar_record_create() Fail(%d)", ret);
2523                 g_strfreev(t);
2524                 return;
2525                 /* LCOV_EXCL_STOP */
2526         }
2527         ret = cal_record_set_int(alarm, _calendar_alarm.action, CALENDAR_ALARM_ACTION_AUDIO);
2528         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2529
2530         int len = g_strv_length(t);
2531         int i;
2532         int index = VCAL_VER_10_AALARM_NONE;
2533         for (i = 0; i < len; i++) {
2534                 if (index)
2535                         index++;
2536                 if (NULL == t[i] || '\0' == *t[i])
2537                         continue;
2538
2539                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("PTM") < strlen(t[i])) {
2540                         /* runTime */
2541                         index = VCAL_VER_10_AALARM_RUN_TIME;
2542                         calendar_time_s alarm_time = {0};
2543                         ret = _get_caltime(t[i], &alarm_time, ud);
2544                         if (CALENDAR_ERROR_NONE != ret) {
2545                                 /* LCOV_EXCL_START */
2546                                 ERR("_get_caltime() Fail(%d)", ret);
2547                                 index = VCAL_VER_10_AALARM_NONE;
2548                                 break;
2549                                 /* LCOV_EXCL_STOP */
2550                         }
2551
2552                         if (true == ud->has_rrule) {
2553                                 calendar_time_s start_time = {0};
2554                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &start_time);
2555
2556                                 int diff = 0;
2557                                 ret = _sub_caltime(ud, &start_time, &alarm_time, &diff);
2558                                 if (CALENDAR_ERROR_NONE != ret) {
2559                                         /* LCOV_EXCL_START */
2560                                         ERR("_sub_caltime() Fail(%d)", ret);
2561                                         index = VCAL_VER_10_AALARM_NONE;
2562                                         break;
2563                                         /* LCOV_EXCL_STOP */
2564                                 }
2565                                 _set_alarm_tick_unit(alarm, alarm_time, diff);
2566
2567                         } else {
2568                                 _set_alarm_tick_unit(alarm, alarm_time, -1); /* -1 goes to specific time */
2569                         }
2570                 } else if (VCAL_VER_10_AALARM_AUDIO_CONTENT == index) {
2571                         /* audioContent */
2572                         DBG("Content [%s]", t[i]);
2573                         ret = cal_record_set_str(alarm, _calendar_alarm.attach, t[i]);
2574                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2575                 } else {
2576                         /* TYPE, VALUE */
2577                 }
2578         }
2579
2580         if (VCAL_VER_10_AALARM_NONE == index) {
2581                 DBG("No alarm");
2582                 calendar_record_destroy(alarm, true);
2583                 g_strfreev(t);
2584                 return;
2585         }
2586
2587         switch (ud->type) {
2588         case VCALENDAR_TYPE_VEVENT:
2589                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2590                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2591                 break;
2592         case VCALENDAR_TYPE_VTODO:
2593                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2594                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2595                 break;
2596         }
2597         g_strfreev(t);
2598 }
2599
2600 static void __work_component_property_exdate(char *value, calendar_record_h record, struct user_data *ud)
2601 {
2602         RET_IF(NULL == value);
2603         RET_IF('\0' == *value);
2604         RET_IF(NULL == record);
2605         RET_IF(NULL == ud);
2606
2607         int ret = 0;
2608         switch (ud->type) {
2609         case CALENDAR_BOOK_TYPE_EVENT:
2610                 ret = cal_record_set_str(record, _calendar_event.exdate, value + 1);
2611                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2612                 break;
2613         case CALENDAR_BOOK_TYPE_TODO:
2614                 /* LCOV_EXCL_START */
2615                 ERR("No exdate in todo");
2616                 break;
2617                 /* LCOV_EXCL_STOP */
2618         }
2619 }
2620
2621 static void __work_component_property_x_allday(char *value, calendar_record_h record, struct user_data *ud)
2622 {
2623         RET_IF(NULL == value);
2624         RET_IF('\0' == *value);
2625         RET_IF(NULL == record);
2626         RET_IF(NULL == ud);
2627
2628         int ret = 0;
2629         if (CAL_STRING_EQUAL == strncmp(value, ":SET", strlen(":SET"))) {
2630                 DBG("x-allday: set");
2631                 ud->is_allday = true;
2632
2633                 calendar_time_s caltime = {0};
2634                 switch (ud->type) {
2635                 case CALENDAR_BOOK_TYPE_EVENT:
2636                         ret = calendar_record_get_caltime(record, _calendar_event.start_time, &caltime);
2637                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2638                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2639                                 caltime.time.date.hour = 0;
2640                                 caltime.time.date.minute = 0;
2641                                 caltime.time.date.second = 0;
2642                                 ret = cal_record_set_caltime(record, _calendar_event.start_time, caltime);
2643                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2644                         }
2645                         ret = calendar_record_get_caltime(record, _calendar_event.end_time, &caltime);
2646                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2647                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2648                                 caltime.time.date.hour = 0;
2649                                 caltime.time.date.minute = 0;
2650                                 caltime.time.date.second = 0;
2651                                 ret = cal_record_set_caltime(record, _calendar_event.end_time, caltime);
2652                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2653                         }
2654                         ret = calendar_record_get_caltime(record, _calendar_event.until_time, &caltime);
2655                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2656                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2657                                 caltime.time.date.hour = 0;
2658                                 caltime.time.date.minute = 0;
2659                                 caltime.time.date.second = 0;
2660                                 ret = cal_record_set_caltime(record, _calendar_event.until_time, caltime);
2661                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2662                         }
2663                         break;
2664                 case CALENDAR_BOOK_TYPE_TODO:
2665                         ret = calendar_record_get_caltime(record, _calendar_todo.start_time, &caltime);
2666                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2667                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2668                                 caltime.time.date.hour = 0;
2669                                 caltime.time.date.minute = 0;
2670                                 caltime.time.date.second = 0;
2671                                 ret = cal_record_set_caltime(record, _calendar_todo.start_time, caltime);
2672                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2673                         }
2674                         ret = calendar_record_get_caltime(record, _calendar_todo.due_time, &caltime);
2675                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2676                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2677                                 caltime.time.date.hour = 0;
2678                                 caltime.time.date.minute = 0;
2679                                 caltime.time.date.second = 0;
2680                                 ret = cal_record_set_caltime(record, _calendar_todo.due_time, caltime);
2681                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2682                         }
2683                         break;
2684                 }
2685         }
2686 }
2687
2688 static void __work_component_property_x_lunar(char *value, calendar_record_h record, struct user_data *ud)
2689 {
2690         RET_IF(NULL == value);
2691         RET_IF('\0' == *value);
2692         RET_IF(NULL == record);
2693         RET_IF(NULL == ud);
2694
2695         int ret = 0;
2696         if (CAL_STRING_EQUAL == strncmp(value, ":SET", strlen(":SET"))) {
2697                 DBG("x-lunar: set");
2698                 switch (ud->type) {
2699                 case CALENDAR_BOOK_TYPE_EVENT:
2700                         ret = cal_record_set_int(record, _calendar_event.calendar_system_type, CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR);
2701                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2702                         break;
2703                 case CALENDAR_BOOK_TYPE_TODO:
2704                         DBG("Not supported lunar in todo");
2705                         break;
2706                 }
2707         }
2708 }
2709
2710 static void __work_component_property_valarm_action(char *value, calendar_record_h alarm, struct user_data *ud)
2711 {
2712         RET_IF(NULL == value);
2713         RET_IF('\0' == *value);
2714         RET_IF(NULL == alarm);
2715
2716         const char *prop[CALENDAR_ALARM_ACTION_MAX] = {":AUDIO", ":DISPLAY", ":EMAIL"};
2717
2718         int ret = 0;
2719         int i;
2720         for (i = 0; i < CALENDAR_ALARM_ACTION_MAX; i++) {
2721                 if (CAL_STRING_EQUAL == strncmp(value,  prop[i], strlen(prop[i]))) {
2722                         ret = cal_record_set_int(alarm, _calendar_alarm.action, i);
2723                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2724                         break;
2725                 }
2726         }
2727 }
2728
2729 static void __work_component_property_valarm_trigger(char *value, calendar_record_h record, calendar_record_h alarm, struct user_data *ud)
2730 {
2731         CAL_FN_CALL();
2732
2733         RET_IF(NULL == value);
2734         RET_IF('\0' == *value);
2735         RET_IF(NULL == alarm);
2736         RET_IF(NULL == ud);
2737
2738         int ret = 0;
2739         char **t = NULL;
2740         t =  g_strsplit_set(value, ";:", -1);
2741         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2742
2743         int related = VCAL_RELATED_NONE;
2744         int len = g_strv_length(t);
2745         int i;
2746         for (i = 0; i < len; i++) {
2747                 if (NULL == t[i] || '\0' == *t[i]) continue;
2748
2749                 if (CAL_STRING_EQUAL == strncmp(t[i], "RELATED", strlen("RELATED"))) {
2750                         if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("RELATED"), "=START", strlen("=START")))
2751                                 related = VCAL_RELATED_START;
2752                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("RELATED"), "=END", strlen("=END")))
2753                                 related = VCAL_RELATED_END;
2754                         else
2755                                 ERR("Invalid related:[%s]", t[i]);
2756                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "VALUE", strlen("VALUE"))) {
2757                         /* do nothing */
2758                 } else {
2759                         if ('0' <= *t[i] && *t[i] <= '9' && strlen("YYYYDDMM") <= strlen(t[i])) {
2760                                 calendar_time_s caltime = {0};
2761                                 _get_caltime(t[i], &caltime, ud);
2762                                 ret = cal_record_set_caltime(alarm, _calendar_alarm.alarm_time, caltime);
2763                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
2764                                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_SPECIFIC);
2765                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2766                         } else {
2767                                 int unit = 0;
2768                                 int tick = 0;
2769                                 __decode_duration(t[i], strlen(t[i]), &tick, &unit);
2770                                 if (CALENDAR_ALARM_TIME_UNIT_SPECIFIC == unit || 0 < tick) {
2771                                         if (CALENDAR_ALARM_TIME_UNIT_SPECIFIC == unit)
2772                                                 DBG("alarm tick is second, changed as specific.");
2773                                         if (0 < tick)
2774                                                 DBG("alarm is set after start/end time(%d).", tick);
2775
2776                                         calendar_time_s caltime = {0};
2777                                         if (VCAL_RELATED_NONE == related) {
2778                                                 switch (ud->type) {
2779                                                 case CALENDAR_BOOK_TYPE_EVENT:
2780                                                         related = VCAL_RELATED_START;
2781                                                         break;
2782                                                 case CALENDAR_BOOK_TYPE_TODO:
2783                                                         related = VCAL_RELATED_END;
2784                                                         break;
2785                                                 }
2786                                         }
2787                                         switch (related) {
2788                                         case VCAL_RELATED_START:
2789                                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &caltime);
2790                                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
2791                                                 break;
2792                                         case VCAL_RELATED_END:
2793                                                 ret = calendar_record_get_caltime(record, _calendar_event.end_time, &caltime);
2794                                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
2795                                                 break;
2796                                         }
2797                                         cal_time_modify_caltime(&caltime, tick * unit);
2798                                         ret = cal_record_set_caltime(alarm, _calendar_alarm.alarm_time, caltime);
2799                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
2800                                         ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_SPECIFIC);
2801                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2802                                 } else {
2803                                         ret = cal_record_set_int(alarm, _calendar_alarm.tick, (-1 * tick));
2804                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2805                                         ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, unit);
2806                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2807                                 }
2808                         }
2809                 }
2810         }
2811
2812         g_strfreev(t);
2813 }
2814
2815 static void __work_component_property_valarm_repeat(char *value, calendar_record_h alarm, struct user_data *ud)
2816 {
2817         return;
2818 }
2819
2820 static void __work_component_property_valarm_attach(char *value, calendar_record_h alarm, struct user_data *ud)
2821 {
2822         RET_IF(NULL == value);
2823         RET_IF('\0' == *value);
2824         RET_IF(NULL == alarm);
2825
2826         int ret = cal_record_set_str(alarm, _calendar_alarm.attach, value + 1);
2827         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2828 }
2829
2830 static void __work_component_property_valarm_description(char *value, calendar_record_h alarm, struct user_data *ud)
2831 {
2832         RET_IF(NULL == value);
2833         RET_IF('\0' == *value);
2834         RET_IF(NULL == alarm);
2835
2836         int ret = cal_record_set_str(alarm, _calendar_alarm.description, value + 1);
2837         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2838 }
2839
2840 static void __work_component_property_valarm_summary(char *value, calendar_record_h alarm, struct user_data *ud)
2841 {
2842         RET_IF(NULL == value);
2843         RET_IF('\0' == *value);
2844         RET_IF(NULL == alarm);
2845
2846         int ret = cal_record_set_str(alarm, _calendar_alarm.summary, value);
2847         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2848 }
2849
2850 static void __work_component_property_valarm_duration(char *value, calendar_record_h alarm, struct user_data *ud)
2851 {
2852         return;
2853 }
2854
2855 static char* __work_component_property_begin(char *cursor, calendar_record_h record, struct user_data *ud)
2856 {
2857         CAL_FN_CALL();
2858
2859         RETV_IF(NULL == cursor, NULL);
2860         RETV_IF(NULL == record, NULL);
2861         RETV_IF(NULL == ud, NULL);
2862
2863         if (0 != strncmp(cursor, ":VALARM", strlen(":VALARM"))) {
2864                 DBG("this is not valarm");
2865                 return __crlf(cursor);
2866         }
2867
2868         __init_component_property_valarm();
2869
2870         int ret = 0;
2871         calendar_record_h alarm = NULL;
2872         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2873         RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
2874
2875         cursor = __crlf(cursor); /* crlf: BEGIN:VALARM */
2876         bool exit_loop = false;
2877         while (cursor) {
2878                 int index = 0;
2879                 cursor = __get_index(cursor, component_property_valarm, VCAL_COMPONENT_PROPERTY_VALARM_MAX, &index);
2880
2881                 char *value = NULL;
2882                 switch (index) {
2883                 case VCAL_COMPONENT_PROPERTY_VALARM_ACTION:
2884                         cursor = __get_value(cursor, &value);
2885                         __work_component_property_valarm_action(value, alarm, ud);
2886                         free(value);
2887                         value = NULL;
2888                         break;
2889
2890                 case VCAL_COMPONENT_PROPERTY_VALARM_TRIGGER:
2891                         cursor = __get_value(cursor, &value);
2892                         __work_component_property_valarm_trigger(value, record, alarm, ud);
2893                         free(value);
2894                         value = NULL;
2895                         break;
2896
2897                 case VCAL_COMPONENT_PROPERTY_VALARM_REPEAT:
2898                         cursor = __get_value(cursor, &value);
2899                         __work_component_property_valarm_repeat(value, alarm, ud);
2900                         free(value);
2901                         value = NULL;
2902                         break;
2903
2904                 case VCAL_COMPONENT_PROPERTY_VALARM_ATTACH:
2905                         cursor = __get_value(cursor, &value);
2906                         __work_component_property_valarm_attach(value, alarm, ud);
2907                         free(value);
2908                         value = NULL;
2909                         break;
2910
2911                 case VCAL_COMPONENT_PROPERTY_VALARM_DESCRIPTION:
2912                         cursor = __get_value(cursor, &value);
2913                         __work_component_property_valarm_description(value, alarm, ud);
2914                         free(value);
2915                         value = NULL;
2916                         break;
2917
2918                 case VCAL_COMPONENT_PROPERTY_VALARM_SUMMARY:
2919                         cursor = __get_value(cursor, &value);
2920                         __work_component_property_valarm_summary(value, alarm, ud);
2921                         free(value);
2922                         value = NULL;
2923                         break;
2924
2925                 case VCAL_COMPONENT_PROPERTY_VALARM_DURATION:
2926                         cursor = __get_value(cursor, &value);
2927                         __work_component_property_valarm_duration(value, alarm, ud);
2928                         free(value);
2929                         value = NULL;
2930                         break;
2931
2932                 case VCAL_COMPONENT_PROPERTY_VALARM_END:
2933                         DBG("exit valarm");
2934                         exit_loop = true;
2935                         break;
2936
2937                 default:
2938                         /* LCOV_EXCL_START */
2939                         ERR("Invalid index(%d)", index);
2940                         cursor = __crlf(cursor);
2941                         break;
2942                         /* LCOV_EXCL_STOP */
2943                 }
2944
2945                 if (true == exit_loop) break;
2946         }
2947
2948         switch (ud->type) {
2949         case VCALENDAR_TYPE_VEVENT:
2950                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2951                 break;
2952         case VCALENDAR_TYPE_VTODO:
2953                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2954                 break;
2955         }
2956         RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_add_child_record() Fail(%d)", ret);
2957         return cursor;
2958 }
2959
2960 static char* __work_component_vevent(char *cursor, calendar_record_h record, struct user_data *ud)
2961 {
2962         RETV_IF(NULL == cursor, NULL);
2963         RETV_IF(NULL == record, NULL);
2964
2965         bool exit_loop = false;
2966         while (cursor) {
2967                 int index = 0;
2968                 cursor = __get_index(cursor, component_property, VCAL_COMPONENT_PROPERTY_MAX, &index);
2969
2970                 char *value = NULL;
2971                 switch (index) {
2972                 case VCAL_COMPONENT_PROPERTY_DTSTAMP:
2973                         cursor = __get_value(cursor, &value);
2974                         __work_component_property_dtstamp(value, record, ud);
2975                         free(value);
2976                         value = NULL;
2977                         break;
2978                 case VCAL_COMPONENT_PROPERTY_UID:
2979                         cursor = __get_value(cursor, &value);
2980                         __work_component_property_uid(value, record, ud);
2981                         free(value);
2982                         value = NULL;
2983                         break;
2984                 case VCAL_COMPONENT_PROPERTY_RECURRENCE_ID:
2985                         cursor = __get_value(cursor, &value);
2986                         __work_component_property_recurrence_id(value, record, ud);
2987                         free(value);
2988                         value = NULL;
2989                         break;
2990                 case VCAL_COMPONENT_PROPERTY_DTSTART:
2991                         cursor = __get_value(cursor, &value);
2992                         __work_component_property_dtstart(value, record, ud);
2993                         free(value);
2994                         value = NULL;
2995                         break;
2996                 case VCAL_COMPONENT_PROPERTY_CREATED:
2997                         cursor = __get_value(cursor, &value);
2998                         __work_component_property_created(value, record, ud);
2999                         free(value);
3000                         value = NULL;
3001                         break;
3002                 case VCAL_COMPONENT_PROPERTY_DCREATED:
3003                         cursor = __get_value(cursor, &value);
3004                         __work_component_property_created(value, record, ud);
3005                         free(value);
3006                         value = NULL;
3007                         break;
3008                 case VCAL_COMPONENT_PROPERTY_DESCRIPTION:
3009                         cursor = __get_value(cursor, &value);
3010                         __work_component_property_description(value, record, ud);
3011                         free(value);
3012                         value = NULL;
3013                         break;
3014                 case VCAL_COMPONENT_PROPERTY_LAST_MODIFIED:
3015                         cursor = __get_value(cursor, &value);
3016                         __work_component_property_last_modified(value, record, ud);
3017                         free(value);
3018                         value = NULL;
3019                         break;
3020                 case VCAL_COMPONENT_PROPERTY_LOCATION:
3021                         cursor = __get_value(cursor, &value);
3022                         __work_component_property_location(value, record, ud);
3023                         free(value);
3024                         value = NULL;
3025                         break;
3026                 case VCAL_COMPONENT_PROPERTY_PRIORITY:
3027                         cursor = __get_value(cursor, &value);
3028                         __work_component_property_priority(value + 1, record, ud);
3029                         free(value);
3030                         value = NULL;
3031                         break;
3032                 case VCAL_COMPONENT_PROPERTY_STATUS:
3033                         cursor = __get_value(cursor, &value);
3034                         __work_component_property_status(value, record, ud);
3035                         free(value);
3036                         value = NULL;
3037                         break;
3038                 case VCAL_COMPONENT_PROPERTY_SUMMARY:
3039                         cursor = __get_value(cursor, &value);
3040                         __work_component_property_summary(value, record, ud);
3041                         free(value);
3042                         value = NULL;
3043                         break;
3044                 case VCAL_COMPONENT_PROPERTY_RRULE:
3045                         cursor = __get_value(cursor, &value);
3046                         __work_component_property_rrule(value, record, ud);
3047                         free(value);
3048                         value = NULL;
3049                         break;
3050                 case VCAL_COMPONENT_PROPERTY_DTEND:
3051                         if (CAL_STRING_EQUAL != strcmp(((cal_record_s*)(record))->view_uri, _calendar_event._uri))
3052                                 break;
3053                         cursor = __get_value(cursor, &value);
3054                         __work_component_property_dtend(value, record, ud);
3055                         free(value);
3056                         value = NULL;
3057                         break;
3058                 case VCAL_COMPONENT_PROPERTY_DUE:
3059                         if (CAL_STRING_EQUAL != strcmp(((cal_record_s*)(record))->view_uri, _calendar_todo._uri))
3060                                 break;
3061                         cursor = __get_value(cursor, &value);
3062                         __work_component_property_dtend(value, record, ud);
3063                         free(value);
3064                         value = NULL;
3065                         break;
3066                 case VCAL_COMPONENT_PROPERTY_ATTENDEE:
3067                         cursor = __get_value(cursor, &value);
3068                         __work_component_property_attendee(value, record, ud);
3069                         free(value);
3070                         value = NULL;
3071                         break;
3072                 case VCAL_COMPONENT_PROPERTY_CATEGORIES:
3073                         cursor = __get_value(cursor, &value);
3074                         __work_component_property_categories(value, record, ud);
3075                         free(value);
3076                         value = NULL;
3077                         break;
3078                 case VCAL_COMPONENT_PROPERTY_DALARM:
3079                         cursor = __get_value(cursor, &value);
3080                         __work_component_property_dalarm(value, record, ud);
3081                         free(value);
3082                         value = NULL;
3083                         break;
3084                 case VCAL_COMPONENT_PROPERTY_MALARM:
3085                         cursor = __get_value(cursor, &value);
3086                         __work_component_property_malarm(value, record, ud);
3087                         free(value);
3088                         value = NULL;
3089                         break;
3090                 case VCAL_COMPONENT_PROPERTY_AALARM:
3091                         cursor = __get_value(cursor, &value);
3092                         __work_component_property_aalarm(value, record, ud);
3093                         free(value);
3094                         value = NULL;
3095                         break;
3096                 case VCAL_COMPONENT_PROPERTY_EXDATE:
3097                         cursor = __get_value(cursor, &value);
3098                         __work_component_property_exdate(value, record, ud);
3099                         free(value);
3100                         value = NULL;
3101                         break;
3102                 case VCAL_COMPONENT_PROPERTY_X_ALLDAY:
3103                         cursor = __get_value(cursor, &value);
3104                         __work_component_property_x_allday(value, record, ud);
3105                         free(value);
3106                         value = NULL;
3107                         break;
3108                 case VCAL_COMPONENT_PROPERTY_X_LUNAR:
3109                         cursor = __get_value(cursor, &value);
3110                         __work_component_property_x_lunar(value, record, ud);
3111                         free(value);
3112                         value = NULL;
3113                         break;
3114                 case VCAL_COMPONENT_PROPERTY_BEGIN:
3115                         cursor = __work_component_property_begin(cursor, record, ud);
3116                         if (NULL == cursor)
3117                                 cursor = __crlf(cursor);
3118                         break;
3119                 case VCAL_COMPONENT_PROPERTY_END:
3120                         DBG("exit record");
3121                         cursor = __crlf(cursor);
3122                         exit_loop = true;
3123                         break;
3124                 case VCAL_COMPONENT_PROPERTY_EXTENDED:
3125                         cursor = __get_value(cursor, &value);
3126                         free(value);
3127                         value = NULL;
3128                         break;
3129                 default:
3130                         cursor = __crlf(cursor);
3131                         break;
3132                 }
3133                 if (true == exit_loop) break;
3134         }
3135         return cursor;
3136 }
3137
3138 static char* __work_component_vjournal(char *cursor, calendar_record_h record, struct user_data *ud)
3139 {
3140         RETV_IF(NULL == cursor, NULL);
3141
3142         DBG("Not supported vjournal");
3143
3144         bool exit_loop = false;
3145         while (cursor) {
3146                 int index = 0;
3147                 cursor = __get_index(cursor, component_property, VCAL_COMPONENT_PROPERTY_MAX, &index);
3148                 switch (index) {
3149                 case VCAL_COMPONENT_PROPERTY_END:
3150                         DBG("exit record");
3151                         cursor = __crlf(cursor);
3152                         exit_loop = true;
3153                         break;
3154
3155                 default:
3156                         cursor = __crlf(cursor);
3157                         break;
3158                 }
3159                 if (true == exit_loop) break;
3160         }
3161         return cursor;
3162 }
3163
3164 static char* __work_component_vfreebusy(char *cursor, calendar_record_h record, struct user_data *ud)
3165 {
3166         RETV_IF(NULL == cursor, NULL);
3167
3168         DBG("Not supported vfreebusy");
3169
3170         bool exit_loop = false;
3171         while (cursor) {
3172                 int index = 0;
3173                 cursor = __get_index(cursor, component_property, VCAL_COMPONENT_PROPERTY_MAX, &index);
3174                 switch (index) {
3175                 case VCAL_COMPONENT_PROPERTY_END:
3176                         DBG("exit record");
3177                         cursor = __crlf(cursor);
3178                         exit_loop = true;
3179                         break;
3180
3181                 default:
3182                         cursor = __crlf(cursor);
3183                         break;
3184                 }
3185                 if (true == exit_loop) break;
3186         }
3187         return cursor;
3188 }
3189
3190 static void __work_component_property_vtimezone_standard_dtstart(char *value, calendar_record_h record, struct user_data *ud)
3191 {
3192         CAL_FN_CALL();
3193
3194         RET_IF(NULL == value);
3195         RET_IF('\0' == *value);
3196         RET_IF(NULL == record);
3197
3198         int ret = 0;
3199         int y = 0, m = 0, d = 0;
3200         int h = 0, n = 0, s = 0;
3201         sscanf(value +1, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
3202         ret = cal_record_set_int(record, _calendar_timezone.standard_start_month, m);
3203         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3204         ret = cal_record_set_int(record, _calendar_timezone.standard_start_hour, h);
3205         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3206
3207         long long int t = cal_time_convert_lli(value +1);
3208         int nth = 0, wday = 0;
3209         cal_time_get_nth_wday(t, &nth, &wday);
3210         ret = cal_record_set_int(record, _calendar_timezone.standard_start_position_of_week, nth);
3211         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3212         ret = cal_record_set_int(record, _calendar_timezone.standard_start_day, wday);
3213         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3214 }
3215 static void __work_component_property_vtimezone_standard_tzoffsetfrom(char *value, calendar_record_h record, struct user_data *ud)
3216 {
3217         return;
3218 }
3219 static void __work_component_property_vtimezone_standard_tzoffsetto(char *value, calendar_record_h record, struct user_data *ud)
3220 {
3221         CAL_FN_CALL();
3222
3223         RET_IF(NULL == value);
3224         RET_IF('\0' == *value);
3225         RET_IF(NULL == record);
3226
3227         char c;
3228         int h = 0, m = 0;
3229         sscanf(value, "%c%02d%02d", &c, &h, &m);
3230
3231         int offset = h * 60 + m;
3232         if ('-' == c) offset *= -1;
3233
3234         int ret = 0;
3235         ret = cal_record_set_int(record, _calendar_timezone.standard_bias, offset);
3236         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3237         ret = cal_record_set_int(record, _calendar_timezone.tz_offset_from_gmt, offset);
3238         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3239
3240         if (NULL == ud->timezone_tzid || '\0' == *ud->timezone_tzid) {
3241                 char buf[CAL_STR_SHORT_LEN32] = {0};
3242                 snprintf(buf, sizeof(buf), "Etc/GMT%c%d", offset < 0 ? '+' : '-', h);
3243                 ud->timezone_tzid = strdup(buf);
3244                 __adjust_tzid(ud->timezone_tzid);
3245                 DBG("timezone_tzid[%s]", ud->timezone_tzid);
3246         }
3247 }
3248 static void __work_component_property_vtimezone_standard_tzname(char *value, calendar_record_h record, struct user_data *ud)
3249 {
3250         RET_IF(NULL == value);
3251         RET_IF('\0' == *value);
3252         RET_IF(NULL == record);
3253
3254         int ret = cal_record_set_str(record, _calendar_timezone.standard_name, value);
3255         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
3256 }
3257 static void __work_component_property_vtimezone_standard_rdate(char *value, calendar_record_h record, struct user_data *ud)
3258 {
3259         return;
3260 }
3261 static char* __work_component_vtimezone_standard(char *cursor, calendar_record_h record, struct user_data *ud)
3262 {
3263         CAL_FN_CALL();
3264
3265         RETV_IF(NULL == cursor, __crlf(cursor));
3266         RETV_IF('\0' == *cursor, __crlf(cursor));
3267         RETV_IF(NULL == record, __crlf(cursor));
3268
3269         cursor = __crlf(cursor);
3270         bool exit_loop = false;
3271         while (cursor) {
3272                 int index = 0;
3273                 cursor = __get_index(cursor, component_property_vtimezone, VCAL_COMPONENT_PROPERTY_VTIMEZONE_MAX, &index);
3274
3275                 char *value = NULL;
3276                 switch (index) {
3277                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_DTSTART:
3278                         cursor = __get_value(cursor, &value);
3279                         __work_component_property_vtimezone_standard_dtstart(value +1, record, ud);
3280                         free(value);
3281                         value = NULL;
3282                         break;
3283                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETFROM:
3284                         cursor = __get_value(cursor, &value);
3285                         __work_component_property_vtimezone_standard_tzoffsetfrom(value, record, ud);
3286                         free(value);
3287                         value = NULL;
3288                         break;
3289                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETTO:
3290                         cursor = __get_value(cursor, &value);
3291                         __work_component_property_vtimezone_standard_tzoffsetto(value +1, record, ud);
3292                         free(value);
3293                         value = NULL;
3294                         break;
3295                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZNAME:
3296                         cursor = __get_value(cursor, &value);
3297                         __work_component_property_vtimezone_standard_tzname(value +1, record, ud);
3298                         free(value);
3299                         value = NULL;
3300                         break;
3301                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_RDATE:
3302                         cursor = __get_value(cursor, &value);
3303                         __work_component_property_vtimezone_standard_rdate(value, record, ud);
3304                         free(value);
3305                         value = NULL;
3306                         break;
3307                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_END:
3308                         cursor = __crlf(cursor);
3309                         exit_loop = true;
3310                         break;
3311                 default:
3312                         cursor = __crlf(cursor);
3313                         break;
3314                 }
3315                 if (true == exit_loop) break;
3316         }
3317         return cursor;
3318 }
3319
3320 static void __work_component_property_vtimezone_daylight_dtstart(char *value, calendar_record_h record, struct user_data *ud)
3321 {
3322         RET_IF(NULL == value);
3323         RET_IF('\0' == *value);
3324         RET_IF(NULL == record);
3325
3326         int ret = 0;
3327         int y = 0, m = 0, d = 0;
3328         int h = 0, n = 0, s = 0;
3329         sscanf(value +1, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
3330         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_month, m);
3331         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3332         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_hour, h);
3333         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3334
3335         long long int t = cal_time_convert_lli(value +1);
3336         int nth = 0, wday = 0;
3337         cal_time_get_nth_wday(t, &nth, &wday);
3338         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_position_of_week, nth);
3339         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3340         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_day, wday);
3341         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3342 }
3343 static void __work_component_property_vtimezone_daylight_tzoffsetfrom(char *value, calendar_record_h record, struct user_data *ud)
3344 {
3345         return;
3346 }
3347 static void __work_component_property_vtimezone_daylight_tzoffsetto(char *value, calendar_record_h record, struct user_data *ud)
3348 {
3349         RET_IF(NULL == value);
3350         RET_IF('\0' == *value);
3351         RET_IF(NULL == record);
3352
3353         char c;
3354         int h = 0, m = 0;
3355         sscanf(value, "%c%02d%02d", &c, &h, &m);
3356
3357         int offset = h * 60 + m;
3358         if ('-' == c) offset *= -1;
3359
3360         int ret = cal_record_set_int(record, _calendar_timezone.day_light_bias, offset);
3361         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3362 }
3363 static void __work_component_property_vtimezone_daylight_tzname(char *value, calendar_record_h record, struct user_data *ud)
3364 {
3365         RET_IF(NULL == value);
3366         RET_IF('\0' == *value);
3367         RET_IF(NULL == record);
3368
3369         int ret = cal_record_set_str(record, _calendar_timezone.day_light_name, value);
3370         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
3371 }
3372 static void __work_component_property_vtimezone_daylight_rdate(char *value, calendar_record_h record, struct user_data *ud)
3373 {
3374         return;
3375 }
3376 static char* __work_component_vtimezone_daylight(char *cursor, calendar_record_h record, struct user_data *ud)
3377 {
3378         RETV_IF(NULL == cursor, __crlf(cursor));
3379         RETV_IF('\0' == *cursor, __crlf(cursor));
3380         RETV_IF(NULL == record, __crlf(cursor));
3381
3382         cursor = __crlf(cursor);
3383         bool exit_loop = false;
3384         while (cursor) {
3385                 int index = 0;
3386                 cursor = __get_index(cursor, component_property_vtimezone, VCAL_COMPONENT_PROPERTY_VTIMEZONE_MAX, &index);
3387
3388                 char *value = NULL;
3389                 switch (index) {
3390                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_DTSTART:
3391                         cursor = __get_value(cursor, &value);
3392                         __work_component_property_vtimezone_daylight_dtstart(value +1, record, ud);
3393                         free(value);
3394                         value = NULL;
3395                         break;
3396                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETFROM:
3397                         cursor = __get_value(cursor, &value);
3398                         __work_component_property_vtimezone_daylight_tzoffsetfrom(value, record, ud);
3399                         free(value);
3400                         value = NULL;
3401                         break;
3402                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETTO:
3403                         cursor = __get_value(cursor, &value);
3404                         __work_component_property_vtimezone_daylight_tzoffsetto(value +1, record, ud);
3405                         free(value);
3406                         value = NULL;
3407                         break;
3408                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZNAME:
3409                         cursor = __get_value(cursor, &value);
3410                         __work_component_property_vtimezone_daylight_tzname(value +1, record, ud);
3411                         free(value);
3412                         value = NULL;
3413                         break;
3414                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_RDATE:
3415                         cursor = __get_value(cursor, &value);
3416                         __work_component_property_vtimezone_daylight_rdate(value, record, ud);
3417                         free(value);
3418                         value = NULL;
3419                         break;
3420                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_END:
3421                         cursor = __crlf(cursor);
3422                         exit_loop = true;
3423                         break;
3424                 default:
3425                         cursor = __crlf(cursor);
3426                         break;
3427                 }
3428                 if (true == exit_loop) break;
3429         }
3430         return cursor;
3431 }
3432
3433 static char* __work_component_vtimezone(char *cursor, calendar_record_h record, struct user_data *ud)
3434 {
3435         CAL_FN_CALL();
3436
3437         RETV_IF(NULL == cursor, NULL);
3438         RETV_IF(NULL == record, NULL);
3439
3440         __init_component_property_vtimezone();
3441
3442         while (cursor) {
3443                 if (CAL_STRING_EQUAL == strncmp(cursor, "TZID:", strlen("TZID:"))) {
3444                         char *p = cursor + strlen("TZID");
3445                         if (NULL == p || '\0' == *p) {
3446                                 /* LCOV_EXCL_START */
3447                                 ERR("Inavlid tzid");
3448                                 cursor = __crlf(cursor);
3449                                 continue;
3450                                 /* LCOV_EXCL_STOP */
3451                         }
3452                         if (ud->timezone_tzid) {
3453                                 free(ud->timezone_tzid);
3454                                 ud->timezone_tzid = NULL;
3455                         }
3456                         char *value = NULL;
3457                         cursor = __get_value(p, &value);
3458                         __adjust_tzid(value);
3459                         DBG("tzid[%s]", value +1);
3460                         if (true == cal_time_is_available_tzid(value +1))
3461                                 ud->timezone_tzid = strdup(value +1);
3462                         else
3463                                 DBG("Invalid tzid string[%s]", value +1);
3464
3465                         free(value);
3466                 } else if (CAL_STRING_EQUAL == strncmp(cursor, "BEGIN:STANDARD", strlen("BEGIN:STANDARD"))) {
3467                         cursor = __work_component_vtimezone_standard(cursor, record, ud);
3468                 } else if (CAL_STRING_EQUAL == strncmp(cursor, "BEGIN:DAYLIGHT", strlen("BEGIN:DAYLIGHT"))) {
3469                         cursor = __work_component_vtimezone_daylight(cursor, record, ud);
3470                 } else if (CAL_STRING_EQUAL == strncmp(cursor, "END", strlen("END"))) {
3471                         cursor = __crlf(cursor);
3472                         break;
3473                 } else {
3474                         DBG("Unable to parse");
3475                         __print_cursor(cursor, __LINE__);
3476                         cursor = __crlf(cursor);
3477                 }
3478         }
3479         return cursor;
3480 }
3481
3482 static char* __work_property_begin(char *cursor, calendar_record_h *out_record, struct user_data *ud)
3483 {
3484         CAL_FN_CALL();
3485         RETV_IF(NULL == cursor, NULL);
3486         RETV_IF('\0' == *cursor, NULL);
3487         RETV_IF(NULL == out_record, NULL);
3488         RETV_IF(NULL == ud, NULL);
3489
3490         int ret = 0;
3491         int index = 0;
3492         cursor = __get_index(cursor +1, vcal_component, VCAL_COMPONENT_MAX, &index);
3493         cursor = __crlf(cursor);
3494         calendar_record_h record = NULL;
3495         switch (index) {
3496         case VCAL_COMPONENT_VEVENT:
3497                 ret = calendar_record_create(_calendar_event._uri, &record);
3498                 RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
3499                 ud->type = CALENDAR_BOOK_TYPE_EVENT;
3500                 ud->has_rrule = __check_has_rrule(cursor);
3501                 cursor = __work_component_vevent(cursor, record, ud);
3502                 break;
3503
3504         case VCAL_COMPONENT_VTODO:
3505                 ret = calendar_record_create(_calendar_todo._uri, &record);
3506                 RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
3507                 ud->type = CALENDAR_BOOK_TYPE_TODO;
3508                 ud->has_rrule = __check_has_rrule(cursor);
3509                 cursor = __work_component_vevent(cursor, record, ud); /* same as event */
3510                 break;
3511
3512         case VCAL_COMPONENT_VJOURNAL:
3513                 cursor = __work_component_vjournal(cursor, record, ud);
3514                 break;
3515
3516         case VCAL_COMPONENT_VFREEBUSY:
3517                 cursor = __work_component_vfreebusy(cursor, record, ud);
3518                 break;
3519
3520         case VCAL_COMPONENT_VTIMEZONE:
3521                 ret = calendar_record_create(_calendar_timezone._uri, &record);
3522                 RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
3523                 cursor = __work_component_vtimezone(cursor, record, ud);
3524                 break;
3525         }
3526         *out_record = record;
3527         return cursor;
3528 }
3529
3530 int cal_vcalendar_parse_vcalendar_object(char *stream, calendar_list_h list, vcalendar_foreach_s *foreach_data)
3531 {
3532         CAL_FN_CALL();
3533
3534         RETV_IF(NULL == stream, CALENDAR_ERROR_INVALID_PARAMETER);
3535         RETV_IF(NULL == list, CALENDAR_ERROR_INVALID_PARAMETER);
3536
3537         __init_component();
3538         __init_property();
3539         __init_component_property();
3540         __unfolding(stream);
3541
3542         struct user_data *ud = calloc(1, sizeof(struct user_data));
3543         RETVM_IF(NULL == ud, CALENDAR_ERROR_OUT_OF_MEMORY, "calloc() Fail");
3544         ud->version = VCAL_VER_2; /* default */
3545
3546         calendar_record_h record = NULL;
3547
3548         int count = 0;
3549         bool exit_loop = false;
3550         char *cursor = (char *)stream;
3551         while (cursor) {
3552                 int index = 0;
3553                 char *value = NULL;
3554                 cursor = __get_index(cursor, vcal_property, VCAL_PROPERTY_MAX, &index);
3555                 switch (index) {
3556                 case VCAL_PROPERTY_VERSION:
3557                         cursor = __get_value(cursor, &value);
3558                         __get_version(value, &ud->version);
3559                         free(value);
3560                         value = NULL;
3561                         break;
3562
3563                 case VCAL_PROPERTY_TZ:
3564                         if (ud->timezone_tzid)
3565                                 break;
3566                         cursor = __get_value(cursor, &value);
3567                         __get_tz(value + 1, &ud->timezone_tzid);
3568                         __adjust_tzid(ud->timezone_tzid);
3569                         DBG("timezone_tzid[%s]", ud->timezone_tzid);
3570                         free(value);
3571                         value = NULL;
3572                         break;
3573
3574                 case VCAL_PROPERTY_BEGIN: /* BEGIN:VEVENT */
3575                         cursor = __work_property_begin(cursor, &record, ud);
3576                         calendar_list_add(list, record);
3577                         count++;
3578                         if (foreach_data) {
3579                                 foreach_data->ret = foreach_data->callback(record, foreach_data->user_data);
3580                                 if (false == foreach_data->ret)
3581                                         exit_loop = true;
3582                         }
3583                         break;
3584
3585                 case VCAL_PROPERTY_END: /* END:VCALENDAR */
3586                         DBG("exit VCALENDAR");
3587                         /* fini vcalendar */
3588                         exit_loop = true;
3589                         break;
3590
3591                 default:
3592                         DBG("skip invalid property, index(%d)", index);
3593                         cursor = __crlf(cursor);
3594                         break;
3595                 }
3596                 if (true == exit_loop)
3597                         break;
3598         }
3599
3600         DBG("count(%d)", count);
3601         if (0 == count)
3602                 DBG("No record");
3603         free(ud->timezone_tzid);
3604         free(ud);
3605
3606         return CALENDAR_ERROR_NONE;
3607 }