1 #include "../pith/headers.h"
2 #include "../pith/mailpart.h"
3 #include "../pith/store.h"
4 #include "../pith/string.h"
5 #include "../pith/ical.h"
7 typedef struct ical_iana_comp_s
{
8 char *comp
; /* component name */
9 size_t len
; /* size of component name (strlen(x->comp)) */
10 int pos
; /* position of this component in comp array */
11 void *(*parse
)(char **); /* parser */
12 void (*give
)(void **); /* free memory */
15 typedef struct ical_iana_prop_s
{
16 char *prop
; /* component PROPerty name */
17 size_t len
; /* size of component name (strlen(x->prop)) */
18 int pos
; /* location of this component in the prop array */
19 void *(*parse
)(); /* parser */
20 void (*give
)(void **); /* free memory */
23 int ical_january_first(int); /* args: year */
24 void ical_adjust_date(struct tm
*, VTIMEZONE_S
*);
26 void ical_initialize(void);
28 int ical_non_ascii_valid(unsigned char);
29 char *ical_unfold_line(char *);
30 ICLINE_S
*ical_parse_line(char **, char *);
32 ICLINE_S
*ical_cline_cpy(ICLINE_S
*);
33 ICAL_PARAMETER_S
*ical_parameter_cpy(ICAL_PARAMETER_S
*param
);
35 char *ical_get_value(char **);
36 unsigned char *ical_decode(char *, unsigned short);
39 void *ical_parse_vcalendar(char **);
40 void *ical_parse_vevent(char **);
41 void *ical_parse_vtodo(char **);
42 void *ical_parse_vjournal(char **);
43 void *ical_parse_vfreebusy(char **);
44 void *ical_parse_vtimezone(char **);
45 void *ical_parse_valarm(char **);
46 void *ical_parse_timezone(char **);
47 ICAL_S
*ical_parse_unknown_comp(char **, int);
48 ICAL_S
*ical_parse_generic_comp(char **, int);
51 void ical_free_vevent(void **);
52 void ical_free_vtodo(void **);
53 void ical_free_vjournal(void **);
54 void ical_free_vfreebusy(void **);
55 void ical_free_vtimezone(void **);
56 void ical_free_timezone(void **);
57 void ical_free_valarm(void **);
58 void ical_free_unknown_comp(ICAL_S
**);
60 /* parse properties */
61 void *ical_cline_from_token(void *, char **, char *);
62 void *ical_gencline_from_token(void *, char **, char *);
64 void *ical_parse_rrule(void *, char **, char *);
65 void *ical_parse_time(void *, char **, char *);
66 void *ical_parse_offset(void *, char **, char *);
68 void *ical_parse_freq(void *, char *);
69 void *ical_parse_until(void *, char *);
70 void *ical_parse_count(void *, char *);
71 void *ical_parse_interval(void *, char *);
72 void *ical_parse_weekday_list(void *, char *);
73 void *ical_parse_number_list(void *, char *);
75 int ical_get_number_value(char *, int, int);
76 void ical_set_date(ICLINE_S
*, VTIMEZONE_S
*);
77 void ical_set_date_vevent(void *, void *);
80 void ical_free_prop(void ***, ICAL_PROP_S
*, int);
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_fs_give(void **);
86 void ical_free_weekday_list(void **);
88 /* utility functions */
89 void ical_date_time (char *, size_t, struct tm
*);
90 char *ical_get_tzid(ICAL_PARAMETER_S
*);
93 struct tm day_zero
; /* date for january 1, 1601 */
94 int month_len
[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
96 #define UTF8_COMPLETE (1)
100 unsigned long ical_buf_len
;
103 /* parsing structures */
105 /* this is the list of V-components to a Calendar from RFC 5545 */
106 ICAL_COMP_S ical_comp
[] = {
107 {"VCALENDAR", 9, VCalendar
, ical_parse_vcalendar
, ical_free_vcalendar
},
108 {"VTIMEZONE", 9, VTimeZone
, ical_parse_vtimezone
, ical_free_vtimezone
},
109 {"VEVENT", 6, VEvent
, ical_parse_vevent
, ical_free_vevent
},
110 {"VTODO", 5, VTodo
, ical_parse_vtodo
, ical_free_vtodo
},
111 {"VJOURNAL", 8, VJournal
, ical_parse_vjournal
, ical_free_vjournal
},
112 {"VALARM", 6, VAlarm
, ical_parse_valarm
, ical_free_valarm
},
113 {"VFREEBUSY", 9, VFreeBusy
, ical_parse_vfreebusy
, ical_free_vfreebusy
},
114 {NULL
, 0, VUnknown
, NULL
, 0}
117 /* array for properties */
118 ICAL_PROP_S rrule_prop
[] = {
119 {"FREQ", 4, RRFreq
, ical_parse_freq
, ical_fs_give
},
120 {"UNTIL", 5, RRUntil
, ical_parse_until
, ical_fs_give
},
121 {"COUNT", 5, RRCount
, ical_parse_count
, ical_fs_give
},
122 {"INTERVAL", 8, RRInterval
, ical_parse_interval
, ical_fs_give
},
123 {"BYSECOND", 8, RRBysecond
, ical_parse_number_list
, ical_free_weekday_list
},
124 {"BYMINUTE", 8, RRByminute
, ical_parse_number_list
, ical_free_weekday_list
},
125 {"BYHOUR", 6, RRByhour
, ical_parse_number_list
, ical_free_weekday_list
},
126 {"BYDAY", 5, RRByday
, ical_parse_weekday_list
,ical_free_weekday_list
},
127 {"BYWEEKNO", 8, RRByweekno
, 0, 0},
128 {"BYMONTH", 7, RRBymonth
, ical_parse_number_list
, ical_free_weekday_list
},
129 {"BYSETPOS", 8, RRBysetpos
, 0, 0},
130 {"BYWKST", 6, RRWkst
, 0, 0},
132 10, RRBymonthday
, 0, 0},
133 {"BYYEARDAY", 9, RRByyearday
, 0, 0},
134 {NULL
, 0, RRUnknown
, 0, 0}
137 ICAL_PROP_S event_prop
[] = {
138 {"DTSTAMP", 7, EvDtstamp
, ical_cline_from_token
, ical_free_cline
},
139 {"UID", 3, EvUid
, ical_cline_from_token
, ical_free_cline
},
140 {"DTSTART", 7, EvDtstart
, ical_cline_from_token
, ical_free_cline
},
141 {"CLASS", 5, EvClass
, ical_cline_from_token
, ical_free_cline
},
142 {"CREATED", 7, EvCreated
, ical_cline_from_token
, ical_free_cline
},
143 {"DESCRIPTION", 11, EvDescription
, ical_cline_from_token
, ical_free_cline
},
144 {"GEO", 3, EvGeo
, ical_cline_from_token
, ical_free_cline
},
145 {"LASTMOD", 7, EvLastMod
, ical_cline_from_token
, ical_free_cline
},
146 {"LOCATION", 8, EvLocation
, ical_cline_from_token
, ical_free_cline
},
147 {"ORGANIZER", 9, EvOrganizer
, ical_cline_from_token
, ical_free_cline
},
148 {"PRIORITY", 8, EvPriority
, ical_cline_from_token
, ical_free_cline
},
149 {"SEQUENCE", 8, EvSequence
, ical_cline_from_token
, ical_free_cline
},
150 {"STATUS", 6, EvStatus
, ical_cline_from_token
, ical_free_cline
},
151 {"SUMMARY", 7, EvSummary
, ical_cline_from_token
, ical_free_cline
},
152 {"TRANSP", 6, EvTransp
, ical_cline_from_token
, ical_free_cline
},
153 {"URL", 3, EvUrl
, ical_cline_from_token
, ical_free_cline
},
154 {"RECURRENCE-ID", 13, EvRecurrence
, ical_cline_from_token
, ical_free_cline
},
155 {"RRULE", 5, EvRrule
, ical_parse_rrule
, ical_free_rrule
},
156 {"DTEND", 5, EvDtend
, ical_cline_from_token
, ical_free_cline
},
157 {"DURATION", 8, EvDuration
, ical_cline_from_token
, ical_free_cline
},
158 {"ATTACH", 6, EvAttach
, ical_gencline_from_token
, ical_free_gencline
},
159 {"ATTENDEE", 8, EvAttendee
, ical_gencline_from_token
, ical_free_gencline
},
160 {"CATEGORIES", 10, EvCategories
, ical_gencline_from_token
, ical_free_gencline
},
161 {"COMMENT", 7, EvComment
, ical_gencline_from_token
, ical_free_gencline
},
162 {"CONTACT", 7, EvContact
, ical_gencline_from_token
, ical_free_gencline
},
163 {"EXDATE", 6, EvExdate
, ical_gencline_from_token
, ical_free_gencline
},
164 {"RSTATUS", 7, EvRstatus
, ical_gencline_from_token
, ical_free_gencline
},
165 {"RELATED", 7, EvRelated
, ical_gencline_from_token
, ical_free_gencline
},
166 {"RESOURCES", 9, EvResources
, ical_gencline_from_token
, ical_free_gencline
},
167 {"RDATE", 5, EvRdate
, ical_gencline_from_token
, ical_free_gencline
},
168 {NULL
, 0, EvUnknown
, 0, 0}
171 ICAL_PROP_S tz_comp
[] = {
172 {"TZID", 4, TZCid
, ical_cline_from_token
, ical_free_cline
},
173 {"LAST-MODIFIED", 13, TZCLastMod
, ical_cline_from_token
, ical_free_cline
},
174 {"TZURL", 5, TZCUrl
, ical_cline_from_token
, ical_free_cline
},
175 {NULL
, 0, TZCUnknown
, 0, 0}
178 ICAL_PROP_S tz_prop
[] = {
179 {"DTSTART", 7, TZPDtstart
, ical_parse_time
, ical_fs_give
},
180 {"TZOFFSETTO", 10, TZPOffsetto
, ical_parse_offset
, ical_fs_give
},
181 {"TZOFFSETFROM", 12, TZPOffsetfrom
, ical_parse_offset
, ical_fs_give
},
182 {"RRULE", 5, TZPRrule
, ical_parse_rrule
, ical_free_rrule
},
183 {"COMMENT", 7, TZPComment
, ical_gencline_from_token
, ical_free_gencline
},
184 {"RDATE", 5, TZPRdate
, ical_gencline_from_token
, ical_free_gencline
},
185 {"TZNAME", 6, TZPTzname
, ical_gencline_from_token
, ical_free_gencline
},
186 {NULL
, 0, TZPUnknown
, 0, 0}
189 ICAL_PROP_S alarm_prop
[] = {
190 {"ACTION", 6, AlAction
, ical_cline_from_token
, ical_free_cline
},
191 {"TRIGGER", 7, AlTrigger
, ical_cline_from_token
, ical_free_cline
},
192 {"DURATION", 8, AlDuration
, ical_cline_from_token
, ical_free_cline
},
193 {"REPEAT", 6, AlRepeat
, ical_cline_from_token
, ical_free_cline
},
194 {"DESCRIPTION", 11, AlDescription
, ical_cline_from_token
, ical_free_cline
},
195 {"SUMMARY", 7, AlSummary
, ical_cline_from_token
, ical_free_cline
},
196 {"ATTACH", 6, AlAttach
, ical_gencline_from_token
, ical_free_gencline
},
197 {"ATTENDEE", 8, AlAttendee
, ical_gencline_from_token
, ical_free_gencline
},
198 {NULL
, 0, AlUnknown
, 0, 0}
201 /* some useful macros for character analysis */
203 #define ical_wspace(X) \
204 ((X) == ' ' || (X) == '\t')
206 #define ical_name_allowed_char(X) \
207 (((X) >= 'A' && (X) <= 'Z') || \
208 ((X) >= 'a' && (X) <= 'z') || \
211 #define ical_control(X) \
212 (((X) >= 0x00 && (X) <= 0x08) || \
213 ((X) >= 0x0A && (X) <= 0x1F) || \
216 #define ical_safe_char(X) \
217 (ical_non_ascii_valid(X) \
220 || ((X) >= 0x23 && (X) <= 0x2B) \
221 || ((X) >= 0x2D && (X) <= 0x39) \
222 || ((X) >= 0x3C && (X) <= 0x7E))
224 #define ical_qsafe_char(X) \
225 (ical_non_ascii_valid((X)) \
228 || ((X) >= 0x23 && (X) <= 0x7E))
230 #define ical_value_char(X) \
231 (ical_non_ascii_valid(X) \
233 || ((X) >= 0x21 && (X) <= 0x7E))
235 /* Finally, here begins the code. */
238 ical_decode(char *text
, unsigned short encoding
)
241 unsigned long callen
;
243 if(encoding
== ENCQUOTEDPRINTABLE
){
244 t
= rfc822_qprint ((unsigned char *) text
,strlen(text
),&callen
);
246 tlen
= strlen(text
) + 1;
247 strncpy(text
, (char *) t
, tlen
);
248 text
[tlen
- 1] = '\0';
249 fs_give((void **) &t
);
252 return (unsigned char *) text
;
258 -1 - if an error occurred
259 Args: a pointer to the text. If there is an error, the text is not modified.
262 ical_remove_escapes(char **textp
)
269 if(textp
== NULL
) return 0;
271 t
= cpystr(*textp
); /* work on a copy of the text */
272 tlen
= strlen(*textp
) + 1; /* and record its size */
273 /* the variable text below points to the beginning of the filtered text */
274 for (text
= s
= t
, escaped
= 0; rv
== 0 && *s
!= '\0'; s
++){
275 if(*s
== '\\' && escaped
== 0){
298 *t
= '\0'; /* tie off filtered text */
299 t
= text
; /* reset t to the beginning */
301 strncpy(*textp
, t
, tlen
); /* overwrite given text with filtered text */
302 (*textp
)[tlen
- 1] = '\0';
304 fs_give((void **) &t
);
309 ical_debug(char *fcn
, char *text
)
312 strncpy(piece
, text
, 49);
313 piece
[sizeof(piece
)-1] = '\0';
314 dprint((2, "%s: %s\n", fcn
, piece
));
318 *** FREE MEMORY FUNCTIONS
322 ical_free_param(ICAL_PARAMETER_S
**param
)
324 if(param
== NULL
|| *param
== NULL
)
327 if((*param
)->name
) fs_give((void **) &(*param
)->name
);
328 if((*param
)->value
) fs_give((void **) &(*param
)->value
);
329 if((*param
)->next
) ical_free_param(&(*param
)->next
);
330 fs_give((void **)param
);
334 ical_free_cline(void **icv
)
336 ICLINE_S
**ic
= (ICLINE_S
**) icv
;
338 if(ic
== NULL
|| *ic
== NULL
)
341 if((*ic
)->token
) fs_give((void **) &(*ic
)->token
);
342 if((*ic
)->param
) ical_free_param(&(*ic
)->param
);
343 if((*ic
)->value
) fs_give((void **) &(*ic
)->value
);
348 ical_free_gencline(void **giclpv
)
350 GEN_ICLINE_S
**giclp
= (GEN_ICLINE_S
**) giclpv
;
352 if(giclp
== NULL
|| *giclp
== NULL
) return;
354 if((*giclp
)->cline
) ical_free_cline((void **) &(*giclp
)->cline
);
355 if((*giclp
)->next
) ical_free_gencline((void **) &(*giclp
)->next
);
356 fs_give((void **)giclp
);
360 ical_free_vcalendar(void **vcalpv
)
362 VCALENDAR_S
**vcalp
= (VCALENDAR_S
**)vcalpv
;
364 if(vcalp
== NULL
|| *vcalp
== NULL
) return;
366 if((*vcalp
)->prodid
) ical_free_cline((void **) &(*vcalp
)->prodid
);
367 if((*vcalp
)->version
) ical_free_cline((void **) &(*vcalp
)->version
);
368 if((*vcalp
)->calscale
) ical_free_cline((void **) &(*vcalp
)->calscale
);
369 if((*vcalp
)->method
) ical_free_cline((void **) &(*vcalp
)->method
);
370 if((*vcalp
)->uk_prop
) ical_free_gencline((void **) &(*vcalp
)->uk_prop
);
373 for(i
= 0; i
< VUnknown
; i
++)
374 if((*vcalp
)->comp
[i
]) (ical_comp
[i
].give
)(&(*vcalp
)->comp
[i
]);
375 fs_give((void **) &(*vcalp
)->comp
);
377 if((*vcalp
)->uk_comp
) ical_free_unknown_comp(&(*vcalp
)->uk_comp
);
382 ical_free_vevent(void **veventpv
)
384 VEVENT_S
**veventp
= (VEVENT_S
**) veventpv
;
386 if(veventp
== NULL
|| *veventp
== NULL
) return;
388 ical_free_prop(&(*veventp
)->prop
, event_prop
, EvUnknown
);
389 if((*veventp
)->uk_prop
) ical_free_gencline((void **) &(*veventp
)->uk_prop
);
390 if((*veventp
)->valarm
) ical_free_valarm((void **) &(*veventp
)->valarm
);
391 if((*veventp
)->next
) ical_free_vevent((void **) &(*veventp
)->next
);
396 ical_fs_give(void **x
)
398 if(x
!= NULL
&& *x
!= NULL
)
403 ical_free_rrule(void **rrulepv
)
405 RRULE_S
**rrulep
= (RRULE_S
**) rrulepv
;
407 if(rrulep
&& *rrulep
){
408 ical_free_prop(&(*rrulep
)->prop
, rrule_prop
, RRUnknown
);
409 ical_free_param(&(*rrulep
)->param
);
415 ical_free_weekday_list(void **wkdylv
)
417 BYWKDY_S
**wkdyl
= (BYWKDY_S
**) wkdylv
;
419 if(wkdyl
== NULL
) return;
422 ical_free_weekday_list((void **) &(*wkdyl
)->next
);
429 ical_free_vtodo(void **vtodopv
)
434 ical_free_vjournal(void **vjournalpv
)
439 ical_free_vfreebusy(void **vfbpv
)
444 ical_free_prop(void ***propv
, ICAL_PROP_S
*aux_comp
, int max
)
448 if(propv
== NULL
|| *propv
== NULL
) return;
450 for(i
= 0; i
< max
; i
++)
452 for(j
= 0; aux_comp
[j
].prop
!= NULL
&& aux_comp
[j
].pos
!= i
; j
++);
453 if(aux_comp
[j
].give
) (aux_comp
[j
].give
)(&(*propv
)[i
]);
455 fs_give((void **) propv
);
460 ical_free_vtimezone(void **vtzpv
)
462 VTIMEZONE_S
**vtzp
= (VTIMEZONE_S
**) vtzpv
;
464 if(vtzp
== NULL
|| *vtzp
== NULL
) return;
466 ical_free_prop(&(*vtzp
)->prop
, tz_comp
, TZCUnknown
);
467 if((*vtzp
)->uk_prop
) ical_free_gencline((void **) &(*vtzp
)->uk_prop
);
468 if((*vtzp
)->standardc
) ical_free_timezone((void **) &(*vtzp
)->standardc
);
469 if((*vtzp
)->daylightc
) ical_free_timezone((void **) &(*vtzp
)->daylightc
);
474 ical_free_timezone(void **tzpv
)
476 ICAL_TZPROP_S
**tzp
= (ICAL_TZPROP_S
**) tzpv
;
478 if(tzp
== NULL
|| *tzp
== NULL
) return;
480 ical_free_prop(&(*tzp
)->prop
, tz_prop
, TZPUnknown
);
481 if((*tzp
)->uk_prop
) ical_free_gencline((void **) &(*tzp
)->uk_prop
);
482 if((*tzp
)->next
) ical_free_timezone((void **) &(*tzp
)->next
);
487 ical_free_valarm(void **valarmpv
)
489 VALARM_S
**valarmp
= (VALARM_S
**) valarmpv
;
491 if(valarmp
== NULL
|| *valarmp
== NULL
) return;
493 ical_free_prop(&(*valarmp
)->prop
, alarm_prop
, AlUnknown
);
494 if((*valarmp
)->uk_prop
) ical_free_gencline((void **) &(*valarmp
)->uk_prop
);
495 if((*valarmp
)->next
) ical_free_timezone((void **) &(*valarmp
)->next
);
500 ical_free_unknown_comp(ICAL_S
**icalp
)
503 if(icalp
== NULL
|| *icalp
== NULL
) return;
504 for(i
= 0; ical_comp
[i
].comp
&& strucmp((*icalp
)->comp
,ical_comp
[i
].comp
); i
++);
505 if(ical_comp
[i
].give
)
506 (ical_comp
[i
].give
)(&(*icalp
)->value
);
508 ical_free_gencline((void **) &(*icalp
)->value
);
509 fs_give((void **)&(*icalp
)->comp
);
510 ical_free_unknown_comp(&(*icalp
)->next
);
511 ical_free_unknown_comp(&(*icalp
)->branch
);
512 fs_give((void **)icalp
);
516 ical_unfold_line(char *line
)
523 for(i
= 0, j
= 0; line
[j
] != '\0';)
525 case '\r': if(line
[j
+1] == '\n' && ical_wspace(line
[j
+2])){
526 j
+= 3; /* get past white space */
529 case '\n': if(ical_wspace(line
[j
+1])){
530 j
+= 2; /* get past white space */
533 default : line
[i
++] = line
[j
++];
540 ical_get_parameter(char **line
)
542 ICAL_PARAMETER_S
*param
= NULL
;
545 if(line
== NULL
|| *line
== NULL
)
548 for(s
= *line
; s
&& *s
&& ical_name_allowed_char(*s
) ; s
++);
554 param
= fs_get(sizeof(ICAL_PARAMETER_S
));
555 memset((void *)param
, 0, sizeof(ICAL_PARAMETER_S
));
557 param
->name
= cpystr(*line
);
559 *line
= s
+1; /* step over '=' */
560 quoted
= **line
== '"' ? 1 : 0;
562 for(s
= ++*line
; s
&& *s
&& ical_qsafe_char((unsigned char) *s
); s
++);
563 if(*s
!= '"'){ /* error, do not parse this line */
564 ical_free_param(¶m
);
565 *line
= strchr(s
, ':'); /* reset line to closest ':' */
570 for(s
= *line
; s
&& *s
&& (ical_safe_char((unsigned char) *s
)); s
++);
573 param
->value
= cpystr(*line
);
574 *s
= c
; /* restore character */
575 *line
= quoted
? s
+ 1 : s
;
579 param
->next
= ical_get_parameter(line
);
586 ical_get_value(char **line
)
590 if(line
== NULL
|| *line
== NULL
)
593 for (s
= *line
; *s
&& ical_value_char((unsigned char) *s
); s
++);
602 s
= strchr(*line
, '\r');
610 ical_parameter_cpy(ICAL_PARAMETER_S
*param
)
612 ICAL_PARAMETER_S
*rv
;
614 if(param
== NULL
) return NULL
;
616 rv
= fs_get(sizeof(ICAL_PARAMETER_S
));
617 memset((void *)rv
, 0, sizeof(ICAL_PARAMETER_S
));
619 if(param
->name
) rv
->name
= cpystr(param
->name
);
620 if(param
->value
) rv
->value
= cpystr(param
->value
);
621 if(param
->next
) rv
->next
= ical_parameter_cpy(param
->next
);
627 ical_cline_cpy(ICLINE_S
*icl
)
634 rv
= fs_get(sizeof(ICLINE_S
));
635 memset((void *)rv
, 0, sizeof(ICLINE_S
));
637 if(icl
->token
) rv
->token
= cpystr(icl
->token
);
638 if(icl
->param
) rv
->param
= ical_parameter_cpy(icl
->param
);
639 if(icl
->value
) rv
->value
= cpystr(icl
->value
);
644 /* Given a \r\n-ending line (called *text), isolate the occurrence
645 * of the token in that line.
646 * Return the token, and modify the pointer to *text to point to the
647 * end of the token. Modify sep to contain the character following
649 * ical-line = token ':'/';' rest of the line\r\n
650 * on error return null, and set *text to the next line, if possible.
653 ical_isolate_token(char **text
, char *sep
)
657 for(t
= s
= *text
; *t
&& ical_name_allowed_char(*s
); s
++);
658 /* only followed by parameter or value */
659 if(*s
== ':' || *s
== ';'){
661 *s
= '\0'; /* isolate token at pointer s */
664 else{ /* bad data - bail out of here */
666 if(*s
== '\0' || (s
= strstr(s
, "\r\n")) == NULL
)
668 else /* move to next line */
676 ical_parse_text(char *text
)
679 VCALENDAR_S
*vcal
= NULL
;
681 ical_debug("ical_parse_text", text
);
684 text
= ical_unfold_line(text
);
685 for(s
= text
; s
&& *s
!= '\0'; s
++){
686 if(*s
!= 'B' && *s
!= 'b')
688 if(!struncmp(s
+1, "EGIN:VCALENDAR\r\n", 16)){
689 s
+= 17; /* 17 = strlen("BEGIN:VCALENDAR\r\n") */
690 vcal
= (VCALENDAR_S
*) ical_parse_vcalendar(&s
);
698 ical_parse_time(void *ic_datep
, char **text
, char *token
)
703 datep
= fs_get(sizeof(struct tm
));
704 icl
= ical_parse_line(text
, token
);
705 ical_parse_date(icl
->value
, datep
);
706 ical_free_cline((void **) &icl
);
707 ic_datep
= (void *) datep
;
713 ical_parse_interval(void *longvp
, char *value
)
716 unsigned long *longp
;
718 longp
= fs_get(sizeof(unsigned long));
719 *longp
= atoi(value
);
720 longvp
= (void *) longp
;
727 ical_parse_offset(void *offsetv
, char **text
, char *token
)
733 offset
= fs_get(sizeof(int));
735 icl
= ical_parse_line(text
, token
);
737 if(*icl
->value
== '+' || *icl
->value
== '-')
738 value
= icl
->value
+ 1;
742 h
= ical_get_number_value(value
, 0, 2);
743 m
= ical_get_number_value(value
, 2, 4);
745 *offset
= 60*(60*h
+ m
);
746 if(*icl
->value
== '-')
749 ical_free_cline((void **) &icl
);
750 offsetv
= (void *) offset
;
755 /* This function processes the information in *text, and returns
756 * a pointer to the information in iclp, but only if iclp is NULL
757 * otherwise, it simply returns the current value and advances the
759 * Call this function as follows
760 * rv = (cast here *) ical_cline_from_token((void *)rv, &text, token);
763 ical_cline_from_token(void *iclp
, char **text
, char *token
)
767 ical_debug("ical_cline_from_token", *text
);
769 icl
= ical_parse_line(text
, token
);
772 ical_free_cline((void **)&icl
);
780 ical_gencline_from_token(void *giclv
, char **text
, char *token
)
782 GEN_ICLINE_S
*gicl
= NULL
;
784 if(!struncmp(*text
, token
, strlen(token
))){
785 gicl
= fs_get(sizeof(GEN_ICLINE_S
));
786 memset((void *) gicl
, 0, sizeof(GEN_ICLINE_S
));
787 gicl
->cline
= ical_parse_line(text
, token
);
788 // gicl->line = (ICLINE_S *) ical_cline_from_token((void *) gicl->cline, text, token);
789 gicl
->next
= (GEN_ICLINE_S
*) ical_gencline_from_token((void *) gicl
->next
, text
, token
);
793 ical_free_gencline((void **) &gicl
);
795 giclv
= (void *) gicl
;
801 *** PARSE COMPONENT FUNCTIONS
805 ical_parse_vcalendar(char **text
)
812 dprint((9, "ical_parse_vcalendar:\n"));
813 ical_debug("ical_parse_vcalendar", *text
);
815 vcal
= fs_get(sizeof(VCALENDAR_S
));
816 memset((void *) vcal
, 0, sizeof(VCALENDAR_S
));
818 /* s must always point the the beginning of a line */
819 for(s
= *text
; s
&& *s
!= '\0';){
821 s
= ical_isolate_token(&t
, &c
);
828 *t
= c
; /* restore character */
829 if(s
){ /* figure out the token */
830 int ukn
= 0; /* unknown token */
834 case 'b': if(!struncmp(s
+1, "EGIN", 4)){
835 s
+= 6; /* 6 = strlen("BEGIN:") */
836 for(i
= 0; ical_comp
[i
].comp
837 && (struncmp(s
, ical_comp
[i
].comp
, ical_comp
[i
].len
)
838 || struncmp(s
+ ical_comp
[i
].len
, "\r\n", 2)); i
++);
840 if(ical_comp
[i
].parse
){
841 s
+= ical_comp
[i
].len
+ 2;
842 v
= (ical_comp
[i
].parse
)(&s
);
843 if(vcal
->comp
== NULL
){
844 vcal
->comp
= fs_get((VUnknown
+1)*sizeof(void *));
845 memset((void *) vcal
->comp
, 0, (VUnknown
+1)*sizeof(void *));
848 if(vcal
->comp
[ical_comp
[i
].pos
] == NULL
)
849 vcal
->comp
[ical_comp
[i
].pos
] = v
;
851 if((vcal
->method
&& vcal
->method
->value
852 && strucmp(vcal
->method
->value
, "PUBLISH"))
853 || struncmp(ical_comp
[i
].comp
, "VEVENT", 6))
854 (ical_comp
[i
].give
)(&v
);
856 VEVENT_S
*vevent
= (VEVENT_S
*) vcal
->comp
[VEvent
];
857 for(; vevent
&& vevent
->next
; vevent
= vevent
->next
);
862 v
= (void *) ical_parse_unknown_comp(&s
, 0);
863 if(vcal
->uk_comp
== NULL
)
864 vcal
->uk_comp
= (ICAL_S
*) v
;
867 for(ic
= vcal
->uk_comp
; ic
&& ic
->branch
; ic
= ic
->branch
);
868 ic
->branch
= (ICAL_S
*) v
;
875 case 'c': if(!struncmp(s
+1, "ALSCALE", 7)){
876 v
= (void *) vcal
->calscale
;
877 v
= ical_cline_from_token(v
, &s
, "CALSCALE");
878 vcal
->calscale
= (ICLINE_S
*) v
;
884 case 'e': if(!struncmp(s
+1, "ND", 2)){
886 s
+= 4; /* 4 = strlen("END:") */
887 if(!struncmp(s
, "VCALENDAR\r\n", 11)){
888 *text
= s
+ 11; /* 11 = strlen("VCALENDAR\r\n") */
889 return (void *) vcal
;
891 // else ukn++; FIX THIS, this is not quite right
896 case 'm': if(!struncmp(s
+1, "ETHOD", 5)){
897 v
= (void *) vcal
->method
;
898 v
= ical_cline_from_token(v
, &s
, "METHOD");
899 vcal
->method
= (ICLINE_S
*) v
;
905 case 'p': if(!struncmp(s
+1, "RODID", 5)){
906 v
= (void *) vcal
->prodid
;
907 v
= ical_cline_from_token(v
, &s
, "PRODID");
908 vcal
->prodid
= (ICLINE_S
*) v
;
914 case 'v': if(!struncmp(s
+1, "ERSION", 6)){
915 v
= (void *) vcal
->version
;
916 v
= ical_cline_from_token(v
, &s
, "VERSION");
917 vcal
->version
= (ICLINE_S
*) v
;
923 } /* end of switch(*s) */
925 if(ical_buf_len
< t
- s
){
926 fs_resize((void **)&ical_buf
, t
-s
+1);
932 if(vcal
->uk_prop
== NULL
){
933 vcal
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
934 memset((void *)vcal
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
935 vcal
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
939 for (gcl
= vcal
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
940 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
941 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
942 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
950 /* ok, we have parsed the vcalendar, now parse some special properties */
951 /* start by parsing dates */
952 ical_set_date_vevent(vcal
->comp
[VEvent
], vcal
->comp
[VTimeZone
]);
953 return (void *) vcal
;
957 ical_parse_vevent(char **text
)
963 ical_debug("ical_parse_vevent", *text
);
964 vevent
= fs_get(sizeof(VEVENT_S
));
965 memset((void *)vevent
, 0, sizeof(VEVENT_S
));
967 /* s must always point the the beginning of a line */
968 for(s
= *text
; s
&& *s
!= '\0';){
970 s
= ical_isolate_token(&t
, &c
);
976 *t
= c
; /* restore separator */
978 if(s
){ /* figure out the token */
979 int ukn
= 0; /* unknown token */
980 if(!struncmp(s
, "BEGIN", 5)){
981 s
+= 6; /* 6 = strlen("BEGIN:") */
982 if(!struncmp(s
, "VALARM\r\n", 8)){
983 s
+= 8; /* 8 = strlen("VALARM\r\n"); */
984 if(vevent
->valarm
== NULL
)
985 vevent
->valarm
= ical_parse_valarm(&s
);
988 for(valrm
= vevent
->valarm
; valrm
&& valrm
->next
;
989 valrm
= valrm
->next
);
990 valrm
->next
= ical_parse_valarm(&s
);
993 ICAL_S
*uk_comp
= ical_parse_unknown_comp(&s
, 0);
994 ical_free_unknown_comp(&uk_comp
);
996 } else if(!struncmp(s
, "END", t
-s
-1)){
997 s
+= 4; /* 4 = strlen("END:") */
998 if(!struncmp(s
, "VEVENT\r\n",8)){
999 *text
= s
+ 8; /* 8 = strlen("VCALENDAR\r\n") */
1000 return (void *) vevent
;
1002 } else{ Event_prop i
;
1003 for(i
= 0; i
< EvUnknown
; i
++)
1004 if(!struncmp(s
, event_prop
[i
].prop
, t
-s
))
1006 if(event_prop
[i
].parse
){
1008 if(vevent
->prop
== NULL
){
1009 vevent
->prop
= fs_get((EvUnknown
+1)*sizeof(void *));
1010 memset((void *)vevent
->prop
, 0, (EvUnknown
+1)*sizeof(void *));
1012 v
= vevent
->prop
[event_prop
[i
].pos
];
1013 v
= (event_prop
[i
].parse
)(v
, &s
, event_prop
[i
].prop
);
1014 vevent
->prop
[event_prop
[i
].pos
] = v
;
1021 if(ical_buf_len
< t
- s
){
1022 fs_resize((void **)&ical_buf
, t
-s
+1);
1026 strcpy(ical_buf
, s
);
1028 if(vevent
->uk_prop
== NULL
){
1029 vevent
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
1030 memset((void *)vevent
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
1031 vevent
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
1035 for (gcl
= vevent
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
1036 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1037 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1038 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1041 } /* end of if(s) */
1045 return (void *) vevent
;
1049 ical_parse_vtimezone(char **text
)
1056 ical_debug("ical_parse_vtimezone", *text
);
1057 vtz
= fs_get(sizeof(VTIMEZONE_S
));
1058 memset((void *)vtz
, 0, sizeof(VTIMEZONE_S
));
1060 /* s must always point the the beginning of a line */
1061 for(s
= *text
; s
&& *s
!= '\0';){
1063 s
= ical_isolate_token(&t
, &c
);
1069 *t
= c
; /* restore separator */
1071 if(s
){ /* figure out the token */
1072 int ukn
= 0; /* unknown token */
1073 if(!struncmp(s
, "BEGIN", 5)){
1074 s
+= 6; /* 6 = strlen("BEGIN:") */
1075 if(!struncmp(s
, "STANDARD\r\n", 10)){
1076 s
+= 10; /* 10 = strlen("STANDARD\r\n"); */
1077 v
= ical_parse_timezone(&s
);
1078 if(vtz
->standardc
== NULL
)
1079 vtz
->standardc
= (ICAL_TZPROP_S
*) v
;
1082 for(dl
= vtz
->standardc
; dl
&& dl
->next
; dl
= dl
->next
);
1083 dl
->next
= (ICAL_TZPROP_S
*) v
;
1085 } else if(!struncmp(s
, "DAYLIGHT\r\n", 10)){
1086 s
+= 10; /* 10 = strlen("DAYLIGHT\r\n"); */
1087 v
= ical_parse_timezone(&s
);
1088 if(vtz
->daylightc
== NULL
)
1089 vtz
->daylightc
= (ICAL_TZPROP_S
*) v
;
1092 for(dl
= vtz
->daylightc
; dl
&& dl
->next
; dl
= dl
->next
);
1093 dl
->next
= (ICAL_TZPROP_S
*) v
;
1096 ICAL_S
*uk_comp
= ical_parse_unknown_comp(&s
, 0);
1097 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
, "VTIMEZONE\r\n",11)){
1102 *text
= s
+ 11; /* 11 = strlen("VTIMEZONE\r\n") */
1103 return (void *) vtz
;
1106 for(i
= 0; i
< TZCUnknown
; i
++)
1107 if(!struncmp(s
, tz_comp
[i
].prop
, t
-s
))
1109 if(tz_comp
[i
].parse
){
1111 if(vtz
->prop
== NULL
){
1112 vtz
->prop
= fs_get(TZCUnknown
*sizeof(void *));
1113 memset((void *)vtz
->prop
, 0, TZCUnknown
*sizeof(void *));
1115 v
= vtz
->prop
[tz_comp
[i
].pos
];
1116 v
= (tz_comp
[i
].parse
)(v
, &s
, tz_comp
[i
].prop
);
1117 vtz
->prop
[tz_comp
[i
].pos
] = v
;
1124 if(ical_buf_len
< t
- s
){
1125 fs_resize((void **)&ical_buf
, t
-s
+1);
1129 strcpy(ical_buf
, s
);
1131 if(vtz
->uk_prop
== NULL
){
1132 vtz
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
1133 memset((void *)vtz
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
1134 vtz
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
1138 for (gcl
= vtz
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
1139 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1140 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1141 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1144 } /* end of if(s) */
1148 return (void *) vtz
;
1152 ical_parse_timezone(char **text
)
1156 ICAL_TZPROP_S
*tzprop
;
1158 ical_debug("ical_parse_timezone", *text
);
1159 tzprop
= fs_get(sizeof(ICAL_TZPROP_S
));
1160 memset((void *)tzprop
, 0, sizeof(ICAL_TZPROP_S
));
1162 /* s must always point the the beginning of a line */
1163 for(s
= *text
; s
&& *s
!= '\0';){
1165 s
= ical_isolate_token(&t
, &c
);
1171 *t
= c
; /* restore separator */
1173 if(s
){ /* figure out the token */
1174 int ukn
= 0; /* unknown token */
1175 if(!struncmp(s
, "BEGIN", 5)){
1177 s
+= 6; /* 6 = strlen("BEGIN:") */
1178 uk_comp
= ical_parse_unknown_comp(&s
, 0);
1179 ical_free_unknown_comp(&uk_comp
);
1180 } else if(!struncmp(s
, "END", t
-s
-1)){
1181 s
+= 4; /* 4 = strlen("END:") */
1182 if(!struncmp(s
, "STANDARD\r\n", 10)
1183 || !struncmp(s
, "DAYLIGHT\r\n", 10)){
1184 *text
= s
+ 10; /* 10 = strlen("STANDARD\r\n") */
1185 return (void *) tzprop
;
1188 for(i
= 0; i
< TZPUnknown
; i
++)
1189 if(!struncmp(s
, tz_prop
[i
].prop
, t
-s
))
1191 if(tz_prop
[i
].parse
){
1193 if(tzprop
->prop
== NULL
){
1194 tzprop
->prop
= fs_get(TZPUnknown
*sizeof(void *));
1195 memset((void *)tzprop
->prop
, 0, TZPUnknown
*sizeof(void *));
1197 v
= tzprop
->prop
[tz_prop
[i
].pos
];
1198 v
= (tz_prop
[i
].parse
)(v
, &s
, tz_prop
[i
].prop
);
1199 tzprop
->prop
[tz_prop
[i
].pos
] = v
;
1206 if(ical_buf_len
< t
- s
){
1207 fs_resize((void **)&ical_buf
, t
-s
+1);
1211 strcpy(ical_buf
, s
);
1213 if(tzprop
->uk_prop
== NULL
){
1214 tzprop
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
1215 memset((void *)tzprop
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
1216 tzprop
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
1220 for (gcl
= tzprop
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
1221 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1222 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1223 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1226 } /* end of if(s) */
1230 return (void *) tzprop
;
1234 ical_parse_valarm(char **text
)
1240 ical_debug("ical_parse_valarm", *text
);
1241 valarm
= fs_get(sizeof(VALARM_S
));
1242 memset((void *)valarm
, 0, sizeof(VALARM_S
));
1244 /* s must always point the the beginning of a line */
1245 for(s
= *text
; s
&& *s
!= '\0';){
1247 s
= ical_isolate_token(&t
, &c
);
1253 *t
= c
; /* restore separator */
1255 if(s
){ /* figure out the token */
1256 int ukn
= 0; /* unknown token */
1257 if(!struncmp(s
, "BEGIN", 5)){
1259 s
+= 6; /* 6 = strlen("BEGIN:") */
1260 uk_comp
= ical_parse_unknown_comp(&s
, 0);
1261 ical_free_unknown_comp(&uk_comp
);
1262 } else if(!struncmp(s
, "END", t
-s
-1)){
1263 s
+= 4; /* 4 = strlen("END:") */
1264 if(!struncmp(s
, "VALARM\r\n", 8)){
1265 *text
= s
+ 8; /* 8 = strlen("VALARM\r\n") */
1266 return (void *) valarm
;
1268 } else{ Alarm_prop i
;
1269 for(i
= 0; i
< AlUnknown
; i
++)
1270 if(!struncmp(s
, alarm_prop
[i
].prop
, t
-s
))
1272 if(alarm_prop
[i
].parse
){
1274 if(valarm
->prop
== NULL
){
1275 valarm
->prop
= fs_get((AlUnknown
+1)*sizeof(void *));
1276 memset((void *)valarm
->prop
, 0, (AlUnknown
+1)*sizeof(void *));
1278 v
= valarm
->prop
[alarm_prop
[i
].pos
];
1279 v
= (alarm_prop
[i
].parse
)(v
, &s
, alarm_prop
[i
].prop
);
1280 valarm
->prop
[alarm_prop
[i
].pos
] = v
;
1287 if(ical_buf_len
< t
- s
){
1288 fs_resize((void **)&ical_buf
, t
-s
+1);
1292 strcpy(ical_buf
, s
);
1294 if(valarm
->uk_prop
== NULL
){
1295 valarm
->uk_prop
= fs_get(sizeof(GEN_ICLINE_S
));
1296 memset((void *)valarm
->uk_prop
, 0, sizeof(GEN_ICLINE_S
));
1297 valarm
->uk_prop
->cline
= ical_parse_line(&s
, ical_buf
);
1301 for (gcl
= valarm
->uk_prop
; gcl
&& gcl
->next
; gcl
= gcl
->next
);
1302 gcl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1303 memset((void *)gcl
->next
, 0, sizeof(GEN_ICLINE_S
));
1304 gcl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1307 } /* end of if(s) */
1311 return (void *) valarm
;
1315 ical_parse_vtodo(char **text
)
1321 ical_parse_vjournal(char **text
)
1327 ical_parse_vfreebusy(char **text
)
1333 ical_parse_generic_comp(char **text
, int level
)
1338 GEN_ICLINE_S
*gcl
= NULL
;
1341 ical_debug("ical_parse_generic_comp", *text
);
1342 ical
= fs_get(sizeof(ICAL_S
));
1343 memset((void *)ical
, 0, sizeof(ICAL_S
));
1345 ical
->comp
= ical_get_value(text
);
1346 token
= fs_get(strlen(ical
->comp
) + 2 + 1);
1347 sprintf(token
, "%s\r\n", ical
->comp
); /* this is allocated memory */
1349 /* s must always point the the beginning of a line */
1350 for(s
= *text
; s
&& *s
!= '\0';){
1352 s
= ical_isolate_token(&t
, &c
);
1359 *t
= c
; /* restore character */
1360 if(s
){ /* figure out the token */
1361 int ukn
= 0; /* unknown token */
1364 case 'b': if(!struncmp(s
+1, "EGIN", 4)){
1365 s
+= 6; /* 6 = strlen("BEGIN:") */
1366 if(ical
->next
== NULL
)
1367 ical
->next
= ical_parse_unknown_comp(&s
, level
+1);
1372 for(i
= 0, b
= ical
; i
<= level
&& b
&& b
->next
; b
= b
->next
, i
++);
1373 if(b
->branch
== NULL
)
1374 b
->branch
= ical_parse_unknown_comp(&s
, level
+1);
1376 for(; b
&& b
->branch
; b
= b
->branch
);
1377 b
->branch
= ical_parse_unknown_comp(&s
, level
+1);
1384 case 'e': if(!struncmp(s
+1, "ND", 2)){
1386 s
+= 4; /* 4 = strlen("END:") */
1387 if(!struncmp(s
, token
, strlen(token
))){
1388 *text
= s
+ strlen(token
);
1389 ical
->value
= (void *) gcl
;
1397 } /* end of switch(*s) */
1399 if(ical_buf_len
< t
- s
){
1400 fs_resize((void **)&ical_buf
, t
-s
+1);
1404 strcpy(ical_buf
, s
);
1407 gcl
= fs_get(sizeof(GEN_ICLINE_S
));
1408 memset((void *)gcl
, 0, sizeof(GEN_ICLINE_S
));
1409 gcl
->cline
= ical_parse_line(&s
, ical_buf
);
1412 GEN_ICLINE_S
*gencl
;
1413 for (gencl
= gcl
; gencl
&& gencl
->next
; gencl
= gencl
->next
);
1414 gencl
->next
= fs_get(sizeof(GEN_ICLINE_S
));
1415 memset((void *)gencl
->next
, 0, sizeof(GEN_ICLINE_S
));
1416 gencl
->next
->cline
= ical_parse_line(&s
, ical_buf
);
1419 } /* end of if(s) */
1422 ical
->value
= (void *) gcl
;
1428 ical_parse_unknown_comp(char **text
, int level
)
1433 ical_debug("ical_parse_unknown_comp", *text
);
1434 for(i
= 0; ical_comp
[i
].comp
1435 && (struncmp(*text
, ical_comp
[i
].comp
, ical_comp
[i
].len
)
1436 || struncmp(*text
+ ical_comp
[i
].len
, "\r\n", 2)); i
++);
1438 if(ical_comp
[i
].parse
){
1439 *text
+= ical_comp
[i
].len
+ 2;
1440 ical
= fs_get(sizeof(ICAL_S
));
1441 memset((void *)ical
, 0, sizeof(ICAL_S
));
1442 ical
->comp
= cpystr(ical_comp
[i
].comp
);
1443 ical
->value
= (ical_comp
[i
].parse
)(text
);
1445 ical
= ical_parse_generic_comp(text
, level
);
1451 ical_parse_line(char **text
, char *name
)
1456 ic
= fs_get(sizeof(ICLINE_S
));
1457 memset((void *)ic
, 0, sizeof(ICLINE_S
));
1459 ic
->token
= cpystr(name
);
1463 ic
->param
= ical_get_parameter(&s
);
1467 ic
->value
= ical_get_value(&s
);
1475 *** PARSE PROPERTY FUNCTIONS
1479 ical_parse_freq(void *fvalp
, char *text
)
1483 fval
= fs_get(sizeof(Freq_value
));
1487 if(text
== NULL
) return fvalp
;
1489 if(!strucmp(text
, "SECONDLY")) *fval
= FSecondly
;
1490 else if(!strucmp(text
, "MINUTELY")) *fval
= FMinutely
;
1491 else if(!strucmp(text
, "HOURLY")) *fval
= FHourly
;
1492 else if(!strucmp(text
, "DAILY")) *fval
= FDaily
;
1493 else if(!strucmp(text
, "WEEKLY")) *fval
= FWeekly
;
1494 else if(!strucmp(text
, "MONTHLY")) *fval
= FMonthly
;
1495 else if(!strucmp(text
, "YEARLY")) *fval
= FYearly
;
1497 fvalp
= (void *) fval
;
1503 ical_parse_until(void *Tmp
, char *text
)
1508 Tm
= fs_get(sizeof(struct tm
));
1509 ical_parse_date(text
, Tm
);
1517 ical_parse_count(void *countp
, char *text
)
1522 count
= fs_get(sizeof(int));
1523 *count
= atoi(text
);
1524 countp
= (void *) count
;
1531 ical_parse_weekday_list(void *bywkdyp
, char *wklist
)
1533 BYWKDY_S
*bywkdy
, *w
;
1539 bywkdyp
= (void *) bywkdy
;
1541 if(wklist
== NULL
) return bywkdyp
;
1544 for(t
= s
= wklist
; done
== 0; s
++){
1545 if(*s
!= ',' && *s
!= '\0')
1550 else /* c == '\0' */
1554 for(w
= bywkdy
; w
&& w
->next
; w
= w
->next
);
1555 w
= fs_get(sizeof(BYWKDY_S
));
1556 memset((void *)w
, 0, sizeof(BYWKDY_S
));
1557 if(!strucmp(t
+len
-2, "SU")) w
->wd
= Sunday
;
1558 else if(!strucmp(t
+len
-2, "MO")) w
->wd
= Monday
;
1559 else if(!strucmp(t
+len
-2, "TU")) w
->wd
= Tuesday
;
1560 else if(!strucmp(t
+len
-2, "WE")) w
->wd
= Wednesday
;
1561 else if(!strucmp(t
+len
-2, "TH")) w
->wd
= Thursday
;
1562 else if(!strucmp(t
+len
-2, "FR")) w
->wd
= Friday
;
1563 else if(!strucmp(t
+len
-2, "SA")) w
->wd
= Saturday
;
1564 // t[len - 2] = '\0';
1566 w
->value
= strtoul(t
, &t
, 10);
1576 ical_free_weekday_list((void **)&bywkdy
);
1578 bywkdyp
= (void *) bywkdy
;
1584 ical_parse_number_list(void *bynop
, char *nolist
)
1591 bynop
= (void *) byno
;
1593 if(nolist
== NULL
) return bynop
;
1595 for(t
= s
= nolist
; done
== 0; s
++){
1596 if(*s
!= ',' && *s
!= '\0')
1601 else /* c == '\0' */
1604 for(n
= byno
; n
&& n
->next
; n
= n
->next
);
1605 n
= fs_get(sizeof(BYWKDY_S
));
1606 memset((void *)n
, 0, sizeof(BYWKDY_S
));
1607 n
->value
= strtoul(t
, &t
, 10);
1616 ical_free_weekday_list((void **)&byno
);
1618 bynop
= (void *) byno
;
1624 ical_parse_rrule(void *rrulep
, char **text
, char *token
)
1629 ICAL_PARAMETER_S
*param
, *p
;
1632 if(text
== NULL
|| *text
== NULL
|| struncmp(*text
, "RRULE", 5))
1635 rrule
= fs_get(sizeof(RRULE_S
));
1636 memset((void *) rrule
, 0, sizeof(RRULE_S
));
1638 /* recurring rules are special. First, we parse the icline that contains it */
1639 icl
= ical_parse_line(text
, token
);
1641 /* now we copy the parameters that it contains */
1642 rrule
->param
= ical_parameter_cpy(icl
->param
);
1644 /* then we parse icl->value as if it was a parameter */
1646 param
= ical_get_parameter(&s
);
1648 /* now we check which values were given, and fill the prop array */
1649 rrule
->prop
= fs_get((RRUnknown
+1)*sizeof(void *));
1650 memset((void *) rrule
->prop
, 0, (RRUnknown
+1)*sizeof(void *));
1652 for(p
= param
; p
!= NULL
; p
= p
->next
){
1653 for(i
= 0; rrule_prop
[i
].prop
!= NULL
&& strucmp(p
->name
, rrule_prop
[i
].prop
); i
++);
1654 if(rrule_prop
[i
].parse
){
1655 void *v
= rrule
->prop
[rrule_prop
[i
].pos
];
1656 v
= (rrule_prop
[i
].parse
)(v
, p
->value
);
1657 rrule
->prop
[rrule_prop
[i
].pos
] = v
;
1660 rrule
->prop
[RRUnknown
] = NULL
;
1662 ical_free_param(¶m
);
1663 ical_free_cline((void **)&icl
);
1666 ical_free_rrule((void **)&rrule
);
1668 rrulep
= (void *) rrule
;
1673 /*** UTF-8 for ICAL ***/
1676 ical_non_ascii_valid(unsigned char c
)
1678 static unsigned char icu
[6];
1679 static int utf8_len
= 0;
1680 static int utf8_type
= 0;
1684 utf8_type
= (c
>= 0xF0 && c
<= 0xF4)
1685 ? 4 : (c
>= 0xE0 && c
<= 0xEF)
1686 ? 3 : (c
>= 0xC2 && c
<= 0xDF)
1692 icu
[utf8_len
++] = c
; /* count it */
1697 else if(utf8_len
== 2){
1698 rv
= (icu
[0] >= 0xC2 && icu
[0] <= 0xDF)
1699 && (icu
[1] >= 0x80 && icu
[1] <= 0xBF) ? UTF8_COMPLETE
: 0;
1702 } else if (utf8_type
== 3){
1707 rv
= (icu
[1] >= 0xA0 && icu
[1] <= 0xBF)
1708 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1709 else if(icu
[0] >= 0xE1 && icu
[0] <= 0xEC)
1710 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0xBF)
1711 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1712 else if(icu
[0] == 0xED)
1713 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0x9F)
1714 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1715 else if(icu
[0] >= 0xE1 && icu
[0] <= 0xEC)
1716 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0xBF)
1717 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF) ? UTF8_COMPLETE
: 0;
1720 } else if (utf8_type
== 4){
1725 rv
= (icu
[1] >= 0x90 && icu
[1] <= 0xBF)
1726 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF)
1727 && (icu
[3] >= 0x80 && icu
[3] <= 0xBF) ? UTF8_COMPLETE
: 0;
1728 else if(icu
[0] >= 0xF1 && icu
[0] <= 0xF3)
1729 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0xBF)
1730 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF)
1731 && (icu
[3] >= 0x80 && icu
[3] <= 0xBF) ? UTF8_COMPLETE
: 0;
1732 else if(icu
[0] == 0xF4)
1733 rv
= (icu
[1] >= 0x80 && icu
[1] <= 0x8F)
1734 && (icu
[2] >= 0x80 && icu
[2] <= 0xBF)
1735 && (icu
[3] >= 0x80 && icu
[3] <= 0xBF) ? UTF8_COMPLETE
: 0;
1743 ical_get_number_value(char *value
, int beg_pos
, int end_pos
)
1749 value
[end_pos
] = '\0';
1750 rv
= strtoul(value
+ beg_pos
, &err
, 10);
1751 if(err
!= NULL
&& *err
!= '\0') return -1;
1757 ical_free_duration(ICAL_DURATION_S
**ic_d
)
1759 if(ic_d
== NULL
|| *ic_d
== NULL
)
1762 if((*ic_d
)->next
) ical_free_duration(&(*ic_d
)->next
);
1763 fs_give((void **)ic_d
);
1766 /* returns 0 if no error, -1 if some error */
1768 ical_parse_duration(char *value
, ICAL_DURATION_S
*ic_d
)
1770 int i
, j
= 0, rv
= 0;
1772 if(value
== NULL
|| ic_d
== NULL
) return -1;
1774 memset((void *)ic_d
, 0, sizeof(ICAL_DURATION_S
));
1776 if(value
[i
= 0] == '-'){
1779 } else if(value
[i
] == '+')
1782 if(value
[i
++] == 'P'){
1783 for(j
= i
; value
[j
] != '\0' && value
[j
] != ','; j
++){
1784 if(!isdigit(value
[j
]))
1786 case 'W': ic_d
->weeks
= ical_get_number_value(value
, i
, j
-1);
1789 case 'D': ic_d
->days
= ical_get_number_value(value
, i
, j
-1);
1792 case 'H': ic_d
->hours
= ical_get_number_value(value
, i
, j
-1);
1795 case 'M': ic_d
->minutes
= ical_get_number_value(value
, i
, j
-1);
1798 case 'S': ic_d
->seconds
= ical_get_number_value(value
, i
, j
-1);
1801 case 'T': i
= j
+ 1;
1811 if(value
[j
++] == ','){
1812 ICAL_DURATION_S next
;
1813 rv
= ical_parse_duration(value
+j
, &next
);
1820 /* return -1 if any error,
1821 ICAL_DATE_TIME if value has the DATE-TIME form
1822 ICAL_DATE if value has the DATE form only
1823 ICAL_DATE_TIME_GMT if value has the DATE-TIME form and is in GMT.
1826 ical_parse_date(char *value
, struct tm
*t
)
1832 if(t
== NULL
) return rv
;
1833 memset((void *)&Tm
, 0, sizeof(struct tm
));
1835 if(value
== NULL
) return rv
;
1837 rv
= ICAL_DATE_TIME
; /* assume DATE-TIME format */
1838 /* a simple check for the format of the string */
1839 for(i
= 0; isdigit(value
[i
]); i
++);
1840 if (i
== 8 && value
[i
] == '\0')
1843 if (i
!= 8 || value
[i
++] != 'T') return -1;
1844 if(rv
== ICAL_DATE_TIME
) {
1845 for(; isdigit(value
[i
]); i
++);
1846 if(i
!= 15 || (value
[i
] != '\0' && (value
[i
] != 'Z' || value
[i
+1] != '\0')))
1848 if(i
== 15 && value
[i
] == 'Z')
1849 rv
= ICAL_DATE_TIME_GMT
;
1852 Tm
.tm_year
= ical_get_number_value(value
, 0, 4) - 1900;
1853 Tm
.tm_mon
= ical_get_number_value(value
, 4, 6) - 1;
1854 Tm
.tm_mday
= ical_get_number_value(value
, 6, 8);
1855 if(rv
!= ICAL_DATE
){
1856 Tm
.tm_hour
= ical_get_number_value(value
, 9, 11);
1857 Tm
.tm_min
= ical_get_number_value(value
, 11, 13);
1858 Tm
.tm_sec
= ical_get_number_value(value
, 13, 15);
1859 Tm
.tm_isdst
= rv
| ICAL_DST_UNKNOWN
;
1865 return (t
->tm_mon
> 11 || t
->tm_mon
< 0
1866 || t
->tm_mday
> 31 || t
->tm_mday
< 0
1867 || t
->tm_hour
> 23 || t
->tm_hour
< 0
1868 || t
->tm_min
> 59 || t
->tm_min
< 0
1869 || t
->tm_sec
> 60 || t
->tm_sec
< 0)
1874 ical_set_date(ICLINE_S
*icl
, VTIMEZONE_S
*vtz
)
1876 int date_form
; /* date forms from section 3.3.4 in RFC 5545 */
1877 ICAL_PARAMETER_S
*param
;
1881 if(icl
== NULL
) return;
1883 for(param
= icl
->param
; param
!= NULL
; param
= param
->next
)
1884 if(!strucmp(param
->name
, "TZID"))
1888 date_form
= 3; /* local time with timezone */
1889 else if(icl
->value
[strlen(icl
->value
)-1] == 'Z')
1890 date_form
= 2; /* utc time */
1891 else date_form
= 1; /* local time */
1893 ical_parse_date(icl
->value
, &ic_date
);
1894 ic_date
.tm_wday
= ical_day_of_week(ic_date
); /* find out day of the week */
1898 case 2: ical_adjust_date(&ic_date
, vtz
);
1901 default: alpine_panic ("Impossible date_form");
1906 ical_std_or_daylight(struct tm
*date
, VTIMEZONE_S
*vtz
)
1908 struct tm standard
, daylight
;
1909 ICLINE_S
*tzid
= (ICLINE_S
*) vtz
->prop
[TZCid
];
1911 // standard = daylight;
1918 /* adjusts time to given time zone */
1920 ical_adjust_date(struct tm
*date
, VTIMEZONE_S
*vtz
)
1922 char *tzname
= NULL
;
1924 ICAL_TZPROP_S
*cur_std_day
;
1930 if((icl
= (ICLINE_S
*)vtz
->prop
[TZCid
]) != NULL
)
1931 tzname
= cpystr(icl
->value
);
1934 cur_std_day
= ical_std_or_daylight(date
, vtz
);
1938 ical_set_date_vevent(void *veventv
, void *vtzv
)
1940 VEVENT_S
*vevent
= (VEVENT_S
*) veventv
;
1941 VTIMEZONE_S
*vtz
= (VTIMEZONE_S
*) vtzv
;
1944 ical_set_date(vevent
->prop
[EvDtstamp
], vtz
);
1945 ical_set_date(vevent
->prop
[EvDtstart
], vtz
);
1946 ical_set_date(vevent
->prop
[EvDtend
], vtz
);
1950 #define LEAP_YEAR(X) ((((X) % 4 == 0) \
1951 && (((X) % 100 != 0) || ((X) % 400 == 0))) \
1954 #define CAL_OFFSET(X) (((X) == 1752) ? 5 : (LEAP_YEAR((X)) ? 2 : 1))
1956 /* given a year, after day_zero, return the day
1957 * of the week of the first of january of that year. On error,
1958 * return a negative number.
1959 * Assumption: day_zero is the date of january 1, of some year.
1962 ical_january_first(int year
)
1964 int i
, january_first
;
1966 if(year
< day_zero
.tm_year
) return -1; /* not supported */
1969 january_first
= day_zero
.tm_wday
;
1970 for(i
= 1900 + day_zero
.tm_year
+ 1; i
<= year
; i
++)
1971 january_first
+= CAL_OFFSET(i
-1);
1973 return january_first
% 7;
1976 /* given a month, week day, and year, return all days of the month
1977 * that have that day as the week day. For example, return all
1978 * sundays in november 2012.
1981 ical_day_from_week(int month
, Weekday day
, int year
)
1988 fday
= ical_first_of_month(month
, year
);
1989 year
+= 1900; /* restore year */
1990 if(year
== 1752 && month
== 8){
1993 for(nday
= 1, wday
= (Weekday
) fday
; wday
!= day
; wday
= (wday
+1) % 7, nday
++)
1995 rv
= fs_get(6*sizeof(int));
1996 memset((void *) rv
, 0, 6*sizeof(int));
1997 for(i
= 0; nday
<= month_len
[month
]; i
++){
2001 if(LEAP_YEAR(year
) && month
== 1 && nday
== 29)
2009 /* given a month and a year, return the weekday of the first of the
2010 * month in that year.
2011 * return value: on error -1, otherwise the day of the week.
2014 ical_first_of_month(int month
, int year
)
2018 if((d
= ical_january_first(year
)) < 0)
2022 for(i
= 0; i
< month
; i
++)
2025 if(LEAP_YEAR(year
) && month
>= 2)
2028 if(year
== 1752 && month
>= 9)
2034 /* given a day, month and year, return the weekday of that day
2035 * return value: on error -1, otherwise the day of the week.
2038 ical_day_of_week(struct tm date
)
2042 if((d
= ical_first_of_month(date
.tm_mon
, date
.tm_year
)) < 0)
2045 d
+= date
.tm_mday
- 1;
2047 if(date
.tm_year
+ 1900 == 1752){
2048 if(date
.tm_mday
> 2 && date
.tm_mday
< 14)
2050 if(date
.tm_mday
>= 14)
2057 /* given an initial date dtstart, and a recurring rule, rrule,
2058 * adjust the date to the first date on the same year, when
2059 * the rule actually starts
2062 adjust_date_rrule(struct tm
*dtstart
, RRULE_S
*rrule
)
2066 memset((void *) &t
, 0, sizeof(struct tm
));
2067 t
.tm_year
= dtstart
->tm_year
; /* same year */
2068 if(rrule
->prop
[RRFreq
]){
2070 if(rrule
->prop
[RRCount
]){
2072 else if(rrule
->prop
[RRInterval
]){
2074 if(rrule
->prop
[RRBysecond
]){
2075 BYWKDY_S
*sec
= (BYWKDY_S
*) rrule
->prop
[RRBysecond
], *seco
;
2076 for (seco
= sec
; seco
!= NULL
; seco
= seco
->next
)
2077 if(seco
== sec
) t
.tm_sec
= seco
->value
;
2078 else if (seco
->value
< t
.tm_sec
)
2079 t
.tm_sec
= seco
->value
;
2081 if (rrule
->prop
[RRByminute
]){
2082 BYWKDY_S
*sec
= (BYWKDY_S
*) rrule
->prop
[RRByminute
], *seco
;
2083 for (seco
= sec
; seco
!= NULL
; seco
= seco
->next
)
2084 if(seco
== sec
) t
.tm_min
= seco
->value
;
2085 else if (seco
->value
< t
.tm_sec
)
2086 t
.tm_min
= seco
->value
;
2088 if (rrule
->prop
[RRByhour
]){
2089 BYWKDY_S
*sec
= (BYWKDY_S
*) rrule
->prop
[RRByhour
], *seco
;
2090 for (seco
= sec
; seco
!= NULL
; seco
= seco
->next
)
2091 if(seco
== sec
) t
.tm_hour
= seco
->value
;
2092 else if (seco
->value
< t
.tm_sec
)
2093 t
.tm_hour
= seco
->value
;
2095 if (rrule
->prop
[RRByday
]){
2097 if (rrule
->prop
[RRByweekno
]){
2099 if (rrule
->prop
[RRBymonthday
]){
2101 if (rrule
->prop
[RRByyearday
]){
2103 if (rrule
->prop
[RRByweekno
]){
2105 if (rrule
->prop
[RRBymonth
]){
2106 BYWKDY_S
*m
= (BYWKDY_S
*) rrule
->prop
[RRBymonth
], *mo
;
2107 for (mo
= m
; mo
!= NULL
; mo
= mo
->next
)
2108 if(mo
== m
) t
.tm_mon
= mo
->value
- 1;
2109 else if (mo
->value
- 1 < t
.tm_mon
)
2110 t
.tm_mon
= mo
->value
- 1;
2112 if (rrule
->prop
[RRBysetpos
]){
2114 if (rrule
->prop
[RRWkst
]){
2120 ical_initialize(void)
2122 static int inited
= 0;
2127 ical_buf_len
= 1024;
2128 ical_buf
= fs_get(ical_buf_len
+1);
2130 memset((void *) &day_zero
, 0, sizeof(struct tm
));
2131 day_zero
.tm_year
= 1601 - 1900;
2132 day_zero
.tm_mday
= 1;
2133 day_zero
.tm_wday
= 4;
2138 /* At this time, we are going to print the date in 24 hour format
2139 * if there is no string for AM or PM, but we use AM or PM when available.
2140 * We plan to make this user configurable, but not today...
2143 ical_date_time (char *tmp
, size_t len
, struct tm
*ic_datep
)
2145 /* test of the AM/PM string is available */
2146 our_strftime(tmp
, len
, "%p", ic_datep
);
2149 our_strftime(tmp
, len
, "%a %x %I:%M %p", ic_datep
);
2151 our_strftime(tmp
, len
, "%a %x %H:%M", ic_datep
);
2154 /* If the icline has a TZID parameter, return its value, otherwise, return
2155 * NULL. Returned value freed by caller.
2158 ical_get_tzid(ICAL_PARAMETER_S
*param
)
2165 if(strucmp(param
->name
, "TZID") == 0)
2166 tzid
= cpystr(param
->value
);
2168 tzid
= ical_get_tzid(param
->next
);
2173 /* we create a summary of the event, and pass that back as
2177 ical_vevent_summary(VCALENDAR_S
*vcal
)
2179 VEVENT_SUMMARY_S
*rv
, *vsummary
= NULL
;
2184 static int offset
= 1000000; /* impossible value */
2188 if(vcal
== NULL
) return NULL
;
2190 if(offset
== 1000000)
2191 offset
= timezone_offset_to_gmt(&dst
);
2193 method
= vcal
->method
;
2195 vevent
= (VEVENT_S
*) vcal
->comp
[VEvent
];
2196 if(vevent
== NULL
|| vevent
->prop
== NULL
)
2199 for(vevent
= (VEVENT_S
*) vcal
->comp
[VEvent
];
2200 vevent
!= NULL
&& vevent
->prop
!= NULL
;
2201 vevent
= vevent
->next
, rv
= rv
->next
){
2203 rv
= fs_get(sizeof(VEVENT_SUMMARY_S
));
2204 memset((void *) rv
, 0, sizeof(VEVENT_SUMMARY_S
));
2206 if(method
!= NULL
&& !strucmp(method
->value
, "CANCEL"))
2209 if((icl
= (ICLINE_S
*) vevent
->prop
[EvPriority
]) != NULL
)
2210 rv
->priority
= atoi(icl
->value
);
2212 if((icl
= (ICLINE_S
*) vevent
->prop
[EvSummary
]) != NULL
){
2213 rv
->summary
= cpystr(icl
->value
? icl
->value
: _("No Summary"));
2214 ical_remove_escapes(&rv
->summary
);
2217 if((icl
= (ICLINE_S
*) vevent
->prop
[EvClass
]) != NULL
)
2218 rv
->class = cpystr(icl
->value
? icl
->value
: _("PUBLIC"));
2220 rv
->class = cpystr(_("PUBLIC"));
2222 if((icl
= (ICLINE_S
*) vevent
->prop
[EvOrganizer
]) != NULL
){
2223 char *cn
, *sender
, *address
;
2224 ICAL_PARAMETER_S
*param
;
2226 cn
= sender
= address
= NULL
;
2227 for(param
= icl
->param
; param
!= NULL
; param
= param
->next
)
2228 if(!strucmp(param
->name
, "CN"))
2230 else if(!strucmp(param
->name
, "SENT-BY"))
2231 sender
= param
->value
;
2234 if(!struncmp(sender
, "MAILTO:", 7))
2236 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "<%s>", sender
);
2237 rv
->sender
= cpystr(tmp_20k_buf
);
2240 if((address
= icl
->value
) != NULL
){
2241 if(!struncmp(address
, "MAILTO:", 7))
2243 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s<%s>",
2244 cn
? cn
: "", cn
? " " : "",
2245 address
? address
: _("Unknown address"));
2246 rv
->organizer
= cpystr(tmp_20k_buf
);
2248 } /* end of if(organizer) */
2250 if((icl
= (ICLINE_S
*) vevent
->prop
[EvLocation
]) != NULL
){
2251 rv
->location
= cpystr(icl
->value
? icl
->value
: _("Location undisclosed"));
2252 ical_remove_escapes(&rv
->location
);
2255 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDtstart
]) != NULL
){
2257 char tmp
[200], *tzid
;
2258 int icd
; /* ical date return value */
2260 memset((void *)&ic_date
, 0, sizeof(struct tm
));
2261 icd
= ical_parse_date(icl
->value
, &ic_date
) & 0x00fff;
2262 tzid
= ical_get_tzid(icl
->param
);
2264 ic_date
.tm_wday
= ical_day_of_week(ic_date
);
2265 if(ic_date
.tm_isdst
& ICAL_DATE_TIME_GMT
){ /* GMT time */
2266 ic_date
.tm_isdst
= dst
;
2267 ourtime
= mktime(&ic_date
);
2268 if(ourtime
!= (time_t) -1){
2270 ic_date
= *localtime(&ourtime
);
2273 ic_date
.tm_isdst
= dst
;
2275 case ICAL_DATE_TIME
: /* DATE-TIME */
2276 ical_date_time(tmp
, sizeof(tmp
), &ic_date
);
2278 case ICAL_DATE
: /* DATE */
2279 our_strftime(tmp
, sizeof(tmp
), "%a %x", &ic_date
);
2281 case ICAL_DATE_TIME_GMT
: /* DATE-TIME in GMT */
2282 our_strftime(tmp
, sizeof(tmp
), "%a %x %I:%M %p", &ic_date
);
2284 default: alpine_panic("Unhandled ical date format");
2289 strncpy(tmp
, _("Error while parsing event date"), sizeof(tmp
));
2290 tmp
[sizeof(tmp
) - 1] = '\0';
2293 if(icl
->value
== NULL
)
2294 rv
->evstart
= cpystr(_("Unknown Start Date"));
2296 size_t len
= strlen(tmp
) + 1;
2299 len
+= strlen(tzid
) + 3; /* 3 = strlen(" ()") */
2301 rv
->evstart
= fs_get(len
*sizeof(char));
2302 snprintf(rv
->evstart
, len
, "%s%s%s%s", tmp
,
2303 tzid
!= NULL
? " (" : "",
2304 tzid
!= NULL
? tzid
: "",
2305 tzid
!= NULL
? ")" : "");
2306 rv
->evstart
[len
-1] = '\0';
2309 fs_give((void **)&tzid
);
2310 } /* end of if dtstart */
2312 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDuration
]) != NULL
){
2314 ICAL_DURATION_S ic_d
, icd2
;
2315 if(ical_parse_duration(icl
->value
, &ic_d
) == 0){
2316 char tmp
[MAILTMPLEN
+1];
2318 for(i
= 1, icd2
= ic_d
; icd2
.next
!= NULL
; icd2
= *icd2
.next
, i
++);
2319 rv
->duration
= fs_get((i
+1)*sizeof(char *));
2326 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2327 "%d %s ", ic_d
.weeks
, ic_d
.weeks
== 1 ? _("week") : _("weeks"));
2329 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2330 "%d %s ", ic_d
.days
, ic_d
.days
== 1 ? _("day") : _("days"));
2332 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2333 "%d %s ", ic_d
.hours
, ic_d
.hours
== 1 ? _("hour") : _("hours"));
2334 if(ic_d
.minutes
> 0)
2335 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2336 "%d %s ", ic_d
.minutes
, ic_d
.minutes
== 1 ? _("minute") : _("minutes"));
2337 if(ic_d
.seconds
> 0)
2338 utf8_snprintf(tmp
+strlen(tmp
), MAILTMPLEN
- strlen(tmp
),
2339 "%d %s ", ic_d
.seconds
, ic_d
.seconds
== 1 ? _("second") : _("seconds"));
2341 tmp
[MAILTMPLEN
] = '\0';
2342 rv
->duration
[i
++] = cpystr(tmp
);
2344 if(ic_d
.next
!= NULL
)
2348 } while (done
== 0);
2349 rv
->duration
[i
] = NULL
;
2351 } /* end of DURATION */
2352 else if((icl
= (ICLINE_S
*) vevent
->prop
[EvDtend
]) != NULL
){
2354 char tmp
[200], *tzid
;
2357 memset((void *)&ic_date
, 0, sizeof(struct tm
));
2358 icd
= ical_parse_date(icl
->value
, &ic_date
) & 0x00fff;
2359 tzid
= ical_get_tzid(icl
->param
);
2361 ic_date
.tm_wday
= ical_day_of_week(ic_date
);
2362 if(ic_date
.tm_isdst
& ICAL_DATE_TIME_GMT
){ /* GMT time */
2363 ic_date
.tm_isdst
= dst
;
2364 ourtime
= mktime(&ic_date
);
2365 if(ourtime
!= (time_t) -1){
2367 ic_date
= *localtime(&ourtime
);
2370 ic_date
.tm_isdst
= dst
;
2372 case ICAL_DATE_TIME
: /* DATE-TIME */
2373 ical_date_time(tmp
, sizeof(tmp
), &ic_date
);
2375 case ICAL_DATE
: /* DATE */
2376 our_strftime(tmp
, sizeof(tmp
), "%a %x", &ic_date
);
2378 case ICAL_DATE_TIME_GMT
: /* DATE-TIME in GMT */
2379 our_strftime(tmp
, sizeof(tmp
), "%a %x %I:%M %p", &ic_date
);
2381 default: alpine_panic("Unhandled ical date format");
2386 strncpy(tmp
, _("Error while parsing event date"), sizeof(tmp
));
2387 tmp
[sizeof(tmp
) - 1] = '\0';
2390 if(icl
->value
== NULL
)
2391 rv
->evend
= cpystr(_("Unknown End Date"));
2393 size_t len
= strlen(tmp
) + 1;
2396 len
+= strlen(tzid
) + 3; /* 3 = strlen(" ()") */
2398 rv
->evend
= fs_get(len
*sizeof(char));
2399 snprintf(rv
->evend
, len
, "%s%s%s%s", tmp
,
2400 tzid
!= NULL
? " (" : "",
2401 tzid
!= NULL
? tzid
: "",
2402 tzid
!= NULL
? ")" : "");
2403 rv
->evend
[len
-1] = '\0';
2406 fs_give((void **)&tzid
);
2407 } /* end of if dtend */
2409 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDtstamp
]) != NULL
){
2411 char tmp
[200], *tzid
;
2414 memset((void *)&ic_date
, 0, sizeof(struct tm
));
2415 icd
= ical_parse_date(icl
->value
, &ic_date
) & 0x00fff;
2416 tzid
= ical_get_tzid(icl
->param
);
2418 ic_date
.tm_wday
= ical_day_of_week(ic_date
);
2419 if(ic_date
.tm_isdst
& ICAL_DATE_TIME_GMT
){ /* GMT time */
2420 ic_date
.tm_isdst
= dst
;
2421 ourtime
= mktime(&ic_date
);
2422 if(ourtime
!= (time_t) -1){
2424 ic_date
= *localtime(&ourtime
);
2427 ic_date
.tm_isdst
= dst
;
2429 case ICAL_DATE_TIME
: /* DATE-TIME */
2430 ical_date_time(tmp
, sizeof(tmp
), &ic_date
);
2432 case ICAL_DATE
: /* DATE */
2433 our_strftime(tmp
, sizeof(tmp
), "%a %x", &ic_date
);
2435 case ICAL_DATE_TIME_GMT
: /* DATE-TIME in GMT */
2436 our_strftime(tmp
, sizeof(tmp
), "%a %x %I:%M %p", &ic_date
);
2438 default: alpine_panic("Unhandled ical date format");
2443 strncpy(tmp
, _("Error while parsing event date"), sizeof(tmp
));
2444 tmp
[sizeof(tmp
) - 1] = '\0';
2446 if(icl
->value
== NULL
)
2447 rv
->dtstamp
= cpystr(_("Unknown when event was scheduled"));
2449 size_t len
= strlen(tmp
) + 1;
2452 len
+= strlen(tzid
) + 3; /* 3 = strlen(" ()") */
2454 rv
->dtstamp
= fs_get(len
*sizeof(char));
2455 snprintf(rv
->dtstamp
, len
, "%s%s%s%s", tmp
,
2456 tzid
!= NULL
? " (" : "",
2457 tzid
!= NULL
? tzid
: "",
2458 tzid
!= NULL
? ")" : "");
2459 rv
->dtstamp
[len
-1] = '\0';
2461 } /* end of if dtstamp */
2463 if((gicl
= (GEN_ICLINE_S
*) vevent
->prop
[EvAttendee
]) != NULL
){
2466 for(nattendees
= 0; gicl
!= NULL
; gicl
= gicl
->next
, nattendees
++);
2467 rv
->attendee
= fs_get((nattendees
+1)*sizeof(char *));
2469 gicl
= (GEN_ICLINE_S
*) vevent
->prop
[EvAttendee
];
2470 for(i
= 0; gicl
!= NULL
; gicl
= gicl
->next
, i
++){
2471 char *role
, *partstat
, *rsvp
;
2473 ICAL_PARAMETER_S
*param
;
2476 role
= partstat
= rsvp
= cn
= mailto
= NULL
;
2477 for(param
= icl
->param
; param
!= NULL
; param
= param
->next
){
2478 if(!strucmp(param
->name
, "ROLE")){
2479 if(!strucmp(param
->value
, "REQ-PARTICIPANT"))
2480 role
= _("[Required]");
2481 else if(!strucmp(param
->value
, "OPT-PARTICIPANT"))
2482 role
= _("[Optional]");
2483 else if(!strucmp(param
->value
, "NON-PARTICIPANT"))
2484 role
= _("[Informed]");
2485 else if(!strucmp(param
->value
, "CHAIR"))
2486 role
= _("[ Chair ]");
2488 role
= param
->value
;
2490 else if(!strucmp(param
->name
, "PARTSTAT")){
2491 if(!strucmp(param
->value
, "NEEDS-ACTION"))
2492 partstat
= _("[Need-Reply]");
2493 else if(!strucmp(param
->value
, "ACCEPTED"))
2494 partstat
= _("[ Accepted ]");
2495 else if(!strucmp(param
->value
, "DECLINED"))
2496 partstat
= _("[ Declined ]");
2497 else if(!strucmp(param
->value
, "TENTATIVE"))
2498 partstat
= _("[ Tentative]");
2499 else if(!strucmp(param
->value
, "DELEGATED"))
2500 partstat
= _("[ Delegated]");
2502 partstat
= param
->value
;
2504 else if(!strucmp(param
->name
, "RSVP"))
2505 rsvp
= param
->value
;
2506 else if(!strucmp(param
->name
, "CN"))
2509 if(icl
->value
&& !struncmp(icl
->value
, "MAILTO:", strlen("MAILTO:")))
2510 mailto
= icl
->value
+ 7; /* 7 = strlen("MAILTO:") */
2511 if(!strucmp(cn
, mailto
))
2513 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s%s%s%s%s<%s>",
2514 role
&& *role
? role
: "",
2515 role
&& *role
? " " : "",
2516 partstat
? partstat
: _("[Unknown Reply]"),
2518 cn
&& *cn
? cn
: "",
2519 cn
&& *cn
? " " : "",
2520 mailto
? mailto
: _("Unknown address"));
2521 rv
->attendee
[i
] = cpystr(tmp_20k_buf
);
2523 rv
->attendee
[i
] = NULL
;
2524 } /* end of ATTENDEES */
2526 if((icl
= (ICLINE_S
*) vevent
->prop
[EvDescription
]) != NULL
){
2527 char *s
, *t
, *u
, *v
;
2530 if(icl
->value
== NULL
){
2531 free_vevent_summary(&rv
);
2535 v
= cpystr(icl
->value
); /* process a copy of icl->value */
2537 for(i
= 1, escaped
= 0, s
= v
; s
&& *s
; s
++){
2538 if(*s
== '\\' && escaped
== 0){ escaped
= 1; continue; }
2540 if(!(*s
== '\\' || *s
== ',' || *s
== 'n' || *s
== 'N' || *s
== ';')){
2541 free_vevent_summary(&rv
);
2542 fs_give((void **)&v
);
2548 if(*s
== ',') i
++; /* a non-scaped comma is a new value for text */
2551 rv
->description
= fs_get((i
+1)*sizeof(unsigned char *));
2553 for (s
= t
= u
= v
, escaped
= 0; *t
!= '\0'; t
++){
2554 if(*t
== '\\' && escaped
== 0){ escaped
= 1; continue; }
2566 default: free_vevent_summary(&rv
);
2567 fs_give((void **)&v
);
2575 rv
->description
[i
++] = (unsigned char *) cpystr((char *) ical_decode(s
, vcal
->encoding
));
2581 rv
->description
[i
++] = (unsigned char *) cpystr((char *) ical_decode(s
, vcal
->encoding
));
2582 rv
->description
[i
] = NULL
;
2583 fs_give((void **)&v
);
2584 } /* end of if(description) */
2585 /* last instruction of the loop */
2586 if(vsummary
== NULL
)
2589 VEVENT_SUMMARY_S
*vesy
;
2590 for(vesy
= vsummary
; vesy
&& vesy
->next
; vesy
= vesy
->next
);
2593 } /* end of "for" loop */
2598 free_vevent_summary(VEVENT_SUMMARY_S
**vesy
)
2601 if(vesy
== NULL
|| *vesy
== NULL
) return;
2603 if((*vesy
)->class) fs_give((void **)&(*vesy
)->class);
2604 if((*vesy
)->summary
) fs_give((void **)&(*vesy
)->summary
);
2605 if((*vesy
)->sender
) fs_give((void **)&(*vesy
)->sender
);
2606 if((*vesy
)->organizer
) fs_give((void **)&(*vesy
)->organizer
);
2607 if((*vesy
)->location
) fs_give((void **)&(*vesy
)->location
);
2608 if((*vesy
)->evstart
) fs_give((void **)&(*vesy
)->evstart
);
2609 if((*vesy
)->evend
) fs_give((void **)&(*vesy
)->evend
);
2610 if((*vesy
)->dtstamp
) fs_give((void **)&(*vesy
)->dtstamp
);
2611 if((*vesy
)->duration
){
2612 for(i
= 0; (*vesy
)->duration
[i
] != NULL
; i
++)
2613 fs_give((void **) &(*vesy
)->duration
[i
]);
2614 fs_give((void **) (*vesy
)->duration
);
2616 if((*vesy
)->attendee
){
2617 for(i
= 0; (*vesy
)->attendee
[i
] != NULL
; i
++)
2618 fs_give((void **) &(*vesy
)->attendee
[i
]);
2619 fs_give((void **) &(*vesy
)->attendee
);
2621 if((*vesy
)->description
){
2622 for(i
= 0; (*vesy
)->description
[i
] != NULL
; i
++)
2623 fs_give((void **) &(*vesy
)->description
[i
]);
2624 fs_give((void **) &(*vesy
)->description
);
2626 if((*vesy
)->next
) free_vevent_summary(&(*vesy
)->next
);
2627 fs_give((void **) vesy
);
2634 fs_give((void **)&ical_buf
);