[svace] checked null before using pointer
[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         if (NULL == s) {
809                 /* LCOV_EXCL_START */
810                 ERR("g_strsplit() Fail");
811                 return NULL;
812                 /* LCOV_EXCL_STOP */
813         }
814
815         int count_param = g_strv_length(s);
816         DBG("count_param(%d)", count_param);
817         int i;
818         for (i = 0; i < count_param; i++) {
819                 if (NULL == s[i] || '\0' == *s[i])
820                         continue;
821
822                 if (CAL_STRING_EQUAL != strncmp(s[i], "TZID=", strlen("TZID=")))
823                         continue;
824
825                 if (ud->datetime_tzid)
826                         break;
827
828                 char *tzid = NULL;
829                 tzid = strdup(s[i] + strlen("TZID="));
830                 if (NULL == tzid) {
831                         /* LCOV_EXCL_START */
832                         ERR("strdup() Fail");
833                         break;
834                         /* LCOV_EXCL_STOP */
835                 }
836                 __adjust_tzid(tzid);
837                 DBG("modified tzid[%s]", tzid);
838
839                 if (true == cal_time_is_available_tzid(tzid)) {
840                         DBG("VALID tzid");
841                         ud->datetime_tzid = tzid;
842                         break;
843                 }
844                 free(tzid);
845
846                 if (ud->timezone_tzid && *ud->timezone_tzid) {
847                         ud->datetime_tzid = strdup(ud->timezone_tzid);
848                         if (NULL == ud->datetime_tzid) {
849                                 /* LCOV_EXCL_START */
850                                 ERR("strdup() Fail");
851                                 break;
852                                 /* LCOV_EXCL_STOP */
853                         }
854                         DBG("set datetime_tzid[%s] as timezone_tzid", ud->datetime_tzid);
855                 } else {
856                         /* LCOV_EXCL_START */
857                         ERR("INVALID tzid");
858                         /* LCOV_EXCL_STOP */
859                 }
860                 break;
861         }
862         g_strfreev(s);
863         /* param end */
864
865         DBG("(%d) (%d) [%s]", strlen(p), len_param, p + strlen(p) +1);
866         return p + strlen(p) +1;
867 }
868
869 static void __decode_duration(char *cursor, int len, int *tick, int *unit)
870 {
871         RET_IF(NULL == cursor);
872         RET_IF('\0' == *cursor);
873         RET_IF(NULL == tick);
874         RET_IF(NULL == unit);
875
876         char buf[8] = {0};
877         int sign = 1;
878         int digit = 0;
879         int t = 0, u = 0;
880         int i;
881         for (i = 0; i < len; i++) {
882                 switch (*(cursor + i)) {
883                 case '0':
884                 case '1':
885                 case '2':
886                 case '3':
887                 case '4':
888                 case '5':
889                 case '6':
890                 case '7':
891                 case '8':
892                 case '9':
893                         digit++;
894                         break;
895                 case '+':
896                         break;
897                 case '-':
898                         sign = -1;
899                         break;
900                 case 'P':
901                         break;
902                 case 'T':
903                         break;
904                 case 'W':
905                         u = CALENDAR_ALARM_TIME_UNIT_WEEK;
906                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
907                         t = atoi(buf) * u;
908                         DBG("[%s] (%d)", buf, t);
909                         digit = 0;
910                         break;
911                 case 'D':
912                         u = CALENDAR_ALARM_TIME_UNIT_DAY;
913                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
914                         t += atoi(buf) * u;
915                         DBG("[%s] (%d)", buf, t);
916                         digit = 0;
917                         break;
918                 case 'H':
919                         u = CALENDAR_ALARM_TIME_UNIT_HOUR;
920                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
921                         t += atoi(buf) * u;
922                         DBG("[%s] (%d)", buf, t);
923                         digit = 0;
924                         break;
925                 case 'M':
926                         u = CALENDAR_ALARM_TIME_UNIT_MINUTE;
927                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
928                         t += atoi(buf) * u;
929                         DBG("[%s] (%d)", buf, t);
930                         digit = 0;
931                         break;
932                 case 'S':
933                         u = CALENDAR_ALARM_TIME_UNIT_SPECIFIC;
934                         snprintf(buf, digit + 1, "%s", cursor + i - digit);
935                         t += atoi(buf) * u;
936                         DBG("[%s] (%d)", buf, t);
937                         digit = 0;
938                         break;
939                 default:
940                         /* LCOV_EXCL_START */
941                         ERR("Invalid value");
942                         break;
943                         /* LCOV_EXCL_STOP */
944                 }
945         }
946
947         t *= sign;
948         _get_tick_unit(t, tick, unit);
949 }
950
951 static bool __is_digit(char *p)
952 {
953         while (*p) {
954                 if ((*p < '0' || '9' < *p) && '+' != *p && '-' != *p)
955                         return false;
956                 p++;
957         }
958         return true;
959 }
960
961 static char* __get_index(char *cursor, const char **array, int len, int *index)
962 {
963         RETV_IF(NULL == index, NULL);
964
965         int i;
966         char *new = NULL;
967         for (i = 1; i < len; i++) {
968                 new = __check_word(cursor, array[i]);
969                 if (new) break;
970         }
971         if (len == i) {
972                 *index = 0;
973                 return cursor;
974         }
975
976         *index = i;
977         DBG("index(%d) [%s]", i, array[i]);
978         return cursor + strlen(array[i]);
979 }
980
981 static void __get_version(char *value, int *version)
982 {
983         CAL_FN_CALL();
984
985         RET_IF(NULL == value);
986         RET_IF(NULL == version);
987
988         if (CAL_STRING_EQUAL == strncmp(value, ":1.0", strlen(":1.0")))
989                 *version = 1;
990         else
991                 *version = 2;
992
993         DBG("version(%d)", *version);
994 }
995
996 static int _get_caltime(char *p, calendar_time_s *caltime, struct user_data *ud)
997 {
998         RETV_IF(NULL == p, CALENDAR_ERROR_INVALID_PARAMETER);
999         RETV_IF('\0' == *p, CALENDAR_ERROR_INVALID_PARAMETER);
1000         RETV_IF(NULL == caltime, CALENDAR_ERROR_INVALID_PARAMETER);
1001         RETV_IF(NULL == ud, CALENDAR_ERROR_INVALID_PARAMETER);
1002
1003         int ret = CALENDAR_ERROR_NONE;
1004
1005         switch (strlen(p)) {
1006         case VCAL_DATETIME_LENGTH_YYYYMMDD:
1007                 caltime->type = CALENDAR_TIME_LOCALTIME;
1008                 sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDD,
1009                                 &(caltime->time.date.year), &(caltime->time.date.month), &(caltime->time.date.mday));
1010                 caltime->time.date.hour = 0;
1011                 caltime->time.date.minute = 0;
1012                 caltime->time.date.second = 0;
1013                 DBG(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                 break;
1017         case VCAL_DATETIME_LENGTH_YYYYMMDDTHHMMSS:
1018                 sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS,
1019                                 &(caltime->time.date.year), &(caltime->time.date.month), &(caltime->time.date.mday),
1020                                 &(caltime->time.date.hour), &(caltime->time.date.minute), &(caltime->time.date.second));
1021
1022                 if (VCAL_VER_1 == ud->version) {
1023                         caltime->type = CALENDAR_TIME_LOCALTIME;
1024                 } else {
1025                         if (NULL == ud->datetime_tzid || '\0' == *ud->datetime_tzid) {
1026                                 if (NULL == ud->timezone_tzid || '\0' == *ud->timezone_tzid) {
1027                                         /* Without tzid is localtime */
1028                                         caltime->type = CALENDAR_TIME_LOCALTIME;
1029                                         DBG(CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS,
1030                                                         caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1031                                                         caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1032                                 } else {
1033                                         /* No 'Z' with tzid means utime */
1034                                         caltime->type = CALENDAR_TIME_UTIME;
1035                                         caltime->time.utime = cal_time_convert_itol(ud->timezone_tzid,
1036                                                         caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1037                                                         caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1038                                         DBG("timezone_tzid[%s] (%lld)", ud->timezone_tzid, caltime->time.utime);
1039                                 }
1040                         } else {
1041                                 /* No 'Z' with tzid means utime */
1042                                 caltime->type = CALENDAR_TIME_UTIME;
1043                                 caltime->time.utime = cal_time_convert_itol(ud->datetime_tzid,
1044                                                 caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1045                                                 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1046                                 DBG("datetime_tzid[%s] (%lld)", ud->datetime_tzid, caltime->time.utime);
1047                         }
1048                 }
1049                 break;
1050         case VCAL_DATETIME_LENGTH_YYYYMMDDTHHMMSSZ:
1051                 if (ud->is_allday) {
1052                         caltime->type = CALENDAR_TIME_LOCALTIME;
1053                         sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ,
1054                                         &(caltime->time.date.year), &(caltime->time.date.month), &(caltime->time.date.mday),
1055                                         &(caltime->time.date.hour), &(caltime->time.date.minute), &(caltime->time.date.second));
1056                         caltime->time.date.hour = 0;
1057                         caltime->time.date.minute = 0;
1058                         caltime->time.date.second = 0;
1059                         DBG(CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS,
1060                                         caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
1061                                         caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
1062                 } else {
1063                         caltime->type = CALENDAR_TIME_UTIME;
1064                         caltime->time.utime = cal_time_convert_lli(p);
1065                         DBG("(%lld)", caltime->time.utime);
1066                 }
1067                 break;
1068         default:
1069                 /* LCOV_EXCL_START */
1070                 ERR("Invalid time format[%s]", p);
1071                 ret = CALENDAR_ERROR_INVALID_PARAMETER;
1072                 break;
1073                 /* LCOV_EXCL_STOP */
1074         }
1075         return ret;
1076 }
1077
1078 /*
1079  * TZ:+05
1080  * TZ:
1081  * TZ:+5
1082  * TZ:5:30
1083  * TZ:+05:30
1084  */
1085 static void __parse_tz(const char *tz, int *h, int *m)
1086 {
1087         RET_IF(NULL == tz);
1088
1089         char **t = g_strsplit(tz, ":", -1);
1090         RETM_IF(NULL == t, "g_strsplit() is NULL");
1091
1092         int sign = 0;
1093         if ('-' == *t[0])
1094                 sign = -1;
1095         else if ('+' == *t[0])
1096                 sign = 1;
1097         else
1098                 sign = 0;
1099
1100         if (0 == strlen(t[0])) {
1101                 /* LCOV_EXCL_START */
1102                 ERR("No hour");
1103                 g_strfreev(t);
1104                 return;
1105                 /* LCOV_EXCL_STOP */
1106         }
1107
1108         char buf[8] = {0};
1109         if (sign) {
1110                 snprintf(buf, strlen(t[0]), "%s", t[0] + 1);
1111         } else {
1112                 sign = 1;
1113                 snprintf(buf, strlen(t[0]) + 1, "%s", t[0]);
1114         }
1115         if (h) *h = sign * atoi(buf);
1116
1117         if (1 == g_strv_length(t)) {
1118                 if (m) *m = 0;
1119                 g_strfreev(t);
1120                 return;
1121         }
1122
1123         snprintf(buf, strlen(t[1]) + 1, "%s", t[1]);
1124         if (m) *m = atoi(buf);
1125
1126         g_strfreev(t);
1127 }
1128
1129 static void __get_tz(char *value, char **tz)
1130 {
1131         RET_IF(NULL == value);
1132         RET_IF(NULL == tz);
1133
1134         int h = 0, m = 0;
1135         __parse_tz(value +1, &h, &m); /* +1 to skip ':' */
1136
1137         char buf[CAL_STR_SHORT_LEN32] = {0};
1138         if (0 == m)
1139                 snprintf(buf, sizeof(buf), "Etc/GMT%c%d", h < 0 ? '+' : '-', h);
1140         else
1141                 cal_time_get_registered_tzid_with_offset(h * 3600 + m * 60, buf, sizeof(buf));
1142
1143         DBG("set tzid [%s]", buf);
1144
1145         *tz = strdup(buf);
1146 }
1147
1148 static void __work_component_property_dtstamp(char *value, calendar_record_h record, struct user_data *ud)
1149 {
1150         return;
1151 }
1152
1153 static void __work_component_property_uid(char *value, calendar_record_h record, struct user_data *ud)
1154 {
1155         RET_IF(NULL == value);
1156         RET_IF('\0' == *value);
1157         RET_IF(NULL == record);
1158         RET_IF(NULL == ud);
1159
1160         int ret = 0;
1161         char *s = __decode_charset(value);
1162         __decode_escaped_char(s);
1163         switch (ud->type) {
1164         case CALENDAR_BOOK_TYPE_EVENT:
1165                 ret = cal_record_set_str(record, _calendar_event.uid, s);
1166                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1167                 break;
1168         case CALENDAR_BOOK_TYPE_TODO:
1169                 ret = cal_record_set_str(record, _calendar_todo.uid, s);
1170                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1171                 break;
1172         }
1173         free(s);
1174 }
1175
1176 static void __work_component_property_recurrence_id(char *value, calendar_record_h record, struct user_data *ud)
1177 {
1178         RET_IF(NULL == value);
1179         RET_IF('\0' == *value);
1180         RET_IF(NULL == record);
1181         RET_IF(NULL == ud);
1182
1183         int ret = 0;
1184         switch (ud->type) {
1185         case CALENDAR_BOOK_TYPE_EVENT:
1186                 ret = cal_record_set_str(record, _calendar_event.recurrence_id, value +1);
1187                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1188                 break;
1189         case CALENDAR_BOOK_TYPE_TODO:
1190                 DBG("Not supported in todo");
1191                 break;
1192         }
1193 }
1194
1195 static void __work_component_property_dtstart(char *value, calendar_record_h record, struct user_data *ud)
1196 {
1197         RET_IF(NULL == value);
1198         RET_IF('\0' == *value);
1199         RET_IF(NULL == record);
1200         RET_IF(NULL == ud);
1201
1202         int ret = 0;
1203
1204         value = __decode_datetime(value, ud);
1205         calendar_time_s dtstart = {0};
1206         ret = _get_caltime(value, &dtstart, ud);
1207         if (CALENDAR_ERROR_NONE != ret) {
1208                 /* LCOV_EXCL_START */
1209                 ERR("_get_caltime() Fail(%d)", ret);
1210                 return;
1211                 /* LCOV_EXCL_STOP */
1212         }
1213
1214         char *tzid = NULL;
1215         tzid = ud->datetime_tzid ? ud->datetime_tzid : (ud->timezone_tzid ? ud->timezone_tzid : NULL);
1216
1217         switch (ud->type) {
1218         case CALENDAR_BOOK_TYPE_EVENT:
1219                 if (tzid && *tzid) {
1220                         ret = cal_record_set_str(record, _calendar_event.start_tzid, tzid);
1221                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1222                 }
1223                 ret = cal_record_set_caltime(record, _calendar_event.start_time, dtstart);
1224                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1225                 break;
1226         case CALENDAR_BOOK_TYPE_TODO:
1227                 if (tzid && *tzid) {
1228                         ret = cal_record_set_str(record, _calendar_todo.start_tzid, tzid);
1229                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1230                 }
1231                 ret = cal_record_set_caltime(record, _calendar_todo.start_time, dtstart);
1232                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1233                 break;
1234         }
1235
1236         /* check if dtend is earlier than dtstart. */
1237         if (CALENDAR_BOOK_TYPE_TODO == ud->type) /* skip in todo */
1238                 return;
1239
1240         calendar_time_s dtend = {0};
1241         ret = calendar_record_get_caltime(record, _calendar_event.end_time, &dtend);
1242         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
1243
1244         if (0 == dtend.time.utime) /* not set yet */
1245                 return;
1246
1247         int diff = 0;
1248         _sub_caltime(ud, &dtstart, &dtend, &diff);
1249         if (diff <= 0) /* proper data */
1250                 return;
1251
1252         WARN("dtend < dtstart so set end time to start");
1253         dtend = dtstart;
1254 }
1255
1256 static void __work_component_property_created(char *value, calendar_record_h record, struct user_data *ud)
1257 {
1258         RET_IF(NULL == value);
1259         RET_IF('\0' == *value);
1260         RET_IF(NULL == record);
1261         RET_IF(NULL == ud);
1262
1263         int ret = 0;
1264         switch (ud->type) {
1265         case CALENDAR_BOOK_TYPE_EVENT:
1266                 ret = cal_record_set_lli(record, _calendar_event.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         case CALENDAR_BOOK_TYPE_TODO:
1271                 ret = cal_record_set_lli(record, _calendar_todo.created_time, cal_time_convert_lli(value));
1272                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_lli() Fail(%d)", ret);
1273                 break;
1274         }
1275 }
1276
1277 static void __work_component_property_description(char *value, calendar_record_h record, struct user_data *ud)
1278 {
1279         RET_IF(NULL == value);
1280         RET_IF('\0' == *value);
1281         RET_IF(NULL == record);
1282         RET_IF(NULL == ud);
1283
1284         int ret = 0;
1285         char *s = __decode_charset(value);
1286         __decode_escaped_char(s);
1287         switch (ud->type) {
1288         case CALENDAR_BOOK_TYPE_EVENT:
1289                 ret = cal_record_set_str(record, _calendar_event.description, s);
1290                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1291                 break;
1292         case CALENDAR_BOOK_TYPE_TODO:
1293                 ret = cal_record_set_str(record, _calendar_todo.description, s);
1294                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1295                 break;
1296         }
1297         free(s);
1298 }
1299
1300 static void __work_component_property_last_modified(char *value, calendar_record_h record, struct user_data *ud)
1301 {
1302         RET_IF(NULL == value);
1303         RET_IF('\0' == *value);
1304         RET_IF(NULL == record);
1305         RET_IF(NULL == ud);
1306
1307         int ret = 0;
1308         switch (ud->type) {
1309         case CALENDAR_BOOK_TYPE_EVENT:
1310                 ret = cal_record_set_lli(record, _calendar_event.last_modified_time, cal_time_convert_lli(value));
1311                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_lli() Fail(%d)", ret);
1312                 break;
1313         case CALENDAR_BOOK_TYPE_TODO:
1314                 ret = cal_record_set_lli(record, _calendar_todo.last_modified_time, cal_time_convert_lli(value));
1315                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_lli() Fail(%d)", ret);
1316                 break;
1317         }
1318 }
1319
1320 static void __work_component_property_location(char *value, calendar_record_h record, struct user_data *ud)
1321 {
1322         RET_IF(NULL == value);
1323         RET_IF('\0' == *value);
1324         RET_IF(NULL == record);
1325         RET_IF(NULL == ud);
1326
1327         int ret = 0;
1328         char *s = __decode_charset(value);
1329         __decode_escaped_char(s);
1330         switch (ud->type) {
1331         case CALENDAR_BOOK_TYPE_EVENT:
1332                 ret = cal_record_set_str(record, _calendar_event.location, s);
1333                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1334                 break;
1335         case CALENDAR_BOOK_TYPE_TODO:
1336                 ret = cal_record_set_str(record, _calendar_todo.location, s);
1337                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1338                 break;
1339         }
1340         free(s);
1341 }
1342
1343 static int __decode_priority(char *value, struct user_data *ud)
1344 {
1345         int original_priority = atoi(value);
1346         int modified_priority = 0;
1347
1348         switch (ud->version) {
1349         case VCAL_VER_1:
1350                 switch (original_priority) {
1351                 case 0:
1352                         modified_priority = CALENDAR_TODO_PRIORITY_LOW;
1353                         break;
1354                 case 1:
1355                         modified_priority = CALENDAR_TODO_PRIORITY_NORMAL;
1356                         break;
1357                 case 2:
1358                         modified_priority = CALENDAR_TODO_PRIORITY_HIGH;
1359                         break;
1360                 default:
1361                         DBG("Unable to parse [%s]", value);
1362                         modified_priority = CALENDAR_TODO_PRIORITY_NONE;
1363                         break;
1364                 }
1365                 break;
1366
1367         case VCAL_VER_2:
1368         default:
1369                 switch (original_priority) {
1370                 case 1 ... 4:
1371                         modified_priority = CALENDAR_TODO_PRIORITY_HIGH;
1372                         break;
1373                 case 5:
1374                         modified_priority = CALENDAR_TODO_PRIORITY_NORMAL;
1375                         break;
1376                 case 6 ... 9:
1377                         modified_priority = CALENDAR_TODO_PRIORITY_LOW;
1378                         break;
1379                 default:
1380                         DBG("Unable to parse [%s]", value);
1381                         modified_priority = CALENDAR_TODO_PRIORITY_NONE;
1382                         break;
1383                 }
1384                 break;
1385         }
1386         DBG("convert priority(%d) -> (%d)", original_priority, modified_priority);
1387         return modified_priority;
1388 }
1389
1390 static void __work_component_property_priority(char *value, calendar_record_h record, struct user_data *ud)
1391 {
1392         RET_IF(NULL == value);
1393         RET_IF('\0' == *value);
1394         RET_IF(NULL == record);
1395         RET_IF(NULL == ud);
1396         RETM_IF(*value < '0' || '9' < *value, "out of range[%s]", value);
1397
1398         int ret = 0;
1399         int modified_priority = __decode_priority(value, ud);
1400         switch (ud->type) {
1401         case CALENDAR_BOOK_TYPE_EVENT:
1402                 ret = cal_record_set_int(record, _calendar_event.priority, modified_priority);
1403                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1404                 break;
1405         case CALENDAR_BOOK_TYPE_TODO:
1406                 ret = cal_record_set_int(record, _calendar_todo.priority, modified_priority);
1407                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1408                 break;
1409         }
1410 }
1411
1412 static void __work_component_property_status(char *value, calendar_record_h record, struct user_data *ud)
1413 {
1414         RET_IF(NULL == value);
1415         RET_IF('\0' == *value);
1416         RET_IF(NULL == record);
1417         RET_IF(NULL == ud);
1418
1419         int ret = 0;
1420         int status = 0;
1421         switch (ud->type) {
1422         case CALENDAR_BOOK_TYPE_EVENT:
1423                 if (CAL_STRING_EQUAL == strncmp(value, ":TENTATIVE", strlen(":TENTATIVE")))
1424                         status = CALENDAR_EVENT_STATUS_TENTATIVE;
1425                 else if (CAL_STRING_EQUAL == strncmp(value, ":CONFIRMED", strlen(":CONFIRMED")))
1426                         status = CALENDAR_EVENT_STATUS_CONFIRMED;
1427                 else if (CAL_STRING_EQUAL == strncmp(value, ":CANCELLED", strlen(":CANCELLED")))
1428                         status = CALENDAR_EVENT_STATUS_CANCELLED;
1429                 else
1430                         status = CALENDAR_EVENT_STATUS_NONE;
1431
1432                 ret = cal_record_set_int(record, _calendar_event.event_status, status);
1433                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1434                 break;
1435         case CALENDAR_BOOK_TYPE_TODO:
1436                 if (CAL_STRING_EQUAL == strncmp(value, ":NEEDS-ACTION", strlen(":NEEDS-ACTION")))
1437                         status = CALENDAR_TODO_STATUS_NEEDS_ACTION;
1438                 else if (CAL_STRING_EQUAL == strncmp(value, ":NEEDS ACTION", strlen(":NEEDS ACTION")))
1439                         status = CALENDAR_TODO_STATUS_NEEDS_ACTION;
1440                 else if (CAL_STRING_EQUAL == strncmp(value, ":COMPLETED", strlen(":COMPLETED")))
1441                         status = CALENDAR_TODO_STATUS_COMPLETED;
1442                 else if (CAL_STRING_EQUAL == strncmp(value, ":IN-PROCESS", strlen(":IN-PROCESS")))
1443                         status = CALENDAR_TODO_STATUS_IN_PROCESS;
1444                 else if (CAL_STRING_EQUAL == strncmp(value, ":CANCELLED", strlen(":CANCELLED")))
1445                         status = CALENDAR_TODO_STATUS_CANCELED;
1446                 else
1447                         status = CALENDAR_TODO_STATUS_NONE;
1448
1449                 ret = cal_record_set_int(record, _calendar_todo.todo_status, status);
1450                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1451                 break;
1452         }
1453 }
1454
1455 static void __work_component_property_summary(char *value, calendar_record_h record, struct user_data *ud)
1456 {
1457         RET_IF(NULL == value);
1458         RET_IF('\0' == *value);
1459         RET_IF(NULL == record);
1460         RET_IF(NULL == ud);
1461
1462         int ret = 0;
1463         char *s = __decode_charset(value);
1464         __decode_escaped_char(s);
1465         switch (ud->type) {
1466         case CALENDAR_BOOK_TYPE_EVENT:
1467                 ret = cal_record_set_str(record, _calendar_event.summary, s);
1468                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1469                 break;
1470         case CALENDAR_BOOK_TYPE_TODO:
1471                 ret = cal_record_set_str(record, _calendar_todo.summary, s);
1472                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1473                 break;
1474         }
1475         free(s);
1476 }
1477
1478 static bool __is_wday_string(char *p)
1479 {
1480         RETV_IF(NULL == p, false);
1481         RETV_IF('0' == *p, false);
1482
1483         if ('S' == *p && 'U' == *(p +1))
1484                 return true;
1485         else if ('M' == *p && 'O' == *(p +1))
1486                 return true;
1487         else if ('T' == *p && 'U' == *(p +1))
1488                 return true;
1489         else if ('W' == *p && 'E' == *(p +1))
1490                 return true;
1491         else if ('T' == *p && 'H' == *(p +1))
1492                 return true;
1493         else if ('F' == *p && 'R' == *(p +1))
1494                 return true;
1495         else if ('S' == *p && 'A' == *(p +1))
1496                 return true;
1497         else
1498                 return false;
1499
1500 }
1501
1502 static int __get_frequency(char *p)
1503 {
1504         if ('Y' == *p && 'M' == *(p +1))
1505                 return VCAL_RECURRENCE_YEARLY_BYMONTH;
1506         else if ('Y' == *p && 'D' == *(p +1))
1507                 return VCAL_RECURRENCE_YEARLY_BYYEARDAY;
1508         else if ('M' == *p && 'P' == *(p +1))
1509                 return VCAL_RECURRENCE_MONTHLY_BYDAY;
1510         else if ('M' == *p && 'D' == *(p +1))
1511                 return VCAL_RECURRENCE_MONTHLY_BYMONTHDAY;
1512         else if ('W' == *p && 'E' != *(p +1))  /* check 'E' for WE(Wednesday) */
1513                 return VCAL_RECURRENCE_WEEKLY;
1514         else if ('D' == *p)
1515                 return VCAL_RECURRENCE_DAILY;
1516         else
1517                 return VCAL_RECURRENCE_NONE;
1518 }
1519
1520 static void __set_bystr(int freq_mode, calendar_record_h record, char *bystr)
1521 {
1522         RET_IF(NULL == record);
1523         RET_IF(NULL == bystr);
1524         RET_IF('\0' == *bystr);
1525
1526         DBG("bystr[%s]", bystr);
1527         bystr[strlen(bystr) -1] = '\0'; /* to remove ',' */
1528         int ret = 0;
1529         switch (freq_mode) {
1530         case VCAL_RECURRENCE_YEARLY_BYMONTH:
1531                 ret = cal_record_set_str(record, _calendar_event.bymonth, bystr);
1532                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1533                 break;
1534         case VCAL_RECURRENCE_YEARLY_BYYEARDAY:
1535                 ret = cal_record_set_str(record, _calendar_event.byyearday, bystr);
1536                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1537                 break;
1538         case VCAL_RECURRENCE_MONTHLY_BYMONTHDAY:
1539                 ret = cal_record_set_str(record, _calendar_event.bymonthday, bystr);
1540                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1541                 break;
1542         case VCAL_RECURRENCE_MONTHLY_BYDAY:
1543                 ret = cal_record_set_str(record, _calendar_event.byday, bystr);
1544                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1545                 break;
1546         case VCAL_RECURRENCE_WEEKLY:
1547                 ret = cal_record_set_str(record, _calendar_event.byday, bystr);
1548                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1549                 break;
1550         case VCAL_RECURRENCE_DAILY:
1551                 break;
1552         }
1553 }
1554
1555 /*
1556  * Yearly |bymonth   |YM1 6 7 #10
1557  *                   |YM1 1 6 12 #5 MP1 1+ MO 1- FR
1558  * Yearly |byyearday |YD3 1 100 200 #10
1559  * Monthly|byposition|MP2 1+ SU 1- SU #10
1560  * Monthly|byday     |MD1 1 1- #10
1561  * Weekly |          |W2 MO WE FR 19941224T000000Z
1562  * Daly   |          |D2 #0
1563  */
1564 static void __work_component_property_rrule_ver_1(char *value, calendar_record_h record, struct user_data *ud)
1565 {
1566         CAL_FN_CALL();
1567
1568         RET_IF(NULL == value);
1569         RET_IF('\0' == *value);
1570         RET_IF(NULL == record);
1571         RET_IF(NULL == ud);
1572
1573         int ret = 0;
1574         char **t = NULL;
1575         t =  g_strsplit_set(value, ": ", -1);
1576         RETM_IF(NULL == t, "g_strsplit_set() Fail");
1577
1578         /* start */
1579         int len = g_strv_length(t);
1580
1581         int frequency = 0;
1582         int freq_mode = 0;
1583         bool has_by = false;
1584
1585         char bystr[CAL_STR_MIDDLE_LEN] = {0};
1586         int len_str = 0;
1587
1588         int week[5] = {0};
1589         int week_index = 0;
1590
1591         int i;
1592         for (i = 0; i < len; i++) {
1593                 if (NULL == t[i] || '\0' == *t[i])
1594                         continue;
1595
1596                 DBG("[%s]", t[i]);
1597
1598                 if (true == __is_wday_string(t[i])) {
1599                         has_by = true;
1600                         if (week_index) {
1601                                 int j = 0;
1602                                 for (j = 0; j < week_index; j++)
1603                                         len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%d%s,", week[j], t[i]);
1604
1605                         } else {
1606                                 len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%s,", t[i]);
1607                         }
1608                         DBG("[%s] week_index(%d)", bystr, week_index);
1609                 } else if ('L' == *t[i] && 'D' == *(t[i] +1)) {  /* last day */
1610                         has_by = true;
1611                         len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%s,", "-1");
1612
1613                 } else if ('W' == *t[i] && 'K' == *(t[i] +1) && 'S' == *(t[i] +2) && 'T' == *(t[i] +3)) { /* +4 is '=' */
1614                         if ('S' == *(t[i] +5) && 'U' == *(t[i] +6))
1615                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SUNDAY);
1616                         else if ('M' == *(t[i] +5))
1617                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_MONDAY);
1618                         else if ('T' == *(t[i] +5) && 'U' == *(t[i] +6))
1619                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_TUESDAY);
1620                         else if ('W' == *(t[i] +5))
1621                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_WEDNESDAY);
1622                         else if ('T' == *(t[i] +5) && 'H' == *(t[i] +6))
1623                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_THURSDAY);
1624                         else if ('F' == *(t[i] +5))
1625                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_FRIDAY);
1626                         else if ('S' == *(t[i] +5) && 'A' == *(t[i] +6))
1627                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SATURDAY);
1628                         else
1629                                 ERR("Invalid parameter[%s]", t[i]);
1630
1631                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1632                 } else if (true == __is_digit(t[i])) {
1633
1634                         char buf[8] = {0};
1635                         bool exit_loop = false;
1636                         int sign = 1;
1637                         int j = 0;
1638                         switch (freq_mode) {
1639                         case VCAL_RECURRENCE_MONTHLY_BYDAY:
1640                         case VCAL_RECURRENCE_WEEKLY:
1641                                 if (true == has_by)
1642                                         week_index = 0;
1643
1644                                 while (t[i] + j && *(t[i] +j)) {
1645                                         switch (*(t[i] +j)) {
1646                                         case '+':
1647                                                 exit_loop = true;
1648                                                 sign = 1;
1649                                                 break;
1650                                         case '-':
1651                                                 exit_loop = true;
1652                                                 sign = -1;
1653                                                 break;
1654                                         default:
1655                                                 break;
1656                                         }
1657                                         if (true == exit_loop) break;
1658                                         j++;
1659                                 }
1660                                 snprintf(buf, j +1, "%s", t[i]);
1661                                 week[week_index] = atoi(buf) * sign;
1662                                 week_index++;
1663                                 break;
1664                         default:
1665                                 has_by = true;
1666                                 while (t[i] + j && *(t[i] +j)) {
1667                                         switch (*(t[i] +j)) {
1668                                         case '+':
1669                                                 exit_loop = true;
1670                                                 sign = 1;
1671                                                 break;
1672                                         case '-':
1673                                                 exit_loop = true;
1674                                                 sign = -1;
1675                                                 break;
1676                                         default:
1677                                                 break;
1678                                         }
1679                                         if (true == exit_loop) break;
1680                                         j++;
1681                                 }
1682                                 snprintf(buf, j +1, "%s", t[i]);
1683                                 len_str += snprintf(bystr + len_str, sizeof(bystr) - len_str, "%d,", (atoi(buf) * sign));
1684                                 break;
1685                         }
1686                 } else {
1687                         if (true == has_by) {
1688                                 __set_bystr(freq_mode, record, bystr);
1689                                 week_index = 0;
1690                                 memset(bystr, 0x0, strlen(bystr));
1691                                 len_str = 0;
1692                                 has_by = false;
1693                         }
1694                         if (VCAL_RECURRENCE_NONE != (freq_mode = __get_frequency(t[i]))) {
1695                                 if (0 == frequency) {
1696                                         int interval = 0;
1697                                         switch (freq_mode) {
1698                                         case VCAL_RECURRENCE_YEARLY_BYMONTH:
1699                                                 frequency = CALENDAR_RECURRENCE_YEARLY;
1700                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1701                                                 break;
1702                                         case VCAL_RECURRENCE_YEARLY_BYYEARDAY:
1703                                                 frequency = CALENDAR_RECURRENCE_YEARLY;
1704                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1705                                                 break;
1706                                         case VCAL_RECURRENCE_MONTHLY_BYDAY:
1707                                                 frequency = CALENDAR_RECURRENCE_MONTHLY;
1708                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1709                                                 break;
1710                                         case VCAL_RECURRENCE_MONTHLY_BYMONTHDAY:
1711                                                 frequency = CALENDAR_RECURRENCE_MONTHLY;
1712                                                 interval = ('\0' == *(t[i] +2)) ? 1 : atoi(t[i] +2);
1713                                                 break;
1714                                         case VCAL_RECURRENCE_WEEKLY:
1715                                                 frequency = CALENDAR_RECURRENCE_WEEKLY;
1716                                                 interval = ('\0' == *(t[i] +1)) ? 1 : atoi(t[i] +1);
1717                                                 break;
1718                                         case VCAL_RECURRENCE_DAILY:
1719                                                 frequency = CALENDAR_RECURRENCE_DAILY;
1720                                                 interval = ('\0' == *(t[i] +1)) ? 1 : atoi(t[i] +1);
1721                                                 break;
1722                                         }
1723                                         ret = cal_record_set_int(record, _calendar_event.freq, frequency);
1724                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1725                                         ret = cal_record_set_int(record, _calendar_event.interval, interval);
1726                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1727                                         DBG("frequency[%d] interval(%d)", frequency, interval);
1728                                 }
1729                         } else {
1730                                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("YYYYMMDDTHHMMSS") <= strlen(t[i])) {
1731                                         DBG("until");
1732                                         calendar_time_s caltime = {0};
1733                                         _get_caltime(t[i], &caltime, ud);
1734                                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_UNTIL);
1735                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1736                                         ret = cal_record_set_caltime(record, _calendar_event.until_time, caltime);
1737                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1738
1739                                 } else if ('#' == *t[i]) {
1740                                         /* count */
1741                                         if (true == __is_digit(t[i] +1)) {
1742                                                 if (0 == atoi(t[i] +1)) {
1743                                                         DBG("endless");
1744                                                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_NONE);
1745                                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1746                                                 } else {
1747                                                         DBG("count (%d)", atoi(t[i] +1));
1748                                                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_COUNT);
1749                                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1750                                                         ret = cal_record_set_int(record, _calendar_event.count, atoi(t[i] +1));
1751                                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1752                                                 }
1753                                         } else {
1754                                                 ERR("Unable to parse count[%s]", t[i]);
1755                                         }
1756                                 } else {
1757                                         DBG("Invalid");
1758                                 }
1759                         }
1760                 }
1761         }
1762         if (true == has_by)
1763                 __set_bystr(freq_mode, record, bystr);
1764
1765         g_strfreev(t);
1766 }
1767
1768 static void __work_component_property_rrule_ver_2(char *value, calendar_record_h record, struct user_data *ud)
1769 {
1770         int ret = 0;
1771         char **t = NULL;
1772
1773         RET_IF(NULL == value);
1774         RET_IF('\0' == *value);
1775         RET_IF(NULL == record);
1776         RET_IF(NULL == ud);
1777
1778         t =  g_strsplit_set(value, ";:", -1);
1779         RETM_IF(NULL == t, "g_strsplit_set() Fail");
1780
1781         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_NONE);
1782         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1783
1784         int len = g_strv_length(t);
1785         int i;
1786         for (i = 0; i < len; i++) {
1787                 if (NULL == t[i] || '\0' == *t[i]) continue;
1788
1789                 if (CAL_STRING_EQUAL == strncmp(t[i], "FREQ=", strlen("FREQ="))) {
1790                         int frequency = 0;
1791                         if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=YEARLY", strlen("=YEARLY")))
1792                                 frequency = CALENDAR_RECURRENCE_YEARLY;
1793                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=MONTHLY", strlen("=MONTHLY")))
1794                                 frequency = CALENDAR_RECURRENCE_MONTHLY;
1795                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=WEEKLY", strlen("=WEEKLY")))
1796                                 frequency = CALENDAR_RECURRENCE_WEEKLY;
1797                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("FREQ"), "=DAILY", strlen("=DAILY")))
1798                                 frequency = CALENDAR_RECURRENCE_DAILY;
1799                         else
1800                                 frequency = CALENDAR_RECURRENCE_NONE;
1801
1802                         DBG("frequency(%d) [%s]", frequency, t[i] + strlen("FREQ") + 1);
1803                         ret = cal_record_set_int(record, _calendar_event.freq, frequency);
1804                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1805
1806                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "UNTIL=", strlen("UNTIL="))) {
1807                         calendar_time_s caltime = {0};
1808                         _get_caltime(t[i] + strlen("UNTIL="), &caltime, ud);
1809                         ret = cal_record_set_caltime(record, _calendar_event.until_time, caltime);
1810                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1811                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_UNTIL);
1812                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1813                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "COUNT=", strlen("COUNT="))) {
1814                         int count = atoi(t[i] + strlen("COUNT="));
1815                         if (count < 1) count = 1;
1816                         ret = cal_record_set_int(record,  _calendar_event.count, count);
1817                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1818                         ret = cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_COUNT);
1819                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1820                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "INTERVAL=", strlen("INTERVAL="))) {
1821                         int interval = atoi(t[i] + strlen("INTERVAL="));
1822                         if (interval < 1) interval = 1;
1823                         ret = cal_record_set_int(record, _calendar_event.interval, interval);
1824                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1825                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYYEARDAY=", strlen("BYYEARDAY="))) {
1826                         ret = cal_record_set_str(record, _calendar_event.byyearday, t[i] + strlen("BYYEARDAY="));
1827                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1828                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYWEEKNO=", strlen("BYWEEKNO="))) {
1829                         ret = cal_record_set_str(record, _calendar_event.byweekno, t[i] + strlen("BYWEEKNO="));
1830                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1831                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYMONTH=", strlen("BYMONTH="))) {
1832                         ret = cal_record_set_str(record, _calendar_event.bymonth, t[i] + strlen("BYMONTH="));
1833                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1834                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYMONTHDAY=", strlen("BYMONTHDAY="))) {
1835                         ret = cal_record_set_str(record, _calendar_event.bymonthday, t[i] + strlen("BYMONTHDAY="));
1836                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1837                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYDAY=", strlen("BYDAY="))) {
1838                         ret = cal_record_set_str(record, _calendar_event.byday, t[i] + strlen("BYDAY="));
1839                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1840                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "BYSETPOS=", strlen("BYSETPOS="))) {
1841                         ret = cal_record_set_str(record, _calendar_event.bysetpos, t[i] + strlen("BYSETPOS="));
1842                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1843                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "WKST=", strlen("WKST="))) {
1844                         if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "SU", strlen("SU")))
1845                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SUNDAY);
1846                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "MO", strlen("MO")))
1847                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_MONDAY);
1848                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "TU", strlen("TU")))
1849                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_TUESDAY);
1850                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "WE", strlen("WE")))
1851                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_WEDNESDAY);
1852                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "TH", strlen("TH")))
1853                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_THURSDAY);
1854                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "FR", strlen("FR")))
1855                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_FRIDAY);
1856                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("WKST="), "SA", strlen("SA")))
1857                                 ret = cal_record_set_int(record, _calendar_event.wkst, CALENDAR_SATURDAY);
1858                         else
1859                                 DBG("Unable to parse[%s]", t[i]);
1860
1861                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
1862                 } else {
1863                         DBG("Unable to parse[%s]", t[i]);
1864                 }
1865         }
1866
1867         g_strfreev(t);
1868 }
1869
1870 static void __work_component_property_rrule(char *value, calendar_record_h record, struct user_data *ud)
1871 {
1872         CAL_FN_CALL();
1873
1874         RET_IF(NULL == value);
1875         RET_IF('\0' == *value);
1876         RET_IF(NULL == record);
1877         RET_IF(NULL == ud);
1878
1879         int version = ud->version;
1880         /* check if this field has different version content */
1881         if (CAL_STRING_EQUAL == strncmp(value, ":FREQ=", strlen(":FREQ=")))
1882                 version = VCAL_VER_2;
1883         else
1884                 version = VCAL_VER_1;
1885
1886         switch (ud->type) {
1887         case CALENDAR_BOOK_TYPE_EVENT:
1888                 switch (version) {
1889                 case VCAL_VER_1:
1890                         __work_component_property_rrule_ver_1(value, record, ud);
1891                         break;
1892                 case VCAL_VER_2:
1893                         __work_component_property_rrule_ver_2(value, record, ud);
1894                         break;
1895                 }
1896                 break;
1897         case CALENDAR_BOOK_TYPE_TODO:
1898                 DBG("Not support rrule in todo");
1899                 break;
1900         }
1901 }
1902
1903 static void __work_component_property_dtend(char *value, calendar_record_h record, struct user_data *ud)
1904 {
1905         RET_IF(NULL == value);
1906         RET_IF('\0' == *value);
1907         RET_IF(NULL == record);
1908         RET_IF(NULL == ud);
1909
1910         int ret = 0;
1911
1912         value = __decode_datetime(value, ud);
1913         calendar_time_s dtend = {0};
1914         ret = _get_caltime(value, &dtend, ud);
1915         if (CALENDAR_ERROR_NONE != ret) {
1916                 /* LCOV_EXCL_START */
1917                 ERR("_get_caltime() Fail(%d)", ret);
1918                 return;
1919                 /* LCOV_EXCL_STOP */
1920         }
1921
1922         char *tzid = NULL;
1923         tzid = ud->datetime_tzid ? ud->datetime_tzid : (ud->timezone_tzid ? ud->timezone_tzid : NULL);
1924
1925         /* check if dtend is earlier than dtstart. */
1926         do {
1927                 if (CALENDAR_BOOK_TYPE_TODO == ud->type) /* skip in todo */
1928                         break;
1929
1930                 calendar_time_s dtstart = {0};
1931                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &dtstart);
1932                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
1933
1934                 if (0 == dtstart.time.utime) /* not set yet */
1935                         break;
1936
1937                 int diff = 0;
1938                 _sub_caltime(ud, &dtstart, &dtend, &diff);
1939                 if (diff <= 0) /* proper data */
1940                         break;
1941
1942                 WARN("dtend < dtstart so set end time to start");
1943                 dtend = dtstart;
1944         } while (0);
1945
1946         switch (ud->type) {
1947         case CALENDAR_BOOK_TYPE_EVENT:
1948                 if (tzid && *tzid) {
1949                         ret = cal_record_set_str(record, _calendar_event.end_tzid, tzid);
1950                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1951                 }
1952                 ret = cal_record_set_caltime(record, _calendar_event.end_time, dtend);
1953                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1954                 break;
1955         case CALENDAR_BOOK_TYPE_TODO:
1956                 if (tzid && *tzid) {
1957                         ret = cal_record_set_str(record, _calendar_todo.due_tzid, tzid);
1958                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
1959                 }
1960                 ret = cal_record_set_caltime(record, _calendar_todo.due_time, dtend);
1961                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
1962                 break;
1963         }
1964 }
1965
1966 static void __work_component_property_attendee_mailto(calendar_record_h attendee, char *value)
1967 {
1968         RET_IF(NULL == value);
1969         RET_IF('\0' == *value);
1970         RET_IF(NULL == attendee);
1971
1972         int ret = 0;
1973         char *mailto = NULL;
1974         ret = calendar_record_get_str(attendee, _calendar_attendee.email, &mailto);
1975         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_str() Fail");
1976         if (mailto)
1977                 return;
1978
1979         ret = cal_record_set_str(attendee, _calendar_attendee.email, value);
1980         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
1981 }
1982 static void __work_component_property_attendee_cutype(calendar_record_h attendee, char *value)
1983 {
1984         int ret = 0;
1985
1986         RET_IF(NULL == value);
1987         RET_IF('\0' == *value);
1988         RET_IF(NULL == attendee);
1989
1990         const char *prop = NULL;
1991         if (CAL_STRING_EQUAL == strncmp(value, "INDIVIDUAL", strlen("INDIVIDUAL"))) {
1992                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_INDIVIDUAL);
1993                 if (strlen(value) > strlen("INDIVIDUAL"))
1994                         prop = "INDIVIDUAL";
1995
1996         } else if (CAL_STRING_EQUAL == strncmp(value, "GROUP", strlen("GROUP"))) {
1997                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_GROUP);
1998                 if (strlen(value) > strlen("GROUP"))
1999                         prop = "GROUP";
2000
2001         } else if (CAL_STRING_EQUAL == strncmp(value, "RESOURCE", strlen("RESOURCE"))) {
2002                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_RESOURCE);
2003                 if (strlen(value) > strlen("RESOURCE"))
2004                         prop = "RESOURCE";
2005
2006         } else if (CAL_STRING_EQUAL == strncmp(value, "ROOM", strlen("ROOM"))) {
2007                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_ROOM);
2008                 if (strlen(value) > strlen("ROOM"))
2009                         prop = "ROOM";
2010
2011         } else if (CAL_STRING_EQUAL == strncmp(value, "UNKNOWN", strlen("UNKNOWN"))) {
2012                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_CUTYPE_UNKNOWN);
2013                 if (strlen(value) > strlen("UNKNOWN"))
2014                         prop = "UNKNOWN";
2015
2016         } else {
2017                 /* LCOV_EXCL_START */
2018                 ERR("Invalid value[%s]", value);
2019                 /* LCOV_EXCL_STOP */
2020         }
2021         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2022
2023         /* check mailto */
2024         if (prop && CAL_STRING_EQUAL == strncmp(value + strlen(prop), ":MAILTO", strlen(":MAILTO")))
2025                 __work_component_property_attendee_mailto(attendee, value + strlen(prop) + strlen(":MAILTO") +1);
2026 }
2027 static void __work_component_property_attendee_member(calendar_record_h attendee, char *value)
2028 {
2029         RET_IF(NULL == value);
2030         RET_IF('\0' == *value);
2031         RET_IF(NULL == attendee);
2032
2033         int ret = cal_record_set_str(attendee, _calendar_attendee.member, value);
2034         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2035 }
2036 static void __work_component_property_attendee_role(calendar_record_h attendee, char *value)
2037 {
2038         int ret = 0;
2039
2040         RET_IF(NULL == value);
2041         RET_IF('\0' == *value);
2042         RET_IF(NULL == attendee);
2043
2044         const char *prop = NULL;
2045         if (CAL_STRING_EQUAL == strncmp(value, "REQ-PARTICIPANT", strlen("REQ-PARTICIPANT"))) {
2046                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_REQ_PARTICIPANT);
2047                 if (strlen(value) > strlen("REQ-PARTICIPANT"))
2048                         prop = "REQ-PARTICIPANT";
2049         } else if (CAL_STRING_EQUAL == strncmp(value, "OPT-PARTICIPANT", strlen("OPT-PARTICIPANT"))) {
2050                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_OPT_PARTICIPANT);
2051                 if (strlen(value) > strlen("OPT-PARTICIPANT"))
2052                         prop = "OPT-PARTICIPANT";
2053         } else if (CAL_STRING_EQUAL == strncmp(value, "NON-PARTICIPANT", strlen("NON-PARTICIPANT"))) {
2054                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_NON_PARTICIPANT);
2055                 if (strlen(value) > strlen("NON-PARTICIPANT"))
2056                         prop = "NON-PARTICIPANT";
2057         } else if (CAL_STRING_EQUAL == strncmp(value, "CHAIR", strlen("CHAIR"))) {
2058                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_ROLE_CHAIR);
2059                 if (strlen(value) > strlen("CHAIR"))
2060                         prop = "CHAIR";
2061         } else {
2062                 /* LCOV_EXCL_START */
2063                 ERR("Invalid value[%s]", value);
2064                 /* LCOV_EXCL_STOP */
2065         }
2066         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2067
2068         /* check mailto */
2069         if (prop && CAL_STRING_EQUAL == strncmp(value + strlen(prop), ":MAILTO", strlen(":MAILTO")))
2070                 __work_component_property_attendee_mailto(attendee, value + strlen(prop) + strlen(":MAILTO") +1);
2071 }
2072 static void __work_component_property_attendee_partstat(calendar_record_h attendee, char *value)
2073 {
2074         int ret = 0;
2075
2076         RET_IF(NULL == value);
2077         RET_IF('\0' == *value);
2078         RET_IF(NULL == attendee);
2079
2080         const char *prop = NULL;
2081         if (CAL_STRING_EQUAL == strncmp(value, "NEEDS-ACTION", strlen("NEEDS-ACTION"))) {
2082                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_PENDING);
2083                 if (strlen(value) > strlen("NEEDS-ACTION"))
2084                         prop = "NEEDS-ACTION";
2085
2086         } else if (CAL_STRING_EQUAL == strncmp(value, "ACCEPTED", strlen("ACCEPTED"))) {
2087                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_ACCEPTED);
2088                 if (strlen(value) > strlen("ACCEPTED"))
2089                         prop = "ACCEPTED";
2090
2091         } else if (CAL_STRING_EQUAL == strncmp(value, "DECLINED", strlen("DECLINED"))) {
2092                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_DECLINED);
2093                 if (strlen(value) > strlen("DECLINED"))
2094                         prop = "DECLINED";
2095
2096         } else if (CAL_STRING_EQUAL == strncmp(value, "TENTATIVE", strlen("TENTATIVE"))) {
2097                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_TENTATIVE);
2098                 if (strlen(value) > strlen("TENTATIVE"))
2099                         prop = "TENTATIVE";
2100
2101         } else if (CAL_STRING_EQUAL == strncmp(value, "DELEGATED", strlen("DELEGATED"))) {
2102                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_DELEGATED);
2103                 if (strlen(value) > strlen("DELEGATED"))
2104                         prop = "DELEGATED";
2105
2106         } else if (CAL_STRING_EQUAL == strncmp(value, "COMPLETED", strlen("COMPLETED"))) {
2107                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_COMPLETED);
2108                 if (strlen(value) > strlen("COMPLETED"))
2109                         prop = "COMPLETED";
2110
2111         } else if (CAL_STRING_EQUAL == strncmp(value, "IN-PROCESS", strlen("IN-PROCESS"))) {
2112                 ret = cal_record_set_int(attendee, _calendar_attendee.cutype, CALENDAR_ATTENDEE_STATUS_IN_PROCESS);
2113                 if (strlen(value) > strlen("IN-PROCESS"))
2114                         prop = "IN-PROCESS";
2115
2116         } else {
2117                 /* LCOV_EXCL_START */
2118                 ERR("Invalid value[%s]", value);
2119                 /* LCOV_EXCL_STOP */
2120         }
2121         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2122
2123         /* check mailto */
2124         if (prop && CAL_STRING_EQUAL == strncmp(value + strlen(prop), ":MAILTO", strlen(":MAILTO")))
2125                 __work_component_property_attendee_mailto(attendee, value + strlen(prop) + strlen(":MAILTO") +1);
2126 }
2127 static void __work_component_property_attendee_rsvp(calendar_record_h attendee, char *value)
2128 {
2129         RET_IF(NULL == value);
2130         RET_IF('\0' == *value);
2131         RET_IF(NULL == attendee);
2132
2133         int ret = 0;
2134         if (CAL_STRING_EQUAL == strncmp(value, "TRUE", strlen("TRUE")))
2135                 ret = cal_record_set_int(attendee, _calendar_attendee.rsvp, 1);
2136         else
2137                 ret = cal_record_set_int(attendee, _calendar_attendee.rsvp, 0);
2138
2139         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2140 }
2141 static void __work_component_property_attendee_delegated_to(calendar_record_h attendee, char *value)
2142 {
2143         RET_IF(NULL == value);
2144         RET_IF('\0' == *value);
2145         RET_IF(NULL == attendee);
2146
2147         int ret = 0;
2148         ret = cal_record_set_str(attendee, _calendar_attendee.delegatee_uri, value);
2149         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
2150 }
2151 static void __work_component_property_attendee_delegated_from(calendar_record_h attendee, char *value)
2152 {
2153         RET_IF(NULL == value);
2154         RET_IF('\0' == *value);
2155         RET_IF(NULL == attendee);
2156
2157         int ret = 0;
2158         ret = cal_record_set_str(attendee, _calendar_attendee.delegator_uri, value);
2159         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
2160 }
2161 static void __work_component_property_attendee_sent_by(calendar_record_h attendee, char *value)
2162 {
2163         return;
2164 }
2165 static void __work_component_property_attendee_cn(calendar_record_h attendee, char *value)
2166 {
2167         RET_IF(NULL == value);
2168         RET_IF('\0' == *value);
2169         RET_IF(NULL == attendee);
2170
2171         int ret = 0;
2172         ret = cal_record_set_str(attendee, _calendar_attendee.name, value);
2173         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail");
2174 }
2175 static void __work_component_property_attendee_dir(calendar_record_h attendee, char *value)
2176 {
2177         return;
2178 }
2179
2180 /*
2181  * example
2182  * ATTENDEE;ROLE=REQ-PARTICIPANT;DELEGATED-FROM="MAILTO:bob@host.com";PARTSTAT=ACCEPTED;CN=Jane Doe:MAILTO:jdoe@host1.com
2183  * ATTENDEE;CN=John Smith;DIR="ldap://host.com:6666/o=eDABC%20Industries,c=3DUS??(cn=3DBJim%20Dolittle)":MAILTO:jimdo@host1.com
2184  * ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP:MAILTO:employee-A@host.com
2185  * ATTENDEE;CN=MAILTO:MAILTO:MAILTO@host.com
2186  */
2187 static void __work_component_property_attendee(char *value, calendar_record_h record, struct user_data *ud)
2188 {
2189         RET_IF(NULL == value);
2190         RET_IF('\0' == *value);
2191         RET_IF(NULL == record);
2192         RET_IF(NULL == ud);
2193
2194         int ret = 0;
2195         calendar_record_h attendee = NULL;
2196         ret = calendar_record_create(_calendar_attendee._uri, &attendee);
2197         RETM_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_create() Fail(%d)", ret);
2198
2199         char **t = NULL;
2200         t =  g_strsplit(value, ";", -1);
2201         RETM_IF(NULL == t, "g_strsplit() Fail");
2202
2203         int len = g_strv_length(t);
2204         int i;
2205         for (i = 0; i < len; i++) {
2206                 if (NULL == t[i] || '\0' == *t[i]) continue;
2207
2208                 if (CAL_STRING_EQUAL == strncmp(t[i], "CUTYPE", strlen("CUTYPE")))
2209                         __work_component_property_attendee_cutype(attendee, t[i] + strlen("CUTYPE") +1);
2210                 else if (CAL_STRING_EQUAL == strncmp(t[i], "MEMBER", strlen("MEMBER")))
2211                         __work_component_property_attendee_member(attendee, t[i] + strlen("MEMBER") +1);
2212                 else if (CAL_STRING_EQUAL == strncmp(t[i], "ROLE", strlen("ROLE")))
2213                         __work_component_property_attendee_role(attendee, t[i] + strlen("ROLE") +1);
2214                 else if (CAL_STRING_EQUAL == strncmp(t[i], "PARTSTAT", strlen("PARTSTAT")))
2215                         __work_component_property_attendee_partstat(attendee, t[i] + strlen("PARTSTAT") +1);
2216                 else if (CAL_STRING_EQUAL == strncmp(t[i], "RSVP", strlen("RSVP")))
2217                         __work_component_property_attendee_rsvp(attendee, t[i] + strlen("RSVP") +1);
2218                 else if (CAL_STRING_EQUAL == strncmp(t[i], "DELEGATED-TO", strlen("DELEGATED-TO")))
2219                         __work_component_property_attendee_delegated_to(attendee, t[i] + strlen("DELEGATED-TO") +1);
2220                 else if (CAL_STRING_EQUAL == strncmp(t[i], "DELEGATED-FROM", strlen("DELEGATED-FROM")))
2221                         __work_component_property_attendee_delegated_from(attendee, t[i] + strlen("DELEGATED-FROM") +1);
2222                 else if (CAL_STRING_EQUAL == strncmp(t[i], "SENT_BY", strlen("SENT_BY")))
2223                         __work_component_property_attendee_sent_by(attendee, t[i] + strlen("SENT_BY") +1);
2224                 else if (CAL_STRING_EQUAL == strncmp(t[i], "CN", strlen("CN")))
2225                         __work_component_property_attendee_cn(attendee, t[i] + strlen("CN") +1);
2226                 else if (CAL_STRING_EQUAL == strncmp(t[i], "DIR", strlen("DIR")))
2227                         __work_component_property_attendee_dir(attendee, t[i] + strlen("DIR") +1);
2228                 else if (CAL_STRING_EQUAL == strncmp(t[i], ":MAILTO", strlen(":MAILTO")))
2229                         __work_component_property_attendee_mailto(attendee, t[i] + strlen(":MAILTO") +1);
2230                 else
2231                         ERR("Invalid value[%s]", t[i]);
2232
2233         }
2234         g_strfreev(t);
2235
2236         switch (ud->type) {
2237         case CALENDAR_BOOK_TYPE_EVENT:
2238                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_attendee, attendee);
2239                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2240                 break;
2241         case CALENDAR_BOOK_TYPE_TODO:
2242                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_attendee, attendee);
2243                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2244                 break;
2245         }
2246 }
2247
2248 static void __work_component_property_categories(char *value, calendar_record_h record, struct user_data *ud)
2249 {
2250         RET_IF(NULL == value);
2251         RET_IF('\0' == *value);
2252         RET_IF(NULL == record);
2253         RET_IF(NULL == ud);
2254
2255         int ret = 0;
2256         char *s = __decode_charset(value);
2257         __decode_escaped_char(s);
2258         switch (ud->type) {
2259         case CALENDAR_BOOK_TYPE_EVENT:
2260                 ret = cal_record_set_str(record, _calendar_event.categories, s);
2261                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2262                 break;
2263         case CALENDAR_BOOK_TYPE_TODO:
2264                 ret = cal_record_set_str(record, _calendar_todo.categories, s);
2265                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2266                 break;
2267         }
2268         free(s);
2269 }
2270
2271 static void _set_alarm_tick_unit(calendar_record_h alarm, calendar_time_s alarm_time, int diff)
2272 {
2273         int ret = 0;
2274
2275         RET_IF(NULL == alarm);
2276
2277         if (diff < 0) {
2278                 DBG("set specific alarm");
2279                 ret = cal_record_set_caltime(alarm, _calendar_alarm.alarm_time, alarm_time);
2280                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
2281                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_SPECIFIC);
2282                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2283         } else if (0 == diff) {
2284                 DBG("set alarm in start time");
2285                 ret = cal_record_set_int(alarm, _calendar_alarm.tick, 0);
2286                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2287                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_HOUR);
2288                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2289         } else {
2290                 int tick = 0;
2291                 int unit = 0;
2292                 _get_tick_unit(diff, &tick, &unit);
2293                 ret = cal_record_set_int(alarm, _calendar_alarm.tick, tick);
2294                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2295                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, unit);
2296                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2297         }
2298 }
2299
2300 /*
2301  * for ver 1.0
2302  * dalarmparts  = 0*3(strnosemi ";") strnosemi; runTime, snoozeTime, repeatCount, displayString
2303  * DALARM:19960415T235000;PT5M;2;Your Taxes Are Due !!!
2304  */
2305 static void __work_component_property_dalarm(char *value, calendar_record_h record, struct user_data *ud)
2306 {
2307         RET_IF(NULL == value);
2308         RET_IF('\0' == *value);
2309         RET_IF(NULL == record);
2310         RET_IF(NULL == ud);
2311
2312         int ret = 0;
2313         char **t = NULL;
2314         t =  g_strsplit_set(value, ";:", -1);
2315         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2316
2317         calendar_record_h alarm = NULL;
2318         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2319         if (CALENDAR_ERROR_NONE != ret) {
2320                 /* LCOV_EXCL_START */
2321                 ERR("calendar_record_create() Fail(%d)", ret);
2322                 g_strfreev(t);
2323                 return;
2324                 /* LCOV_EXCL_STOP */
2325         }
2326         ret = cal_record_set_int(alarm, _calendar_alarm.action, CALENDAR_ALARM_ACTION_DISPLAY);
2327         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2328
2329         int len = g_strv_length(t);
2330         int i;
2331         int index = VCAL_VER_10_DALARM_NONE;
2332         for (i = 0; i < len; i++) {
2333                 if (index)
2334                         index++;
2335                 if (NULL == t[i] || '\0' == *t[i])
2336                         continue;
2337
2338                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("PTM") < strlen(t[i])) {
2339                         /* runTime */
2340                         index = VCAL_VER_10_DALARM_RUN_TIME;
2341                         calendar_time_s alarm_time = {0};
2342                         ret = _get_caltime(t[i], &alarm_time, ud);
2343                         if (CALENDAR_ERROR_NONE != ret) {
2344                                 /* LCOV_EXCL_START */
2345                                 ERR("_get_caltime() Fail(%d)", ret);
2346                                 index = VCAL_VER_10_AALARM_NONE;
2347                                 break;
2348                                 /* LCOV_EXCL_STOP */
2349                         }
2350
2351                         if (true == ud->has_rrule) {
2352                                 calendar_time_s start_time = {0};
2353                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &start_time);
2354
2355                                 int diff = 0;
2356                                 ret = _sub_caltime(ud, &start_time, &alarm_time, &diff);
2357                                 if (CALENDAR_ERROR_NONE != ret) {
2358                                         /* LCOV_EXCL_START */
2359                                         ERR("_sub_caltime() Fail(%d)", ret);
2360                                         index = VCAL_VER_10_DALARM_NONE;
2361                                         break;
2362                                         /* LCOV_EXCL_STOP */
2363                                 }
2364                                 _set_alarm_tick_unit(alarm, alarm_time, diff);
2365
2366                         } else {
2367                                 _set_alarm_tick_unit(alarm, alarm_time, -1); /* -1 goes to specific time */
2368                         }
2369                 } else if (VCAL_VER_10_DALARM_DISPLAY_STRING == index) { /* displayString */
2370                         DBG("displayString [%s]", t[i]);
2371                         ret = cal_record_set_str(alarm, _calendar_alarm.summary, t[i]);
2372                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2373
2374                 } else {
2375                         /* TYPE, VALUE */
2376                 }
2377         }
2378
2379         if (VCAL_VER_10_DALARM_NONE == index) {
2380                 DBG("No alarm");
2381                 calendar_record_destroy(alarm, true);
2382                 g_strfreev(t);
2383                 return;
2384         }
2385
2386         switch (ud->type) {
2387         case VCALENDAR_TYPE_VEVENT:
2388                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2389                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2390                 break;
2391         case VCALENDAR_TYPE_VTODO:
2392                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2393                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2394                 break;
2395         }
2396         g_strfreev(t);
2397 }
2398
2399 /*
2400  * for ver 1.0
2401  * malarmparts  = 0*4(strnosemi ";") strnosemi; runTime, snoozeTime, repeatCount, addressString, noteString
2402  */
2403 static void __work_component_property_malarm(char *value, calendar_record_h record, struct user_data *ud)
2404 {
2405         /* diff with aalarm: action */
2406         RET_IF(NULL == value);
2407         RET_IF('\0' == *value);
2408         RET_IF(NULL == record);
2409         RET_IF(NULL == ud);
2410
2411         int ret = 0;
2412         char **t = NULL;
2413         t =  g_strsplit_set(value, ";:", -1);
2414         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2415
2416         calendar_record_h alarm = NULL;
2417         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2418         if (CALENDAR_ERROR_NONE != ret) {
2419                 /* LCOV_EXCL_START */
2420                 ERR("calendar_record_create() Fail(%d)", ret);
2421                 g_strfreev(t);
2422                 return;
2423                 /* LCOV_EXCL_STOP */
2424         }
2425         ret = cal_record_set_int(alarm, _calendar_alarm.action, CALENDAR_ALARM_ACTION_EMAIL);
2426         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2427
2428         int len = g_strv_length(t);
2429         int i;
2430         int index = VCAL_VER_10_MALARM_NONE;
2431         for (i = 0; i < len; i++) {
2432                 if (index)
2433                         index++;
2434                 if (NULL == t[i] || '\0' == *t[i])
2435                         continue;
2436
2437                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("PTM") < strlen(t[i])) {
2438                         /* runTime */
2439                         index = VCAL_VER_10_MALARM_RUN_TIME;
2440                         calendar_time_s alarm_time = {0};
2441                         ret = _get_caltime(t[i], &alarm_time, ud);
2442                         if (CALENDAR_ERROR_NONE != ret) {
2443                                 /* LCOV_EXCL_START */
2444                                 ERR("_get_caltime() Fail(%d)", ret);
2445                                 index = VCAL_VER_10_AALARM_NONE;
2446                                 break;
2447                                 /* LCOV_EXCL_STOP */
2448                         }
2449
2450                         if (true == ud->has_rrule) {
2451                                 calendar_time_s start_time = {0};
2452                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &start_time);
2453                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
2454
2455                                 int diff = 0;
2456                                 ret = _sub_caltime(ud, &start_time, &alarm_time, &diff);
2457                                 if (CALENDAR_ERROR_NONE != ret) {
2458                                         /* LCOV_EXCL_START */
2459                                         ERR("_sub_caltime() Fail(%d)", ret);
2460                                         index = VCAL_VER_10_MALARM_NONE;
2461                                         break;
2462                                         /* LCOV_EXCL_STOP */
2463                                 }
2464                                 _set_alarm_tick_unit(alarm, alarm_time, diff);
2465
2466                         } else {
2467                                 _set_alarm_tick_unit(alarm, alarm_time, -1); /* -1 goes to specific time */
2468                         }
2469                 } else if (VCAL_VER_10_MALARM_ADDRESS_STRING == index) { /* addressString */
2470                         DBG("addressString [%s]", t[i]);
2471                         ret = cal_record_set_str(alarm, _calendar_alarm.attach, t[i]);
2472                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2473
2474                 } else if (VCAL_VER_10_MALARM_NOTE_STRING == index) { /* noteString */
2475                         DBG("noteString [%s]", t[i]);
2476                         ret = cal_record_set_str(alarm, _calendar_alarm.description, t[i]);
2477                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2478
2479                 } else {
2480                         /* TYPE, VALUE */
2481                 }
2482         }
2483
2484         if (VCAL_VER_10_MALARM_NONE == index) {
2485                 DBG("No alarm");
2486                 calendar_record_destroy(alarm, true);
2487                 g_strfreev(t);
2488                 return;
2489         }
2490
2491         switch (ud->type) {
2492         case VCALENDAR_TYPE_VEVENT:
2493                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2494                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2495                 break;
2496         case VCALENDAR_TYPE_VTODO:
2497                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2498                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2499                 break;
2500         }
2501         g_strfreev(t);
2502 }
2503 /*
2504  * for ver 1.0
2505  * aalarmparts  = 0*3(strnosemi ";") strnosemi; runTime, snoozeTime, repeatCount, audioContent
2506  * AALARM;TYPE=WAVE;VALUE=URL:19960415T235959; ; ; file:///mmedia/taps.wav
2507  * AALARM;TYPE=WAVE;VALUE=CONTENT-ID:19960903T060000;PT15M;4;<jsmith.part2.=960901T083000.xyzMail@host1.com>
2508  */
2509 static void __work_component_property_aalarm(char *value, calendar_record_h record, struct user_data *ud)
2510 {
2511         CAL_FN_CALL();
2512
2513         RET_IF(NULL == value);
2514         RET_IF('\0' == *value);
2515         RET_IF(NULL == record);
2516         RET_IF(NULL == ud);
2517
2518         int ret = 0;
2519         char **t = NULL;
2520         t =  g_strsplit_set(value, ";:", -1);
2521         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2522
2523         calendar_record_h alarm = NULL;
2524         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2525         if (CALENDAR_ERROR_NONE != ret) {
2526                 /* LCOV_EXCL_START */
2527                 ERR("calendar_record_create() Fail(%d)", ret);
2528                 g_strfreev(t);
2529                 return;
2530                 /* LCOV_EXCL_STOP */
2531         }
2532         ret = cal_record_set_int(alarm, _calendar_alarm.action, CALENDAR_ALARM_ACTION_AUDIO);
2533         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2534
2535         int len = g_strv_length(t);
2536         int i;
2537         int index = VCAL_VER_10_AALARM_NONE;
2538         for (i = 0; i < len; i++) {
2539                 if (index)
2540                         index++;
2541                 if (NULL == t[i] || '\0' == *t[i])
2542                         continue;
2543
2544                 if ('0' <= *t[i] && *t[i] <= '9' && strlen("PTM") < strlen(t[i])) {
2545                         /* runTime */
2546                         index = VCAL_VER_10_AALARM_RUN_TIME;
2547                         calendar_time_s alarm_time = {0};
2548                         ret = _get_caltime(t[i], &alarm_time, ud);
2549                         if (CALENDAR_ERROR_NONE != ret) {
2550                                 /* LCOV_EXCL_START */
2551                                 ERR("_get_caltime() Fail(%d)", ret);
2552                                 index = VCAL_VER_10_AALARM_NONE;
2553                                 break;
2554                                 /* LCOV_EXCL_STOP */
2555                         }
2556
2557                         if (true == ud->has_rrule) {
2558                                 calendar_time_s start_time = {0};
2559                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &start_time);
2560
2561                                 int diff = 0;
2562                                 ret = _sub_caltime(ud, &start_time, &alarm_time, &diff);
2563                                 if (CALENDAR_ERROR_NONE != ret) {
2564                                         /* LCOV_EXCL_START */
2565                                         ERR("_sub_caltime() Fail(%d)", ret);
2566                                         index = VCAL_VER_10_AALARM_NONE;
2567                                         break;
2568                                         /* LCOV_EXCL_STOP */
2569                                 }
2570                                 _set_alarm_tick_unit(alarm, alarm_time, diff);
2571
2572                         } else {
2573                                 _set_alarm_tick_unit(alarm, alarm_time, -1); /* -1 goes to specific time */
2574                         }
2575                 } else if (VCAL_VER_10_AALARM_AUDIO_CONTENT == index) {
2576                         /* audioContent */
2577                         DBG("Content [%s]", t[i]);
2578                         ret = cal_record_set_str(alarm, _calendar_alarm.attach, t[i]);
2579                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2580                 } else {
2581                         /* TYPE, VALUE */
2582                 }
2583         }
2584
2585         if (VCAL_VER_10_AALARM_NONE == index) {
2586                 DBG("No alarm");
2587                 calendar_record_destroy(alarm, true);
2588                 g_strfreev(t);
2589                 return;
2590         }
2591
2592         switch (ud->type) {
2593         case VCALENDAR_TYPE_VEVENT:
2594                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2595                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2596                 break;
2597         case VCALENDAR_TYPE_VTODO:
2598                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2599                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_add_child_record() Fail(%d)", ret);
2600                 break;
2601         }
2602         g_strfreev(t);
2603 }
2604
2605 static void __work_component_property_exdate(char *value, calendar_record_h record, struct user_data *ud)
2606 {
2607         RET_IF(NULL == value);
2608         RET_IF('\0' == *value);
2609         RET_IF(NULL == record);
2610         RET_IF(NULL == ud);
2611
2612         int ret = 0;
2613         switch (ud->type) {
2614         case CALENDAR_BOOK_TYPE_EVENT:
2615                 ret = cal_record_set_str(record, _calendar_event.exdate, value + 1);
2616                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2617                 break;
2618         case CALENDAR_BOOK_TYPE_TODO:
2619                 /* LCOV_EXCL_START */
2620                 ERR("No exdate in todo");
2621                 break;
2622                 /* LCOV_EXCL_STOP */
2623         }
2624 }
2625
2626 static void __work_component_property_x_allday(char *value, calendar_record_h record, struct user_data *ud)
2627 {
2628         RET_IF(NULL == value);
2629         RET_IF('\0' == *value);
2630         RET_IF(NULL == record);
2631         RET_IF(NULL == ud);
2632
2633         int ret = 0;
2634         if (CAL_STRING_EQUAL == strncmp(value, ":SET", strlen(":SET"))) {
2635                 DBG("x-allday: set");
2636                 ud->is_allday = true;
2637
2638                 calendar_time_s caltime = {0};
2639                 switch (ud->type) {
2640                 case CALENDAR_BOOK_TYPE_EVENT:
2641                         ret = calendar_record_get_caltime(record, _calendar_event.start_time, &caltime);
2642                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2643                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2644                                 caltime.time.date.hour = 0;
2645                                 caltime.time.date.minute = 0;
2646                                 caltime.time.date.second = 0;
2647                                 ret = cal_record_set_caltime(record, _calendar_event.start_time, caltime);
2648                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2649                         }
2650                         ret = calendar_record_get_caltime(record, _calendar_event.end_time, &caltime);
2651                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2652                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2653                                 caltime.time.date.hour = 0;
2654                                 caltime.time.date.minute = 0;
2655                                 caltime.time.date.second = 0;
2656                                 ret = cal_record_set_caltime(record, _calendar_event.end_time, caltime);
2657                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2658                         }
2659                         ret = calendar_record_get_caltime(record, _calendar_event.until_time, &caltime);
2660                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2661                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2662                                 caltime.time.date.hour = 0;
2663                                 caltime.time.date.minute = 0;
2664                                 caltime.time.date.second = 0;
2665                                 ret = cal_record_set_caltime(record, _calendar_event.until_time, caltime);
2666                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2667                         }
2668                         break;
2669                 case CALENDAR_BOOK_TYPE_TODO:
2670                         ret = calendar_record_get_caltime(record, _calendar_todo.start_time, &caltime);
2671                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2672                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2673                                 caltime.time.date.hour = 0;
2674                                 caltime.time.date.minute = 0;
2675                                 caltime.time.date.second = 0;
2676                                 ret = cal_record_set_caltime(record, _calendar_todo.start_time, caltime);
2677                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2678                         }
2679                         ret = calendar_record_get_caltime(record, _calendar_todo.due_time, &caltime);
2680                         WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail");
2681                         if (CALENDAR_TIME_LOCALTIME == caltime.type) {
2682                                 caltime.time.date.hour = 0;
2683                                 caltime.time.date.minute = 0;
2684                                 caltime.time.date.second = 0;
2685                                 ret = cal_record_set_caltime(record, _calendar_todo.due_time, caltime);
2686                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail");
2687                         }
2688                         break;
2689                 }
2690         }
2691 }
2692
2693 static void __work_component_property_x_lunar(char *value, calendar_record_h record, struct user_data *ud)
2694 {
2695         RET_IF(NULL == value);
2696         RET_IF('\0' == *value);
2697         RET_IF(NULL == record);
2698         RET_IF(NULL == ud);
2699
2700         int ret = 0;
2701         if (CAL_STRING_EQUAL == strncmp(value, ":SET", strlen(":SET"))) {
2702                 DBG("x-lunar: set");
2703                 switch (ud->type) {
2704                 case CALENDAR_BOOK_TYPE_EVENT:
2705                         ret = cal_record_set_int(record, _calendar_event.calendar_system_type, CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR);
2706                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2707                         break;
2708                 case CALENDAR_BOOK_TYPE_TODO:
2709                         DBG("Not supported lunar in todo");
2710                         break;
2711                 }
2712         }
2713 }
2714
2715 static void __work_component_property_valarm_action(char *value, calendar_record_h alarm, struct user_data *ud)
2716 {
2717         RET_IF(NULL == value);
2718         RET_IF('\0' == *value);
2719         RET_IF(NULL == alarm);
2720
2721         const char *prop[CALENDAR_ALARM_ACTION_MAX] = {":AUDIO", ":DISPLAY", ":EMAIL"};
2722
2723         int ret = 0;
2724         int i;
2725         for (i = 0; i < CALENDAR_ALARM_ACTION_MAX; i++) {
2726                 if (CAL_STRING_EQUAL == strncmp(value,  prop[i], strlen(prop[i]))) {
2727                         ret = cal_record_set_int(alarm, _calendar_alarm.action, i);
2728                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2729                         break;
2730                 }
2731         }
2732 }
2733
2734 static void __work_component_property_valarm_trigger(char *value, calendar_record_h record, calendar_record_h alarm, struct user_data *ud)
2735 {
2736         CAL_FN_CALL();
2737
2738         RET_IF(NULL == value);
2739         RET_IF('\0' == *value);
2740         RET_IF(NULL == alarm);
2741         RET_IF(NULL == ud);
2742
2743         int ret = 0;
2744         char **t = NULL;
2745         t =  g_strsplit_set(value, ";:", -1);
2746         RETM_IF(NULL == t, "g_strsplit_set() Fail");
2747
2748         int related = VCAL_RELATED_NONE;
2749         int len = g_strv_length(t);
2750         int i;
2751         for (i = 0; i < len; i++) {
2752                 if (NULL == t[i] || '\0' == *t[i]) continue;
2753
2754                 if (CAL_STRING_EQUAL == strncmp(t[i], "RELATED", strlen("RELATED"))) {
2755                         if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("RELATED"), "=START", strlen("=START")))
2756                                 related = VCAL_RELATED_START;
2757                         else if (CAL_STRING_EQUAL == strncmp(t[i] + strlen("RELATED"), "=END", strlen("=END")))
2758                                 related = VCAL_RELATED_END;
2759                         else
2760                                 ERR("Invalid related:[%s]", t[i]);
2761                 } else if (CAL_STRING_EQUAL == strncmp(t[i], "VALUE", strlen("VALUE"))) {
2762                         /* do nothing */
2763                 } else {
2764                         if ('0' <= *t[i] && *t[i] <= '9' && strlen("YYYYDDMM") <= strlen(t[i])) {
2765                                 calendar_time_s caltime = {0};
2766                                 _get_caltime(t[i], &caltime, ud);
2767                                 ret = cal_record_set_caltime(alarm, _calendar_alarm.alarm_time, caltime);
2768                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
2769                                 ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_SPECIFIC);
2770                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2771                         } else {
2772                                 int unit = 0;
2773                                 int tick = 0;
2774                                 __decode_duration(t[i], strlen(t[i]), &tick, &unit);
2775                                 if (CALENDAR_ALARM_TIME_UNIT_SPECIFIC == unit || 0 < tick) {
2776                                         if (CALENDAR_ALARM_TIME_UNIT_SPECIFIC == unit)
2777                                                 DBG("alarm tick is second, changed as specific.");
2778                                         if (0 < tick)
2779                                                 DBG("alarm is set after start/end time(%d).", tick);
2780
2781                                         calendar_time_s caltime = {0};
2782                                         if (VCAL_RELATED_NONE == related) {
2783                                                 switch (ud->type) {
2784                                                 case CALENDAR_BOOK_TYPE_EVENT:
2785                                                         related = VCAL_RELATED_START;
2786                                                         break;
2787                                                 case CALENDAR_BOOK_TYPE_TODO:
2788                                                         related = VCAL_RELATED_END;
2789                                                         break;
2790                                                 }
2791                                         }
2792                                         switch (related) {
2793                                         case VCAL_RELATED_START:
2794                                                 ret = calendar_record_get_caltime(record, _calendar_event.start_time, &caltime);
2795                                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
2796                                                 break;
2797                                         case VCAL_RELATED_END:
2798                                                 ret = calendar_record_get_caltime(record, _calendar_event.end_time, &caltime);
2799                                                 WARN_IF(CALENDAR_ERROR_NONE != ret, "calendar_record_get_caltime() Fail(%d)", ret);
2800                                                 break;
2801                                         }
2802                                         cal_time_modify_caltime(&caltime, tick * unit);
2803                                         ret = cal_record_set_caltime(alarm, _calendar_alarm.alarm_time, caltime);
2804                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_caltime() Fail(%d)", ret);
2805                                         ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_SPECIFIC);
2806                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2807                                 } else {
2808                                         ret = cal_record_set_int(alarm, _calendar_alarm.tick, (-1 * tick));
2809                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2810                                         ret = cal_record_set_int(alarm, _calendar_alarm.tick_unit, unit);
2811                                         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
2812                                 }
2813                         }
2814                 }
2815         }
2816
2817         g_strfreev(t);
2818 }
2819
2820 static void __work_component_property_valarm_repeat(char *value, calendar_record_h alarm, struct user_data *ud)
2821 {
2822         return;
2823 }
2824
2825 static void __work_component_property_valarm_attach(char *value, calendar_record_h alarm, struct user_data *ud)
2826 {
2827         RET_IF(NULL == value);
2828         RET_IF('\0' == *value);
2829         RET_IF(NULL == alarm);
2830
2831         int ret = cal_record_set_str(alarm, _calendar_alarm.attach, value + 1);
2832         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2833 }
2834
2835 static void __work_component_property_valarm_description(char *value, calendar_record_h alarm, struct user_data *ud)
2836 {
2837         RET_IF(NULL == value);
2838         RET_IF('\0' == *value);
2839         RET_IF(NULL == alarm);
2840
2841         int ret = cal_record_set_str(alarm, _calendar_alarm.description, value + 1);
2842         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2843 }
2844
2845 static void __work_component_property_valarm_summary(char *value, calendar_record_h alarm, struct user_data *ud)
2846 {
2847         RET_IF(NULL == value);
2848         RET_IF('\0' == *value);
2849         RET_IF(NULL == alarm);
2850
2851         int ret = cal_record_set_str(alarm, _calendar_alarm.summary, value);
2852         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
2853 }
2854
2855 static void __work_component_property_valarm_duration(char *value, calendar_record_h alarm, struct user_data *ud)
2856 {
2857         return;
2858 }
2859
2860 static char* __work_component_property_begin(char *cursor, calendar_record_h record, struct user_data *ud)
2861 {
2862         CAL_FN_CALL();
2863
2864         RETV_IF(NULL == cursor, NULL);
2865         RETV_IF(NULL == record, NULL);
2866         RETV_IF(NULL == ud, NULL);
2867
2868         if (0 != strncmp(cursor, ":VALARM", strlen(":VALARM"))) {
2869                 DBG("this is not valarm");
2870                 return __crlf(cursor);
2871         }
2872
2873         __init_component_property_valarm();
2874
2875         int ret = 0;
2876         calendar_record_h alarm = NULL;
2877         ret = calendar_record_create(_calendar_alarm._uri, &alarm);
2878         RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
2879
2880         cursor = __crlf(cursor); /* crlf: BEGIN:VALARM */
2881         bool exit_loop = false;
2882         while (cursor) {
2883                 int index = 0;
2884                 cursor = __get_index(cursor, component_property_valarm, VCAL_COMPONENT_PROPERTY_VALARM_MAX, &index);
2885
2886                 char *value = NULL;
2887                 switch (index) {
2888                 case VCAL_COMPONENT_PROPERTY_VALARM_ACTION:
2889                         cursor = __get_value(cursor, &value);
2890                         __work_component_property_valarm_action(value, alarm, ud);
2891                         free(value);
2892                         value = NULL;
2893                         break;
2894
2895                 case VCAL_COMPONENT_PROPERTY_VALARM_TRIGGER:
2896                         cursor = __get_value(cursor, &value);
2897                         __work_component_property_valarm_trigger(value, record, alarm, ud);
2898                         free(value);
2899                         value = NULL;
2900                         break;
2901
2902                 case VCAL_COMPONENT_PROPERTY_VALARM_REPEAT:
2903                         cursor = __get_value(cursor, &value);
2904                         __work_component_property_valarm_repeat(value, alarm, ud);
2905                         free(value);
2906                         value = NULL;
2907                         break;
2908
2909                 case VCAL_COMPONENT_PROPERTY_VALARM_ATTACH:
2910                         cursor = __get_value(cursor, &value);
2911                         __work_component_property_valarm_attach(value, alarm, ud);
2912                         free(value);
2913                         value = NULL;
2914                         break;
2915
2916                 case VCAL_COMPONENT_PROPERTY_VALARM_DESCRIPTION:
2917                         cursor = __get_value(cursor, &value);
2918                         __work_component_property_valarm_description(value, alarm, ud);
2919                         free(value);
2920                         value = NULL;
2921                         break;
2922
2923                 case VCAL_COMPONENT_PROPERTY_VALARM_SUMMARY:
2924                         cursor = __get_value(cursor, &value);
2925                         __work_component_property_valarm_summary(value, alarm, ud);
2926                         free(value);
2927                         value = NULL;
2928                         break;
2929
2930                 case VCAL_COMPONENT_PROPERTY_VALARM_DURATION:
2931                         cursor = __get_value(cursor, &value);
2932                         __work_component_property_valarm_duration(value, alarm, ud);
2933                         free(value);
2934                         value = NULL;
2935                         break;
2936
2937                 case VCAL_COMPONENT_PROPERTY_VALARM_END:
2938                         DBG("exit valarm");
2939                         exit_loop = true;
2940                         break;
2941
2942                 default:
2943                         /* LCOV_EXCL_START */
2944                         ERR("Invalid index(%d)", index);
2945                         cursor = __crlf(cursor);
2946                         break;
2947                         /* LCOV_EXCL_STOP */
2948                 }
2949
2950                 if (true == exit_loop) break;
2951         }
2952
2953         switch (ud->type) {
2954         case VCALENDAR_TYPE_VEVENT:
2955                 ret = calendar_record_add_child_record(record, _calendar_event.calendar_alarm, alarm);
2956                 break;
2957         case VCALENDAR_TYPE_VTODO:
2958                 ret = calendar_record_add_child_record(record, _calendar_todo.calendar_alarm, alarm);
2959                 break;
2960         }
2961         RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_add_child_record() Fail(%d)", ret);
2962         return cursor;
2963 }
2964
2965 static char* __work_component_vevent(char *cursor, calendar_record_h record, struct user_data *ud)
2966 {
2967         RETV_IF(NULL == cursor, NULL);
2968         RETV_IF(NULL == record, NULL);
2969
2970         bool exit_loop = false;
2971         while (cursor) {
2972                 int index = 0;
2973                 cursor = __get_index(cursor, component_property, VCAL_COMPONENT_PROPERTY_MAX, &index);
2974
2975                 char *value = NULL;
2976                 switch (index) {
2977                 case VCAL_COMPONENT_PROPERTY_DTSTAMP:
2978                         cursor = __get_value(cursor, &value);
2979                         __work_component_property_dtstamp(value, record, ud);
2980                         free(value);
2981                         value = NULL;
2982                         break;
2983                 case VCAL_COMPONENT_PROPERTY_UID:
2984                         cursor = __get_value(cursor, &value);
2985                         __work_component_property_uid(value, record, ud);
2986                         free(value);
2987                         value = NULL;
2988                         break;
2989                 case VCAL_COMPONENT_PROPERTY_RECURRENCE_ID:
2990                         cursor = __get_value(cursor, &value);
2991                         __work_component_property_recurrence_id(value, record, ud);
2992                         free(value);
2993                         value = NULL;
2994                         break;
2995                 case VCAL_COMPONENT_PROPERTY_DTSTART:
2996                         cursor = __get_value(cursor, &value);
2997                         __work_component_property_dtstart(value, record, ud);
2998                         free(value);
2999                         value = NULL;
3000                         break;
3001                 case VCAL_COMPONENT_PROPERTY_CREATED:
3002                         cursor = __get_value(cursor, &value);
3003                         __work_component_property_created(value, record, ud);
3004                         free(value);
3005                         value = NULL;
3006                         break;
3007                 case VCAL_COMPONENT_PROPERTY_DCREATED:
3008                         cursor = __get_value(cursor, &value);
3009                         __work_component_property_created(value, record, ud);
3010                         free(value);
3011                         value = NULL;
3012                         break;
3013                 case VCAL_COMPONENT_PROPERTY_DESCRIPTION:
3014                         cursor = __get_value(cursor, &value);
3015                         __work_component_property_description(value, record, ud);
3016                         free(value);
3017                         value = NULL;
3018                         break;
3019                 case VCAL_COMPONENT_PROPERTY_LAST_MODIFIED:
3020                         cursor = __get_value(cursor, &value);
3021                         __work_component_property_last_modified(value, record, ud);
3022                         free(value);
3023                         value = NULL;
3024                         break;
3025                 case VCAL_COMPONENT_PROPERTY_LOCATION:
3026                         cursor = __get_value(cursor, &value);
3027                         __work_component_property_location(value, record, ud);
3028                         free(value);
3029                         value = NULL;
3030                         break;
3031                 case VCAL_COMPONENT_PROPERTY_PRIORITY:
3032                         cursor = __get_value(cursor, &value);
3033                         __work_component_property_priority(value + 1, record, ud);
3034                         free(value);
3035                         value = NULL;
3036                         break;
3037                 case VCAL_COMPONENT_PROPERTY_STATUS:
3038                         cursor = __get_value(cursor, &value);
3039                         __work_component_property_status(value, record, ud);
3040                         free(value);
3041                         value = NULL;
3042                         break;
3043                 case VCAL_COMPONENT_PROPERTY_SUMMARY:
3044                         cursor = __get_value(cursor, &value);
3045                         __work_component_property_summary(value, record, ud);
3046                         free(value);
3047                         value = NULL;
3048                         break;
3049                 case VCAL_COMPONENT_PROPERTY_RRULE:
3050                         cursor = __get_value(cursor, &value);
3051                         __work_component_property_rrule(value, record, ud);
3052                         free(value);
3053                         value = NULL;
3054                         break;
3055                 case VCAL_COMPONENT_PROPERTY_DTEND:
3056                         if (CAL_STRING_EQUAL != strcmp(((cal_record_s*)(record))->view_uri, _calendar_event._uri))
3057                                 break;
3058                         cursor = __get_value(cursor, &value);
3059                         __work_component_property_dtend(value, record, ud);
3060                         free(value);
3061                         value = NULL;
3062                         break;
3063                 case VCAL_COMPONENT_PROPERTY_DUE:
3064                         if (CAL_STRING_EQUAL != strcmp(((cal_record_s*)(record))->view_uri, _calendar_todo._uri))
3065                                 break;
3066                         cursor = __get_value(cursor, &value);
3067                         __work_component_property_dtend(value, record, ud);
3068                         free(value);
3069                         value = NULL;
3070                         break;
3071                 case VCAL_COMPONENT_PROPERTY_ATTENDEE:
3072                         cursor = __get_value(cursor, &value);
3073                         __work_component_property_attendee(value, record, ud);
3074                         free(value);
3075                         value = NULL;
3076                         break;
3077                 case VCAL_COMPONENT_PROPERTY_CATEGORIES:
3078                         cursor = __get_value(cursor, &value);
3079                         __work_component_property_categories(value, record, ud);
3080                         free(value);
3081                         value = NULL;
3082                         break;
3083                 case VCAL_COMPONENT_PROPERTY_DALARM:
3084                         cursor = __get_value(cursor, &value);
3085                         __work_component_property_dalarm(value, record, ud);
3086                         free(value);
3087                         value = NULL;
3088                         break;
3089                 case VCAL_COMPONENT_PROPERTY_MALARM:
3090                         cursor = __get_value(cursor, &value);
3091                         __work_component_property_malarm(value, record, ud);
3092                         free(value);
3093                         value = NULL;
3094                         break;
3095                 case VCAL_COMPONENT_PROPERTY_AALARM:
3096                         cursor = __get_value(cursor, &value);
3097                         __work_component_property_aalarm(value, record, ud);
3098                         free(value);
3099                         value = NULL;
3100                         break;
3101                 case VCAL_COMPONENT_PROPERTY_EXDATE:
3102                         cursor = __get_value(cursor, &value);
3103                         __work_component_property_exdate(value, record, ud);
3104                         free(value);
3105                         value = NULL;
3106                         break;
3107                 case VCAL_COMPONENT_PROPERTY_X_ALLDAY:
3108                         cursor = __get_value(cursor, &value);
3109                         __work_component_property_x_allday(value, record, ud);
3110                         free(value);
3111                         value = NULL;
3112                         break;
3113                 case VCAL_COMPONENT_PROPERTY_X_LUNAR:
3114                         cursor = __get_value(cursor, &value);
3115                         __work_component_property_x_lunar(value, record, ud);
3116                         free(value);
3117                         value = NULL;
3118                         break;
3119                 case VCAL_COMPONENT_PROPERTY_BEGIN:
3120                         cursor = __work_component_property_begin(cursor, record, ud);
3121                         if (NULL == cursor)
3122                                 cursor = __crlf(cursor);
3123                         break;
3124                 case VCAL_COMPONENT_PROPERTY_END:
3125                         DBG("exit record");
3126                         cursor = __crlf(cursor);
3127                         exit_loop = true;
3128                         break;
3129                 case VCAL_COMPONENT_PROPERTY_EXTENDED:
3130                         cursor = __get_value(cursor, &value);
3131                         free(value);
3132                         value = NULL;
3133                         break;
3134                 default:
3135                         cursor = __crlf(cursor);
3136                         break;
3137                 }
3138                 if (true == exit_loop) break;
3139         }
3140         return cursor;
3141 }
3142
3143 static char* __work_component_vjournal(char *cursor, calendar_record_h record, struct user_data *ud)
3144 {
3145         RETV_IF(NULL == cursor, NULL);
3146
3147         DBG("Not supported vjournal");
3148
3149         bool exit_loop = false;
3150         while (cursor) {
3151                 int index = 0;
3152                 cursor = __get_index(cursor, component_property, VCAL_COMPONENT_PROPERTY_MAX, &index);
3153                 switch (index) {
3154                 case VCAL_COMPONENT_PROPERTY_END:
3155                         DBG("exit record");
3156                         cursor = __crlf(cursor);
3157                         exit_loop = true;
3158                         break;
3159
3160                 default:
3161                         cursor = __crlf(cursor);
3162                         break;
3163                 }
3164                 if (true == exit_loop) break;
3165         }
3166         return cursor;
3167 }
3168
3169 static char* __work_component_vfreebusy(char *cursor, calendar_record_h record, struct user_data *ud)
3170 {
3171         RETV_IF(NULL == cursor, NULL);
3172
3173         DBG("Not supported vfreebusy");
3174
3175         bool exit_loop = false;
3176         while (cursor) {
3177                 int index = 0;
3178                 cursor = __get_index(cursor, component_property, VCAL_COMPONENT_PROPERTY_MAX, &index);
3179                 switch (index) {
3180                 case VCAL_COMPONENT_PROPERTY_END:
3181                         DBG("exit record");
3182                         cursor = __crlf(cursor);
3183                         exit_loop = true;
3184                         break;
3185
3186                 default:
3187                         cursor = __crlf(cursor);
3188                         break;
3189                 }
3190                 if (true == exit_loop) break;
3191         }
3192         return cursor;
3193 }
3194
3195 static void __work_component_property_vtimezone_standard_dtstart(char *value, calendar_record_h record, struct user_data *ud)
3196 {
3197         CAL_FN_CALL();
3198
3199         RET_IF(NULL == value);
3200         RET_IF('\0' == *value);
3201         RET_IF(NULL == record);
3202
3203         int ret = 0;
3204         int y = 0, m = 0, d = 0;
3205         int h = 0, n = 0, s = 0;
3206         sscanf(value +1, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
3207         ret = cal_record_set_int(record, _calendar_timezone.standard_start_month, m);
3208         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3209         ret = cal_record_set_int(record, _calendar_timezone.standard_start_hour, h);
3210         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3211
3212         long long int t = cal_time_convert_lli(value +1);
3213         int nth = 0, wday = 0;
3214         cal_time_get_nth_wday(t, &nth, &wday);
3215         ret = cal_record_set_int(record, _calendar_timezone.standard_start_position_of_week, nth);
3216         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3217         ret = cal_record_set_int(record, _calendar_timezone.standard_start_day, wday);
3218         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3219 }
3220 static void __work_component_property_vtimezone_standard_tzoffsetfrom(char *value, calendar_record_h record, struct user_data *ud)
3221 {
3222         return;
3223 }
3224 static void __work_component_property_vtimezone_standard_tzoffsetto(char *value, calendar_record_h record, struct user_data *ud)
3225 {
3226         CAL_FN_CALL();
3227
3228         RET_IF(NULL == value);
3229         RET_IF('\0' == *value);
3230         RET_IF(NULL == record);
3231
3232         char c;
3233         int h = 0, m = 0;
3234         sscanf(value, "%c%02d%02d", &c, &h, &m);
3235
3236         int offset = h * 60 + m;
3237         if ('-' == c) offset *= -1;
3238
3239         int ret = 0;
3240         ret = cal_record_set_int(record, _calendar_timezone.standard_bias, offset);
3241         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3242         ret = cal_record_set_int(record, _calendar_timezone.tz_offset_from_gmt, offset);
3243         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3244
3245         if (NULL == ud->timezone_tzid || '\0' == *ud->timezone_tzid) {
3246                 char buf[CAL_STR_SHORT_LEN32] = {0};
3247                 snprintf(buf, sizeof(buf), "Etc/GMT%c%d", offset < 0 ? '+' : '-', h);
3248                 ud->timezone_tzid = strdup(buf);
3249                 __adjust_tzid(ud->timezone_tzid);
3250                 DBG("timezone_tzid[%s]", ud->timezone_tzid);
3251         }
3252 }
3253 static void __work_component_property_vtimezone_standard_tzname(char *value, calendar_record_h record, struct user_data *ud)
3254 {
3255         RET_IF(NULL == value);
3256         RET_IF('\0' == *value);
3257         RET_IF(NULL == record);
3258
3259         int ret = cal_record_set_str(record, _calendar_timezone.standard_name, value);
3260         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
3261 }
3262 static void __work_component_property_vtimezone_standard_rdate(char *value, calendar_record_h record, struct user_data *ud)
3263 {
3264         return;
3265 }
3266 static char* __work_component_vtimezone_standard(char *cursor, calendar_record_h record, struct user_data *ud)
3267 {
3268         CAL_FN_CALL();
3269
3270         RETV_IF(NULL == cursor, __crlf(cursor));
3271         RETV_IF('\0' == *cursor, __crlf(cursor));
3272         RETV_IF(NULL == record, __crlf(cursor));
3273
3274         cursor = __crlf(cursor);
3275         bool exit_loop = false;
3276         while (cursor) {
3277                 int index = 0;
3278                 cursor = __get_index(cursor, component_property_vtimezone, VCAL_COMPONENT_PROPERTY_VTIMEZONE_MAX, &index);
3279
3280                 char *value = NULL;
3281                 switch (index) {
3282                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_DTSTART:
3283                         cursor = __get_value(cursor, &value);
3284                         __work_component_property_vtimezone_standard_dtstart(value +1, record, ud);
3285                         free(value);
3286                         value = NULL;
3287                         break;
3288                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETFROM:
3289                         cursor = __get_value(cursor, &value);
3290                         __work_component_property_vtimezone_standard_tzoffsetfrom(value, record, ud);
3291                         free(value);
3292                         value = NULL;
3293                         break;
3294                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETTO:
3295                         cursor = __get_value(cursor, &value);
3296                         __work_component_property_vtimezone_standard_tzoffsetto(value +1, record, ud);
3297                         free(value);
3298                         value = NULL;
3299                         break;
3300                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZNAME:
3301                         cursor = __get_value(cursor, &value);
3302                         __work_component_property_vtimezone_standard_tzname(value +1, record, ud);
3303                         free(value);
3304                         value = NULL;
3305                         break;
3306                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_RDATE:
3307                         cursor = __get_value(cursor, &value);
3308                         __work_component_property_vtimezone_standard_rdate(value, record, ud);
3309                         free(value);
3310                         value = NULL;
3311                         break;
3312                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_END:
3313                         cursor = __crlf(cursor);
3314                         exit_loop = true;
3315                         break;
3316                 default:
3317                         cursor = __crlf(cursor);
3318                         break;
3319                 }
3320                 if (true == exit_loop) break;
3321         }
3322         return cursor;
3323 }
3324
3325 static void __work_component_property_vtimezone_daylight_dtstart(char *value, calendar_record_h record, struct user_data *ud)
3326 {
3327         RET_IF(NULL == value);
3328         RET_IF('\0' == *value);
3329         RET_IF(NULL == record);
3330
3331         int ret = 0;
3332         int y = 0, m = 0, d = 0;
3333         int h = 0, n = 0, s = 0;
3334         sscanf(value +1, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
3335         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_month, m);
3336         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3337         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_hour, h);
3338         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3339
3340         long long int t = cal_time_convert_lli(value +1);
3341         int nth = 0, wday = 0;
3342         cal_time_get_nth_wday(t, &nth, &wday);
3343         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_position_of_week, nth);
3344         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3345         ret = cal_record_set_int(record, _calendar_timezone.day_light_start_day, wday);
3346         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3347 }
3348 static void __work_component_property_vtimezone_daylight_tzoffsetfrom(char *value, calendar_record_h record, struct user_data *ud)
3349 {
3350         return;
3351 }
3352 static void __work_component_property_vtimezone_daylight_tzoffsetto(char *value, calendar_record_h record, struct user_data *ud)
3353 {
3354         RET_IF(NULL == value);
3355         RET_IF('\0' == *value);
3356         RET_IF(NULL == record);
3357
3358         char c;
3359         int h = 0, m = 0;
3360         sscanf(value, "%c%02d%02d", &c, &h, &m);
3361
3362         int offset = h * 60 + m;
3363         if ('-' == c) offset *= -1;
3364
3365         int ret = cal_record_set_int(record, _calendar_timezone.day_light_bias, offset);
3366         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_int() Fail(%d)", ret);
3367 }
3368 static void __work_component_property_vtimezone_daylight_tzname(char *value, calendar_record_h record, struct user_data *ud)
3369 {
3370         RET_IF(NULL == value);
3371         RET_IF('\0' == *value);
3372         RET_IF(NULL == record);
3373
3374         int ret = cal_record_set_str(record, _calendar_timezone.day_light_name, value);
3375         WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_record_set_str() Fail(%d)", ret);
3376 }
3377 static void __work_component_property_vtimezone_daylight_rdate(char *value, calendar_record_h record, struct user_data *ud)
3378 {
3379         return;
3380 }
3381 static char* __work_component_vtimezone_daylight(char *cursor, calendar_record_h record, struct user_data *ud)
3382 {
3383         RETV_IF(NULL == cursor, __crlf(cursor));
3384         RETV_IF('\0' == *cursor, __crlf(cursor));
3385         RETV_IF(NULL == record, __crlf(cursor));
3386
3387         cursor = __crlf(cursor);
3388         bool exit_loop = false;
3389         while (cursor) {
3390                 int index = 0;
3391                 cursor = __get_index(cursor, component_property_vtimezone, VCAL_COMPONENT_PROPERTY_VTIMEZONE_MAX, &index);
3392
3393                 char *value = NULL;
3394                 switch (index) {
3395                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_DTSTART:
3396                         cursor = __get_value(cursor, &value);
3397                         __work_component_property_vtimezone_daylight_dtstart(value +1, record, ud);
3398                         free(value);
3399                         value = NULL;
3400                         break;
3401                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETFROM:
3402                         cursor = __get_value(cursor, &value);
3403                         __work_component_property_vtimezone_daylight_tzoffsetfrom(value, record, ud);
3404                         free(value);
3405                         value = NULL;
3406                         break;
3407                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZOFFSETTO:
3408                         cursor = __get_value(cursor, &value);
3409                         __work_component_property_vtimezone_daylight_tzoffsetto(value +1, record, ud);
3410                         free(value);
3411                         value = NULL;
3412                         break;
3413                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_TZNAME:
3414                         cursor = __get_value(cursor, &value);
3415                         __work_component_property_vtimezone_daylight_tzname(value +1, record, ud);
3416                         free(value);
3417                         value = NULL;
3418                         break;
3419                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_RDATE:
3420                         cursor = __get_value(cursor, &value);
3421                         __work_component_property_vtimezone_daylight_rdate(value, record, ud);
3422                         free(value);
3423                         value = NULL;
3424                         break;
3425                 case VCAL_COMPONENT_PROPERTY_VTIMEZONE_END:
3426                         cursor = __crlf(cursor);
3427                         exit_loop = true;
3428                         break;
3429                 default:
3430                         cursor = __crlf(cursor);
3431                         break;
3432                 }
3433                 if (true == exit_loop) break;
3434         }
3435         return cursor;
3436 }
3437
3438 static char* __work_component_vtimezone(char *cursor, calendar_record_h record, struct user_data *ud)
3439 {
3440         CAL_FN_CALL();
3441
3442         RETV_IF(NULL == cursor, NULL);
3443         RETV_IF(NULL == record, NULL);
3444
3445         __init_component_property_vtimezone();
3446
3447         while (cursor) {
3448                 if (CAL_STRING_EQUAL == strncmp(cursor, "TZID:", strlen("TZID:"))) {
3449                         char *p = cursor + strlen("TZID");
3450                         if (NULL == p || '\0' == *p) {
3451                                 /* LCOV_EXCL_START */
3452                                 ERR("Inavlid tzid");
3453                                 cursor = __crlf(cursor);
3454                                 continue;
3455                                 /* LCOV_EXCL_STOP */
3456                         }
3457                         if (ud->timezone_tzid) {
3458                                 free(ud->timezone_tzid);
3459                                 ud->timezone_tzid = NULL;
3460                         }
3461                         char *value = NULL;
3462                         cursor = __get_value(p, &value);
3463                         __adjust_tzid(value);
3464                         DBG("tzid[%s]", value +1);
3465                         if (true == cal_time_is_available_tzid(value +1))
3466                                 ud->timezone_tzid = strdup(value +1);
3467                         else
3468                                 DBG("Invalid tzid string[%s]", value +1);
3469
3470                         free(value);
3471                 } else if (CAL_STRING_EQUAL == strncmp(cursor, "BEGIN:STANDARD", strlen("BEGIN:STANDARD"))) {
3472                         cursor = __work_component_vtimezone_standard(cursor, record, ud);
3473                 } else if (CAL_STRING_EQUAL == strncmp(cursor, "BEGIN:DAYLIGHT", strlen("BEGIN:DAYLIGHT"))) {
3474                         cursor = __work_component_vtimezone_daylight(cursor, record, ud);
3475                 } else if (CAL_STRING_EQUAL == strncmp(cursor, "END", strlen("END"))) {
3476                         cursor = __crlf(cursor);
3477                         break;
3478                 } else {
3479                         DBG("Unable to parse");
3480                         __print_cursor(cursor, __LINE__);
3481                         cursor = __crlf(cursor);
3482                 }
3483         }
3484         return cursor;
3485 }
3486
3487 static char* __work_property_begin(char *cursor, calendar_record_h *out_record, struct user_data *ud)
3488 {
3489         CAL_FN_CALL();
3490         RETV_IF(NULL == cursor, NULL);
3491         RETV_IF('\0' == *cursor, NULL);
3492         RETV_IF(NULL == out_record, NULL);
3493         RETV_IF(NULL == ud, NULL);
3494
3495         int ret = 0;
3496         int index = 0;
3497         cursor = __get_index(cursor +1, vcal_component, VCAL_COMPONENT_MAX, &index);
3498         cursor = __crlf(cursor);
3499         calendar_record_h record = NULL;
3500         switch (index) {
3501         case VCAL_COMPONENT_VEVENT:
3502                 ret = calendar_record_create(_calendar_event._uri, &record);
3503                 RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
3504                 ud->type = CALENDAR_BOOK_TYPE_EVENT;
3505                 ud->has_rrule = __check_has_rrule(cursor);
3506                 cursor = __work_component_vevent(cursor, record, ud);
3507                 break;
3508
3509         case VCAL_COMPONENT_VTODO:
3510                 ret = calendar_record_create(_calendar_todo._uri, &record);
3511                 RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
3512                 ud->type = CALENDAR_BOOK_TYPE_TODO;
3513                 ud->has_rrule = __check_has_rrule(cursor);
3514                 cursor = __work_component_vevent(cursor, record, ud); /* same as event */
3515                 break;
3516
3517         case VCAL_COMPONENT_VJOURNAL:
3518                 cursor = __work_component_vjournal(cursor, record, ud);
3519                 break;
3520
3521         case VCAL_COMPONENT_VFREEBUSY:
3522                 cursor = __work_component_vfreebusy(cursor, record, ud);
3523                 break;
3524
3525         case VCAL_COMPONENT_VTIMEZONE:
3526                 ret = calendar_record_create(_calendar_timezone._uri, &record);
3527                 RETVM_IF(CALENDAR_ERROR_NONE != ret, NULL, "calendar_record_create() Fail(%d)", ret);
3528                 cursor = __work_component_vtimezone(cursor, record, ud);
3529                 break;
3530         }
3531         *out_record = record;
3532         return cursor;
3533 }
3534
3535 int cal_vcalendar_parse_vcalendar_object(char *stream, calendar_list_h list, vcalendar_foreach_s *foreach_data)
3536 {
3537         CAL_FN_CALL();
3538
3539         RETV_IF(NULL == stream, CALENDAR_ERROR_INVALID_PARAMETER);
3540         RETV_IF(NULL == list, CALENDAR_ERROR_INVALID_PARAMETER);
3541
3542         __init_component();
3543         __init_property();
3544         __init_component_property();
3545         __unfolding(stream);
3546
3547         struct user_data *ud = calloc(1, sizeof(struct user_data));
3548         RETVM_IF(NULL == ud, CALENDAR_ERROR_OUT_OF_MEMORY, "calloc() Fail");
3549         ud->version = VCAL_VER_2; /* default */
3550
3551         calendar_record_h record = NULL;
3552
3553         int count = 0;
3554         bool exit_loop = false;
3555         char *cursor = (char *)stream;
3556         while (cursor) {
3557                 int index = 0;
3558                 char *value = NULL;
3559                 cursor = __get_index(cursor, vcal_property, VCAL_PROPERTY_MAX, &index);
3560                 switch (index) {
3561                 case VCAL_PROPERTY_VERSION:
3562                         cursor = __get_value(cursor, &value);
3563                         __get_version(value, &ud->version);
3564                         free(value);
3565                         value = NULL;
3566                         break;
3567
3568                 case VCAL_PROPERTY_TZ:
3569                         if (ud->timezone_tzid)
3570                                 break;
3571                         cursor = __get_value(cursor, &value);
3572                         __get_tz(value + 1, &ud->timezone_tzid);
3573                         __adjust_tzid(ud->timezone_tzid);
3574                         DBG("timezone_tzid[%s]", ud->timezone_tzid);
3575                         free(value);
3576                         value = NULL;
3577                         break;
3578
3579                 case VCAL_PROPERTY_BEGIN: /* BEGIN:VEVENT */
3580                         cursor = __work_property_begin(cursor, &record, ud);
3581                         calendar_list_add(list, record);
3582                         count++;
3583                         if (foreach_data) {
3584                                 foreach_data->ret = foreach_data->callback(record, foreach_data->user_data);
3585                                 if (false == foreach_data->ret)
3586                                         exit_loop = true;
3587                         }
3588                         break;
3589
3590                 case VCAL_PROPERTY_END: /* END:VCALENDAR */
3591                         DBG("exit VCALENDAR");
3592                         /* fini vcalendar */
3593                         exit_loop = true;
3594                         break;
3595
3596                 default:
3597                         DBG("skip invalid property, index(%d)", index);
3598                         cursor = __crlf(cursor);
3599                         break;
3600                 }
3601                 if (true == exit_loop)
3602                         break;
3603         }
3604
3605         DBG("count(%d)", count);
3606         if (0 == count)
3607                 DBG("No record");
3608         free(ud->timezone_tzid);
3609         free(ud);
3610
3611         return CALENDAR_ERROR_NONE;
3612 }