3 * Copyright (c) 1996-2012 by the citadel.org team
5 * This program is open source software. You can redistribute it and/or
6 * modify it under the terms of the GNU General Public License, version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
16 extern IcalKindEnumMap icalproperty_kind_map[];
17 extern IcalMethodEnumMap icalproperty_method_map[];
19 HashList *IcalComponentMap = NULL;
20 CtxType CTX_ICAL = CTX_NONE;
21 CtxType CTX_ICALPROPERTY = CTX_NONE;
22 CtxType CTX_ICALMETHOD = CTX_NONE;
23 CtxType CTX_ICALTIME = CTX_NONE;
24 CtxType CTX_ICALATTENDEE = CTX_NONE;
25 CtxType CTX_ICALCONFLICT = CTX_NONE;
27 void tmplput_ICalItem(StrBuf * Target, WCTemplputParams * TP) {
28 icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
30 icalproperty_kind Kind;
33 Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 0, ICAL_ANY_PROPERTY);
34 p = icalcomponent_get_first_property(cal, Kind);
36 str = icalproperty_get_comment(p);
37 StrBufAppendTemplateStr(Target, TP, str, 1);
41 void tmplput_CtxICalProperty(StrBuf * Target, WCTemplputParams * TP) {
42 icalproperty *p = (icalproperty *) CTX(CTX_ICALPROPERTY);
45 str = icalproperty_get_comment(p);
46 StrBufAppendTemplateStr(Target, TP, str, 0);
49 int ReleaseIcalSubCtx(StrBuf * Target, WCTemplputParams * TP) {
50 WCTemplputParams *TPP = TP;
55 int cond_ICalIsA(StrBuf * Target, WCTemplputParams * TP) {
56 icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
57 icalcomponent_kind c = GetTemplateTokenNumber(Target, TP, 2, ICAL_NO_COMPONENT);
58 return icalcomponent_isa(cal) == c;
61 int cond_ICalHaveItem(StrBuf * Target, WCTemplputParams * TP) {
62 icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
64 icalproperty_kind Kind;
66 Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 2, ICAL_ANY_PROPERTY);
67 p = icalcomponent_get_first_property(cal, Kind);
69 WCTemplputParams *DynamicTP;
71 DynamicTP = (WCTemplputParams *) malloc(sizeof(WCTemplputParams));
72 StackDynamicContext(TP,
74 p, CTX_ICALPROPERTY, 0, TP->Tokens, ReleaseIcalSubCtx, TP->Tokens->Params[1]->lvalue);
81 int ReleaseIcalTimeCtx(StrBuf * Target, WCTemplputParams * TP) {
82 WCTemplputParams *TPP = TP;
89 int cond_ICalHaveTimeItem(StrBuf * Target, WCTemplputParams * TP) {
90 icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
92 icalproperty_kind Kind;
94 Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 2, ICAL_ANY_PROPERTY);
95 p = icalcomponent_get_first_property(cal, Kind);
97 struct icaltimetype *t;
98 struct icaltimetype tt;
99 WCTemplputParams *DynamicTP;
101 DynamicTP = (WCTemplputParams *) malloc(sizeof(WCTemplputParams) + sizeof(struct icaltimetype));
102 t = (struct icaltimetype *) &DynamicTP[1];
103 memset(&tt, 0, sizeof(struct icaltimetype));
105 case ICAL_DTSTART_PROPERTY:
106 tt = icalproperty_get_dtstart(p);
108 case ICAL_DTEND_PROPERTY:
109 tt = icalproperty_get_dtend(p);
114 memcpy(t, &tt, sizeof(struct icaltimetype));
116 StackDynamicContext(TP,
117 DynamicTP, t, CTX_ICALTIME, 0, TP->Tokens, ReleaseIcalTimeCtx, TP->Tokens->Params[1]->lvalue);
125 int cond_ICalTimeIsDate(StrBuf * Target, WCTemplputParams * TP) {
126 struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
130 void tmplput_ICalTime_Date(StrBuf * Target, WCTemplputParams * TP) {
134 struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
136 memset(&d_tm, 0, sizeof d_tm);
137 d_tm.tm_year = t->year - 1900;
138 d_tm.tm_mon = t->month - 1;
139 d_tm.tm_mday = t->day;
140 len = wc_strftime(buf, sizeof(buf), "%x", &d_tm);
141 StrBufAppendBufPlain(Target, buf, len, 0);
143 void tmplput_ICalTime_Time(StrBuf * Target, WCTemplputParams * TP) {
146 struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
149 tt = icaltime_as_timet(*t);
150 len = webcit_fmt_date(buf, sizeof(buf), tt, DATEFMT_FULL);
151 StrBufAppendBufPlain(Target, buf, len, 0);
154 void tmplput_ICalDate(StrBuf * Target, WCTemplputParams * TP) {
155 icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
157 icalproperty_kind Kind;
158 struct icaltimetype t;
162 Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 0, ICAL_ANY_PROPERTY);
163 p = icalcomponent_get_first_property(cal, Kind);
166 t = icalproperty_get_dtend(p);
167 tt = icaltime_as_timet(t);
168 len = webcit_fmt_date(buf, 256, tt, DATEFMT_FULL);
169 StrBufAppendBufPlain(Target, buf, len, 0);
173 void tmplput_CtxICalPropertyDate(StrBuf * Target, WCTemplputParams * TP) {
174 icalproperty *p = (icalproperty *) CTX(CTX_ICALPROPERTY);
175 struct icaltimetype t;
180 t = icalproperty_get_dtend(p);
181 tt = icaltime_as_timet(t);
182 len = webcit_fmt_date(buf, sizeof(buf), tt, DATEFMT_FULL);
183 StrBufAppendBufPlain(Target, buf, len, 0);
188 void render_MIME_ICS_TPL(StrBuf * Target, WCTemplputParams * TP, StrBuf * FoundCharset) {
189 wc_mime_attachment *Mime = CTX(CTX_MIME_ATACH);
190 icalproperty_method the_method = ICAL_METHOD_NONE;
191 icalproperty *method = NULL;
192 icalcomponent *cal = NULL;
193 icalcomponent *c = NULL;
194 WCTemplputParams SubTP;
195 WCTemplputParams SuperTP;
197 static int divcount = 0;
199 if (StrLength(Mime->Data) == 0) {
202 if (StrLength(Mime->Data) > 0) {
203 cal = icalcomponent_new_from_string(ChrPtr(Mime->Data));
206 StrBufAppendPrintf(Mime->Data, _("There was an error parsing this calendar item."));
207 StrBufAppendPrintf(Mime->Data, "<br>\n");
211 putlbstr("divname", ++divcount);
214 putbstr("cal_partnum", NewStrBufDup(Mime->PartNum));
215 putlbstr("msgnum", Mime->msgnum);
217 memset(&SubTP, 0, sizeof(WCTemplputParams));
218 memset(&SuperTP, 0, sizeof(WCTemplputParams));
220 /*//ical_dezonify(cal); */
222 /* If the component has subcomponents, recurse through them. */
223 c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
224 c = (c != NULL) ? c : cal;
226 method = icalcomponent_get_first_property(cal, ICAL_METHOD_PROPERTY);
227 if (method != NULL) {
228 the_method = icalproperty_get_method(method);
231 StackContext(TP, &SuperTP, &the_method, CTX_ICALMETHOD, 0, TP->Tokens);
233 StackContext(&SuperTP, &SubTP, c, CTX_ICAL, 0, SuperTP.Tokens);
234 FlushStrBuf(Mime->Data);
235 /// DoTemplate(HKEY("ical_attachment_display"), Mime->Data, &SubTP);
236 DoTemplate(HKEY("ical_edit"), Mime->Data, &SubTP);
238 /*/ cal_process_object(Mime->Data, cal, 0, Mime->msgnum, ChrPtr(Mime->PartNum)); */
240 /* Free the memory we obtained from libical's constructor */
241 StrBufPlain(Mime->ContentType, HKEY("text/html"));
242 StrBufAppendPrintf(WC->trailing_javascript,
243 "eventEditAllDay(); \n"
244 "RecurrenceShowHide(); \n" "EnableOrDisableCheckButton(); \n");
246 UnStackContext(&SuperTP);
247 UnStackContext(&SubTP);
248 icalcomponent_free(cal);
250 void CreateIcalComponendKindLookup(void) {
253 IcalComponentMap = NewHash(1, NULL);
254 while (icalproperty_kind_map[i].NameLen != 0) {
255 RegisterNS(icalproperty_kind_map[i].Name,
256 icalproperty_kind_map[i].NameLen, 0, 10, tmplput_ICalItem, NULL, CTX_ICAL);
257 Put(IcalComponentMap,
258 icalproperty_kind_map[i].Name,
259 icalproperty_kind_map[i].NameLen, &icalproperty_kind_map[i], reference_free_handler);
269 int cond_ICalIsMethod(StrBuf * Target, WCTemplputParams * TP) {
270 icalproperty_method *the_method = (icalproperty_method *) CTX(CTX_ICALMETHOD);
271 icalproperty_method which_method;
273 which_method = GetTemplateTokenNumber(Target, TP, 2, ICAL_METHOD_X);
274 return *the_method == which_method;
278 typedef struct CalendarConflict {
280 long existing_msgnum;
281 StrBuf *conflict_event_uid;
282 StrBuf *conflict_event_summary;
284 void DeleteConflict(void *vConflict) {
285 CalendarConflict *c = (CalendarConflict *) vConflict;
287 FreeStrBuf(&c->conflict_event_uid);
288 FreeStrBuf(&c->conflict_event_summary);
291 HashList *iterate_FindConflict(StrBuf * Target, WCTemplputParams * TP) {
293 HashList *Conflicts = NULL;
294 CalendarConflict *Conflict;
295 wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
297 serv_printf("ICAL conflicts|%ld|%s|", Mime->msgnum, ChrPtr(Mime->PartNum));
300 StrBuf_ServGetln(Line);
301 if (GetServerStatus(Line, NULL) == 1) {
302 const char *Pos = NULL;
305 Conflicts = NewHash(1, Flathash);
306 while (!Done && (StrBuf_ServGetln(Line) >= 0))
307 if ((StrLength(Line) == 3) && !strcmp(ChrPtr(Line), "000")) {
311 Conflict = (CalendarConflict *) malloc(sizeof(CalendarConflict));
312 Conflict->conflict_event_uid = NewStrBufPlain(NULL, StrLength(Line));
313 Conflict->conflict_event_summary = NewStrBufPlain(NULL, StrLength(Line));
315 Conflict->existing_msgnum = StrBufExtractNext_long(Line, &Pos, '|');
316 StrBufSkip_NTokenS(Line, &Pos, '|', 1);
317 StrBufExtract_NextToken(Conflict->conflict_event_uid, Line, &Pos, '|');
318 StrBufExtract_NextToken(Conflict->conflict_event_summary, Line, &Pos, '|');
319 Conflict->is_update = StrBufExtractNext_long(Line, &Pos, '|');
321 Put(Conflicts, IKEY(n), Conflict, DeleteConflict);
327 syslog(LOG_DEBUG, "...done.\n");
333 void tmplput_ConflictEventMsgID(StrBuf * Target, WCTemplputParams * TP) {
334 CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
335 char buf[sizeof(long) * 16];
337 snprintf(buf, sizeof(buf), "%ld", C->existing_msgnum);
338 StrBufAppendTemplateStr(Target, TP, buf, 0);
340 void tmplput_ConflictEUID(StrBuf * Target, WCTemplputParams * TP) {
341 CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
343 StrBufAppendTemplate(Target, TP, C->conflict_event_uid, 0);
345 void tmplput_ConflictSummary(StrBuf * Target, WCTemplputParams * TP) {
346 CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
348 StrBufAppendTemplate(Target, TP, C->conflict_event_summary, 0);
350 int cond_ConflictIsUpdate(StrBuf * Target, WCTemplputParams * TP) {
351 CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
355 typedef struct CalAttendee {
357 icalparameter_partstat partstat;
360 void DeleteAtt(void *vAtt) {
361 CalAttendee *att = (CalAttendee *) vAtt;
362 FreeStrBuf(&att->AttendeeStr);
366 HashList *iterate_get_ical_attendees(StrBuf * Target, WCTemplputParams * TP) {
367 icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
368 icalparameter *partstat_param;
371 HashList *Attendees = NULL;
375 /* If the component has attendees, iterate through them. */
376 for (p = icalcomponent_get_first_property(cal, ICAL_ATTENDEE_PROPERTY);
377 (p != NULL); p = icalcomponent_get_next_property(cal, ICAL_ATTENDEE_PROPERTY)) {
378 ch = icalproperty_get_attendee(p);
379 if ((ch != NULL) && !strncasecmp(ch, "MAILTO:", 7)) {
380 Att = (CalAttendee *) malloc(sizeof(CalAttendee));
382 /** screen name or email address */
383 Att->AttendeeStr = NewStrBufPlain(ch + 7, -1);
384 StrBufTrim(Att->AttendeeStr);
386 /** participant status */
387 partstat_param = icalproperty_get_first_parameter(p, ICAL_PARTSTAT_PARAMETER);
388 if (partstat_param == NULL) {
389 Att->partstat = ICAL_PARTSTAT_X;
392 Att->partstat = icalparameter_get_partstat(partstat_param);
394 if (Attendees == NULL)
395 Attendees = NewHash(1, Flathash);
396 Put(Attendees, IKEY(n), Att, DeleteAtt);
403 void tmplput_ICalAttendee(StrBuf * Target, WCTemplputParams * TP) {
404 CalAttendee *Att = (CalAttendee *) CTX(CTX_ICALATTENDEE);
405 StrBufAppendTemplate(Target, TP, Att->AttendeeStr, 0);
407 int cond_ICalAttendeeState(StrBuf * Target, WCTemplputParams * TP) {
408 CalAttendee *Att = (CalAttendee *) CTX(CTX_ICALATTENDEE);
409 icalparameter_partstat which_partstat;
411 which_partstat = GetTemplateTokenNumber(Target, TP, 2, ICAL_PARTSTAT_X);
412 return Att->partstat == which_partstat;
415 /* If the component has subcomponents, recurse through them. * /
416 for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
418 c = icalcomponent_get_next_component(cal, ICAL_ANY_COMPONENT)) {
419 // Recursively process subcomponent
420 cal_process_object(Target, c, recursion_level+1, msgnum, cal_partnum);
425 void InitModule_ICAL_SUBST(void) {
426 RegisterCTX(CTX_ICAL);
429 RegisterMimeRenderer(HKEY("text/calendar"), render_MIME_ICS_TPL, 1, 501);
430 RegisterMimeRenderer(HKEY("application/ics"), render_MIME_ICS_TPL, 1, 500);
433 CreateIcalComponendKindLookup();
434 RegisterConditional("COND:ICAL:PROPERTY", 1, cond_ICalHaveItem, CTX_ICAL);
435 RegisterConditional("COND:ICAL:IS:A", 1, cond_ICalIsA, CTX_ICAL);
438 RegisterIterator("ICAL:CONFLICT", 0, NULL, iterate_FindConflict,
439 NULL, DeleteHash, CTX_MIME_ATACH, CTX_ICALCONFLICT, IT_NOFLAG);
440 RegisterNamespace("ICAL:CONFLICT:MSGID", 0, 1, tmplput_ConflictEventMsgID, NULL, CTX_ICALCONFLICT);
441 RegisterNamespace("ICAL:CONFLICT:EUID", 0, 1, tmplput_ConflictEUID, NULL, CTX_ICALCONFLICT);
442 RegisterNamespace("ICAL:CONFLICT:SUMMARY", 0, 1, tmplput_ConflictSummary, NULL, CTX_ICALCONFLICT);
443 RegisterConditional("ICAL:CONFLICT:IS:UPDATE", 0, cond_ConflictIsUpdate, CTX_ICALCONFLICT);
446 RegisterCTX(CTX_ICALATTENDEE);
447 RegisterIterator("ICAL:ATTENDEES", 0, NULL, iterate_get_ical_attendees,
448 NULL, DeleteHash, CTX_ICALATTENDEE, CTX_ICAL, IT_NOFLAG);
449 RegisterNamespace("ICAL:ATTENDEE", 1, 2, tmplput_ICalAttendee, NULL, CTX_ICALATTENDEE);
450 RegisterConditional("COND:ICAL:ATTENDEE", 1, cond_ICalAttendeeState, CTX_ICALATTENDEE);
452 RegisterCTX(CTX_ICALPROPERTY);
453 RegisterNamespace("ICAL:ITEM", 1, 2, tmplput_ICalItem, NULL, CTX_ICAL);
454 RegisterNamespace("ICAL:PROPERTY:STR", 0, 1, tmplput_CtxICalProperty, NULL, CTX_ICALPROPERTY);
455 RegisterNamespace("ICAL:PROPERTY:DATE", 0, 1, tmplput_CtxICalPropertyDate, NULL, CTX_ICALPROPERTY);
457 RegisterCTX(CTX_ICALMETHOD);
458 RegisterConditional("COND:ICAL:METHOD", 1, cond_ICalIsMethod, CTX_ICALMETHOD);
461 RegisterCTX(CTX_ICALTIME);
462 RegisterConditional("COND:ICAL:DT:PROPERTY", 1, cond_ICalHaveTimeItem, CTX_ICAL);
463 RegisterConditional("COND:ICAL:DT:ISDATE", 0, cond_ICalTimeIsDate, CTX_ICALTIME);
464 RegisterNamespace("ICAL:DT:DATE", 0, 1, tmplput_ICalTime_Date, NULL, CTX_ICALTIME);
465 RegisterNamespace("ICAL:DT:DATETIME", 0, 1, tmplput_ICalTime_Time, NULL, CTX_ICALTIME);
468 void ServerShutdownModule_ICAL(void) {
469 DeleteHash(&IcalComponentMap);