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