1 #include "../pith/headers.h"
2 #include "../pith/mailpart.h"
3 #include "../pith/store.h"
4 #include "../pith/ical.h"
6 typedef struct ical_iana_comp_s
{
7 char *comp
; /* component name */
8 size_t len
; /* size of component name (strlen(x->comp)) */
9 int pos
; /* position of this component in comp array */
10 void *(*parse
)(char **); /* parser */
11 void (*give
)(void **); /* free memory */
14 typedef struct ical_iana_prop_s
{
15 char *prop
; /* component PROPerty name */
16 size_t len
; /* size of component name (strlen(x->prop)) */
17 int pos
; /* location of this component in the prop array */
18 void *(*parse
)(); /* parser */
19 void (*give
)(void **); /* free memory */
22 int ical_january_first(int); /* args: year */
23 void ical_adjust_date(struct tm
*, VTIMEZONE_S
*);
25 void ical_initialize(void);
27 int ical_non_ascii_valid(unsigned char);
28 char *ical_unfold_line(char *);
29 ICLINE_S
*ical_parse_line(char **, char *);
31 ICLINE_S
*ical_cline_cpy(ICLINE_S
*);
32 ICAL_PARAMETER_S
*ical_parameter_cpy(ICAL_PARAMETER_S
*param
);
34 char *ical_get_value(char **);
35 unsigned char *ical_decode(char *, unsigned short);
38 void *ical_parse_vcalendar(char **);
39 void *ical_parse_vevent(char **);
40 void *ical_parse_vtodo(char **);
41 void *ical_parse_vjournal(char **);
42 void *ical_parse_vfreebusy(char **);
43 void *ical_parse_vtimezone(char **);
44 void *ical_parse_valarm(char **);
45 void *ical_parse_timezone(char **);
46 ICAL_S
*ical_parse_unknown_comp(char **, int);
47 ICAL_S
*ical_parse_generic_comp(char **, int);
50 void ical_free_vevent(void **);
51 void ical_free_vtodo(void **);
52 void ical_free_vjournal(void **);
53 void ical_free_vfreebusy(void **);
54 void ical_free_vtimezone(void **);
55 void ical_free_timezone(void **);
56 void ical_free_valarm(void **);
57 void ical_free_unknown_comp(ICAL_S
**);
59 /* parse properties */
60 void *ical_cline_from_token(void *, char **, char *);
61 void *ical_gencline_from_token(void *, char **, char *);
63 void *ical_parse_rrule(void *, char **, char *);
64 void *ical_parse_time(void *, char **, char *);
65 void *ical_parse_offset(void *, char **, char *);
67 void *ical_parse_freq(void *, char *);
68 void *ical_parse_until(void *, char *);
69 void *ical_parse_count(void *, char *);
70 void *ical_parse_interval(void *, char *);
71 void *ical_parse_weekday_list(void *, char *);
72 void *ical_parse_number_list(void *, char *);
74 int ical_get_number_value(char *, int, int);
75 void ical_set_date(ICLINE_S
*, VTIMEZONE_S
*);
76 void ical_set_date_vevent(void *, void *);
79 void ical_free_prop(void **, ICAL_PROP_S
*);
80 void ical_free_null(void **);
81 void ical_free_cline(void **);
82 void ical_free_param(ICAL_PARAMETER_S
**);
83 void ical_free_gencline(void **);
84 void ical_free_rrule(void **);
85 void ical_free_weekday_list(void **);
87 /* utility functions */
88 void ical_date_time (char *, size_t, struct tm
*);
89 char *ical_get_tzid(ICAL_PARAMETER_S
*);
92 struct tm day_zero
; /* date for january 1, 1601 */
93 int month_len
[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
95 #define UTF8_COMPLETE (1)
99 unsigned long ical_buf_len
;
102 /* parsing structures */
104 /* this is the list of V-components to a Calendar from RFC 5545 */
105 ICAL_COMP_S ical_comp
[] = {
106 {"VCALENDAR", 9, VCalendar
, ical_parse_vcalendar
, ical_free_vcalendar
},
107 {"VTIMEZONE", 9, VTimeZone
, ical_parse_vtimezone
, ical_free_vtimezone
},
108 {"VEVENT", 6, VEvent
, ical_parse_vevent
, ical_free_vevent
},
109 {"VTODO", 5, VTodo
, ical_parse_vtodo
, ical_free_vtodo
},
110 {"VJOURNAL", 8, VJournal
, ical_parse_vjournal
, ical_free_vjournal
},
111 {"VALARM", 6, VAlarm
, ical_parse_valarm
, ical_free_valarm
},
112 {"VFREEBUSY", 9, VFreeBusy
, ical_parse_vfreebusy
, ical_free_vfreebusy
},
113 {NULL
, 0, VUnknown
, NULL
, 0}
116 /* array for properties */
117 ICAL_PROP_S rrule_prop
[] = {
118 {"FREQ", 4, RRFreq
, ical_parse_freq
, ical_free_null
},
119 {"UNTIL", 5, RRUntil
, ical_parse_until
, ical_free_null
},
120 {"COUNT", 5, RRCount
, ical_parse_count
, ical_free_null
},
121 {"INTERVAL", 8, RRInterval
, ical_parse_interval
, ical_free_null
},
122 {"BYSECOND", 8, RRBysecond
, ical_parse_number_list
, ical_free_weekday_list
},
123 {"BYMINUTE", 8, RRByminute
, ical_parse_number_list
, ical_free_weekday_list
},
124 {"BYHOUR", 6, RRByhour
, ical_parse_number_list
, ical_free_weekday_list
},
125 {"BYDAY", 5, RRByday
, ical_parse_weekday_list
,ical_free_weekday_list
},
126 {"BYWEEKNO", 8, RRByweekno
, 0, 0},
127 {"BYMONTH", 7, RRBymonth
, ical_parse_number_list
, ical_free_weekday_list
},
128 {"BYSETPOS", 8, RRBysetpos
, 0, 0},
129 {"BYWKST", 6, RRWkst
, 0, 0},
131 10, RRBymonthday
, 0, 0},
132 {"BYYEARDAY", 9, RRByyearday
, 0, 0},
133 {NULL
, 0, RRUnknown
, 0, 0}
136 ICAL_PROP_S event_prop
[] = {
137 {"DTSTAMP", 7, EvDtstamp
, ical_cline_from_token
, ical_free_cline
},
138 {"UID", 3, EvUid
, ical_cline_from_token
, ical_free_cline
},
139 {"DTSTART", 7, EvDtstart
, ical_cline_from_token
, ical_free_cline
},
140 {"CLASS", 5, EvClass
, ical_cline_from_token
, ical_free_cline
},
141 {"CREATED", 7, EvCreated
, ical_cline_from_token
, ical_free_cline
},
142 {"DESCRIPTION", 11, EvDescription
, ical_cline_from_token
, ical_free_cline
},
143 {"GEO", 3, EvGeo
, ical_cline_from_token
, ical_free_cline
},
144 {"LASTMOD", 7, EvLastMod
, ical_cline_from_token
, ical_free_cline
},
145 {"LOCATION", 8, EvLocation
, ical_cline_from_token
, ical_free_cline
},
146 {"ORGANIZER", 9, EvOrganizer
, ical_cline_from_token
, ical_free_cline
},
147 {"PRIORITY", 8, EvPriority
, ical_cline_from_token
, ical_free_cline
},
148 {"SEQUENCE", 8, EvSequence
, ical_cline_from_token
, ical_free_cline
},
149 {"STATUS", 6, EvStatus
, ical_cline_from_token
, ical_free_cline
},
150 {"SUMMARY", 7, EvSummary
, ical_cline_from_token
, ical_free_cline
},
151 {"TRANSP", 6, EvTransp
, ical_cline_from_token
, ical_free_cline
},
152 {"URL", 3, EvUrl
, ical_cline_from_token
, ical_free_cline
},
153 {"RECURRENCE-ID", 13, EvRecurrence
, ical_cline_from_token
, ical_free_cline
},
154 {"RRULE", 5, EvRrule
, ical_parse_rrule
, ical_free_rrule
},
155 {"DTEND", 5, EvDtend
, ical_cline_from_token
, ical_free_cline
},
156 {"DURATION", 8, EvDuration
, ical_cline_from_token
, ical_free_cline
},
157 {"ATTACH", 6, EvAttach
, ical_gencline_from_token
, ical_free_gencline
},
158 {"ATTENDEE", 8, EvAttendee
, ical_gencline_from_token
, ical_free_gencline
},
159 {"CATEGORIES", 10, EvCategories
, ical_gencline_from_token
, ical_free_gencline
},
160 {"COMMENT", 7, EvComment
, ical_gencline_from_token
, ical_free_gencline
},
161 {"CONTACT", 7, EvContact
, ical_gencline_from_token
, ical_free_gencline
},
162 {"EXDATE", 6, EvExdate
, ical_gencline_from_token
, ical_free_gencline
},
163 {"RSTATUS", 7, EvRstatus
, ical_gencline_from_token
, ical_free_gencline
},
164 {"RELATED", 7, EvRelated
, ical_gencline_from_token
, ical_free_gencline
},
165 {"RESOURCES", 9, EvResources
, ical_gencline_from_token
, ical_free_gencline
},
166 {"RDATE", 5, EvRdate
, ical_gencline_from_token
, ical_free_gencline
},
167 {NULL
, 0, EvUnknown
, 0, 0}
170 ICAL_PROP_S tz_comp
[] = {
171 {"TZID", 4, TZCid
, ical_cline_from_token
, ical_free_cline
},
172 {"LAST-MODIFIED", 13, TZCLastMod
, ical_cline_from_token
, ical_free_cline
},
173 {"TZURL", 5, TZCUrl
, ical_cline_from_token
, ical_free_cline
},
174 {NULL
, 0, TZCUnknown
, 0, 0}
177 ICAL_PROP_S tz_prop
[] = {
178 {"DTSTART", 7, TZPDtstart
, ical_parse_time
, ical_free_null
},
179 {"TZOFFSETTO", 10, TZPOffsetto
, ical_parse_offset
, ical_free_null
},
180 {"TZOFFSETFROM", 12, TZPOffsetfrom
, ical_parse_offset
, ical_free_null
},
181 {"RRULE", 5, TZPRrule
, ical_parse_rrule
, ical_free_rrule
},
182 {"COMMENT", 7, TZPComment
, ical_gencline_from_token
, ical_free_gencline
},
183 {"RDATE", 5, TZPRdate
, ical_gencline_from_token
, ical_free_gencline
},
184 {"TZNAME", 6, TZPTzname
, ical_gencline_from_token
, ical_free_gencline
},
185 {NULL
, 0, TZPUnknown
, 0, 0}
188 ICAL_PROP_S alarm_prop
[] = {
189 {"ACTION", 6, AlAction
, ical_cline_from_token
, ical_free_cline
},
190 {"TRIGGER", 7, AlTrigger
, ical_cline_from_token
, ical_free_cline
},
191 {"DURATION", 8, AlDuration
, ical_cline_from_token
, ical_free_cline
},
192 {"REPEAT", 6, AlRepeat
, ical_cline_from_token
, ical_free_cline
},
193 {"DESCRIPTION", 11, AlDescription
, ical_cline_from_token
, ical_free_cline
},
194 {"SUMMARY", 7, AlSummary
, ical_cline_from_token
, ical_free_cline
},
195 {"ATTACH", 6, AlAttach
, ical_gencline_from_token
, ical_free_gencline
},
196 {"ATTENDEE", 8, AlAttendee
, ical_gencline_from_token
, ical_free_gencline
},
197 {NULL
, 0, AlUnknown
, 0, 0}
200 /* some useful macros for character analysis */
202 #define ical_wspace(X) \
203 ((X) == ' ' || (X) == '\t')
205 #define ical_name_allowed_char(X) \
206 (((X) >= 'A' && (X) <= 'Z') || \
207 ((X) >= 'a' && (X) <= 'z') || \
210 #define ical_control(X) \
211 (((X) >= 0x00 && (X) <= 0x08) || \
212 ((X) >= 0x0A && (X) <= 0x1F) || \
215 #define ical_safe_char(X) \
216 (ical_non_ascii_valid(X) \
219 || ((X) >= 0x23 && (X) <= 0x2B) \
220 || ((X) >= 0x2D && (X) <= 0x39) \
221 || ((X) >= 0x3C && (X) <= 0x7E))
223 #define ical_qsafe_char(X) \
224 (ical_non_ascii_valid((X)) \
227 || ((X) >= 0x23 && (X) <= 0x7E))
229 #define ical_value_char(X) \
230 (ical_non_ascii_valid(X) \
232 || ((X) >= 0x21 && (X) <= 0x7E))
234 /* Finally, here begins the code. */
237 ical_decode(char *text
, unsigned short encoding
)
240 unsigned long callen
;
241 if(encoding
== ENCQUOTEDPRINTABLE
){
242 t
= rfc822_qprint ((unsigned char *) text
,strlen(text
),&callen
);
244 strncpy(text
, t
, strlen(t
));
245 fs_give((void **) &t
);
248 return (unsigned char *) text
;
254 -1 - if an error occured
255 Args: a pointer to the text. If there is an error, the text is not modified.
258 ical_remove_escapes(char **textp
)
264 if(textp
== NULL
) return 0;
266 t
= cpystr(*textp
); /* work on a copy of the text */
267 /* the variable text below points to the beginning of the filtered text */
268 for (text
= s
= t
, escaped
= 0; rv
== 0 && *s
!= '\0'; s
++){
269 if(*s
== '\\' && escaped
== 0){
292 *t
= '\0'; /* tie off filtered text */
293 t
= text
; /* reset t to the beginning */
295 fs_give((void **) &t
);
297 strncpy(*textp
, t
, strlen(t
)); /* overwrite given text with filtered text */
298 (*textp
)[strlen(t
)] = '\0';
303 void ical_debug(char *fcn
, char *text
)
306 strncpy(piece
, text
, 49);
307 dprint((9, "%s: %s", fcn
, piece
));
311 *** FREE MEMORY FUNCTIONS
315 ical_free_param(ICAL_PARAMETER_S
**param
)
317 if(param
== NULL
|| *param
== NULL
)
320 if((*param
)->name
) fs_give((void **) &(*param
)->name
);
321 if((*param
)->value
) fs_give((void **) &(*param
)->value
);
322 if((*param
)->next
) ical_free_param(&(*param
)->next
);
323 fs_give((void **)param
);
327 ical_free_null(void **n
)
329 if(n
!= NULL
) *n
= NULL
;
333 ical_free_cline(void **icv
)
335 ICLINE_S
**ic
= (ICLINE_S
**) icv
;
337 if(ic
== NULL
|| *ic
== NULL
)
340 if((*ic
)->token
) fs_give((void **) &(*ic
)->token
);
341 if((*ic
)->param
) ical_free_param(&(*ic
)->param
);
342 if((*ic
)->value
) fs_give((void **) &(*ic
)->value
);
347 ical_free_gencline(void **giclpv
)
349 GEN_ICLINE_S
**giclp
= (GEN_ICLINE_S
**) giclpv
;
351 if(giclp
== NULL
|| *giclp
== NULL
) return;
353 if((*giclp
)->cline
) ical_free_cline((void **) &(*giclp
)->cline
);
354 if((*giclp
)->next
) ical_free_gencline((void **) &(*giclp
)->next
);
358 ical_free_vcalendar(void **vcalpv
)
360 VCALENDAR_S
**vcalp
= (VCALENDAR_S
**)vcalpv
;
362 if(vcalp
== NULL
|| *vcalp
== NULL
) return;
364 if((*vcalp
)->prodid
) ical_free_cline((void **) &(*vcalp
)->prodid
);
365 if((*vcalp
)->version
) ical_free_cline((void **) &(*vcalp
)->version
);
366 if((*vcalp
)->calscale
) ical_free_cline((void **) &(*vcalp
)->calscale
);
367 if((*vcalp
)->method
) ical_free_cline((void **) &(*vcalp
)->method
);
368 if((*vcalp
)->uk_prop
) ical_free_gencline((void **) &(*vcalp
)->uk_prop
);
371 for(i
= 0; i
< VUnknown
; i
++)
372 if((*vcalp
)->comp
[i
]) (ical_comp
[i
].give
)(&(*vcalp
)->comp
[i
]);
373 fs_give((*vcalp
)->comp
);
375 if((*vcalp
)->uk_comp
) ical_free_unknown_comp(&(*vcalp
)->uk_comp
);
380 ical_free_vevent(void **veventpv
)
382 VEVENT_S
**veventp
= (VEVENT_S
**) veventpv
;
384 if(veventp
== NULL
|| *veventp
== NULL
) return;
386 ical_free_prop((*veventp
)->prop
, event_prop
);
387 if((*veventp
)->uk_prop
) ical_free_gencline((void **) &(*veventp
)->uk_prop
);
388 if((*veventp
)->valarm
) ical_free_valarm((void **) &(*veventp
)->valarm
);
393 ical_free_rrule(void **rrulepv
)
395 RRULE_S
**rrulep
= (RRULE_S
**) rrulepv
;
397 if(rrulep
&& *rrulep
){
398 ical_free_prop((*rrulep
)->prop
, rrule_prop
);
399 ical_free_param(&(*rrulep
)->param
);
405 ical_free_weekday_list(void **wkdylv
)
407 BYWKDY_S
**wkdyl
= (BYWKDY_S
**) wkdylv
;
409 if(wkdyl
== NULL
) return;
412 ical_free_weekday_list((void **) &(*wkdyl
)->next
);
419 ical_free_vtodo(void **vtodopv
)
424 ical_free_vjournal(void **vjournalpv
)
429 ical_free_vfreebusy(void **vfbpv
)
434 ical_free_prop(void **propv
, ICAL_PROP_S
*aux_comp
)
438 if(propv
== NULL
) return;
440 for(i
= 0; aux_comp
[i
].prop
!= NULL
; i
++)
442 for(j
= 0; aux_comp
[j
].prop
!= NULL
&& aux_comp
[j
].pos
!= i
; j
++);
443 if(aux_comp
[j
].give
) (aux_comp
[j
].give
)(&propv
[i
]);
450 ical_free_vtimezone(void **vtzpv
)
452 VTIMEZONE_S
**vtzp
= (VTIMEZONE_S
**) vtzpv
;
455 if(vtzp
== NULL
|| *vtzp
== NULL
) return;
457 ical_free_prop((*vtzp
)->prop
, tz_comp
);
459 if((*vtzp
)->uk_prop
) ical_free_gencline((void **) &(*vtzp
)->uk_prop
);
460 if((*vtzp
)->standardc
) ical_free_timezone((void **) &(*vtzp
)->standardc
);
461 if((*vtzp
)->daylightc
) ical_free_timezone((void **) &(*vtzp
)->daylightc
);
466 ical_free_timezone(void **tzpv
)
468 ICAL_TZPROP_S
**tzp
= (ICAL_TZPROP_S
**) tzpv
;
470 if(tzp
== NULL
|| *tzp
== NULL
) return;
472 ical_free_prop((*tzp
)->prop
, tz_prop
);
473 if((*tzp
)->uk_prop
) ical_free_gencline((void **) &(*tzp
)->uk_prop
);
474 if((*tzp
)->next
) ical_free_timezone((void **) &(*tzp
)->next
);
478 void ical_free_valarm(void **valarmpv
)
483 ical_free_unknown_comp(ICAL_S
**icalp
)
486 if(icalp
== NULL
|| *icalp
== NULL
) return;
487 for(i
= 0; ical_comp
[i
].comp
&& strucmp((*icalp
)->comp
,ical_comp
[i
].comp
); i
++);
488 if(ical_comp
[i
].give
)
489 (ical_comp
[i
].give
)(&(*icalp
)->value
);
491 ical_free_gencline((void **) &(*icalp
)->value
);
492 fs_give((void **)&(*icalp
)->comp
);
493 ical_free_unknown_comp(&(*icalp
)->next
);
494 ical_free_unknown_comp(&(*icalp
)->branch
);
495 fs_give((void **)icalp
);
498 char *ical_unfold_line(char *line
)
505 for(i
= 0, j
= 0; line
[j
] != '\0';)
507 case '\r': if(line
[j
+1] == '\n' && ical_wspace(line
[j
+2])){
508 j
+= 3; /* get past white space */
511 default : line
[i
++] = line
[j
++];
518 ical_get_parameter(char **line
)
520 ICAL_PARAMETER_S
*param
= NULL
;
523 if(line
== NULL
|| *line
== NULL
)
526 for(s
= *line
; s
&& *s
&& ical_name_allowed_char(*s
) ; s
++);
532 param
= fs_get(sizeof(ICAL_PARAMETER_S
));
533 memset((void *)param
, 0, sizeof(ICAL_PARAMETER_S
));
535 param
->name
= cpystr(*line
);
537 *line
= s
+1; /* step over '=' */
538 quoted
= **line
== '"' ? 1 : 0;
540 for(s
= ++*line
; s
&& *s
&& ical_qsafe_char((unsigned char) *s
); s
++);
541 if(*s
!= '"'){ /* error, do not parse this line */
542 ical_free_param(¶m
);
543 *line
= strchr(s
, ':'); /* reset line to closest ':' */
548 for(s
= *line
; s
&& *s
&& (ical_safe_char((unsigned char) *s
)); s
++);
551 param
->value
= cpystr(*line
);
552 *s
= c
; /* restore character */
553 *line
= quoted
? s
+ 1 : s
;
557 param
->next
= ical_get_parameter(line
);
563 char *ical_get_value(char **line
)
567 if(line
== NULL
|| *line
== NULL
)
570 for (s
= *line
; *s
&& ical_value_char((unsigned char) *s
); s
++);
579 s
= strchr(*line
, '\r');
587 ical_parameter_cpy(ICAL_PARAMETER_S
*param
)
589 ICAL_PARAMETER_S
*rv
;
591 if(param
== NULL
) return NULL
;
593 rv
= fs_get(sizeof(ICAL_PARAMETER_S
));
594 memset((void *)rv
, 0, sizeof(ICAL_PARAMETER_S
));
596 if(param
->name
) rv
->name
= cpystr(param
->name
);
597 if(param
->value
) rv
->value
= cpystr(param
->value
);
598 if(param
->next
) rv
->next
= ical_parameter_cpy(param
->next
);
604 ical_cline_cpy(ICLINE_S
*icl
)
611 rv
= fs_get(sizeof(ICLINE_S
));
612 memset((void *)rv
, 0, sizeof(ICLINE_S
));
614 if(icl
->token
) rv
->token
= cpystr(icl
->token
);
615 if(icl
->param
) rv
->param
= ical_parameter_cpy(icl
->param
);
616 if(icl
->value
) rv
->value
= cpystr(icl
->value
);
621 /* Given a \r\n-ending line (called *text), isolate the ocurrence
622 * of the token in that line.
623 * Return the token, and modify the pointer to *text to point to the
624 * end of the token. Modify sep to contain the character following
626 * ical-line = token ':'/';' rest of the line\r\n
627 * on error return null, and set *text to the next line, if possible.
630 ical_isolate_token(char **text
, char *sep
)
634 for(t
= s
= *text
; *t
&& ical_name_allowed_char(*s
); s
++);
635 /* only followed by parameter or value */
636 if(*s
== ':' || *s
== ';'){
638 *s
= '\0'; /* isolate token at pointer s */
641 else{ /* bad data - bail out of here */
643 if(*s
== '\0' || (s
= strstr(s
, "\r\n")) == NULL
)
645 else /* move to next line */
653 ical_parse_text(char *text
)
656 VCALENDAR_S
*vcal
= NULL
;
658 ical_debug("ical_parse_text", text
);
661 text
= ical_unfold_line(text
);
662 for(s
= text
; s
&& *s
!= '\0'; s
++){
663 if(*s
!= 'B' && *s
!= 'b')
665 if(!struncmp(s
+1, "EGIN:VCALENDAR\r\n", 16)){
666 s
+= 17; /* 17 = strlen("BEGIN:VCALENDAR\r\n") */
667 vcal
= (VCALENDAR_S
*) ical_parse_vcalendar(&s
);
675 ical_parse_time(void *ic_datep
, char **text
, char *token
)
680 icl
= ical_parse_line(text
, token
);
681 ical_parse_date(icl
->value
, &ic_date
);
682 ical_free_cline((void **) &icl
);
683 ic_datep
= (void *) &ic_date
;
689 ical_parse_interval(void *longvp
, char *value
)
695 longvp
= (void *) &longv
;
702 ical_parse_offset(void *offsetv
, char **text
, char *token
)
708 icl
= ical_parse_line(text
, token
);
710 if(*icl
->value
== '+' || *icl
->value
== '-')
711 value
= icl
->value
+ 1;
715 h
= ical_get_number_value(value
, 0, 2);
716 m
= ical_get_number_value(value
, 2, 4);
718 offset
= 60*(60*h
+ m
);
719 if(*icl
->value
== '-')
722 ical_free_cline((void **) &icl
);
723 offsetv
= (void *) &offset
;
728 /* This function processes the information in *text, and returns
729 * a pointer to the information in iclp, but only if iclp is NULL
730 * otherwise, it simply returns the current value and advances the
732 * Call this function as follows
733 * rv = (cast here *) ical_cline_from_token((void *)rv, &text, token);
736 ical_cline_from_token(void *iclp
, char **text
, char *token
)
740 icl
= ical_parse_line(text
, token
);
743 ical_free_cline((void **)&icl
);
751 ical_gencline_from_token(void *giclv
, char **text
, char *token
)
753 GEN_ICLINE_S
*gicl
= NULL
;
755 if(!struncmp(*text
, token
, strlen(token
))){
756 gicl
= fs_get(sizeof(GEN_ICLINE_S
));
757 memset((void *) gicl
, 0, sizeof(GEN_ICLINE_S
));
758 gicl
->cline
= ical_parse_line(text
, token
);
759 // gicl->line = (ICLINE_S *) ical_cline_from_token((void *) gicl->cline, text, token);
760 gicl
->next
= (GEN_ICLINE_S
*) ical_gencline_from_token((void *) gicl
->next
, text
, token
);
764 ical_free_gencline((void **) &gicl
);
766 giclv
= (void *) gicl
;
772 *** PARSE COMPONENT FUNCTIONS
776 ical_parse_vcalendar(char **text
)
783 dprint((9, "ical_parse_vcalendar:\n"));
784 ical_debug("ical_parse_vcalendar", *text
);
786 vcal
= fs_get(sizeof(VCALENDAR_S
));
787 memset((void *) vcal
, 0, sizeof(VCALENDAR_S
));
789 /* s must always point the the beginning of a line */
790 for(s
= *text
; s
&& *s
!= '\0';){
792 s
= ical_isolate_token(&t
, &c
);
799 *t
= c
; /* restore character */
800 if(s
){ /* figure out the token */
801 int ukn
= 0; /* unknown token */
805 case 'b': if(!struncmp(s
+1, "EGIN", 4)){
806 s
+= 6; /* 6 = strlen("BEGIN:") */
807 for(i
= 0; ical_comp
[i
].comp
808 && (struncmp(s
, ical_comp
[i
].comp
, ical_comp
[i
].len
)
809 || struncmp(s
+ ical_comp
[i
].len
, "\r\n", 2)); i
++);
811 if(ical_comp
[i
].parse
){
812 s
+= ical_comp
[i
].len
+ 2;
813 v
= (ical_comp
[i
].parse
)(&s
);
814 if(vcal
->comp
== NULL
){
815 vcal
->comp
= fs_get(VUnknown
*sizeof(void *));
816 memset((void *) vcal
->comp
, 0, VUnknown
*sizeof(void *));
819 if(vcal
->comp
[ical_comp
[i
].pos
] == NULL
)
820 vcal
->comp
[ical_comp
[i
].pos
] = v
;
822 (ical_comp
[i
].give
)(&v
);
824 v
= (void *) ical_parse_unknown_comp(&s
, 0);
825 if(vcal
->uk_comp
== NULL
)
826 vcal
->uk_comp
= (ICAL_S
*) v
;
829 for(ic
= vcal
->uk_comp
; ic
&& ic
->branch
; ic
= ic
->branch
);
830 ic
->branch
= (ICAL_S
*) v
;
837 case 'c': if(!struncmp(s
+1, "ALSCALE", 7)){
838 v
= (void *) vcal
->calscale
;
839 v
= ical_cline_from_token(v
, &s
, "CALSCALE");
840 vcal
->calscale
= (ICLINE_S
*) v
;
846 case 'e': if(!struncmp(s
+1, "ND", 2)){
848 s
+= 4; /* 4 = strlen("END:") */
849 if(!struncmp(s
, "VCALENDAR\r\n", 11)){
850 *text
= s
+ 11; /* 11 = strlen("VCALENDAR\r\n") */
851 return (void *) vcal
;
853 // else ukn++; FIX THIS, this is not quite right
858 case 'm': if(!struncmp(s
+1, "ETHOD", 5)){
859 v
= (void *) vcal
->method
;
860 v
= ical_cline_from_token(v
, &s
, "METHOD");
861 vcal
->method
= (ICLINE_S
*) v
;
867 case 'p': if(!struncmp(s
+1, "RODID", 5)){
868 v
= (void *) vcal
->prodid
;
869 v
= ical_cline_from_token(v
, &s
, "PRODID");
870 vcal
->prodid
= (ICLINE_S
*) v
;
876 case 'v': if(!struncmp(s
+1, "ERSION", 6)){
877 v
= (void *) vcal
->version
;
878 v
= ical_cline_from_token(v
, &s
, "VERSION");
879 vcal
->version
= (ICLINE_S
*) v
;
885 } /* end of switch(*s) */
887 if(ical_buf_len
< t
- s
){
888 fs_resize((void **)&ical_buf
, t
-s
+1);
894 if(vcal
->uk_prop
== NULL
){
895 vcal
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
896 memset((void *)vcal
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
897 vcal
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
901 for (gcl
= vcal
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
902 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
903 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
904 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
912 /* ok, we have parsed the vcalendar, now parse some special properties */
913 /* start by parsing dates */
914 ical_set_date_vevent(vcal
->comp
[VEvent
], vcal
->comp
[VTimeZone
]);
915 return (void *) vcal
;
919 ical_parse_vevent(char **text
)
925 ical_debug("ical_parse_vevent", *text
);
926 vevent
= fs_get(sizeof(VEVENT_S
));
927 memset((void *)vevent
, 0, sizeof(VEVENT_S
));
929 /* s must always point the the beginning of a line */
930 for(s
= *text
; s
&& *s
!= '\0';){
932 s
= ical_isolate_token(&t
, &c
);
938 *t
= c
; /* restore separator */
940 if(s
){ /* figure out the token */
941 int ukn
= 0; /* unknown token */
942 if(!struncmp(s
, "BEGIN", 5)){
943 s
+= 6; /* 6 = strlen("BEGIN:") */
944 if(!struncmp(s
, "VALARM\r\n", 8)){
945 s
+= 8; /* 8 = strlen("VALARM\r\n"); */
946 if(vevent
->valarm
== NULL
)
947 vevent
->valarm
= ical_parse_valarm(&s
);
950 for(valrm
= vevent
->valarm
; valrm
&& valrm
->next
;
951 valrm
= valrm
->next
);
952 valrm
->next
= ical_parse_valarm(&s
);
955 ICAL_S
*uk_comp
= ical_parse_unknown_comp(&s
, 0);
956 ical_free_unknown_comp(&uk_comp
);
958 } else if(!struncmp(s
, "END", t
-s
-1)){
959 s
+= 4; /* 4 = strlen("END:") */
960 if(!struncmp(s
, "VEVENT\r\n",8)){
961 *text
= s
+ 8; /* 8 = strlen("VCALENDAR\r\n") */
962 return (void *) vevent
;
964 } else{ Event_prop i
;
965 for(i
= 0; i
< EvUnknown
; i
++)
966 if(!struncmp(s
, event_prop
[i
].prop
, t
-s
))
968 if(event_prop
[i
].parse
){
970 if(vevent
->prop
== NULL
){
971 vevent
->prop
= fs_get(EvUnknown
*sizeof(void *));
972 memset((void *)vevent
->prop
, 0, EvUnknown
*sizeof(void *));
974 v
= vevent
->prop
[event_prop
[i
].pos
];
975 v
= (event_prop
[i
].parse
)(v
, &s
, event_prop
[i
].prop
);
976 vevent
->prop
[event_prop
[i
].pos
] = v
;
983 if(ical_buf_len
< t
- s
){
984 fs_resize((void **)&ical_buf
, t
-s
+1);
990 if(vevent
->uk_prop
== NULL
){
991 vevent
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
992 memset((void *)vevent
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
993 vevent
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
997 for (gcl
= vevent
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
998 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
999 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1000 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1003 } /* end of if(s) */
1007 return (void *) vevent
;
1011 ical_parse_vtimezone(char **text
)
1018 ical_debug("ical_parse_vtimezone", *text
);
1019 vtz
= fs_get(sizeof(VTIMEZONE_S
));
1020 memset((void *)vtz
, 0, sizeof(VTIMEZONE_S
));
1022 /* s must always point the the beginning of a line */
1023 for(s
= *text
; s
&& *s
!= '\0';){
1025 s
= ical_isolate_token(&t
, &c
);
1031 *t
= c
; /* restore separator */
1033 if(s
){ /* figure out the token */
1034 int ukn
= 0; /* unknown token */
1035 if(!struncmp(s
, "BEGIN", 5)){
1036 s
+= 6; /* 6 = strlen("BEGIN:") */
1037 if(!struncmp(s
, "STANDARD\r\n", 10)){
1038 s
+= 10; /* 10 = strlen("STANDARD\r\n"); */
1039 v
= ical_parse_timezone(&s
);
1040 if(vtz
->standardc
== NULL
)
1041 vtz
->standardc
= (ICAL_TZPROP_S
*) v
;
1044 for(dl
= vtz
->standardc
; dl
&& dl
->next
; dl
= dl
->next
);
1045 dl
->next
= (ICAL_TZPROP_S
*) v
;
1047 } else if(!struncmp(s
, "DAYLIGHT\r\n", 10)){
1048 s
+= 10; /* 10 = strlen("DAYLIGHT\r\n"); */
1049 v
= ical_parse_timezone(&s
);
1050 if(vtz
->daylightc
== NULL
)
1051 vtz
->daylightc
= (ICAL_TZPROP_S
*) v
;
1054 for(dl
= vtz
->daylightc
; dl
&& dl
->next
; dl
= dl
->next
);
1055 dl
->next
= (ICAL_TZPROP_S
*) v
;
1058 ICAL_S
*uk_comp
= ical_parse_unknown_comp(&s
, 0);
1059 ical_free_unknown_comp(&uk_comp
);
1061 } else if(!struncmp(s
, "END", t
-s
-1)){
1062 s
+= 4; /* 4 = strlen("END:") */
1063 if(!struncmp(s
, "VTIMEZONE\r\n",11)){
1064 *text
= s
+ 11; /* 11 = strlen("VTIMEZONE\r\n") */
1065 return (void *) vtz
;
1068 for(i
= 0; i
< TZCUnknown
; i
++)
1069 if(!struncmp(s
, tz_comp
[i
].prop
, t
-s
))
1071 if(tz_comp
[i
].parse
){
1073 if(vtz
->prop
== NULL
){
1074 vtz
->prop
= fs_get(TZCUnknown
*sizeof(void *));
1075 memset((void *)vtz
->prop
, 0, TZCUnknown
*sizeof(void *));
1077 v
= vtz
->prop
[tz_comp
[i
].pos
];
1078 v
= (tz_comp
[i
].parse
)(v
, &s
, tz_comp
[i
].prop
);
1079 vtz
->prop
[tz_comp
[i
].pos
] = v
;
1086 if(ical_buf_len
< t
- s
){
1087 fs_resize((void **)&ical_buf
, t
-s
+1);
1091 strcpy(ical_buf
, s
);
1093 if(vtz
->uk_prop
== NULL
){
1094 vtz
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
1095 memset((void *)vtz
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
1096 vtz
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
1100 for (gcl
= vtz
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
1101 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1102 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1103 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1106 } /* end of if(s) */
1110 return (void *) vtz
;
1114 ical_parse_timezone(char **text
)
1118 ICAL_TZPROP_S
*tzprop
;
1120 ical_debug("ical_parse_timezone", *text
);
1121 tzprop
= fs_get(sizeof(ICAL_TZPROP_S
));
1122 memset((void *)tzprop
, 0, sizeof(ICAL_TZPROP_S
));
1124 /* s must always point the the beginning of a line */
1125 for(s
= *text
; s
&& *s
!= '\0';){
1127 s
= ical_isolate_token(&t
, &c
);
1133 *t
= c
; /* restore separator */
1135 if(s
){ /* figure out the token */
1136 int ukn
= 0; /* unknown token */
1137 if(!struncmp(s
, "BEGIN", 5)){
1138 s
+= 6; /* 6 = strlen("BEGIN:") */
1139 ICAL_S
*uk_comp
= ical_parse_unknown_comp(&s
, 0);
1140 ical_free_unknown_comp(&uk_comp
);
1141 } else if(!struncmp(s
, "END", t
-s
-1)){
1142 s
+= 4; /* 4 = strlen("END:") */
1143 if(!struncmp(s
, "STANDARD\r\n", 10)
1144 || !struncmp(s
, "DAYLIGHT\r\n", 10)){
1145 *text
= s
+ 10; /* 10 = strlen("STANDARD\r\n") */
1146 return (void *) tzprop
;
1149 for(i
= 0; i
< TZPUnknown
; i
++)
1150 if(!struncmp(s
, tz_prop
[i
].prop
, t
-s
))
1152 if(tz_prop
[i
].parse
){
1154 if(tzprop
->prop
== NULL
){
1155 tzprop
->prop
= fs_get(TZPUnknown
*sizeof(void *));
1156 memset((void *)tzprop
->prop
, 0, TZPUnknown
*sizeof(void *));
1158 v
= tzprop
->prop
[tz_prop
[i
].pos
];
1159 v
= (tz_prop
[i
].parse
)(v
, &s
, tz_prop
[i
].prop
);
1160 tzprop
->prop
[tz_prop
[i
].pos
] = v
;
1167 if(ical_buf_len
< t
- s
){
1168 fs_resize((void **)&ical_buf
, t
-s
+1);
1172 strcpy(ical_buf
, s
);
1174 if(tzprop
->uk_prop
== NULL
){
1175 tzprop
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
1176 memset((void *)tzprop
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
1177 tzprop
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
1181 for (gcl
= tzprop
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
1182 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1183 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1184 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1187 } /* end of if(s) */
1191 return (void *) tzprop
;
1195 ical_parse_valarm(char **text
)
1201 ical_debug("ical_parse_valarm", *text
);
1202 valarm
= fs_get(sizeof(VALARM_S
));
1203 memset((void *)valarm
, 0, sizeof(VALARM_S
));
1205 /* s must always point the the beginning of a line */
1206 for(s
= *text
; s
&& *s
!= '\0';){
1208 s
= ical_isolate_token(&t
, &c
);
1214 *t
= c
; /* restore separator */
1216 if(s
){ /* figure out the token */
1217 int ukn
= 0; /* unknown token */
1218 if(!struncmp(s
, "BEGIN", 5)){
1219 s
+= 6; /* 6 = strlen("BEGIN:") */
1220 ICAL_S
*uk_comp
= ical_parse_unknown_comp(&s
, 0);
1221 ical_free_unknown_comp(&uk_comp
);
1222 } else if(!struncmp(s
, "END", t
-s
-1)){
1223 s
+= 4; /* 4 = strlen("END:") */
1224 if(!struncmp(s
, "ALARM\r\n", 7)){
1225 *text
= s
+ 7; /* 7 = strlen("ALARM\r\n") */
1226 return (void *) valarm
;
1228 } else{ Alarm_prop i
;
1229 for(i
= 0; i
< AlUnknown
; i
++)
1230 if(!struncmp(s
, alarm_prop
[i
].prop
, t
-s
))
1232 if(alarm_prop
[i
].parse
){
1234 if(valarm
->prop
== NULL
){
1235 valarm
->prop
= fs_get(AlUnknown
*sizeof(void *));
1236 memset((void *)valarm
->prop
, 0, AlUnknown
*sizeof(void *));
1238 v
= valarm
->prop
[alarm_prop
[i
].pos
];
1239 v
= (alarm_prop
[i
].parse
)(v
, &s
, alarm_prop
[i
].prop
);
1240 valarm
->prop
[alarm_prop
[i
].pos
] = v
;
1247 if(ical_buf_len
< t
- s
){
1248 fs_resize((void **)&ical_buf
, t
-s
+1);
1252 strcpy(ical_buf
, s
);
1254 if(valarm
->uk_prop
== NULL
){
1255 valarm
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
1256 memset((void *)valarm
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
1257 valarm
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
1261 for (gcl
= valarm
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
1262 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1263 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1264 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1267 } /* end of if(s) */
1271 return (void *) valarm
;
1275 ical_parse_vtodo(char **text
)
1281 ical_parse_vjournal(char **text
)
1287 ical_parse_vfreebusy(char **text
)
1293 ical_parse_generic_comp(char **text
, int level
)
1298 GEN_ICLINE_S
*gcl
= NULL
;
1301 ical_debug("ical_parse_generic_comp", *text
);
1302 ical
= fs_get(sizeof(ICAL_S
));
1303 memset((void *)ical
, 0, sizeof(ICAL_S
));
1305 ical
->comp
= ical_get_value(text
);
1306 token
= fs_get(strlen(ical
->comp
) + 2 + 1);
1307 sprintf(token
, "%s\r\n", ical
->comp
); /* this is allocated memory */
1309 /* s must always point the the beginning of a line */
1310 for(s
= *text
; s
&& *s
!= '\0';){
1312 s
= ical_isolate_token(&t
, &c
);
1319 *t
= c
; /* restore character */
1320 if(s
){ /* figure out the token */
1321 int ukn
= 0; /* unknown token */
1324 case 'b': if(!struncmp(s
+1, "EGIN", 4)){
1325 s
+= 6; /* 6 = strlen("BEGIN:") */
1326 if(ical
->next
== NULL
)
1327 ical
->next
= ical_parse_unknown_comp(&s
, level
+1);
1332 for(i
= 0, b
= ical
; i
<= level
&& b
&& b
->next
; b
= b
->next
, i
++);
1333 if(b
->branch
== NULL
)
1334 b
->branch
= ical_parse_unknown_comp(&s
, level
+1);
1336 for(; b
&& b
->branch
; b
= b
->branch
);
1337 b
->branch
= ical_parse_unknown_comp(&s
, level
+1);
1344 case 'e': if(!struncmp(s
+1, "ND", 2)){
1346 s
+= 4; /* 4 = strlen("END:") */
1347 if(!struncmp(s
, token
, strlen(token
))){
1348 *text
= s
+ strlen(token
);
1349 ical
->value
= (void *) gcl
;
1357 } /* end of switch(*s) */
1359 if(ical_buf_len
< t
- s
){
1360 fs_resize((void **)&ical_buf
, t
-s
+1);
1364 strcpy(ical_buf
, s
);
1367 gcl
= fs_get(sizeof(GEN_ICLINE_S
));
1368 memset((void *)gcl
, 0, sizeof(GEN_ICLINE_S
));
1369 gcl
->cline
= ical_parse_line(&s
, ical_buf
);
1372 GEN_ICLINE_S
*gencl
;
1373 for (gencl
= gcl
; gencl
&& gencl
->next
; gencl
= gencl
->next
);
1374 gencl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1375 memset((void *)gencl
->next
, 0, sizeof(GEN_ICLINE_S
));
1376 gencl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1379 } /* end of if(s) */
1382 ical
->value
= (void *) gcl
;
1388 ical_parse_unknown_comp(char **text
, int level
)
1393 ical_debug("ical_parse_unknown_comp", *text
);
1394 for(i
= 0; ical_comp
[i
].comp
1395 && (struncmp(*text
, ical_comp
[i
].comp
, ical_comp
[i
].len
)
1396 || struncmp(*text
+ ical_comp
[i
].len
, "\r\n", 2)); i
++);
1398 if(ical_comp
[i
].parse
){
1399 *text
+= ical_comp
[i
].len
+ 2;
1400 ical
= fs_get(sizeof(ICAL_S
));
1401 memset((void *)ical
, 0, sizeof(ICAL_S
));
1402 ical
->comp
= cpystr(ical_comp
[i
].comp
);
1403 ical
->value
= (ical_comp
[i
].parse
)(text
);
1405 ical
= ical_parse_generic_comp(text
, level
);
1411 ical_parse_line(char **text
, char *name
)
1416 ic
= fs_get(sizeof(ICLINE_S
));
1417 memset((void *)ic
, 0, sizeof(ICLINE_S
));
1419 ic
->token
= cpystr(name
);
1423 ic
->param
= ical_get_parameter(&s
);
1427 ic
->value
= ical_get_value(&s
);
1435 *** PARSE PROPERTY FUNCTIONS
1439 ical_parse_freq(void *fvalp
, char *text
)
1445 if(text
== NULL
) return fvalp
;
1447 if(!strucmp(text
, "SECONDLY")) fval
= FSecondly
;
1448 else if(!strucmp(text
, "MINUTELY")) fval
= FMinutely
;
1449 else if(!strucmp(text
, "HOURLY")) fval
= FHourly
;
1450 else if(!strucmp(text
, "DAILY")) fval
= FDaily
;
1451 else if(!strucmp(text
, "WEEKLY")) fval
= FWeekly
;
1452 else if(!strucmp(text
, "MONTHLY")) fval
= FMonthly
;
1453 else if(!strucmp(text
, "YEARLY")) fval
= FYearly
;
1455 fvalp
= (void *) &fval
;
1461 ical_parse_until(void *Tmp
, char *text
)
1466 ical_parse_date(text
, &Tm
);
1474 ical_parse_count(void *countp
, char *text
)
1480 countp
= (void *) &count
;
1487 ical_parse_weekday_list(void *bywkdyp
, char *wklist
)
1489 BYWKDY_S
*bywkdy
, *w
;
1495 bywkdyp
= (void *) bywkdy
;
1497 if(wklist
== NULL
) return bywkdyp
;
1499 for(t
= s
= wklist
; done
== 0; s
++){
1500 if(*s
!= ',' && *s
!= '\0')
1505 else /* c == '\0' */
1509 for(w
= bywkdy
; w
&& w
->next
; w
= w
->next
);
1510 w
= fs_get(sizeof(BYWKDY_S
));
1511 memset((void *)w
, 0, sizeof(BYWKDY_S
));
1512 if(!strucmp(t
+len
-2, "SU")) w
->wd
= Sunday
;
1513 else if(!strucmp(t
+len
-2, "MO")) w
->wd
= Monday
;
1514 else if(!strucmp(t
+len
-2, "TU")) w
->wd
= Tuesday
;
1515 else if(!strucmp(t
+len
-2, "WE")) w
->wd
= Wednesday
;
1516 else if(!strucmp(t
+len
-2, "TH")) w
->wd
= Thursday
;
1517 else if(!strucmp(t
+len
-2, "FR")) w
->wd
= Friday
;
1518 else if(!strucmp(t
+len
-2, "SA")) w
->wd
= Saturday
;
1519 // t[len - 2] = '\0';
1521 w
->value
= strtoul(t
, &t
, 10);
1531 ical_free_weekday_list((void **)&bywkdy
);
1533 bywkdyp
= (void *) bywkdy
;
1539 ical_parse_number_list(void *bynop
, char *nolist
)
1546 bynop
= (void *) byno
;
1548 if(nolist
== NULL
) return bynop
;
1550 for(t
= s
= nolist
; done
== 0; s
++){
1551 if(*s
!= ',' && *s
!= '\0')
1556 else /* c == '\0' */
1559 for(n
= byno
; n
&& n
->next
; n
= n
->next
);
1560 n
= fs_get(sizeof(BYWKDY_S
));
1561 memset((void *)n
, 0, sizeof(BYWKDY_S
));
1562 n
->value
= strtoul(t
, &t
, 10);
1571 ical_free_weekday_list((void **)&byno
);
1573 bynop
= (void *) byno
;
1579 ical_parse_rrule(void *rrulep
, char **text
, char *token
)
1584 ICAL_PARAMETER_S
*param
, *p
;
1587 if(text
== NULL
|| *text
== NULL
|| struncmp(*text
, "RRULE", 5))
1590 rrule
= fs_get(sizeof(RRULE_S
));
1591 memset((void *) rrule
, 0, sizeof(RRULE_S
));
1593 /* recurring rules are special. First, we parse the icline that contains it */
1594 icl
= ical_parse_line(text
, token
);
1596 /* now we copy the parameters that it contains */
1597 rrule
->param
= ical_parameter_cpy(icl
->param
);
1599 /* then we parse icl->value as if it was a parameter */
1601 param
= ical_get_parameter(&s
);
1603 /* now we check which values were given, and fill the prop array */
1604 rrule
->prop
= fs_get(RRUnknown
*sizeof(void *));
1605 memset((void *) rrule
->prop
, 0, RRUnknown
*sizeof(void *));
1607 for(p
= param
; p
!= NULL
; p
= p
->next
){
1608 for(i
= 0; rrule_prop
[i
].prop
!= NULL
&& strucmp(p
->name
, rrule_prop
[i
].prop
); i
++);
1609 if(rrule_prop
[i
].parse
){
1610 void *v
= rrule
->prop
[rrule_prop
[i
].pos
];
1611 v
= (rrule_prop
[i
].parse
)(v
, p
->value
);
1612 rrule
->prop
[rrule_prop
[i
].pos
] = v
;
1615 rrule
->prop
[RRUnknown
] = NULL
;
1617 ical_free_param(¶m
);
1618 ical_free_cline((void **)&icl
);
1621 ical_free_rrule((void **)&rrule
);
1623 rrulep
= (void *) rrule
;
1628 /*** UTF-8 for ICAL ***/
1631 ical_non_ascii_valid(unsigned char c
)
1633 static unsigned char icu
[6];
1634 static int utf8_len
= 0;
1635 static int utf8_type
= 0;
1639 utf8_type
= (c
>= 0xF0 && c
<= 0xF4)
1640 ? 4 : (c
>= 0xE0 && c
<= 0xEF)
1641 ? 3 : (c
>= 0xC2 && c
<= 0xDF)
1647 icu
[utf8_len
++] = c
; /* count it */
1652 else if(utf8_len
== 2){
1653 rv
= (icu
[0] >= 0xC2 && icu
[0] <= 0xDF)
1654 && (icu
[1] >= 0x80 && icu
[1] <= 0xBF) ? UTF8_COMPLETE
: 0;
1657 } else if (utf8_type
== 3){
1662 rv
= (icu
[1] >= 0xA0 && icu
[1] <= 0xBF)
1663 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1664 else if(icu
[0] >= 0xE1 && icu
[0] <= 0xEC)
1665 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0xBF)
1666 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1667 else if(icu
[0] == 0xED)
1668 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0x9F)
1669 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1670 else if(icu
[0] >= 0xE1 && icu
[0] <= 0xEC)
1671 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0xBF)
1672 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1675 } else if (utf8_type
== 4){
1680 rv
= (icu
[1] >= 0x90 && icu
[1] <= 0xBF)
1681 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF)
1682 && (icu
[3] >= 0x80 && icu
[3] <= 0xBF) ? UTF8_COMPLETE
: 0;
1683 else if(icu
[0] >= 0xF1 && icu
[0] <= 0xF3)
1684 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0xBF)
1685 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF)
1686 && (icu
[3] >= 0x80 && icu
[3] <= 0xBF) ? UTF8_COMPLETE
: 0;
1687 else if(icu
[0] == 0xF4)
1688 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0x8F)
1689 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF)
1690 && (icu
[3] >= 0x80 && icu
[3] <= 0xBF) ? UTF8_COMPLETE
: 0;
1698 ical_get_number_value(char *value
, int beg_pos
, int end_pos
)
1704 value
[end_pos
] = '\0';
1705 rv
= strtoul(value
+ beg_pos
, &err
, 10);
1706 if(err
!= NULL
&& *err
!= '\0') return -1;
1712 ical_free_duration(ICAL_DURATION_S
**ic_d
)
1714 if(ic_d
== NULL
|| *ic_d
== NULL
)
1717 if((*ic_d
)->next
) ical_free_duration(&(*ic_d
)->next
);
1718 fs_give((void **)ic_d
);
1721 /* returns 0 if no error, -1 if some error */
1723 ical_parse_duration(char *value
, ICAL_DURATION_S
*ic_d
)
1727 if(value
== NULL
|| ic_d
== NULL
) return -1;
1729 memset((void *)ic_d
, 0, sizeof(ICAL_DURATION_S
));
1731 if(value
[i
= 0] == '-'){
1734 } else if(value
[i
] == '+')
1737 if(value
[i
++] == 'P'){
1738 for(j
= i
; value
[j
] != '\0' && value
[j
] != ','; j
++){
1739 if(!isdigit(value
[j
]))
1741 case 'W': ic_d
->weeks
= ical_get_number_value(value
, i
, j
-1);
1744 case 'D': ic_d
->days
= ical_get_number_value(value
, i
, j
-1);
1747 case 'H': ic_d
->hours
= ical_get_number_value(value
, i
, j
-1);
1750 case 'M': ic_d
->minutes
= ical_get_number_value(value
, i
, j
-1);
1753 case 'S': ic_d
->seconds
= ical_get_number_value(value
, i
, j
-1);
1756 case 'T': i
= j
+ 1;
1766 if(value
[j
++] == ','){
1767 ICAL_DURATION_S next
;
1768 rv
= ical_parse_duration(value
+j
, &next
);
1775 /* return -1 if any error,
1776 0 if value has the DATE-TIME form
1777 1 if value has the DATE form only
1778 2 if value has the DATE-TIME form and is in GMT.
1781 ical_parse_date(char *value
, struct tm
*t
)
1787 if(t
== NULL
) return rv
;
1788 memset((void *)&Tm
, 0, sizeof(struct tm
));
1790 if(value
== NULL
) return rv
;
1792 rv
= 0; /* assume DATE-TIME format */
1793 /* a simple check for the format of the string */
1794 for(i
= 0; isdigit(value
[i
]); i
++);
1795 if (i
== 8 && value
[i
] == '\0')
1798 if (i
!= 8 || value
[i
++] != 'T') return -1;
1800 for(; isdigit(value
[i
]); i
++);
1801 if(i
!= 15 || (value
[i
] != '\0' && (value
[i
] != 'Z' || value
[i
+1] != '\0')))
1803 if(i
== 15 && value
[i
] == 'Z')
1807 Tm
.tm_year
= ical_get_number_value(value
, 0, 4) - 1900;
1808 Tm
.tm_mon
= ical_get_number_value(value
, 4, 6) - 1;
1809 Tm
.tm_mday
= ical_get_number_value(value
, 6, 8);
1811 Tm
.tm_hour
= ical_get_number_value(value
, 9, 11);
1812 Tm
.tm_min
= ical_get_number_value(value
, 11, 13);
1813 Tm
.tm_sec
= ical_get_number_value(value
, 13, 15);
1814 Tm
.tm_isdst
= ICAL_DST_UNKNOWN
;
1820 return (t
->tm_mon
> 11 || t
->tm_mon
< 0
1821 || t
->tm_mday
> 31 || t
->tm_mday
< 0
1822 || t
->tm_hour
> 23 || t
->tm_hour
< 0
1823 || t
->tm_min
> 59 || t
->tm_min
< 0
1824 || t
->tm_sec
> 60 || t
->tm_sec
< 0)
1829 ical_set_date(ICLINE_S
*icl
, VTIMEZONE_S
*vtz
)
1831 int date_form
; /* date forms from section 3.3.4 in RFC 5545 */
1832 ICAL_PARAMETER_S
*param
;
1837 if(icl
== NULL
) return;
1839 for(param
= icl
->param
; param
!= NULL
; param
= param
->next
)
1840 if(!strucmp(param
->name
, "TZID"))
1844 date_form
= 3; /* local time with timezone */
1845 else if(icl
->value
[strlen(icl
->value
)-1] == 'Z')
1846 date_form
= 2; /* utc time */
1847 else date_form
= 1; /* local time */
1849 ical_parse_date(icl
->value
, &ic_date
);
1850 ic_date
.tm_wday
= ical_day_of_week(ic_date
); /* find out day of the week */
1854 case 2: ical_adjust_date(&ic_date
, vtz
);
1857 default: alpine_panic ("Impossible date_form");
1862 ical_std_or_daylight(struct tm
*date
, VTIMEZONE_S
*vtz
)
1864 struct tm standard
, daylight
;
1865 ICLINE_S
*tzid
= (ICLINE_S
*) vtz
->prop
[TZCid
];
1867 standard
= daylight
;
1874 /* adjusts time to given time zone */
1876 ical_adjust_date(struct tm
*date
, VTIMEZONE_S
*vtz
)
1878 char *tzname
= NULL
;
1880 ICAL_TZPROP_S
*cur_std_day
;
1886 if((icl
= (ICLINE_S
*)vtz
->prop
[TZCid
]) != NULL
)
1887 tzname
= cpystr(icl
->value
);
1890 cur_std_day
= ical_std_or_daylight(date
, vtz
);
1894 ical_set_date_vevent(void *veventv
, void *vtzv
)
1896 VEVENT_S
*vevent
= (VEVENT_S
*) veventv
;
1897 VTIMEZONE_S
*vtz
= (VTIMEZONE_S
*) vtzv
;
1900 ical_set_date(vevent
->prop
[EvDtstamp
], vtz
);
1901 ical_set_date(vevent
->prop
[EvDtstart
], vtz
);
1902 ical_set_date(vevent
->prop
[EvDtend
], vtz
);
1906 #define LEAP_YEAR(X) ((((X) % 4 == 0) \
1907 && (((X) % 100 != 0) || ((X) % 400 == 0))) \
1910 #define CAL_OFFSET(X) (((X) == 1752) ? 5 : (LEAP_YEAR((X)) ? 2 : 1))
1912 /* given a year, after day_zero, return the day
1913 * of the week of the first of january of that year. On error,
1914 * return a negative number.
1915 * Assumption: day_zero is the date of january 1, of some year.
1918 ical_january_first(int year
)
1920 int i
, january_first
;
1922 if(year
< day_zero
.tm_year
) return -1; /* not supported */
1925 january_first
= day_zero
.tm_wday
;
1926 for(i
= 1900 + day_zero
.tm_year
+ 1; i
<= year
; i
++)
1927 january_first
+= CAL_OFFSET(i
-1);
1929 return january_first
% 7;
1932 /* given a month, week day, and year, return all days of the month
1933 * that have that day as the week day. For example, return all
1934 * sundays in november 2012.
1937 ical_day_from_week(int month
, Weekday day
, int year
)
1944 fday
= ical_first_of_month(month
, year
);
1945 year
+= 1900; /* restore year */
1946 if(year
== 1752 && month
== 8){
1949 for(nday
= 1, wday
= (Weekday
) fday
; wday
!= day
; wday
= (wday
+1) % 7, nday
++)
1951 rv
= fs_get(6*sizeof(int));
1952 memset((void *) rv
, 0, 6*sizeof(int));
1953 for(i
= 0; nday
<= month_len
[month
]; i
++){
1957 if(LEAP_YEAR(year
) && month
== 1 && nday
== 29)
1965 /* given a month and a year, return the weekday of the first of the
1966 * month in that year.
1967 * return value: on error -1, otherwise the day of the week.
1970 ical_first_of_month(int month
, int year
)
1974 if((d
= ical_january_first(year
)) < 0)
1978 for(i
= 0; i
< month
; i
++)
1981 if(LEAP_YEAR(year
) && month
>= 2)
1984 if(year
== 1752 && month
>= 9)
1990 /* given a day, month and year, return the weekday of that day
1991 * return value: on error -1, otherwise the day of the week.
1993 int ical_day_of_week(struct tm date
)
1997 if((d
= ical_first_of_month(date
.tm_mon
, date
.tm_year
)) < 0)
2000 d
+= date
.tm_mday
- 1;
2002 if(date
.tm_year
+ 1900 == 1752){
2003 if(date
.tm_mday
> 2 && date
.tm_mday
< 14)
2005 if(date
.tm_mday
>= 14)
2012 /* given an initial date dtstart, and a recurring rule, rrule,
2013 * adjust the date to the first date on the same year, when
2014 * the rule actually starts
2017 adjust_date_rrule(struct tm
*dtstart
, RRULE_S
*rrule
)
2021 memset((void *) &t
, 0, sizeof(struct tm
));
2022 t
.tm_year
= dtstart
->tm_year
; /* same year */
2023 if(rrule
->prop
[RRFreq
]){
2025 if(rrule
->prop
[RRCount
]){
2027 else if(rrule
->prop
[RRInterval
]){
2029 if(rrule
->prop
[RRBysecond
]){
2030 BYWKDY_S
*sec
= (BYWKDY_S
*) rrule
->prop
[RRBysecond
], *seco
;
2031 for (seco
= sec
; seco
!= NULL
; seco
= seco
->next
)
2032 if(seco
== sec
) t
.tm_sec
= seco
->value
;
2033 else if (seco
->value
< t
.tm_sec
)
2034 t
.tm_sec
= seco
->value
;
2036 if (rrule
->prop
[RRByminute
]){
2037 BYWKDY_S
*sec
= (BYWKDY_S
*) rrule
->prop
[RRByminute
], *seco
;
2038 for (seco
= sec
; seco
!= NULL
; seco
= seco
->next
)
2039 if(seco
== sec
) t
.tm_min
= seco
->value
;
2040 else if (seco
->value
< t
.tm_sec
)
2041 t
.tm_min
= seco
->value
;
2043 if (rrule
->prop
[RRByhour
]){
2044 BYWKDY_S
*sec
= (BYWKDY_S
*) rrule
->prop
[RRByhour
], *seco
;
2045 for (seco
= sec
; seco
!= NULL
; seco
= seco
->next
)
2046 if(seco
== sec
) t
.tm_hour
= seco
->value
;
2047 else if (seco
->value
< t
.tm_sec
)
2048 t
.tm_hour
= seco
->value
;
2050 if (rrule
->prop
[RRByday
]){
2052 if (rrule
->prop
[RRByweekno
]){
2054 if (rrule
->prop
[RRBymonthday
]){
2056 if (rrule
->prop
[RRByyearday
]){
2058 if (rrule
->prop
[RRByweekno
]){
2060 if (rrule
->prop
[RRBymonth
]){
2061 BYWKDY_S
*m
= (BYWKDY_S
*) rrule
->prop
[RRBymonth
], *mo
;
2062 for (mo
= m
; mo
!= NULL
; mo
= mo
->next
)
2063 if(mo
== m
) t
.tm_mon
= mo
->value
- 1;
2064 else if (mo
->value
- 1 < t
.tm_mon
)
2065 t
.tm_mon
= mo
->value
- 1;
2067 if (rrule
->prop
[RRBysetpos
]){
2069 if (rrule
->prop
[RRWkst
]){
2074 ical_initialize(void)
2076 ical_buf_len
= 1024;
2077 ical_buf
= fs_get(ical_buf_len
+1);
2079 memset((void *) &day_zero
, 0, sizeof(struct tm
));
2080 day_zero
.tm_year
= 1601 - 1900;
2081 day_zero
.tm_mday
= 1;
2082 day_zero
.tm_wday
= 4;
2085 /* At this time, we are going to print the date in 24 hour format
2086 * if there is no string for AM or PM, but we use AM or PM when available.
2087 * We plan to make this user configurable, but not today...
2090 ical_date_time (char *tmp
, size_t len
, struct tm
*ic_datep
)
2092 /* test of the AM/PM string is available */
2093 our_strftime(tmp
, len
, "%p", ic_datep
);
2096 our_strftime(tmp
, len
, "%a %x %I:%M %p", ic_datep
);
2098 our_strftime(tmp
, len
, "%a %x %H:%M", ic_datep
);
2101 /* If the icline has a TZID parameter, return its value, otherwise, return
2102 * NULL. Returned value freed by caller.
2105 ical_get_tzid(ICAL_PARAMETER_S
*param
)
2112 if(strucmp(param
->name
, "TZID") == 0)
2113 tzid
= cpystr(param
->value
);
2115 tzid
= ical_get_tzid(param
->next
);
2120 /* we create a summary of the event, and pass that back as
2124 ical_vevent_summary(VCALENDAR_S
*vcal
)
2126 VEVENT_SUMMARY_S
*rv
;
2133 if(vcal
== NULL
) return NULL
;
2135 method
= vcal
->method
;
2136 vevent
= (VEVENT_S
*) vcal
->comp
[VEvent
];
2138 if(vevent
== NULL
|| vevent
->prop
== NULL
)
2141 rv
= fs_get(sizeof(VEVENT_SUMMARY_S
));
2142 memset((void *) rv
, 0, sizeof(VEVENT_SUMMARY_S
));
2144 if(method
!= NULL
&& !strucmp(method
->value
, "CANCEL"))
2147 if((icl
= (ICLINE_S
*) vevent
->prop
[EvPriority
]) != NULL
)
2148 rv
->priority
= atoi(icl
->value
);
2150 if((icl
= (ICLINE_S
*) vevent
->prop
[EvSummary
]) != NULL
)
2151 rv
->summary
= cpystr(icl
->value
? icl
->value
: _("No Summary"));
2153 if((icl
= (ICLINE_S
*) vevent
->prop
[EvClass
]) != NULL
)
2154 rv
->class = cpystr(icl
->value
? icl
->value
: _("PUBLIC"));
2156 rv
->class = cpystr(_("PUBLIC"));
2158 if((icl
= (ICLINE_S
*) vevent
->prop
[EvOrganizer
]) != NULL
){
2159 char *cn
, *sender
, *address
;
2160 ICAL_PARAMETER_S
*param
;
2162 cn
= sender
= address
= NULL
;
2163 for(param
= icl
->param
; param
!= NULL
; param
= param
->next
)
2164 if(!strucmp(param
->name
, "CN"))
2166 else if(!strucmp(param
->name
, "SENT-BY"))
2167 sender
= param
->value
;
2170 if(!struncmp(sender
, "MAILTO:", 7))
2172 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "<%s>", sender
);
2173 rv
->sender
= cpystr(tmp_20k_buf
);
2176 if((address
= icl
->value
) != NULL
){
2177 if(!struncmp(address
, "MAILTO:", 7))
2179 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s<%s>",
2180 cn
? cn
: "", cn
? " " : "",
2181 address
? address
: _("Unknown address"));
2182 rv
->organizer
= cpystr(tmp_20k_buf
);
2184 } /* end of if(organizer) */
2186 if((icl
= (ICLINE_S
*) vevent
->prop
[EvLocation
]) != NULL
)
2187 rv
->location
= cpystr(icl
->value
? icl
->value
: _("Location undisclosed"));
2189 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDtstart
]) != NULL
){
2191 char tmp
[200], *tzid
;
2192 int icd
; /* ical date return value */
2194 memset((void *)&ic_date
, 0, sizeof(struct tm
));
2195 icd
= ical_parse_date(icl
->value
, &ic_date
);
2196 tzid
= ical_get_tzid(icl
->param
);
2198 ic_date
.tm_wday
= ical_day_of_week(ic_date
);
2200 case 0: /* DATE-TIME */
2201 ical_date_time(tmp
, sizeof(tmp
), &ic_date
);
2204 our_strftime(tmp
, sizeof(tmp
), "%a %x", &ic_date
);
2206 case 2: /* DATE-TIME in GMT, Bug: add adjust to time zone */
2207 our_strftime(tmp
, sizeof(tmp
), "%a %x %I:%M %p", &ic_date
);
2209 default: alpine_panic("Unhandled ical date format");
2214 strncpy(tmp
, _("Error while parsing event date"), sizeof(tmp
));
2215 tmp
[sizeof(tmp
) - 1] = '\0';
2218 if(icl
->value
== NULL
)
2219 rv
->evstart
= cpystr(_("Unknown Start Date"));
2221 size_t len
= strlen(tmp
) + 1;
2224 len
+= strlen(tzid
) + 3; /* 3 = strlen(" ()") */
2226 rv
->evstart
= fs_get(len
*sizeof(char));
2227 snprintf(rv
->evstart
, len
, "%s%s%s%s", tmp
,
2228 tzid
!= NULL
? " (" : "",
2229 tzid
!= NULL
? tzid
: "",
2230 tzid
!= NULL
? ")" : "");
2231 rv
->evstart
[len
-1] = '\0';
2233 } /* end of if dtstart */
2235 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDuration
]) != NULL
){
2237 ICAL_DURATION_S ic_d
, icd2
;
2238 if(ical_parse_duration(icl
->value
, &ic_d
) == 0){
2239 char tmp
[MAILTMPLEN
+1];
2241 for(i
= 1, icd2
= ic_d
; icd2
.next
!= NULL
; icd2
= *icd2
.next
, i
++);
2242 rv
->duration
= fs_get((i
+1)*sizeof(char *));
2249 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2250 "%d %s ", ic_d
.weeks
, ic_d
.weeks
== 1 ? _("week") : _("weeks"));
2252 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2253 "%d %s ", ic_d
.days
, ic_d
.days
== 1 ? _("day") : _("days"));
2255 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2256 "%d %s ", ic_d
.hours
, ic_d
.hours
== 1 ? _("hour") : _("hours"));
2257 if(ic_d
.minutes
> 0)
2258 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2259 "%d %s ", ic_d
.minutes
, ic_d
.minutes
== 1 ? _("minute") : _("minutes"));
2260 if(ic_d
.seconds
> 0)
2261 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2262 "%d %s ", ic_d
.seconds
, ic_d
.seconds
== 1 ? _("second") : _("seconds"));
2264 tmp
[MAILTMPLEN
] = '\0';
2265 rv
->duration
[i
++] = cpystr(tmp
);
2267 if(ic_d
.next
!= NULL
)
2271 } while (done
== 0);
2272 rv
->duration
[i
] = NULL
;
2274 } /* end of DURATION */
2275 else if((icl
= (ICLINE_S
*) vevent
->prop
[EvDtend
]) != NULL
){
2277 char tmp
[200], *tzid
;
2280 memset((void *)&ic_date
, 0, sizeof(struct tm
));
2281 icd
= ical_parse_date(icl
->value
, &ic_date
);
2282 tzid
= ical_get_tzid(icl
->param
);
2284 ic_date
.tm_wday
= ical_day_of_week(ic_date
);
2286 case 0: /* DATE-TIME */
2287 ical_date_time(tmp
, sizeof(tmp
), &ic_date
);
2290 our_strftime(tmp
, sizeof(tmp
), "%a %x", &ic_date
);
2292 case 2: /* DATE-TIME in GMT, Bug: add adjust to time zone */
2293 our_strftime(tmp
, sizeof(tmp
), "%a %x %I:%M %p", &ic_date
);
2295 default: alpine_panic("Unhandled ical date format");
2300 strncpy(tmp
, _("Error while parsing event date"), sizeof(tmp
));
2301 tmp
[sizeof(tmp
) - 1] = '\0';
2304 if(icl
->value
== NULL
)
2305 rv
->evend
= cpystr(_("Unknown End Date"));
2307 size_t len
= strlen(tmp
) + 1;
2310 len
+= strlen(tzid
) + 3; /* 3 = strlen(" ()") */
2312 rv
->evend
= fs_get(len
*sizeof(char));
2313 snprintf(rv
->evend
, len
, "%s%s%s%s", tmp
,
2314 tzid
!= NULL
? " (" : "",
2315 tzid
!= NULL
? tzid
: "",
2316 tzid
!= NULL
? ")" : "");
2317 rv
->evend
[len
-1] = '\0';
2319 } /* end of if dtend */
2321 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDtstamp
]) != NULL
){
2323 char tmp
[200], *tzid
;
2326 memset((void *)&ic_date
, 0, sizeof(struct tm
));
2327 icd
= ical_parse_date(icl
->value
, &ic_date
);
2328 tzid
= ical_get_tzid(icl
->param
);
2330 ic_date
.tm_wday
= ical_day_of_week(ic_date
);
2332 case 0: /* DATE-TIME */
2333 ical_date_time(tmp
, sizeof(tmp
), &ic_date
);
2336 our_strftime(tmp
, sizeof(tmp
), "%a %x", &ic_date
);
2338 case 2: /* DATE-TIME in GMT, Bug: add adjust to time zone */
2339 our_strftime(tmp
, sizeof(tmp
), "%a %x %I:%M %p", &ic_date
);
2341 default: alpine_panic("Unhandled ical date format");
2346 strncpy(tmp
, _("Error while parsing event date"), sizeof(tmp
));
2347 tmp
[sizeof(tmp
) - 1] = '\0';
2349 if(icl
->value
== NULL
)
2350 rv
->dtstamp
= cpystr(_("Unknown when event was scheduled"));
2352 size_t len
= strlen(tmp
) + 1;
2355 len
+= strlen(tzid
) + 3; /* 3 = strlen(" ()") */
2357 rv
->dtstamp
= fs_get(len
*sizeof(char));
2358 snprintf(rv
->dtstamp
, len
, "%s%s%s%s", tmp
,
2359 tzid
!= NULL
? " (" : "",
2360 tzid
!= NULL
? tzid
: "",
2361 tzid
!= NULL
? ")" : "");
2362 rv
->dtstamp
[len
-1] = '\0';
2364 } /* end of if dtstamp */
2366 if((gicl
= (GEN_ICLINE_S
*) vevent
->prop
[EvAttendee
]) != NULL
){
2369 for(nattendees
= 0; gicl
!= NULL
; gicl
= gicl
->next
, nattendees
++);
2370 rv
->attendee
= fs_get((nattendees
+1)*sizeof(char *));
2372 gicl
= (GEN_ICLINE_S
*) vevent
->prop
[EvAttendee
];
2373 for(i
= 0; gicl
!= NULL
; gicl
= gicl
->next
, i
++){
2374 char *role
, *partstat
, *rsvp
;
2376 ICAL_PARAMETER_S
*param
;
2379 role
= partstat
= rsvp
= cn
= mailto
= NULL
;
2380 for(param
= icl
->param
; param
!= NULL
; param
= param
->next
){
2381 if(!strucmp(param
->name
, "ROLE")){
2382 if(!strucmp(param
->value
, "REQ-PARTICIPANT"))
2383 role
= _("[Required]");
2384 else if(!strucmp(param
->value
, "OPT-PARTICIPANT"))
2385 role
= _("[Optional]");
2386 else if(!strucmp(param
->value
, "NON-PARTICIPANT"))
2387 role
= _("[Informed]");
2388 else if(!strucmp(param
->value
, "CHAIR"))
2389 role
= _("[ Chair ]");
2391 role
= param
->value
;
2393 else if(!strucmp(param
->name
, "PARTSTAT")){
2394 if(!strucmp(param
->value
, "NEEDS-ACTION"))
2395 partstat
= _("[Need-Reply]");
2396 else if(!strucmp(param
->value
, "ACCEPTED"))
2397 partstat
= _("[ Accepted ]");
2398 else if(!strucmp(param
->value
, "DECLINED"))
2399 partstat
= _("[ Declined ]");
2400 else if(!strucmp(param
->value
, "TENTATIVE"))
2401 partstat
= _("[ Tentative]");
2402 else if(!strucmp(param
->value
, "DELEGATED"))
2403 partstat
= _("[ Delegated]");
2405 partstat
= param
->value
;
2407 else if(!strucmp(param
->name
, "RSVP"))
2408 rsvp
= param
->value
;
2409 else if(!strucmp(param
->name
, "CN"))
2412 if(icl
->value
&& !struncmp(icl
->value
, "MAILTO:", strlen("MAILTO:")))
2413 mailto
= icl
->value
+ 7; /* 7 = strlen("MAILTO:") */
2414 if(!strucmp(cn
, mailto
))
2416 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s%s%s%s%s<%s>",
2417 role
&& *role
? role
: "",
2418 role
&& *role
? " " : "",
2419 partstat
? partstat
: _("[Unknown Reply]"),
2421 cn
&& *cn
? cn
: "",
2422 cn
&& *cn
? " " : "",
2423 mailto
? mailto
: _("Unknown address"));
2424 rv
->attendee
[i
] = cpystr(tmp_20k_buf
);
2426 rv
->attendee
[i
] = NULL
;
2427 } /* end of ATTENDEES */
2429 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDescription
]) != NULL
){
2430 char *s
, *t
, *u
, *v
;
2433 if(icl
->value
== NULL
){
2434 free_vevent_summary(&rv
);
2438 v
= cpystr(icl
->value
); /* process a copy of icl->value */
2440 for(i
= 1, escaped
= 0, s
= v
; s
&& *s
; s
++){
2441 if(*s
== '\\' && escaped
== 0){ escaped
= 1; continue; }
2443 if(!(*s
== '\\' || *s
== ',' || *s
== 'n' || *s
== 'N' || *s
== ';')){
2444 free_vevent_summary(&rv
);
2445 fs_give((void **)&v
);
2451 if(*s
== ',') i
++; /* a non-scaped comma is a new value for text */
2454 rv
->description
= fs_get((i
+1)*sizeof(unsigned char *));
2456 for (s
= t
= u
= v
, escaped
= 0; *t
!= '\0'; t
++){
2457 if(*t
== '\\' && escaped
== 0){ escaped
= 1; continue; }
2469 default: free_vevent_summary(&rv
);
2470 fs_give((void **)&v
);
2478 rv
->description
[i
++] = cpystr(ical_decode(s
, vcal
->encoding
));
2484 rv
->description
[i
++] = cpystr(ical_decode(s
, vcal
->encoding
));
2485 rv
->description
[i
] = NULL
;
2486 fs_give((void **)&v
);
2487 } /* end of if(description) */
2493 free_vevent_summary(VEVENT_SUMMARY_S
**vesy
)
2496 if(vesy
== NULL
|| *vesy
== NULL
) return;
2498 if((*vesy
)->class) fs_give((void **)&(*vesy
)->class);
2499 if((*vesy
)->summary
) fs_give((void **)&(*vesy
)->summary
);
2500 if((*vesy
)->sender
) fs_give((void **)&(*vesy
)->sender
);
2501 if((*vesy
)->organizer
) fs_give((void **)&(*vesy
)->organizer
);
2502 if((*vesy
)->location
) fs_give((void **)&(*vesy
)->location
);
2503 if((*vesy
)->evstart
) fs_give((void **)&(*vesy
)->evstart
);
2504 if((*vesy
)->evend
) fs_give((void **)&(*vesy
)->evend
);
2505 if((*vesy
)->dtstamp
) fs_give((void **)&(*vesy
)->dtstamp
);
2506 if((*vesy
)->duration
){
2507 for(i
= 0; (*vesy
)->duration
[i
] != NULL
; i
++)
2508 fs_give((void **) &(*vesy
)->duration
[i
]);
2509 fs_give((void **) (*vesy
)->duration
);
2511 if((*vesy
)->attendee
){
2512 for(i
= 0; (*vesy
)->attendee
[i
] != NULL
; i
++)
2513 fs_give((void **) &(*vesy
)->attendee
[i
]);
2514 fs_give((void **) (*vesy
)->attendee
);
2516 if((*vesy
)->description
){
2517 for(i
= 0; (*vesy
)->description
[i
] != NULL
; i
++)
2518 fs_give((void **) &(*vesy
)->description
[i
]);
2519 fs_give((void **) (*vesy
)->description
);
2521 fs_give((void **) vesy
);