indent -kr -i8 -brf -bbb -fnc -l132 -nce on all of webcit-classic
[citadel.git] / webcit / ical_subst.c
1
2 /*
3  * Copyright (c) 1996-2012 by the citadel.org team
4  *
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.
7  *
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.
12  */
13
14 #include "webcit.h"
15
16 extern IcalKindEnumMap icalproperty_kind_map[];
17 extern IcalMethodEnumMap icalproperty_method_map[];
18
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;
26
27 void tmplput_ICalItem(StrBuf * Target, WCTemplputParams * TP) {
28         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
29         icalproperty *p;
30         icalproperty_kind Kind;
31         const char *str;
32
33         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 0, ICAL_ANY_PROPERTY);
34         p = icalcomponent_get_first_property(cal, Kind);
35         if (p != NULL) {
36                 str = icalproperty_get_comment(p);
37                 StrBufAppendTemplateStr(Target, TP, str, 1);
38         }
39 }
40
41 void tmplput_CtxICalProperty(StrBuf * Target, WCTemplputParams * TP) {
42         icalproperty *p = (icalproperty *) CTX(CTX_ICALPROPERTY);
43         const char *str;
44
45         str = icalproperty_get_comment(p);
46         StrBufAppendTemplateStr(Target, TP, str, 0);
47 }
48
49 int ReleaseIcalSubCtx(StrBuf * Target, WCTemplputParams * TP) {
50         WCTemplputParams *TPP = TP;
51         UnStackContext(TP);
52         free(TPP);
53         return 0;
54 }
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;
59 }
60
61 int cond_ICalHaveItem(StrBuf * Target, WCTemplputParams * TP) {
62         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
63         icalproperty *p;
64         icalproperty_kind Kind;
65
66         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 2, ICAL_ANY_PROPERTY);
67         p = icalcomponent_get_first_property(cal, Kind);
68         if (p != NULL) {
69                 WCTemplputParams *DynamicTP;
70
71                 DynamicTP = (WCTemplputParams *) malloc(sizeof(WCTemplputParams));
72                 StackDynamicContext(TP,
73                                     DynamicTP,
74                                     p, CTX_ICALPROPERTY, 0, TP->Tokens, ReleaseIcalSubCtx, TP->Tokens->Params[1]->lvalue);
75
76                 return 1;
77         }
78         return 0;
79 }
80
81 int ReleaseIcalTimeCtx(StrBuf * Target, WCTemplputParams * TP) {
82         WCTemplputParams *TPP = TP;
83
84         UnStackContext(TP);
85         free(TPP);
86         return 0;
87 }
88
89 int cond_ICalHaveTimeItem(StrBuf * Target, WCTemplputParams * TP) {
90         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
91         icalproperty *p;
92         icalproperty_kind Kind;
93
94         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 2, ICAL_ANY_PROPERTY);
95         p = icalcomponent_get_first_property(cal, Kind);
96         if (p != NULL) {
97                 struct icaltimetype *t;
98                 struct icaltimetype tt;
99                 WCTemplputParams *DynamicTP;
100
101                 DynamicTP = (WCTemplputParams *) malloc(sizeof(WCTemplputParams) + sizeof(struct icaltimetype));
102                 t = (struct icaltimetype *) &DynamicTP[1];
103                 memset(&tt, 0, sizeof(struct icaltimetype));
104                 switch (Kind) {
105                 case ICAL_DTSTART_PROPERTY:
106                         tt = icalproperty_get_dtstart(p);
107                         break;
108                 case ICAL_DTEND_PROPERTY:
109                         tt = icalproperty_get_dtend(p);
110                         break;
111                 default:
112                         break;
113                 }
114                 memcpy(t, &tt, sizeof(struct icaltimetype));
115
116                 StackDynamicContext(TP,
117                                     DynamicTP, t, CTX_ICALTIME, 0, TP->Tokens, ReleaseIcalTimeCtx, TP->Tokens->Params[1]->lvalue);
118
119                 return 1;
120         }
121         return 0;
122 }
123
124
125 int cond_ICalTimeIsDate(StrBuf * Target, WCTemplputParams * TP) {
126         struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
127         return t->is_date;
128 }
129
130 void tmplput_ICalTime_Date(StrBuf * Target, WCTemplputParams * TP) {
131         struct tm d_tm;
132         long len;
133         char buf[256];
134         struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
135
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);
142 }
143 void tmplput_ICalTime_Time(StrBuf * Target, WCTemplputParams * TP) {
144         long len;
145         char buf[256];
146         struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
147         time_t tt;
148
149         tt = icaltime_as_timet(*t);
150         len = webcit_fmt_date(buf, sizeof(buf), tt, DATEFMT_FULL);
151         StrBufAppendBufPlain(Target, buf, len, 0);
152 }
153
154 void tmplput_ICalDate(StrBuf * Target, WCTemplputParams * TP) {
155         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
156         icalproperty *p;
157         icalproperty_kind Kind;
158         struct icaltimetype t;
159         time_t tt;
160         char buf[256];
161
162         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 0, ICAL_ANY_PROPERTY);
163         p = icalcomponent_get_first_property(cal, Kind);
164         if (p != NULL) {
165                 long len;
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);
170         }
171 }
172
173 void tmplput_CtxICalPropertyDate(StrBuf * Target, WCTemplputParams * TP) {
174         icalproperty *p = (icalproperty *) CTX(CTX_ICALPROPERTY);
175         struct icaltimetype t;
176         time_t tt;
177         char buf[256];
178
179         long len;
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);
184 }
185
186
187
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;
196
197         static int divcount = 0;
198
199         if (StrLength(Mime->Data) == 0) {
200                 MimeLoadData(Mime);
201         }
202         if (StrLength(Mime->Data) > 0) {
203                 cal = icalcomponent_new_from_string(ChrPtr(Mime->Data));
204         }
205         if (cal == NULL) {
206                 StrBufAppendPrintf(Mime->Data, _("There was an error parsing this calendar item."));
207                 StrBufAppendPrintf(Mime->Data, "<br>\n");
208                 return;
209         }
210
211         putlbstr("divname", ++divcount);
212
213
214         putbstr("cal_partnum", NewStrBufDup(Mime->PartNum));
215         putlbstr("msgnum", Mime->msgnum);
216
217         memset(&SubTP, 0, sizeof(WCTemplputParams));
218         memset(&SuperTP, 0, sizeof(WCTemplputParams));
219
220         /*//ical_dezonify(cal); */
221
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;
225
226         method = icalcomponent_get_first_property(cal, ICAL_METHOD_PROPERTY);
227         if (method != NULL) {
228                 the_method = icalproperty_get_method(method);
229         }
230
231         StackContext(TP, &SuperTP, &the_method, CTX_ICALMETHOD, 0, TP->Tokens);
232
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);
237
238         /*/ cal_process_object(Mime->Data, cal, 0, Mime->msgnum, ChrPtr(Mime->PartNum)); */
239
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");
245
246         UnStackContext(&SuperTP);
247         UnStackContext(&SubTP);
248         icalcomponent_free(cal);
249 }
250 void CreateIcalComponendKindLookup(void) {
251         int i = 0;
252
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);
260
261
262                 i++;
263         }
264 }
265
266
267
268
269 int cond_ICalIsMethod(StrBuf * Target, WCTemplputParams * TP) {
270         icalproperty_method *the_method = (icalproperty_method *) CTX(CTX_ICALMETHOD);
271         icalproperty_method which_method;
272
273         which_method = GetTemplateTokenNumber(Target, TP, 2, ICAL_METHOD_X);
274         return *the_method == which_method;
275 }
276
277
278 typedef struct CalendarConflict {
279         long is_update;
280         long existing_msgnum;
281         StrBuf *conflict_event_uid;
282         StrBuf *conflict_event_summary;
283 } CalendarConflict;
284 void DeleteConflict(void *vConflict) {
285         CalendarConflict *c = (CalendarConflict *) vConflict;
286
287         FreeStrBuf(&c->conflict_event_uid);
288         FreeStrBuf(&c->conflict_event_summary);
289         free(c);
290 }
291 HashList *iterate_FindConflict(StrBuf * Target, WCTemplputParams * TP) {
292         StrBuf *Line;
293         HashList *Conflicts = NULL;
294         CalendarConflict *Conflict;
295         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
296
297         serv_printf("ICAL conflicts|%ld|%s|", Mime->msgnum, ChrPtr(Mime->PartNum));
298
299         Line = NewStrBuf();
300         StrBuf_ServGetln(Line);
301         if (GetServerStatus(Line, NULL) == 1) {
302                 const char *Pos = NULL;
303                 int Done = 0;
304                 int n = 0;
305                 Conflicts = NewHash(1, Flathash);
306                 while (!Done && (StrBuf_ServGetln(Line) >= 0))
307                         if ((StrLength(Line) == 3) && !strcmp(ChrPtr(Line), "000")) {
308                                 Done = 1;
309                         }
310                         else {
311                                 Conflict = (CalendarConflict *) malloc(sizeof(CalendarConflict));
312                                 Conflict->conflict_event_uid = NewStrBufPlain(NULL, StrLength(Line));
313                                 Conflict->conflict_event_summary = NewStrBufPlain(NULL, StrLength(Line));
314
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, '|');
320
321                                 Put(Conflicts, IKEY(n), Conflict, DeleteConflict);
322                                 n++;
323                                 Pos = NULL;
324                         }
325         }
326         FreeStrBuf(&Line);
327         syslog(LOG_DEBUG, "...done.\n");
328         return Conflicts;
329 }
330
331
332
333 void tmplput_ConflictEventMsgID(StrBuf * Target, WCTemplputParams * TP) {
334         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
335         char buf[sizeof(long) * 16];
336
337         snprintf(buf, sizeof(buf), "%ld", C->existing_msgnum);
338         StrBufAppendTemplateStr(Target, TP, buf, 0);
339 }
340 void tmplput_ConflictEUID(StrBuf * Target, WCTemplputParams * TP) {
341         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
342
343         StrBufAppendTemplate(Target, TP, C->conflict_event_uid, 0);
344 }
345 void tmplput_ConflictSummary(StrBuf * Target, WCTemplputParams * TP) {
346         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
347
348         StrBufAppendTemplate(Target, TP, C->conflict_event_summary, 0);
349 }
350 int cond_ConflictIsUpdate(StrBuf * Target, WCTemplputParams * TP) {
351         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
352         return C->is_update;
353 }
354
355 typedef struct CalAttendee {
356         StrBuf *AttendeeStr;
357         icalparameter_partstat partstat;
358 } CalAttendee;
359
360 void DeleteAtt(void *vAtt) {
361         CalAttendee *att = (CalAttendee *) vAtt;
362         FreeStrBuf(&att->AttendeeStr);
363         free(vAtt);
364 }
365
366 HashList *iterate_get_ical_attendees(StrBuf * Target, WCTemplputParams * TP) {
367         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
368         icalparameter *partstat_param;
369         icalproperty *p;
370         CalAttendee *Att;
371         HashList *Attendees = NULL;
372         const char *ch;
373         int n = 0;
374
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));
381
382                         /** screen name or email address */
383                         Att->AttendeeStr = NewStrBufPlain(ch + 7, -1);
384                         StrBufTrim(Att->AttendeeStr);
385
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;
390                         }
391                         else {
392                                 Att->partstat = icalparameter_get_partstat(partstat_param);
393                         }
394                         if (Attendees == NULL)
395                                 Attendees = NewHash(1, Flathash);
396                         Put(Attendees, IKEY(n), Att, DeleteAtt);
397                         n++;
398                 }
399         }
400         return Attendees;
401 }
402
403 void tmplput_ICalAttendee(StrBuf * Target, WCTemplputParams * TP) {
404         CalAttendee *Att = (CalAttendee *) CTX(CTX_ICALATTENDEE);
405         StrBufAppendTemplate(Target, TP, Att->AttendeeStr, 0);
406 }
407 int cond_ICalAttendeeState(StrBuf * Target, WCTemplputParams * TP) {
408         CalAttendee *Att = (CalAttendee *) CTX(CTX_ICALATTENDEE);
409         icalparameter_partstat which_partstat;
410
411         which_partstat = GetTemplateTokenNumber(Target, TP, 2, ICAL_PARTSTAT_X);
412         return Att->partstat == which_partstat;
413 }
414
415         /* If the component has subcomponents, recurse through them. * /
416            for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
417            (c != 0);
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);
421            }
422          */
423
424
425 void InitModule_ICAL_SUBST(void) {
426         RegisterCTX(CTX_ICAL);
427
428 /*
429         RegisterMimeRenderer(HKEY("text/calendar"), render_MIME_ICS_TPL, 1, 501);
430         RegisterMimeRenderer(HKEY("application/ics"), render_MIME_ICS_TPL, 1, 500);
431 */
432
433         CreateIcalComponendKindLookup();
434         RegisterConditional("COND:ICAL:PROPERTY", 1, cond_ICalHaveItem, CTX_ICAL);
435         RegisterConditional("COND:ICAL:IS:A", 1, cond_ICalIsA, CTX_ICAL);
436
437
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);
444
445
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);
451
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);
456
457         RegisterCTX(CTX_ICALMETHOD);
458         RegisterConditional("COND:ICAL:METHOD", 1, cond_ICalIsMethod, CTX_ICALMETHOD);
459
460
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);
466 }
467
468 void ServerShutdownModule_ICAL(void) {
469         DeleteHash(&IcalComponentMap);
470 }