Initial commit for branch ical
[alpine.git] / pith / ical.c
blob8364d384de001e27cee95875596c637f3b15245a
1 #include "../pith/headers.h"
2 #include "../pith/mailpart.h"
3 #include "../pith/store.h"
4 #include "../pith/ical.h"
5 #ifdef STANDALONE
6 #include "readfile.h"
7 #include "mem.h"
8 char *lf2crlf(char *);
9 #endif /* STANDALONE */
11 typedef struct ical_iana_comp_s {
12 char *comp; /* component name */
13 size_t len; /* size of component name (strlen(x->comp)) */
14 int pos; /* position of this component in comp array */
15 void *(*parse)(char **); /* parser */
16 void (*give)(void **); /* free memory */
17 } ICAL_COMP_S;
19 typedef struct ical_iana_prop_s {
20 char *prop; /* component name */
21 size_t len; /* size of component name (strlen(x->comp)) */
22 int pos; /* location of this component in the prop array */
23 void (*parse)(); /* parser */
24 void (*give)(void **); /* free memory */
25 } ICAL_PROP_S;
27 int ical_january_first(int); /* args: year */
28 void ical_adjust_date(struct tm *, VTIMEZONE_S *);
30 void ical_initialize(void);
32 int ical_non_ascii_valid(unsigned char);
33 char *ical_unfold_line(char *);
34 ICLINE_S *ical_parse_line(char **, char *);
36 ICLINE_S *ical_cline_cpy(ICLINE_S *);
37 ICAL_PARAMETER_S *ical_parameter_cpy(ICAL_PARAMETER_S *param);
39 char *ical_get_value(char **);
41 /* pase component */
42 void *ical_parse_vcalendar(char **);
43 void *ical_parse_vevent(char **);
44 void *ical_parse_vtodo(char **);
45 void *ical_parse_vjournal(char **);
46 void *ical_parse_vfreebusy(char **);
47 void *ical_parse_vtimezone(char **);
48 void *ical_parse_valarm(char **);
49 void *ical_parse_timezone(char **);
50 ICAL_S *ical_parse_unknown_comp(char **, int);
51 ICAL_S *ical_parse_generic_comp(char **, int);
53 /* free components */
54 void ical_free_vevent(void **);
55 void ical_free_vtodo(void **);
56 void ical_free_vjournal(void **);
57 void ical_free_vfreebusy(void **);
58 void ical_free_vtimezone(void **);
59 void ical_free_timezone(void **);
60 void ical_free_valarm(void **);
61 void ical_free_unknown_comp(ICAL_S **);
63 /* parse properties */
64 void ical_cline_from_token(void **, char **, char *);
65 void ical_gencline_from_token(void **, char **, char *);
67 void ical_parse_rrule(RRULE_S **, char **);
68 void ical_parse_time(struct tm *, char **, char *);
69 void ical_parse_offset(int *, char **, char *);
71 void ical_parse_freq(Freq_value *, char *);
72 void ical_parse_weekday_list(BYWKDY_S **, char *);
73 void ical_parse_number_list(BYWKDY_S **, char *);
74 void ical_parse_interval(unsigned long *, char *);
76 int ical_get_number_value(char *, int, int);
77 void ical_set_date(ICLINE_S *, VTIMEZONE_S *);
78 void ical_set_date_vevent(void *, void *);
80 /* free properties */
81 void ical_free_prop(void **, ICAL_PROP_S *);
82 void ical_free_null(void **);
83 void ical_free_cline(void **);
84 void ical_free_param(ICAL_PARAMETER_S **);
85 void ical_free_gencline(void **);
86 void ical_free_rrule(void **);
87 void ical_free_weekday_list(void **);
89 /* globals */
90 struct tm day_zero; /* date for january 1, 1601 */
91 int month_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
93 #define UTF8_COMPLETE (1)
94 #define NEED_MORE (2)
96 char *ical_buf;
97 unsigned long ical_buf_len;
100 /* parsing structures */
102 /* this is the list of V-components to a Calendar from RFC 5545 */
103 ICAL_COMP_S ical_comp[] = {
104 {"VCALENDAR", 9, VCalendar, ical_parse_vcalendar, ical_free_vcalendar},
105 {"VTIMEZONE", 9, VTimeZone, ical_parse_vtimezone, ical_free_vtimezone},
106 {"VEVENT", 6, VEvent, ical_parse_vevent, ical_free_vevent},
107 {"VTODO", 5, VTodo, ical_parse_vtodo, ical_free_vtodo},
108 {"VJOURNAL", 8, VJournal, ical_parse_vjournal, ical_free_vjournal},
109 {"VALARM", 6, VAlarm, ical_parse_valarm, ical_free_valarm},
110 {"VFREEBUSY", 9, VFreeBusy, ical_parse_vfreebusy, ical_free_vfreebusy},
111 {NULL, 0, VUnknown, NULL, 0}
114 /* array for properties */
115 ICAL_PROP_S rrule_prop[] = {
116 {"FREQ", 4, RRFreq, ical_parse_freq, ical_free_null},
117 {"UNTIL", 5, RRUntil, ical_parse_freq, 0},
118 {"COUNT", 5, RRCount, ical_cline_from_token, ical_free_cline},
119 {"INTERVAL", 8, RRInterval, ical_parse_interval, ical_free_null},
120 {"BYSECOND", 8, RRBysecond, ical_parse_number_list, ical_free_weekday_list},
121 {"BYMINUTE", 8, RRByminute, ical_parse_number_list, ical_free_weekday_list},
122 {"BYHOUR", 6, RRByhour, ical_parse_number_list, ical_free_weekday_list},
123 {"BYDAY", 5, RRByday, ical_parse_weekday_list,ical_free_weekday_list},
124 {"BYWEEKNO", 8, RRByweekno, 0, 0},
125 {"BYMONTH", 7, RRBymonth, ical_parse_number_list, ical_free_weekday_list},
126 {"BYSETPOS", 8, RRBysetpos, 0, 0},
127 {"BYWKST", 6, RRWkst, 0, 0},
128 {"BYMONTHDAY",
129 10, RRBymonthday, 0, 0},
130 {"BYYEARDAY", 9, RRByyearday, 0, 0},
131 {NULL, 0, RRUnknown, 0, 0}
134 ICAL_PROP_S event_prop[] = {
135 {"DTSTAMP", 7, EvDtstamp, ical_cline_from_token, ical_free_cline},
136 {"UID", 3, EvUid, ical_cline_from_token, ical_free_cline},
137 {"DTSTART", 7, EvDtstart, ical_cline_from_token, ical_free_cline},
138 {"CLASS", 5, EvClass, ical_cline_from_token, ical_free_cline},
139 {"CREATED", 7, EvCreated, ical_cline_from_token, ical_free_cline},
140 {"DESCRIPTION", 11, EvDescription, ical_cline_from_token, ical_free_cline},
141 {"GEO", 3, EvGeo, ical_cline_from_token, ical_free_cline},
142 {"LASTMOD", 7, EvLastMod, ical_cline_from_token, ical_free_cline},
143 {"LOCATION", 8, EvLocation, ical_cline_from_token, ical_free_cline},
144 {"ORGANIZER", 9, EvOrganizer, ical_cline_from_token, ical_free_cline},
145 {"PRIORITY", 8, EvPriority, ical_cline_from_token, ical_free_cline},
146 {"SEQUENCE", 8, EvSequence, ical_cline_from_token, ical_free_cline},
147 {"STATUS", 6, EvStatus, ical_cline_from_token, ical_free_cline},
148 {"SUMMARY", 7, EvSummary, ical_cline_from_token, ical_free_cline},
149 {"TRANSP", 6, EvTransp, ical_cline_from_token, ical_free_cline},
150 {"URL", 3, EvUrl, ical_cline_from_token, ical_free_cline},
151 {"RECURRENCE-ID", 13, EvRecurrence, ical_cline_from_token, ical_free_cline},
152 {"RRULE", 5, EvRrule, ical_parse_rrule, ical_free_rrule},
153 {"DTEND", 5, EvDtend, ical_cline_from_token, ical_free_cline},
154 {"DURATION", 8, EvDuration, ical_cline_from_token, ical_free_cline},
155 {"ATTACH", 6, EvAttach, ical_gencline_from_token, ical_free_gencline},
156 {"ATTENDEE", 8, EvAttendee, ical_gencline_from_token, ical_free_gencline},
157 {"CATEGORIES", 10, EvCategories, ical_gencline_from_token, ical_free_gencline},
158 {"COMMENT", 7, EvComment, ical_gencline_from_token, ical_free_gencline},
159 {"CONTACT", 7, EvContact, ical_gencline_from_token, ical_free_gencline},
160 {"EXDATE", 6, EvExdate, ical_gencline_from_token, ical_free_gencline},
161 {"RSTATUS", 7, EvRstatus, ical_gencline_from_token, ical_free_gencline},
162 {"RELATED", 7, EvRelated, ical_gencline_from_token, ical_free_gencline},
163 {"RESOURCES", 9, EvResources, ical_gencline_from_token, ical_free_gencline},
164 {"RDATE", 5, EvRdate, ical_gencline_from_token, ical_free_gencline},
165 {NULL, 0, EvUnknown, 0, 0}
168 ICAL_PROP_S tz_comp[] = {
169 {"TZID", 4, TZCid, ical_cline_from_token, ical_free_cline},
170 {"LAST-MODIFIED", 13, TZCLastMod, ical_cline_from_token, ical_free_cline},
171 {"TZURL", 5, TZCUrl, ical_cline_from_token, ical_free_cline},
172 {NULL, 0, TZCUnknown, 0, 0}
175 ICAL_PROP_S tz_prop[] = {
176 {"DTSTART", 7, TZPDtstart, ical_parse_time, 0},
177 {"TZOFFSETTO", 10, TZPOffsetto, ical_parse_offset, 0},
178 {"TZOFFSETFROM", 12, TZPOffsetfrom, ical_parse_offset, 0},
179 {"RRULE", 5, TZPRrule, ical_parse_rrule, ical_free_rrule},
180 {"COMMENT", 7, TZPComment, ical_gencline_from_token, ical_free_gencline},
181 {"RDATE", 5, TZPRdate, ical_gencline_from_token, ical_free_gencline},
182 {"TZNAME", 6, TZPTzname, ical_gencline_from_token, ical_free_gencline},
183 {NULL, 0, TZPUnknown, 0, 0}
186 ICAL_PROP_S alarm_prop[] = {
187 {"ACTION", 6, AlAction, ical_cline_from_token, ical_free_cline},
188 {"TRIGGER", 7, AlTrigger, ical_cline_from_token, ical_free_cline},
189 {"DURATION", 8, AlDuration, ical_cline_from_token, ical_free_cline},
190 {"REPEAT", 6, AlRepeat, ical_cline_from_token, ical_free_cline},
191 {"DESCRIPTION", 11, AlDescription, ical_cline_from_token, ical_free_cline},
192 {"SUMMARY", 7, AlSummary, ical_cline_from_token, ical_free_cline},
193 {"ATTACH", 6, AlAttach, ical_gencline_from_token, ical_free_gencline},
194 {"ATTENDEE", 8, AlAttendee, ical_gencline_from_token, ical_free_gencline},
195 {NULL, 0, AlUnknown, 0, 0}
198 /* some useful macros for character analysis */
200 #define ical_wspace(X) \
201 ((X) == ' ' || (X) == '\t')
203 #define ical_name_allowed_char(X) \
204 (((X) >= 'A' && (X) <= 'Z') || \
205 ((X) >= 'a' && (X) <= 'z') || \
206 (X) == '-' )
208 #define ical_control(X) \
209 (((X) >= 0x00 && (X) <= 0x08) || \
210 ((X) >= 0x0A && (X) <= 0x1F) || \
211 (X) == 0x7F)
213 #define ical_safe_char(X) \
214 (ical_non_ascii_valid(X) \
215 || ical_wspace(X) \
216 || (X) == 0x21 \
217 || ((X) >= 0x23 && (X) <= 0x2B) \
218 || ((X) >= 0x2D && (X) <= 0x39) \
219 || ((X) >= 0x3C && (X) <= 0x7E))
221 #define ical_qsafe_char(X) \
222 (ical_non_ascii_valid((X)) \
223 || ical_wspace(X) \
224 || (X) == 0x21 \
225 || ((X) >= 0x23 && (X) <= 0x7E))
227 #define ical_value_char(X) \
228 (ical_non_ascii_valid(X) \
229 || ical_wspace(X) \
230 || ((X) >= 0x21 && (X) <= 0x7E))
232 /* Finally, here begins the code. */
234 void ical_debug(char *fcn, char *text)
236 char piece[50];
237 strncpy(piece, text, 49);
238 dprint((9, "%s: %s", fcn, piece));
241 /***
242 *** FREE MEMORY FUNCTIONS
243 ***/
245 void
246 ical_free_param(ICAL_PARAMETER_S **param)
248 if(param == NULL || *param == NULL)
249 return;
251 if((*param)->name) fs_give((void **) &(*param)->name);
252 if((*param)->value) fs_give((void **) &(*param)->value);
253 if((*param)->next) ical_free_param(&(*param)->next);
254 fs_give((void **)param);
257 void
258 ical_free_null(void **n)
260 if(n != NULL) *n = NULL;
263 void
264 ical_free_cline(void **icv)
266 ICLINE_S **ic = (ICLINE_S **) icv;
268 if(ic == NULL || *ic == NULL)
269 return;
271 if((*ic)->token) fs_give((void **) &(*ic)->token);
272 if((*ic)->param) ical_free_param(&(*ic)->param);
273 if((*ic)->value) fs_give((void **) &(*ic)->value);
274 fs_give(icv);
277 void
278 ical_free_gencline(void **giclpv)
280 GEN_ICLINE_S **giclp = (GEN_ICLINE_S **) giclpv;
282 if(giclp == NULL || *giclp == NULL) return;
284 if((*giclp)->cline) ical_free_cline((void **) &(*giclp)->cline);
285 if((*giclp)->next) ical_free_gencline((void **) &(*giclp)->next);
288 void
289 ical_free_vcalendar(void **vcalpv)
291 VCALENDAR_S **vcalp = (VCALENDAR_S **)vcalpv;
293 if(vcalp == NULL || *vcalp == NULL) return;
295 if((*vcalp)->prodid) ical_free_cline((void **) &(*vcalp)->prodid);
296 if((*vcalp)->version) ical_free_cline((void **) &(*vcalp)->version);
297 if((*vcalp)->calscale) ical_free_cline((void **) &(*vcalp)->calscale);
298 if((*vcalp)->method) ical_free_cline((void **) &(*vcalp)->method);
299 if((*vcalp)->uk_prop) ical_free_gencline((void **) &(*vcalp)->uk_prop);
300 if((*vcalp)->comp){
301 Cal_comp i;
302 for(i = 0; i < VUnknown; i++)
303 if((*vcalp)->comp[i]) (ical_comp[i].give)(&(*vcalp)->comp[i]);
304 fs_give((*vcalp)->comp);
306 if((*vcalp)->uk_comp) ical_free_unknown_comp(&(*vcalp)->uk_comp);
307 fs_give(vcalpv);
310 void
311 ical_free_vevent(void **veventpv)
313 VEVENT_S **veventp = (VEVENT_S **) veventpv;
315 if(veventp == NULL || *veventp == NULL) return;
317 ical_free_prop((*veventp)->prop, event_prop);
318 if((*veventp)->uk_prop) ical_free_gencline((void **) &(*veventp)->uk_prop);
319 if((*veventp)->valarm) ical_free_valarm((void **) &(*veventp)->valarm);
320 fs_give(veventpv);
323 void
324 ical_free_rrule(void **rrulepv)
326 RRULE_S **rrulep = (RRULE_S **) rrulepv;
328 if(rrulep && *rrulep){
329 ical_free_prop((*rrulep)->prop, rrule_prop);
330 ical_free_param(&(*rrulep)->param);
331 fs_give(rrulepv);
335 void
336 ical_free_weekday_list(void **wkdylv)
338 BYWKDY_S **wkdyl = (BYWKDY_S **) wkdylv;
340 if(wkdyl == NULL) return;
342 if((*wkdyl)->next)
343 ical_free_weekday_list((void **) &(*wkdyl)->next);
345 fs_give(wkdylv);
349 void
350 ical_free_vtodo(void **vtodopv)
354 void
355 ical_free_vjournal(void **vjournalpv)
359 void
360 ical_free_vfreebusy(void **vfbpv)
364 void
365 ical_free_prop(void **propv, ICAL_PROP_S *aux_comp)
367 int i, j;
369 if(propv == NULL) return;
371 for(i = 0; aux_comp[i].prop != NULL; i++)
372 if(propv[i]){
373 for(j = 0; aux_comp[j].prop != NULL && aux_comp[j].pos != i; j++);
374 if(aux_comp[j].give) (aux_comp[j].give)(&propv[i]);
376 fs_give(propv);
380 void
381 ical_free_vtimezone(void **vtzpv)
383 VTIMEZONE_S **vtzp = (VTIMEZONE_S **) vtzpv;
384 TZ_comp i,j;
386 if(vtzp == NULL || *vtzp == NULL) return;
388 ical_free_prop((*vtzp)->prop, tz_comp);
390 if((*vtzp)->uk_prop) ical_free_gencline((void **) &(*vtzp)->uk_prop);
391 if((*vtzp)->standardc) ical_free_timezone((void **) &(*vtzp)->standardc);
392 if((*vtzp)->daylightc) ical_free_timezone((void **) &(*vtzp)->daylightc);
393 fs_give(vtzpv);
396 void
397 ical_free_timezone(void **tzpv)
399 ICAL_TZPROP_S **tzp = (ICAL_TZPROP_S **) tzpv;
401 if(tzp == NULL || *tzp == NULL) return;
403 ical_free_prop((*tzp)->prop, tz_prop);
404 if((*tzp)->uk_prop) ical_free_gencline((void **) &(*tzp)->uk_prop);
405 if((*tzp)->next) ical_free_timezone((void **) &(*tzp)->next);
406 fs_give(tzpv);
409 void ical_free_valarm(void **valarmpv)
413 void
414 ical_free_unknown_comp(ICAL_S **icalp)
416 int i;
417 if(icalp == NULL || *icalp == NULL) return;
418 for(i = 0; ical_comp[i].comp && strucmp((*icalp)->comp,ical_comp[i].comp); i++);
419 if(ical_comp[i].give)
420 (ical_comp[i].give)(&(*icalp)->value);
421 else
422 ical_free_gencline((void **) &(*icalp)->value);
423 fs_give((void **)&(*icalp)->comp);
424 ical_free_unknown_comp(&(*icalp)->next);
425 ical_free_unknown_comp(&(*icalp)->branch);
426 fs_give((void **)icalp);
429 char *ical_unfold_line(char *line)
431 int i, j;
433 if(line == NULL)
434 return NULL;
436 for(i = 0, j = 0; line[j] != '\0';)
437 switch(line[j]){
438 case '\r': if(line[j+1] == '\n' && ical_wspace(line[j+2])){
439 j += 3; /* get past white space */
440 continue;
442 default : line[i++] = line[j++];
444 line[i] = '\0';
445 return line;
448 ICAL_PARAMETER_S *
449 ical_get_parameter(char **line)
451 ICAL_PARAMETER_S *param = NULL;
452 char *s;
454 if(line == NULL || *line == NULL)
455 return NULL;
457 for(s = *line; s && *s && ical_name_allowed_char(*s) ; s++);
459 if(*s == '='){
460 int quoted;
461 char c;
463 param = fs_get(sizeof(ICAL_PARAMETER_S));
464 memset((void *)param, 0, sizeof(ICAL_PARAMETER_S));
465 *s = '\0';
466 param->name = cpystr(*line);
467 *s = '=';
468 *line = s+1; /* step over '=' */
469 quoted = **line == '"' ? 1 : 0;
470 if(quoted != 0){
471 for(s = ++*line; s && *s && ical_qsafe_char((unsigned char) *s); s++);
472 if(*s != '"'){ /* error, do not parse this line */
473 ical_free_param(&param);
474 *line = strchr(s, ':'); /* reset line to closest ':' */
475 return NULL;
478 else
479 for(s = *line; s && *s && (ical_safe_char((unsigned char) *s)); s++);
480 c = *s;
481 *s = '\0';
482 param->value = cpystr(*line);
483 *s = c; /* restore character */
484 *line = quoted ? s + 1 : s;
486 if(**line == ';'){
487 ++*line;
488 param->next = ical_get_parameter(line);
491 return param;
494 char *ical_get_value(char **line)
496 char *s, *t;
498 if(line == NULL || *line == NULL)
499 return NULL;
501 for (s = *line; *s && ical_value_char((unsigned char) *s); s++);
502 if(*s == '\r'){
503 *s = '\0';
504 t = cpystr(*line);
505 *s = '\r';
506 *line = s+2;
508 return t;
511 ICAL_PARAMETER_S *
512 ical_parameter_cpy(ICAL_PARAMETER_S *param)
514 ICAL_PARAMETER_S *rv;
516 if(param == NULL) return NULL;
518 rv = fs_get(sizeof(ICAL_PARAMETER_S));
519 memset((void *)rv, 0, sizeof(ICAL_PARAMETER_S));
521 if(param->name) rv->name = cpystr(param->name);
522 if(param->value) rv->value = cpystr(param->value);
523 if(param->next) rv->next = ical_parameter_cpy(param->next);
525 return rv;
528 ICLINE_S *
529 ical_cline_cpy(ICLINE_S *icl)
531 ICLINE_S *rv;
533 if(icl == NULL)
534 return NULL;
536 rv = fs_get(sizeof(ICLINE_S));
537 memset((void *)rv, 0, sizeof(ICLINE_S));
539 if(icl->token) rv->token = cpystr(icl->token);
540 if(icl->param) rv->param = ical_parameter_cpy(icl->param);
541 if(icl->value) rv->value = cpystr(icl->value);
543 return rv;
546 /* Given a \r\n-ending line (called *text), isolate the ocurrence
547 * of the token in that line.
548 * Return the token, and modify the pointer to *text to point to the
549 * end of the token. Modify sep to contain the character following
550 * the token
551 * ical-line = token ':'/';' rest of the line\r\n
552 * on error return null, and set *text to the next line, if possible.
554 char *
555 ical_isolate_token(char **text, char *sep)
557 char *s, *t;
559 for(t = s = *text; *t && ical_name_allowed_char(*s); s++);
560 /* only followed by parameter or value */
561 if(*s == ':' || *s == ';'){
562 *sep = *s;
563 *s = '\0'; /* isolate token at pointer s */
564 *text = s;
566 else{ /* bad data - bail out of here */
567 t = NULL;
568 if(*s == '\0' || (s = strstr(s, "\r\n")) == NULL)
569 *text = NULL;
570 else /* move to next line */
571 *text = s + 2;
573 return t;
577 VCALENDAR_S *
578 ical_parse_text(char *text)
580 char *s;
581 VCALENDAR_S *vcal = NULL;
583 ical_debug("ical_parse_text", text);
584 ical_initialize();
586 text = ical_unfold_line(text);
587 for(s = text; s && *s != '\0'; s++){
588 if(*s != 'B' && *s != 'b')
589 continue;
590 if(!struncmp(s+1, "EGIN:VCALENDAR\r\n", 16)){
591 s += 17; /* 17 = strlen("BEGIN:VCALENDAR\r\n") */
592 vcal = (VCALENDAR_S *) ical_parse_vcalendar(&s);
593 break;
596 return vcal;
599 void
600 ical_parse_time(struct tm *ic_date, char **text, char *token)
602 ICLINE_S *icl;
604 icl = ical_parse_line(text, token);
605 ical_parse_date(icl->value, ic_date);
606 ical_free_cline((void **) &icl);
609 void
610 ical_parse_interval(unsigned long *longv, char *value)
612 *longv = atoi(value);
616 void
617 ical_parse_offset(int *offsetv, char **text, char *token)
619 ICLINE_S *icl;
620 char *value;
621 int h, m, offset;
623 icl = ical_parse_line(text, token);
625 if(*icl->value == '+' || *icl->value == '-')
626 value = icl->value + 1;
627 else
628 value = icl->value;
630 h = ical_get_number_value(value, 0, 2);
631 m = ical_get_number_value(value, 2, 4);
633 offset = 60*(60*h + m);
634 if(*icl->value == '-')
635 offset *= -1;
637 *offsetv = offset;
638 ical_free_cline((void **) &icl);
641 void
642 ical_cline_from_token(void **iclv, char **text, char *token)
644 ICLINE_S **icl = (ICLINE_S **)iclv;
646 if(*icl == NULL)
647 *icl = ical_parse_line(text, token);
648 else {
649 ICLINE_S *ic = ical_parse_line(text, token);
650 ical_free_cline((void **)&ic);
654 void
655 ical_gencline_from_token(void **giclv, char **text, char *token)
657 GEN_ICLINE_S *gicl;
659 if(!struncmp(*text, token, strlen(token))){
660 gicl = fs_get(sizeof(GEN_ICLINE_S));
661 memset((void *) gicl, 0, sizeof(GEN_ICLINE_S));
662 ical_cline_from_token((void **) &gicl->cline, text, token);
663 ical_gencline_from_token((void **) &gicl->next, text, token);
664 *giclv = (void *) gicl;
668 /***
669 *** PARSE COMPONENT FUNCTIONS
670 ***/
672 void *
673 ical_parse_vcalendar(char **text)
675 char *s, *t;
676 char c;
677 VCALENDAR_S *vcal;
678 void *v;
680 dprint((9, "ical_parse_vcalendar:\n"));
681 ical_debug("ical_parse_vcalendar", *text);
683 vcal = fs_get(sizeof(VCALENDAR_S));
684 memset((void *)vcal, 0, sizeof(VCALENDAR_S));
686 /* s must always point the the beginning of a line */
687 for(s = *text; s && *s != '\0';){
688 t = s;
689 s = ical_isolate_token(&t, &c);
690 if(s == NULL){
691 if(t != NULL)
692 s = t;
693 continue;
696 *t = c; /* restore character */
697 if(s){ /* figure out the token */
698 int ukn = 0; /* unknown token */
699 int i;
700 switch(*s){
701 case 'B':
702 case 'b': if(!struncmp(s+1, "EGIN", 4)){
703 s += 6; /* 6 = strlen("BEGIN:") */
704 for(i = 0; ical_comp[i].comp
705 && (struncmp(s, ical_comp[i].comp, ical_comp[i].len)
706 || struncmp(s + ical_comp[i].len, "\r\n", 2)); i++);
708 if(ical_comp[i].parse){
709 s += ical_comp[i].len + 2;
710 v = (ical_comp[i].parse)(&s);
711 if(vcal->comp == NULL){
712 vcal->comp = fs_get(VUnknown*sizeof(void *));
713 memset((void *) vcal->comp, 0, VUnknown*sizeof(void *));
716 if(vcal->comp[ical_comp[i].pos] == NULL)
717 vcal->comp[ical_comp[i].pos] = v;
718 else
719 (ical_comp[i].give)(&v);
720 } else {
721 v = (void *) ical_parse_unknown_comp(&s, 0);
722 if(vcal->uk_comp == NULL)
723 vcal->uk_comp = (ICAL_S *) v;
724 else{
725 ICAL_S *ic;
726 for(ic = vcal->uk_comp; ic && ic->branch; ic = ic->branch);
727 ic->branch = (ICAL_S *) v;
730 } else ukn++;
731 break;
733 case 'C':
734 case 'c': if(!struncmp(s+1, "ALSCALE", 7))
735 ical_cline_from_token((void **) &vcal->calscale, &s, "CALSCALE");
736 else ukn++;
737 break;
739 case 'E':
740 case 'e': if(!struncmp(s+1, "ND", 2)){
741 *t = c;
742 s += 4; /* 4 = strlen("END:") */
743 if(!struncmp(s, "VCALENDAR\r\n", 11)){
744 *text = s + 11; /* 11 = strlen("VCALENDAR\r\n") */
745 return (void *) vcal;
747 // else ukn++; FIX THIS, this is not quite right
748 } else ukn++;
749 break;
751 case 'M':
752 case 'm': if(!struncmp(s+1, "ETHOD", 5))
753 ical_cline_from_token((void **) &vcal->method, &s, "METHOD");
754 else ukn++;
755 break;
757 case 'P':
758 case 'p': if(!struncmp(s+1, "RODID", 5))
759 ical_cline_from_token((void **) &vcal->prodid, &s, "PRODID");
760 else ukn++;
761 break;
763 case 'V':
764 case 'v': if(!struncmp(s+1, "ERSION", 6)){
765 ical_cline_from_token((void **) &vcal->version, &s, "VERSION");
766 } else ukn++;
767 break;
769 default : ukn++;
770 break;
771 } /* end of switch(*s) */
772 if(ukn){
773 if(ical_buf_len < t - s){
774 fs_resize((void **)&ical_buf, t-s+1);
775 ical_buf_len = t-s;
777 *t = '\0';
778 strcpy(ical_buf, s);
779 *t = c;
780 if(vcal->uk_prop == NULL){
781 vcal->uk_prop = fs_get(sizeof(GEN_ICLINE_S));
782 memset((void *)vcal->uk_prop, 0, sizeof(GEN_ICLINE_S));
783 vcal->uk_prop->cline = ical_parse_line(&s, ical_buf);
785 else{
786 GEN_ICLINE_S *gcl;
787 for (gcl = vcal->uk_prop; gcl && gcl->next; gcl = gcl->next);
788 gcl->next = fs_get(sizeof(GEN_ICLINE_S));
789 memset((void *)gcl->next, 0, sizeof(GEN_ICLINE_S));
790 gcl->next->cline = ical_parse_line(&s, ical_buf);
793 } /* end of if(s) */
796 *text = s;
798 /* ok, we have parsed the vcalendar, now parse some special properties */
799 /* start by parsing dates */
800 ical_set_date_vevent(vcal->comp[VEvent], vcal->comp[VTimeZone]);
801 return (void *) vcal;
804 void *
805 ical_parse_vevent(char **text)
807 char *s, *t;
808 char c;
809 VEVENT_S *vevent;
811 ical_debug("ical_parse_vevent", *text);
812 vevent = fs_get(sizeof(VEVENT_S));
813 memset((void *)vevent, 0, sizeof(VEVENT_S));
815 /* s must always point the the beginning of a line */
816 for(s = *text; s && *s != '\0';){
817 t = s;
818 s = ical_isolate_token(&t, &c);
819 if(s == NULL){
820 if(t != NULL)
821 s = t;
822 continue;
824 *t = c; /* restore separator */
826 if(s){ /* figure out the token */
827 int ukn = 0; /* unknown token */
828 if(!struncmp(s, "BEGIN", 5)){
829 s += 6; /* 6 = strlen("BEGIN:") */
830 if(!struncmp(s, "VALARM\r\n", 8)){
831 s += 8; /* 8 = strlen("VALARM\r\n"); */
832 if(vevent->valarm == NULL)
833 vevent->valarm = ical_parse_valarm(&s);
834 else{
835 VALARM_S *valrm;
836 for(valrm = vevent->valarm; valrm && valrm->next;
837 valrm = valrm->next);
838 valrm->next = ical_parse_valarm(&s);
840 } else {
841 ICAL_S *uk_comp = ical_parse_unknown_comp(&s, 0);
842 ical_free_unknown_comp(&uk_comp);
844 } else if(!struncmp(s, "END", t-s-1)){
845 s += 4; /* 4 = strlen("END:") */
846 if(!struncmp(s, "VEVENT\r\n",8)){
847 *text = s + 8; /* 8 = strlen("VCALENDAR\r\n") */
848 return (void *) vevent;
850 } else{ Event_prop i;
851 for(i = 0; i < EvUnknown; i++)
852 if(!struncmp(s, event_prop[i].prop, t-s))
853 break;
854 if(event_prop[i].parse){
855 if(vevent->prop == NULL){
856 vevent->prop = fs_get(EvUnknown*sizeof(void *));
857 memset((void *)vevent->prop, 0, EvUnknown*sizeof(void *));
859 (event_prop[i].parse)(&vevent->prop[event_prop[i].pos], &s, event_prop[i].prop);
861 else
862 ukn++;
865 if(ukn){
866 if(ical_buf_len < t - s){
867 fs_resize((void **)&ical_buf, t-s+1);
868 ical_buf_len = t-s;
870 *t = '\0';
871 strcpy(ical_buf, s);
872 *t = c;
873 if(vevent->uk_prop == NULL){
874 vevent->uk_prop = fs_get(sizeof(GEN_ICLINE_S));
875 memset((void *)vevent->uk_prop, 0, sizeof(GEN_ICLINE_S));
876 vevent->uk_prop->cline = ical_parse_line(&s, ical_buf);
878 else{
879 GEN_ICLINE_S *gcl;
880 for (gcl = vevent->uk_prop; gcl && gcl->next; gcl = gcl->next);
881 gcl->next = fs_get(sizeof(GEN_ICLINE_S));
882 memset((void *)gcl->next, 0, sizeof(GEN_ICLINE_S));
883 gcl->next->cline = ical_parse_line(&s, ical_buf);
886 } /* end of if(s) */
889 *text = s;
890 return (void *) vevent;
893 void *
894 ical_parse_vtimezone(char **text)
896 char *s, *t;
897 char c;
898 void *v;
899 VTIMEZONE_S *vtz;
901 ical_debug("ical_parse_vtimezone", *text);
902 vtz = fs_get(sizeof(VTIMEZONE_S));
903 memset((void *)vtz, 0, sizeof(VTIMEZONE_S));
905 /* s must always point the the beginning of a line */
906 for(s = *text; s && *s != '\0';){
907 t = s;
908 s = ical_isolate_token(&t, &c);
909 if(s == NULL){
910 if(t != NULL)
911 s = t;
912 continue;
914 *t = c; /* restore separator */
916 if(s){ /* figure out the token */
917 int ukn = 0; /* unknown token */
918 if(!struncmp(s, "BEGIN", 5)){
919 s += 6; /* 6 = strlen("BEGIN:") */
920 if(!struncmp(s, "STANDARD\r\n", 10)){
921 s += 10; /* 10 = strlen("STANDARD\r\n"); */
922 v = ical_parse_timezone(&s);
923 if(vtz->standardc == NULL)
924 vtz->standardc = (ICAL_TZPROP_S *) v;
925 else{
926 ICAL_TZPROP_S *dl;
927 for(dl = vtz->standardc; dl && dl->next; dl = dl->next);
928 dl->next = (ICAL_TZPROP_S *) v;
930 } else if(!struncmp(s, "DAYLIGHT\r\n", 10)){
931 s += 10; /* 10 = strlen("DAYLIGHT\r\n"); */
932 v = ical_parse_timezone(&s);
933 if(vtz->daylightc == NULL)
934 vtz->daylightc = (ICAL_TZPROP_S *) v;
935 else{
936 ICAL_TZPROP_S *dl;
937 for(dl = vtz->daylightc; dl && dl->next; dl = dl->next);
938 dl->next = (ICAL_TZPROP_S *) v;
940 } else {
941 ICAL_S *uk_comp = ical_parse_unknown_comp(&s, 0);
942 ical_free_unknown_comp(&uk_comp);
944 } else if(!struncmp(s, "END", t-s-1)){
945 s += 4; /* 4 = strlen("END:") */
946 if(!struncmp(s, "VTIMEZONE\r\n",11)){
947 *text = s + 11; /* 11 = strlen("VTIMEZONE\r\n") */
948 return (void *) vtz;
950 } else{ TZ_comp i;
951 for(i = 0; i < TZCUnknown; i++)
952 if(!struncmp(s, tz_comp[i].prop, t-s))
953 break;
954 if(tz_comp[i].parse){
955 if(vtz->prop == NULL){
956 vtz->prop = fs_get(TZCUnknown*sizeof(void *));
957 memset((void *)vtz->prop, 0, TZCUnknown*sizeof(void *));
959 (tz_comp[i].parse)(&vtz->prop[tz_comp[i].pos], &s, tz_comp[i].prop);
961 else
962 ukn++;
965 if(ukn){
966 if(ical_buf_len < t - s){
967 fs_resize((void **)&ical_buf, t-s+1);
968 ical_buf_len = t-s;
970 *t = '\0';
971 strcpy(ical_buf, s);
972 *t = c;
973 if(vtz->uk_prop == NULL){
974 vtz->uk_prop = fs_get(sizeof(GEN_ICLINE_S));
975 memset((void *)vtz->uk_prop, 0, sizeof(GEN_ICLINE_S));
976 vtz->uk_prop->cline = ical_parse_line(&s, ical_buf);
978 else{
979 GEN_ICLINE_S *gcl;
980 for (gcl = vtz->uk_prop; gcl && gcl->next; gcl = gcl->next);
981 gcl->next = fs_get(sizeof(GEN_ICLINE_S));
982 memset((void *)gcl->next, 0, sizeof(GEN_ICLINE_S));
983 gcl->next->cline = ical_parse_line(&s, ical_buf);
986 } /* end of if(s) */
989 *text = s;
990 return (void *) vtz;
993 void *
994 ical_parse_timezone(char **text)
996 char *s, *t;
997 char c;
998 ICAL_TZPROP_S *tzprop;
1000 ical_debug("ical_parse_timezone", *text);
1001 tzprop = fs_get(sizeof(ICAL_TZPROP_S));
1002 memset((void *)tzprop, 0, sizeof(ICAL_TZPROP_S));
1004 /* s must always point the the beginning of a line */
1005 for(s = *text; s && *s != '\0';){
1006 t = s;
1007 s = ical_isolate_token(&t, &c);
1008 if(s == NULL){
1009 if(t != NULL)
1010 s = t;
1011 continue;
1013 *t = c; /* restore separator */
1015 if(s){ /* figure out the token */
1016 int ukn = 0; /* unknown token */
1017 if(!struncmp(s, "BEGIN", 5)){
1018 s += 6; /* 6 = strlen("BEGIN:") */
1019 ICAL_S *uk_comp = ical_parse_unknown_comp(&s, 0);
1020 ical_free_unknown_comp(&uk_comp);
1021 } else if(!struncmp(s, "END", t-s-1)){
1022 s += 4; /* 4 = strlen("END:") */
1023 if(!struncmp(s, "STANDARD\r\n", 10)
1024 || !struncmp(s, "DAYLIGHT\r\n", 10)){
1025 *text = s + 10; /* 10 = strlen("STANDARD\r\n") */
1026 return (void *) tzprop;
1028 } else{ TZ_prop i;
1029 for(i = 0; i < TZPUnknown; i++)
1030 if(!struncmp(s, tz_prop[i].prop, t-s))
1031 break;
1032 if(tz_prop[i].parse){
1033 if(tzprop->prop == NULL){
1034 tzprop->prop = fs_get(TZPUnknown*sizeof(void *));
1035 memset((void *)tzprop->prop, 0, TZPUnknown*sizeof(void *));
1037 (tz_prop[i].parse)(&tzprop->prop[tz_prop[i].pos], &s, tz_prop[i].prop);
1039 else
1040 ukn++;
1043 if(ukn){
1044 if(ical_buf_len < t - s){
1045 fs_resize((void **)&ical_buf, t-s+1);
1046 ical_buf_len = t-s;
1048 *t = '\0';
1049 strcpy(ical_buf, s);
1050 *t = c;
1051 if(tzprop->uk_prop == NULL){
1052 tzprop->uk_prop = fs_get(sizeof(GEN_ICLINE_S));
1053 memset((void *)tzprop->uk_prop, 0, sizeof(GEN_ICLINE_S));
1054 tzprop->uk_prop->cline = ical_parse_line(&s, ical_buf);
1056 else{
1057 GEN_ICLINE_S *gcl;
1058 for (gcl = tzprop->uk_prop; gcl && gcl->next; gcl = gcl->next);
1059 gcl->next = fs_get(sizeof(GEN_ICLINE_S));
1060 memset((void *)gcl->next, 0, sizeof(GEN_ICLINE_S));
1061 gcl->next->cline = ical_parse_line(&s, ical_buf);
1064 } /* end of if(s) */
1067 *text = s;
1068 return (void *) tzprop;
1071 void *
1072 ical_parse_valarm(char **text)
1074 char *s, *t;
1075 char c;
1076 VALARM_S *valarm;
1078 ical_debug("ical_parse_valarm", *text);
1079 valarm = fs_get(sizeof(VALARM_S));
1080 memset((void *)valarm, 0, sizeof(VALARM_S));
1082 /* s must always point the the beginning of a line */
1083 for(s = *text; s && *s != '\0';){
1084 t = s;
1085 s = ical_isolate_token(&t, &c);
1086 if(s == NULL){
1087 if(t != NULL)
1088 s = t;
1089 continue;
1091 *t = c; /* restore separator */
1093 if(s){ /* figure out the token */
1094 int ukn = 0; /* unknown token */
1095 if(!struncmp(s, "BEGIN", 5)){
1096 s += 6; /* 6 = strlen("BEGIN:") */
1097 ICAL_S *uk_comp = ical_parse_unknown_comp(&s, 0);
1098 ical_free_unknown_comp(&uk_comp);
1099 } else if(!struncmp(s, "END", t-s-1)){
1100 s += 4; /* 4 = strlen("END:") */
1101 if(!struncmp(s, "ALARM\r\n", 7)){
1102 *text = s + 7; /* 7 = strlen("ALARM\r\n") */
1103 return (void *) valarm;
1105 } else{ Alarm_prop i;
1106 for(i = 0; i < AlUnknown; i++)
1107 if(!struncmp(s, alarm_prop[i].prop, t-s))
1108 break;
1109 if(alarm_prop[i].parse){
1110 if(valarm->prop == NULL){
1111 valarm->prop = fs_get(AlUnknown*sizeof(void *));
1112 memset((void *)valarm->prop, 0, AlUnknown*sizeof(void *));
1114 (alarm_prop[i].parse)(&valarm->prop[alarm_prop[i].pos], &s, alarm_prop[i].prop);
1116 else
1117 ukn++;
1120 if(ukn){
1121 if(ical_buf_len < t - s){
1122 fs_resize((void **)&ical_buf, t-s+1);
1123 ical_buf_len = t-s;
1125 *t = '\0';
1126 strcpy(ical_buf, s);
1127 *t = c;
1128 if(valarm->uk_prop == NULL){
1129 valarm->uk_prop = fs_get(sizeof(GEN_ICLINE_S));
1130 memset((void *)valarm->uk_prop, 0, sizeof(GEN_ICLINE_S));
1131 valarm->uk_prop->cline = ical_parse_line(&s, ical_buf);
1133 else{
1134 GEN_ICLINE_S *gcl;
1135 for (gcl = valarm->uk_prop; gcl && gcl->next; gcl = gcl->next);
1136 gcl->next = fs_get(sizeof(GEN_ICLINE_S));
1137 memset((void *)gcl->next, 0, sizeof(GEN_ICLINE_S));
1138 gcl->next->cline = ical_parse_line(&s, ical_buf);
1141 } /* end of if(s) */
1144 *text = s;
1145 return (void *) valarm;
1148 void *
1149 ical_parse_vtodo(char **text)
1151 return NULL;
1154 void *
1155 ical_parse_vjournal(char **text)
1157 return NULL;
1160 void *
1161 ical_parse_vfreebusy(char **text)
1163 return NULL;
1166 ICAL_S *
1167 ical_parse_generic_comp(char **text, int level)
1169 ICAL_S *ical;
1170 char *s, *t;
1171 char *token = NULL;
1172 GEN_ICLINE_S *gcl = NULL;
1173 char c;
1175 ical_debug("ical_parse_generic_comp", *text);
1176 ical = fs_get(sizeof(ICAL_S));
1177 memset((void *)ical, 0, sizeof(ICAL_S));
1179 ical->comp = ical_get_value(text);
1180 token = fs_get(strlen(ical->comp) + 2 + 1);
1181 sprintf(token, "%s\r\n", ical->comp); /* this is allocated memory */
1183 /* s must always point the the beginning of a line */
1184 for(s = *text; s && *s != '\0';){
1185 t = s;
1186 s = ical_isolate_token(&t, &c);
1187 if(s == NULL){
1188 if(t != NULL)
1189 s = t;
1190 continue;
1193 *t = c; /* restore character */
1194 if(s){ /* figure out the token */
1195 int ukn = 0; /* unknown token */
1196 switch(*s){
1197 case 'B':
1198 case 'b': if(!struncmp(s+1, "EGIN", 4)){
1199 s += 6; /* 6 = strlen("BEGIN:") */
1200 if(ical->next == NULL)
1201 ical->next = ical_parse_unknown_comp(&s, level+1);
1202 else{
1203 ICAL_S *b;
1204 int i;
1206 for(i = 0, b = ical; i <= level && b && b->next; b = b->next, i++);
1207 if(b->branch == NULL)
1208 b->branch = ical_parse_unknown_comp(&s, level+1);
1209 else {
1210 for(; b && b->branch; b = b->branch);
1211 b->branch = ical_parse_unknown_comp(&s, level+1);
1214 } else ukn++;
1215 break;
1217 case 'E':
1218 case 'e': if(!struncmp(s+1, "ND", 2)){
1219 *t = c;
1220 s += 4; /* 4 = strlen("END:") */
1221 if(!struncmp(s, token, strlen(token))){
1222 *text = s + strlen(token);
1223 ical->value = (void *) gcl;
1224 return ical;
1226 } else ukn++;
1227 break;
1229 default : ukn++;
1230 break;
1231 } /* end of switch(*s) */
1232 if(ukn){
1233 if(ical_buf_len < t - s){
1234 fs_resize((void **)&ical_buf, t-s+1);
1235 ical_buf_len = t-s;
1237 *t = '\0';
1238 strcpy(ical_buf, s);
1239 *t = c;
1240 if(gcl == NULL){
1241 gcl = fs_get(sizeof(GEN_ICLINE_S));
1242 memset((void *)gcl, 0, sizeof(GEN_ICLINE_S));
1243 gcl->cline = ical_parse_line(&s, ical_buf);
1245 else{
1246 GEN_ICLINE_S *gencl;
1247 for (gencl = gcl; gencl && gencl->next; gencl = gencl->next);
1248 gencl->next = fs_get(sizeof(GEN_ICLINE_S));
1249 memset((void *)gencl->next, 0, sizeof(GEN_ICLINE_S));
1250 gencl->next->cline = ical_parse_line(&s, ical_buf);
1253 } /* end of if(s) */
1256 ical->value = (void *) gcl;
1257 *text = s;
1258 return ical;
1261 ICAL_S *
1262 ical_parse_unknown_comp(char **text, int level)
1264 ICAL_S *ical;
1265 int i;
1267 ical_debug("ical_parse_unknown_comp", *text);
1268 for(i = 0; ical_comp[i].comp
1269 && (struncmp(*text, ical_comp[i].comp, ical_comp[i].len)
1270 || struncmp(*text + ical_comp[i].len, "\r\n", 2)); i++);
1272 if(ical_comp[i].parse){
1273 *text += ical_comp[i].len + 2;
1274 ical = fs_get(sizeof(ICAL_S));
1275 memset((void *)ical, 0, sizeof(ICAL_S));
1276 ical->comp = cpystr(ical_comp[i].comp);
1277 ical->value = (ical_comp[i].parse)(text);
1278 } else
1279 ical = ical_parse_generic_comp(text, level);
1281 return ical;
1284 ICLINE_S *
1285 ical_parse_line(char **text, char *name)
1287 ICLINE_S *ic;
1288 char *s = *text;
1290 ic = fs_get(sizeof(ICLINE_S));
1291 memset((void *)ic, 0, sizeof(ICLINE_S));
1293 ic->token = cpystr(name);
1294 s += strlen(name);
1295 if(*s == ';'){
1296 s++;
1297 ic->param = ical_get_parameter(&s);
1299 if(*s == ':'){
1300 s++;
1301 ic->value = ical_get_value(&s);
1304 *text = s;
1305 return ic;
1308 /***
1309 *** PARSE PROPERTY FUNCTIONS
1310 ***/
1312 void
1313 ical_parse_freq(Freq_value *fval, char *text)
1315 if(fval == NULL) return;
1317 *fval = FUnknown;
1319 if(text == NULL) return;
1321 if(!strucmp(text, "SECONDLY")) *fval = FSecondly;
1322 else if(!strucmp(text, "MINUTELY")) *fval = FMinutely;
1323 else if(!strucmp(text, "HOURLY")) *fval = FHourly;
1324 else if(!strucmp(text, "DAILY")) *fval = FDaily;
1325 else if(!strucmp(text, "WEEKLY")) *fval = FWeekly;
1326 else if(!strucmp(text, "MONTHLY")) *fval = FMonthly;
1327 else if(!strucmp(text, "YEARLY")) *fval = FYearly;
1330 void
1331 ical_parse_weekday_list(BYWKDY_S **bywkdyp, char *wklist)
1333 BYWKDY_S *bywkdy, *w;
1334 char *s, *t, c;
1335 int done;
1336 size_t len;
1338 if(bywkdyp == NULL) return;
1339 *bywkdyp = bywkdy = NULL;
1340 if(wklist == NULL) return;
1342 for(t = s = wklist; done == 0; s++){
1343 if(*s != ',' && *s != '\0')
1344 continue;
1345 c = *s;
1346 if(c == ',')
1347 *s = '\0';
1348 else /* c == '\0' */
1349 done++;
1350 len = strlen(t);
1351 if(len > 1){
1352 for(w = bywkdy; w && w->next; w = w->next);
1353 w = fs_get(sizeof(BYWKDY_S));
1354 memset((void *)w, 0, sizeof(BYWKDY_S));
1355 if(!strucmp(t+len-2, "SU")) w->wd = Sunday;
1356 else if(!strucmp(t+len-2, "MO")) w->wd = Monday;
1357 else if(!strucmp(t+len-2, "TU")) w->wd = Tuesday;
1358 else if(!strucmp(t+len-2, "WE")) w->wd = Wednesday;
1359 else if(!strucmp(t+len-2, "TH")) w->wd = Thursday;
1360 else if(!strucmp(t+len-2, "FR")) w->wd = Friday;
1361 else if(!strucmp(t+len-2, "SA")) w->wd = Saturday;
1362 // t[len - 2] = '\0';
1363 if(*t != '\0')
1364 w->value = strtoul(t, &t, 10);
1365 if(bywkdy == NULL)
1366 bywkdy = w;
1368 *s = c;
1369 if(*s == ',')
1370 t = s + 1;
1373 if(*bywkdyp)
1374 ical_free_weekday_list((void **)&bywkdy);
1375 else
1376 *bywkdyp = bywkdy;
1379 void
1380 ical_parse_number_list(BYWKDY_S **bynop, char *nolist)
1382 BYWKDY_S *byno, *n;
1383 char *s, *t, c;
1384 int done;
1386 if(bynop == NULL) return;
1387 *bynop = byno = NULL;
1388 if(nolist == NULL) return;
1390 for(t = s = nolist; done == 0; s++){
1391 if(*s != ',' && *s != '\0')
1392 continue;
1393 c = *s;
1394 if(c == ',')
1395 *s = '\0';
1396 else /* c == '\0' */
1397 done++;
1399 for(n = byno; n && n->next; n = n->next);
1400 n = fs_get(sizeof(BYWKDY_S));
1401 memset((void *)n, 0, sizeof(BYWKDY_S));
1402 n->value = strtoul(t, &t, 10);
1403 if(byno == NULL)
1404 byno = n;
1405 *s = c;
1406 if(*s == ',')
1407 t = s + 1;
1410 if(*bynop)
1411 ical_free_weekday_list((void **)&byno);
1412 else
1413 *bynop = byno;
1416 void
1417 ical_parse_rrule(RRULE_S **rrulep, char **text)
1419 RRULE_S *rrule;
1420 ICLINE_S *icl;
1421 char *s;
1422 ICAL_PARAMETER_S *param, *p;
1423 int i;
1425 if(rrulep == NULL
1426 || text == NULL || *text == NULL || struncmp(*text, "RRULE", 5)) return;
1427 rrule = fs_get(sizeof(RRULE_S));
1428 memset((void *) rrule, 0, sizeof(RRULE_S));
1430 /* recurring rules are special. First, we parse the icline that contains it */
1431 icl = ical_parse_line(text, "RRULE");
1433 /* now we copy the parameters that it contains */
1434 rrule->param = ical_parameter_cpy(icl->param);
1436 /* then we parse icl->value as if it was a parameter */
1437 s = icl->value;
1438 param = ical_get_parameter(&s);
1440 /* now we check which values were given, and fill the prop array */
1441 rrule->prop = fs_get(RRUnknown*sizeof(void *));
1442 memset((void *) rrule->prop, 0, RRUnknown*sizeof(void *));
1444 for(p = param; p != NULL; p = p->next){
1445 for(i = 0; rrule_prop[i].prop != NULL && strucmp(p->name, rrule_prop[i].prop); i++);
1446 if(rrule_prop[i].parse)
1447 (rrule_prop[i].parse)(&rrule->prop[rrule_prop[i].pos], p->value);
1450 ical_free_param(&param);
1451 ical_free_cline((void **)&icl);
1452 if(*rrulep)
1453 ical_free_rrule((void **)&rrule);
1454 else
1455 *rrulep = rrule;
1458 /*** UTF-8 for ICAL ***/
1461 ical_non_ascii_valid(unsigned char c)
1463 static char icu[6];
1464 static int utf8_len = 0;
1465 static int utf8_type = 0;
1466 int rv;
1468 if(utf8_len == 0)
1469 utf8_type = (c >= 0xF0 && c <= 0xF4)
1470 ? 4 : (c >= 0xE0 && c <= 0xEF)
1471 ? 3 : (c >= 0xC2 && c <= 0xDF)
1472 ? 2 : 0;
1474 if(utf8_type == 0)
1475 return 0;
1477 icu[utf8_len++] = c; /* count it */
1479 if(utf8_type == 2){
1480 if(utf8_len < 2)
1481 rv = NEED_MORE;
1482 else if(utf8_len == 2){
1483 rv = (icu[0] >= 0xC2 && icu[0] <= 0xDF)
1484 && (icu[1] >= 0x80 && icu[1] <= 0xBF) ? UTF8_COMPLETE : 0;
1485 utf8_len = 0;
1487 } else if (utf8_type == 3){
1488 if(utf8_len < 3)
1489 rv = NEED_MORE;
1490 else{
1491 if(icu[0] == 0xE0)
1492 rv = (icu[1] >= 0xA0 && icu[1] <= 0xBF)
1493 && (icu[2] >= 0x80 && icu[2] <= 0xBF) ? UTF8_COMPLETE : 0;
1494 else if(icu[0] >= 0xE1 && icu[0] <= 0xEC)
1495 rv = (icu[1] >= 0x80 && icu[1] <= 0xBF)
1496 && (icu[2] >= 0x80 && icu[2] <= 0xBF) ? UTF8_COMPLETE : 0;
1497 else if(icu[0] == 0xED)
1498 rv = (icu[1] >= 0x80 && icu[1] <= 0x9F)
1499 && (icu[2] >= 0x80 && icu[2] <= 0xBF) ? UTF8_COMPLETE : 0;
1500 else if(icu[0] >= 0xE1 && icu[0] <= 0xEC)
1501 rv = (icu[1] >= 0x80 && icu[1] <= 0xBF)
1502 && (icu[2] >= 0x80 && icu[2] <= 0xBF) ? UTF8_COMPLETE : 0;
1503 utf8_len = 0;
1505 } else if (utf8_type == 4){
1506 if(utf8_len < 4)
1507 rv = NEED_MORE;
1508 else{
1509 if(icu[0] == 0xF0)
1510 rv = (icu[1] >= 0x90 && icu[1] <= 0xBF)
1511 && (icu[2] >= 0x80 && icu[2] <= 0xBF)
1512 && (icu[3] >= 0x80 && icu[3] <= 0xBF) ? UTF8_COMPLETE : 0;
1513 else if(icu[0] >= 0xF1 && icu[0] <= 0xF3)
1514 rv = (icu[1] >= 0x80 && icu[1] <= 0xBF)
1515 && (icu[2] >= 0x80 && icu[2] <= 0xBF)
1516 && (icu[3] >= 0x80 && icu[3] <= 0xBF) ? UTF8_COMPLETE : 0;
1517 else if(icu[0] == 0xF4)
1518 rv = (icu[1] >= 0x80 && icu[1] <= 0x8F)
1519 && (icu[2] >= 0x80 && icu[2] <= 0xBF)
1520 && (icu[3] >= 0x80 && icu[3] <= 0xBF) ? UTF8_COMPLETE : 0;
1521 utf8_len = 0;
1524 return rv;
1528 ical_get_number_value(char *value, int beg_pos, int end_pos)
1530 char c, *err;
1531 int rv;
1533 c = value[end_pos];
1534 value[end_pos] = '\0';
1535 rv = strtoul(value + beg_pos, &err, 10);
1536 if(err != NULL && *err != '\0') return -1;
1537 value[end_pos] = c;
1538 return rv;
1541 void
1542 ical_free_duration(ICAL_DURATION_S **ic_d)
1544 if(ic_d == NULL || *ic_d == NULL)
1545 return;
1547 if((*ic_d)->next) ical_free_duration(&(*ic_d)->next);
1548 fs_give((void **)ic_d);
1551 /* returns 0 if no error, -1 if some error */
1553 ical_parse_duration(char *value, ICAL_DURATION_S *ic_d)
1555 int i, j, rv = 0;
1557 if(value == NULL || ic_d == NULL) return -1;
1559 memset((void *)ic_d, 0, sizeof(ICAL_DURATION_S));
1561 if(value[i = 0] == '-'){
1562 i++;
1563 ic_d->sign = 1;
1564 } else if(value[i] == '+')
1565 i++;
1567 if(value[i++] == 'P'){
1568 for(j = i; value[j] != '\0' && value[j] != ','; j++){
1569 if(!isdigit(value[j]))
1570 switch(value[j]){
1571 case 'W': ic_d->weeks = ical_get_number_value(value, i, j-1);
1572 i = ++j;
1573 break;
1574 case 'D': ic_d->days = ical_get_number_value(value, i, j-1);
1575 i = ++j;
1576 break;
1577 case 'H': ic_d->hours = ical_get_number_value(value, i, j-1);
1578 i = ++j;
1579 break;
1580 case 'M': ic_d->minutes = ical_get_number_value(value, i, j-1);
1581 i = ++j;
1582 break;
1583 case 'S': ic_d->seconds = ical_get_number_value(value, i, j-1);
1584 i = ++j;
1585 break;
1586 case 'T': i = j + 1;
1587 break;
1588 default: rv = -1;
1589 break;
1593 else
1594 rv = -1;
1596 if(value[j++] == ','){
1597 ICAL_DURATION_S next;
1598 rv = ical_parse_duration(value+j, &next);
1599 ic_d->next = &next;
1602 return rv;
1605 /* return -1 if any error, 0 if no error */
1607 ical_parse_date(char *value, struct tm *t)
1609 int i;
1610 struct tm Tm;
1612 if(t == NULL) return -1;
1613 memset((void *)&Tm, 0, sizeof(struct tm));
1615 if(value == NULL) return -1;
1617 /* a simple check for the format of the string */
1618 for(i = 0; isdigit(value[i]); i++);
1619 if (i != 8 || value[i++] != 'T') return -1;
1620 for(; isdigit(value[i]); i++);
1621 if(i != 15 || (value[i] != '\0' && (value[i] != 'Z' || value[i+1] != '\0')))
1622 return -1;
1624 Tm.tm_year = ical_get_number_value(value, 0, 4) - 1900;
1625 Tm.tm_mon = ical_get_number_value(value, 4, 6) - 1;
1626 Tm.tm_mday = ical_get_number_value(value, 6, 8);
1627 Tm.tm_hour = ical_get_number_value(value, 9, 11);
1628 Tm.tm_min = ical_get_number_value(value, 11, 13);
1629 Tm.tm_sec = ical_get_number_value(value, 13, 15);
1630 *t = Tm;
1632 return (t->tm_mon > 11 || t->tm_mon < 0
1633 || t->tm_mday > 31 || t->tm_mday < 0
1634 || t->tm_hour > 23 || t->tm_hour < 0
1635 || t->tm_min > 59 || t->tm_min < 0
1636 || t->tm_sec > 60 || t->tm_sec < 0)
1637 ? - 1 : 0;
1640 void
1641 ical_set_date(ICLINE_S *icl, VTIMEZONE_S *vtz)
1643 int date_form; /* date forms from section 3.3.4 in RFC 5545 */
1644 ICAL_PARAMETER_S *param;
1645 char *tz = NULL;
1646 struct tm ic_date;
1647 time_t t;
1649 if(icl == NULL) return;
1651 for(param = icl->param; param != NULL; param = param->next)
1652 if(!strucmp(param->name, "TZID"))
1653 tz = param->value;
1655 if(tz != NULL)
1656 date_form = 3; /* local time with timezone */
1657 else if(icl->value[strlen(icl->value)-1] == 'Z')
1658 date_form = 2; /* utc time */
1659 else date_form = 1; /* local time */
1661 ical_parse_date(icl->value, &ic_date);
1662 ic_date.tm_wday = ical_day_of_week(ic_date); /* find out day of the week */
1664 switch(date_form){
1665 case 1: break;
1666 case 2: ical_adjust_date(&ic_date, vtz);
1667 break;
1668 case 3: break;
1669 default: alpine_panic ("Impossible date_form");
1673 ICAL_TZPROP_S *
1674 ical_std_or_daylight(struct tm *date, VTIMEZONE_S *vtz)
1676 struct tm standard, daylight;
1683 /* adjusts time to given time zone */
1684 void
1685 ical_adjust_date(struct tm *date, VTIMEZONE_S *vtz)
1687 char *tzname = NULL;
1688 ICLINE_S *icl;
1689 ICAL_TZPROP_S *cur_std_day;
1691 if(vtz == NULL)
1692 return;
1694 if(vtz->prop){
1695 if((icl = (ICLINE_S *)vtz->prop[TZCid]) != NULL)
1696 tzname = cpystr(icl->value);
1699 //+++ cur_std_day = ical_std_or_daylight(date, vtz);
1702 void
1703 ical_set_date_vevent(void *veventv, void *vtzv)
1705 VEVENT_S *vevent = (VEVENT_S *) veventv;
1706 VTIMEZONE_S *vtz = (VTIMEZONE_S *) vtzv;
1708 if(vevent){
1709 ical_set_date(vevent->prop[EvDtstamp], vtz);
1710 ical_set_date(vevent->prop[EvDtstart], vtz);
1711 ical_set_date(vevent->prop[EvDtend], vtz);
1715 #define LEAP_YEAR(X) ((((X) % 4 == 0) \
1716 && (((X) % 100 != 0) || ((X) % 400 == 0))) \
1717 || (X) == 1700)
1719 #define CAL_OFFSET(X) (((X) == 1752) ? 5 : (LEAP_YEAR((X)) ? 2 : 1))
1721 /* given a year, after day_zero, return the day
1722 * of the week of the first of january of that year. On error,
1723 * return a negative number.
1724 * Assumption: day_zero is the date of january 1, of some year.
1727 ical_january_first(int year)
1729 int i, january_first;
1731 if(year < day_zero.tm_year) return -1; /* not supported */
1733 year += 1900;
1734 january_first = day_zero.tm_wday;
1735 for(i = 1900 + day_zero.tm_year + 1; i <= year; i++)
1736 january_first += CAL_OFFSET(i-1);
1738 return january_first % 7;
1741 /* given a month, week day, and year, return all days of the month
1742 * that have that day as the week day. For example, return all
1743 * sundays in november 2012.
1745 int *
1746 ical_day_from_week(int month, Weekday day, int year)
1748 int *rv = NULL;
1749 int fday, nday;
1750 Weekday wday;
1751 int i;
1753 fday = ical_first_of_month(month, year);
1754 year += 1900; /* restore year */
1755 if(year == 1752 && month == 8){
1756 fday = 9;
1757 } else {
1758 for(nday = 1, wday = (Weekday) fday; wday != day; wday = (wday+1) % 7, nday++)
1760 rv = fs_get(6*sizeof(int));
1761 memset((void *)&rv, 0, 6*sizeof(int));
1762 for(i = 0; nday <= month_len[month]; i++){
1763 rv[i] = nday;
1764 nday += 7;
1766 if(LEAP_YEAR(year) && month == 1 && nday == 29)
1767 rv[i] = nday;
1770 return rv;
1774 /* given a month and a year, return the weekday of the first of the
1775 * month in that year.
1776 * return value: on error -1, otherwise the day of the week.
1779 ical_first_of_month(int month, int year)
1781 int i, d;
1783 if((d = ical_january_first(year)) < 0)
1784 return -1;
1786 year += 1900;
1787 for(i = 0; i < month; i++)
1788 d += month_len[i];
1790 if(LEAP_YEAR(year) && month >= 2)
1791 d += 1;
1793 if(year == 1752 && month >= 9)
1794 d -= 11;
1796 return d % 7;
1799 /* given a day, month and year, return the weekday of that day
1800 * return value: on error -1, otherwise the day of the week.
1802 int ical_day_of_week(struct tm date)
1804 int d;
1806 if((d = ical_first_of_month(date.tm_mon, date.tm_year)) < 0)
1807 return -1;
1809 d += date.tm_mday - 1;
1811 if(date.tm_year + 1900 == 1752){
1812 if(date.tm_mday > 2 && date.tm_mday < 14)
1813 return -1;
1814 if(date.tm_mday >= 14)
1815 d -= 11;
1817 return d % 7;
1821 /* given an initial date dtstart, and a recurring rule, rrule,
1822 * adjust the date to the first date on the same year, when
1823 * the rule actually starts
1825 struct tm
1826 adjust_date_rrule(struct tm *dtstart, RRULE_S *rrule)
1828 struct tm t;
1830 memset((void *) &t, 0, sizeof(struct tm));
1831 t.tm_year = dtstart->tm_year; /* same year */
1832 if(rrule->prop[RRFreq]){
1834 if(rrule->prop[RRCount]){
1836 else if(rrule->prop[RRInterval]){
1838 if(rrule->prop[RRBysecond]){
1839 BYWKDY_S *sec = (BYWKDY_S *) rrule->prop[RRBysecond], *seco;
1840 for (seco = sec; seco != NULL; seco = seco->next)
1841 if(seco == sec) t.tm_sec = seco->value;
1842 else if (seco->value < t.tm_sec)
1843 t.tm_sec = seco->value;
1845 if (rrule->prop[RRByminute]){
1846 BYWKDY_S *sec = (BYWKDY_S *) rrule->prop[RRByminute], *seco;
1847 for (seco = sec; seco != NULL; seco = seco->next)
1848 if(seco == sec) t.tm_min = seco->value;
1849 else if (seco->value < t.tm_sec)
1850 t.tm_min = seco->value;
1852 if (rrule->prop[RRByhour]){
1853 BYWKDY_S *sec = (BYWKDY_S *) rrule->prop[RRByhour], *seco;
1854 for (seco = sec; seco != NULL; seco = seco->next)
1855 if(seco == sec) t.tm_hour = seco->value;
1856 else if (seco->value < t.tm_sec)
1857 t.tm_hour = seco->value;
1859 if (rrule->prop[RRByday]){
1861 if (rrule->prop[RRByweekno]){
1863 if (rrule->prop[RRBymonthday]){
1865 if (rrule->prop[RRByyearday]){
1867 if (rrule->prop[RRByweekno]){
1869 if (rrule->prop[RRBymonth]){
1870 BYWKDY_S *m = (BYWKDY_S *) rrule->prop[RRBymonth], *mo;
1871 for (mo = m; mo != NULL; mo = mo->next)
1872 if(mo == m) t.tm_mon = mo->value - 1;
1873 else if (mo->value - 1 < t.tm_mon)
1874 t.tm_mon = mo->value - 1;
1876 if (rrule->prop[RRBysetpos]){
1878 if (rrule->prop[RRWkst]){
1882 void
1883 ical_initialize(void)
1885 ical_buf_len = 1024;
1886 ical_buf = fs_get(ical_buf_len+1);
1888 memset((void *) &day_zero, 0, sizeof(struct tm));
1889 day_zero.tm_year = 1601 - 1900;
1890 day_zero.tm_mday = 1;
1891 day_zero.tm_wday = 4;
1894 /* we create a summary of the event, and pass that back as
1895 an ical parameter
1897 VEVENT_SUMMARY_S *
1898 ical_vevent_summary(VCALENDAR_S *vcal)
1900 VEVENT_SUMMARY_S *rv;
1901 ICLINE_S *method;
1902 VEVENT_S *vevent;
1903 GEN_ICLINE_S *gicl;
1904 ICLINE_S *icl;
1906 if(vcal == NULL) return NULL;
1908 method = vcal->method;
1909 vevent = (VEVENT_S *) vcal->comp[VEvent];
1911 if(vevent == NULL || vevent->prop == NULL)
1912 return NULL;
1914 rv = fs_get(sizeof(VEVENT_SUMMARY_S));
1915 memset((void *) rv, 0, sizeof(VEVENT_SUMMARY_S));
1917 if(method != NULL && !strucmp(method->value, "CANCEL"))
1918 rv->cancel++;
1920 if((icl = (ICLINE_S *) vevent->prop[EvPriority]) != NULL)
1921 rv->priority = atoi(icl->value);
1923 if((icl = (ICLINE_S *) vevent->prop[EvSummary]) != NULL)
1924 rv->summary = cpystr(icl->value ? icl->value : _("No Summary"));
1926 if((icl = (ICLINE_S *) vevent->prop[EvClass]) != NULL)
1927 rv->class = cpystr(icl->value ? icl->value : _("PUBLIC"));
1928 else
1929 rv->class = cpystr(_("PUBLIC"));
1931 if((icl = (ICLINE_S *) vevent->prop[EvOrganizer]) != NULL){
1932 char *cn, *sender, *address;
1933 ICAL_PARAMETER_S *param;
1935 cn = sender = address = NULL;
1936 for(param = icl->param; param != NULL; param = param->next)
1937 if(!strucmp(param->name, "CN"))
1938 cn = param->value;
1939 else if(!strucmp(param->name, "SENT-BY"))
1940 sender = param->value;
1942 if(sender != NULL){
1943 if(!struncmp(sender, "MAILTO:", 7))
1944 sender += 7;
1945 utf8_snprintf(tmp_20k_buf, SIZEOF_20KBUF, "<%s>", sender);
1946 rv->sender = cpystr(tmp_20k_buf);
1949 if((address = icl->value) != NULL){
1950 if(!struncmp(address, "MAILTO:", 7))
1951 address += 7;
1952 utf8_snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s<%s>",
1953 cn ? cn : "", cn ? " " : "",
1954 address ? address : _("Unknown address"));
1955 rv->organizer = cpystr(tmp_20k_buf);
1957 } /* end of if(organizer) */
1959 if((icl = (ICLINE_S *) vevent->prop[EvLocation]) != NULL)
1960 rv->location = cpystr(icl->value ? icl->value : _("Location undisclosed"));
1962 if((icl = (ICLINE_S *) vevent->prop[EvDtstart]) != NULL){
1963 struct tm ic_date;
1964 char tmp[200];
1965 memset((void *)&ic_date, 0, sizeof(struct tm));
1966 ical_parse_date(icl->value, &ic_date);
1967 ic_date.tm_wday = ical_day_of_week(ic_date);
1968 our_strftime(tmp, sizeof(tmp), "%a %x %I:%M %p", &ic_date);
1969 rv->evstart = cpystr(icl->value ? tmp : _("Unknown Start Date"));
1970 } /* end of if dtstart */
1972 if((icl = (ICLINE_S *) vevent->prop[EvDuration]) != NULL){
1973 int i, done = 0;
1974 ICAL_DURATION_S ic_d, icd2;
1975 if(ical_parse_duration(icl->value, &ic_d) == 0){
1976 char tmp[MAILTMPLEN+1];
1978 for(i = 1, icd2 = ic_d; icd2.next != NULL; icd2 = *icd2.next, i++);
1979 rv->duration = fs_get((i+1)*sizeof(char *));
1980 i = 0;
1982 do {
1983 tmp[0] = '\0';
1985 if(ic_d.weeks > 0)
1986 utf8_snprintf(tmp+strlen(tmp), MAILTMPLEN - strlen(tmp),
1987 "%d %s ", ic_d.weeks, ic_d.weeks == 1 ? _("week") : _("weeks"));
1988 if(ic_d.days > 0)
1989 utf8_snprintf(tmp+strlen(tmp), MAILTMPLEN - strlen(tmp),
1990 "%d %s ", ic_d.days, ic_d.days == 1 ? _("day") : _("days"));
1991 if(ic_d.hours > 0)
1992 utf8_snprintf(tmp+strlen(tmp), MAILTMPLEN - strlen(tmp),
1993 "%d %s ", ic_d.hours, ic_d.hours == 1 ? _("hour") : _("hours"));
1994 if(ic_d.minutes > 0)
1995 utf8_snprintf(tmp+strlen(tmp), MAILTMPLEN - strlen(tmp),
1996 "%d %s ", ic_d.minutes, ic_d.minutes == 1 ? _("minute") : _("minutes"));
1997 if(ic_d.seconds > 0)
1998 utf8_snprintf(tmp+strlen(tmp), MAILTMPLEN - strlen(tmp),
1999 "%d %s ", ic_d.seconds, ic_d.seconds == 1 ? _("second") : _("seconds"));
2001 tmp[MAILTMPLEN] = '\0';
2002 rv->duration[i++] = cpystr(tmp);
2004 if(ic_d.next != NULL)
2005 ic_d = *ic_d.next;
2006 else
2007 done++;
2008 } while (done == 0);
2009 rv->duration[i] = NULL;
2011 } /* end of DURATION */
2012 else if((icl = (ICLINE_S *) vevent->prop[EvDtend]) != NULL){
2013 struct tm ic_date;
2014 char tmp[200];
2016 memset((void *)&ic_date, 0, sizeof(struct tm));
2017 ical_parse_date(icl->value, &ic_date);
2018 ic_date.tm_wday = ical_day_of_week(ic_date);
2019 our_strftime(tmp, sizeof(tmp), "%a %x %I:%M %p", &ic_date);
2020 rv->evend = cpystr(icl->value ? tmp : _("Unknown End Date"));
2021 } /* end of if dtend */
2023 if((gicl = (GEN_ICLINE_S *) vevent->prop[EvAttendee]) != NULL){
2024 int nattendees, i;
2026 for(nattendees = 0; gicl != NULL; gicl = gicl->next, nattendees++);
2027 rv->attendee = fs_get((nattendees+1)*sizeof(char *));
2029 gicl = (GEN_ICLINE_S *) vevent->prop[EvAttendee];
2030 for(i = 0; gicl != NULL; gicl = gicl->next, i++){
2031 char *role, *partstat, *rsvp;
2032 char *cn, *mailto;
2033 ICAL_PARAMETER_S *param;
2035 icl = gicl->cline;
2036 role = partstat = rsvp = cn = mailto = NULL;
2037 for(param = icl->param; param != NULL; param = param->next){
2038 if(!strucmp(param->name, "ROLE")){
2039 if(!strucmp(param->value, "REQ-PARTICIPANT"))
2040 role = _("[Required]");
2041 else if(!strucmp(param->value, "OPT-PARTICIPANT"))
2042 role = _("[Optional]");
2043 else if(!strucmp(param->value, "NON-PARTICIPANT"))
2044 role = _("[Informed]");
2045 else if(!strucmp(param->value, "CHAIR"))
2046 role = _("[ Chair ]");
2047 else
2048 role = param->value;
2050 else if(!strucmp(param->name, "PARTSTAT")){
2051 if(!strucmp(param->value, "NEEDS-ACTION"))
2052 partstat = _("[Need-Reply]");
2053 else if(!strucmp(param->value, "ACCEPTED"))
2054 partstat = _("[ Accepted ]");
2055 else if(!strucmp(param->value, "DECLINED"))
2056 partstat = _("[ Declined ]");
2057 else if(!strucmp(param->value, "TENTATIVE"))
2058 partstat = _("[ Tentative]");
2059 else if(!strucmp(param->value, "DELEGATED"))
2060 partstat = _("[ Delegated]");
2061 else
2062 partstat = param->value;
2064 else if(!strucmp(param->name, "RSVP"))
2065 rsvp = param->value;
2066 else if(!strucmp(param->name, "CN"))
2067 cn = param->value;
2069 if(icl->value && !struncmp(icl->value, "MAILTO:", strlen("MAILTO:")))
2070 mailto = icl->value + 7; /* 7 = strlen("MAILTO:") */
2071 if(!strucmp(cn, mailto))
2072 cn = "";
2073 utf8_snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s%s%s%s<%s>",
2074 role && *role ? role : "",
2075 role && *role ? " " : "",
2076 partstat ? partstat : _("[Unknown Reply]"),
2077 partstat ? " " : "",
2078 cn && *cn ? cn : "",
2079 cn && *cn ? " " : "",
2080 mailto ? mailto : _("Unknown address"));
2081 rv->attendee[i] = cpystr(tmp_20k_buf);
2083 rv->attendee[i] = NULL;
2084 } /* end of ATTENDEES */
2086 if((icl = (ICLINE_S *) vevent->prop[EvDescription]) != NULL){
2087 char *s, *t, *u, *v;
2088 int i, escaped;
2090 if(icl->value == NULL){
2091 free_vevent_summary(&rv);
2092 return NULL;
2095 v = cpystr(icl->value); /* process a copy of icl->value */
2097 for(i = 1, escaped = 0, s = v; s && *s; s++){
2098 if(*s == '\\'){ escaped = 1; continue; }
2099 if(escaped){
2100 if(!(*s == '\\' || *s == ',' || *s == 'n' || *s == 'N' || *s == ';')){
2101 free_vevent_summary(&rv);
2102 fs_give((void **)&v);
2103 return NULL;
2105 escaped = 0;
2106 continue;
2108 if(*s == ',') i++; /* a non-scaped comma is a new value for text */
2111 rv->description = fs_get((i+1)*sizeof(char *));
2112 i = 0;
2113 for (s = t = u = v, escaped = 0; *t != '\0'; t++){
2114 if(*t == '\\'){ escaped = 1; continue; }
2115 if(escaped){
2116 switch(*t){
2117 case '\\':
2118 case ',':
2119 case ';':
2120 *u++ = *t;
2121 break;
2122 case 'n':
2123 case 'N':
2124 *u++ = '\n';
2125 break;
2126 default: free_vevent_summary(&rv);
2127 fs_give((void **)&v);
2128 return NULL;
2130 escaped = 0;
2131 continue;
2133 if(*t == ','){
2134 *u = '\0';
2135 rv->description[i++] = cpystr(s);
2136 s = u = t+1;
2137 } else
2138 *u++ = *t;
2140 *u = '\0';
2141 rv->description[i++] = cpystr(s);
2142 rv->description[i] = NULL;
2143 fs_give((void **)&v);
2144 } /* end of if(description) */
2146 return rv;
2149 void
2150 free_vevent_summary(VEVENT_SUMMARY_S **vesy)
2152 int i;
2153 if(vesy == NULL || *vesy == NULL) return;
2155 if((*vesy)->class) fs_give((void **)&(*vesy)->class);
2156 if((*vesy)->summary) fs_give((void **)&(*vesy)->summary);
2157 if((*vesy)->sender) fs_give((void **)&(*vesy)->sender);
2158 if((*vesy)->organizer) fs_give((void **)&(*vesy)->organizer);
2159 if((*vesy)->location) fs_give((void **)&(*vesy)->location);
2160 if((*vesy)->evstart) fs_give((void **)&(*vesy)->evstart);
2161 if((*vesy)->evend) fs_give((void **)&(*vesy)->evend);
2162 if((*vesy)->duration){
2163 for(i = 0; (*vesy)->duration[i] != NULL; i++)
2164 fs_give((void **) &(*vesy)->duration[i]);
2165 fs_give((void **) (*vesy)->duration);
2167 if((*vesy)->attendee){
2168 for(i = 0; (*vesy)->attendee[i] != NULL; i++)
2169 fs_give((void **) &(*vesy)->attendee[i]);
2170 fs_give((void **) (*vesy)->attendee);
2172 if((*vesy)->description){
2173 for(i = 0; (*vesy)->description[i] != NULL; i++)
2174 fs_give((void **) &(*vesy)->description[i]);
2175 fs_give((void **) (*vesy)->description);
2177 fs_give((void **) vesy);
2180 #ifdef STANDALONE
2181 void ical_print_line(ICLINE_S icl)
2183 ICAL_PARAMETER_S *p;
2184 printf("token=%s, ", icl.token);
2185 for(p = icl.param; p != NULL; p = p->next){
2186 if(p->name) printf("param->name=%s, ", p->name);
2187 if(p->value) printf("param->value=%s, ", p->value);
2189 printf("value=%s", icl.value);
2190 printf("%c", '\n');
2193 #define CRLFCOUNT 100
2195 char *lf2crlf(char *text)
2197 char *rv, *s;
2198 int i, len;
2200 if(text == NULL || *text == '\0')
2201 return NULL;
2203 len = strlen(text);
2204 rv = fs_get(len+1);
2206 for(i = 0, s = text; *s;){
2207 if(i == len - 1){
2208 len += CRLFCOUNT;
2209 fs_resize((void *)&rv, len);
2211 if(*s == '\n')
2212 rv[i++] = '\r';
2213 rv[i++] = *s++;
2215 rv[i] = '\0';
2216 fs_give((void **)&text);
2217 text = rv;
2219 return rv;
2222 int main (int argc, char *argv[])
2224 char *text;
2225 VCALENDAR_S *vcal;
2227 if(argc != 2){
2228 fprintf(stderr, "Only give one argument: File name to read\n");
2229 _exit(1);
2232 if(readfile(argv[1], &text, NULL) < 0){
2233 fprintf(stderr, "Can not read %s succesfully\n", argv[1]);
2234 _exit(2);
2237 text = lf2crlf(text);
2238 vcal = ical_parse_text(text);
2240 ical_free_vcalendar((void **)&vcal);
2241 return 0;
2245 #endif /* STANDALONE */