5f2393ff9cb95e8604504051feeeef2bca335065
[citadel.git] / webcit / ical_subst.c
1 /*
2  * Copyright (c) 1996-2012 by the citadel.org team
3  *
4  * This program is open source software.  You can redistribute it and/or
5  * modify it under the terms of the GNU General Public License, version 3.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12
13 #include "webcit.h"
14
15 extern IcalKindEnumMap icalproperty_kind_map[];
16 extern IcalMethodEnumMap icalproperty_method_map[];
17
18 HashList *IcalComponentMap = NULL;
19 CtxType CTX_ICAL = CTX_NONE;
20 CtxType CTX_ICALPROPERTY = CTX_NONE;
21 CtxType CTX_ICALMETHOD = CTX_NONE;
22 CtxType CTX_ICALTIME = CTX_NONE;
23 CtxType CTX_ICALATTENDEE = CTX_NONE;
24 CtxType CTX_ICALCONFLICT = CTX_NONE;
25 #if 0
26 void SortPregetMatter(HashList *Cals)
27 {
28         disp_cal *Cal;
29         void *vCal;
30         const char *Key;
31         long KLen;
32         IcalEnumMap *SortMap[10];
33         IcalEnumMap *Map;
34         void *vSort;
35         const char *Next = NULL;
36         const StrBuf *SortVector;
37         StrBuf *SortBy;
38         int i = 0;
39         HashPos *It;
40
41         SortVector = SBSTR("ICALSortVec");
42         if (SortVector == NULL)
43                 return;
44
45         for (i = 0; i < 10; i++) SortMap[i] = NULL;
46         SortBy = NewStrBuf();
47         while (StrBufExtract_NextToken(SortBy, SortVector, &Next, ':') > 0) {
48                 GetHash(IcalComponentMap, SKEY(SortBy), &vSort);
49                 Map = (IcalEnumMap*) vSort;
50                 SortMap[i] = Map;
51                 i++;
52                 if (i > 9)
53                         break;
54         }
55
56         if (i == 0)
57                 return;
58
59         switch (SortMap[i - 1]->map) {
60                 /*      case */
61
62         default:
63                 break;
64         }
65
66         It = GetNewHashPos(Cals, 0);
67         while (GetNextHashPos(Cals, It, &KLen, &Key, &vCal)) {
68                 i = 0;
69                 Cal = (disp_cal*) vCal;
70                 Cal->Status = icalcomponent_get_status(Cal->cal);
71                 Cal->SortBy = Cal->cal;
72                 
73
74                 while ((SortMap[i] != NULL) && 
75                        (Cal->SortBy != NULL)) 
76                 {
77                         /****Cal->SortBy = icalcomponent_get_first_property(Cal->SortBy, SortMap[i++]->map); */
78                 }
79         }
80 }
81 #endif
82
83
84 void tmplput_ICalItem(StrBuf *Target, WCTemplputParams *TP)
85 {
86         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
87         icalproperty *p;
88         icalproperty_kind Kind;
89         const char *str;
90
91         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 0, ICAL_ANY_PROPERTY);
92         p = icalcomponent_get_first_property(cal, Kind);
93         if (p != NULL) {
94                 str = icalproperty_get_comment (p);
95                 StrBufAppendTemplateStr(Target, TP, str, 1);
96         }
97 }
98
99 void tmplput_CtxICalProperty(StrBuf *Target, WCTemplputParams *TP)
100 {
101         icalproperty *p = (icalproperty *) CTX(CTX_ICALPROPERTY);
102         const char *str;
103
104         str = icalproperty_get_comment (p);
105         StrBufAppendTemplateStr(Target, TP, str, 0);
106 }
107
108 int ReleaseIcalSubCtx(StrBuf *Target, WCTemplputParams *TP)
109 {
110         WCTemplputParams *TPP = TP;
111         UnStackContext(TP);
112         free(TPP);
113         return 0;
114 }
115 int cond_ICalIsA(StrBuf *Target, WCTemplputParams *TP)
116 {
117         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
118         icalcomponent_kind c = GetTemplateTokenNumber(Target, TP, 2, ICAL_NO_COMPONENT);
119         return icalcomponent_isa(cal) == c;
120 }
121
122 int cond_ICalHaveItem(StrBuf *Target, WCTemplputParams *TP)
123 {
124         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
125         icalproperty *p;
126         icalproperty_kind Kind;
127
128         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 2, ICAL_ANY_PROPERTY);
129         p = icalcomponent_get_first_property(cal, Kind);
130         if (p != NULL) {
131                 WCTemplputParams *DynamicTP;
132         
133                 DynamicTP = (WCTemplputParams*) malloc(sizeof(WCTemplputParams));
134                 StackDynamicContext (TP, 
135                                      DynamicTP, 
136                                      p,
137                                      CTX_ICALPROPERTY,
138                                      0,
139                                      TP->Tokens,
140                                      ReleaseIcalSubCtx,
141                                      TP->Tokens->Params[1]->lvalue);
142
143                 return 1;
144         }
145         return 0;
146 }
147
148 int ReleaseIcalTimeCtx(StrBuf *Target, WCTemplputParams *TP)
149 {
150         WCTemplputParams *TPP = TP;
151
152         UnStackContext(TP);
153         free(TPP);
154         return 0;
155 }
156
157 int cond_ICalHaveTimeItem(StrBuf *Target, WCTemplputParams *TP)
158 {
159         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
160         icalproperty *p;
161         icalproperty_kind Kind;
162
163         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 2, ICAL_ANY_PROPERTY);
164         p = icalcomponent_get_first_property(cal, Kind);
165         if (p != NULL) {
166                 struct icaltimetype *t;
167                 struct icaltimetype tt;
168                 WCTemplputParams *DynamicTP;
169
170                 DynamicTP = (WCTemplputParams*) malloc(sizeof(WCTemplputParams) + 
171                                                        sizeof(struct icaltimetype));
172                 t = (struct icaltimetype *) &DynamicTP[1];
173                 memset(&tt, 0, sizeof(struct icaltimetype));
174                 switch (Kind)
175                 {
176                 case ICAL_DTSTART_PROPERTY:
177                         tt = icalproperty_get_dtstart(p);
178                         break;
179                 case ICAL_DTEND_PROPERTY:
180                         tt = icalproperty_get_dtend(p);
181                         break;
182                 default:
183                         break;
184                 }
185                 memcpy(t, &tt, sizeof(struct icaltimetype));
186
187                 StackDynamicContext (TP, 
188                                      DynamicTP, 
189                                      t,
190                                      CTX_ICALTIME,
191                                      0,
192                                      TP->Tokens,
193                                      ReleaseIcalTimeCtx,
194                                      TP->Tokens->Params[1]->lvalue);
195
196                 return 1;
197         }
198         return 0;
199 }
200
201
202 int cond_ICalTimeIsDate(StrBuf *Target, WCTemplputParams *TP)
203 {
204         struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
205         return t->is_date;
206 }
207
208 void tmplput_ICalTime_Date(StrBuf *Target, WCTemplputParams *TP)
209 {
210         struct tm d_tm;
211         long len;
212         char buf[256];
213         struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
214
215         memset(&d_tm, 0, sizeof d_tm);
216         d_tm.tm_year = t->year - 1900;
217         d_tm.tm_mon = t->month - 1;
218         d_tm.tm_mday = t->day;
219         len = wc_strftime(buf, sizeof(buf), "%x", &d_tm);
220         StrBufAppendBufPlain(Target, buf, len, 0);
221 }
222 void tmplput_ICalTime_Time(StrBuf *Target, WCTemplputParams *TP)
223 {
224         long len;
225         char buf[256];
226         struct icaltimetype *t = (struct icaltimetype *) CTX(CTX_ICALTIME);
227         time_t tt;
228
229         tt = icaltime_as_timet(*t);
230         len = webcit_fmt_date(buf, sizeof(buf), tt, DATEFMT_FULL);
231         StrBufAppendBufPlain(Target, buf, len, 0);
232 }
233
234 void tmplput_ICalDate(StrBuf *Target, WCTemplputParams *TP)
235 {
236         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
237         icalproperty *p;
238         icalproperty_kind Kind;
239         struct icaltimetype t;
240         time_t tt;
241         char buf[256];
242
243         Kind = (icalproperty_kind) GetTemplateTokenNumber(Target, TP, 0, ICAL_ANY_PROPERTY);
244         p = icalcomponent_get_first_property(cal, Kind);
245         if (p != NULL) {
246                 long len;
247                 t = icalproperty_get_dtend(p);
248                 tt = icaltime_as_timet(t);
249                 len = webcit_fmt_date(buf, 256, tt, DATEFMT_FULL);
250                 StrBufAppendBufPlain(Target, buf, len, 0);
251         }
252 }
253
254 void tmplput_CtxICalPropertyDate(StrBuf *Target, WCTemplputParams *TP)
255 {
256         icalproperty *p = (icalproperty *) CTX(CTX_ICALPROPERTY);
257         struct icaltimetype t;
258         time_t tt;
259         char buf[256];
260
261         long len;
262         t = icalproperty_get_dtend(p);
263         tt = icaltime_as_timet(t);
264         len = webcit_fmt_date(buf, sizeof(buf), tt, DATEFMT_FULL);
265         StrBufAppendBufPlain(Target, buf, len, 0);
266 }
267
268
269
270 void render_MIME_ICS_TPL(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset)
271 {
272         wc_mime_attachment *Mime = CTX(CTX_MIME_ATACH);
273         icalproperty_method the_method = ICAL_METHOD_NONE;
274         icalproperty *method = NULL;
275         icalcomponent *cal;
276         icalcomponent *c;
277         WCTemplputParams SubTP;
278         WCTemplputParams SuperTP;
279
280         static int divcount = 0;
281
282         if (StrLength(Mime->Data) == 0) {
283                 MimeLoadData(Mime);
284         }
285         if (StrLength(Mime->Data) > 0) {
286                 cal = icalcomponent_new_from_string(ChrPtr(Mime->Data));
287         }
288         if (cal == NULL) {
289                 StrBufAppendPrintf(Mime->Data, _("There was an error parsing this calendar item."));
290                 StrBufAppendPrintf(Mime->Data, "<br>\n");
291                 return;
292         }
293
294         putlbstr("divname",  ++divcount);
295
296
297         putbstr("cal_partnum", NewStrBufDup(Mime->PartNum));
298         putlbstr("msgnum", Mime->msgnum);
299
300         memset(&SubTP, 0, sizeof(WCTemplputParams));
301         memset(&SuperTP, 0, sizeof(WCTemplputParams));
302
303         /*//ical_dezonify(cal); */
304
305         /* If the component has subcomponents, recurse through them. */
306         c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
307         c = (c != NULL) ? c : cal;
308
309         method = icalcomponent_get_first_property(cal, ICAL_METHOD_PROPERTY);
310         if (method != NULL) {
311                 the_method = icalproperty_get_method(method);
312         }
313
314         StackContext (TP,
315                       &SuperTP,
316                       &the_method,
317                       CTX_ICALMETHOD,
318                       0,
319                       TP->Tokens);
320
321         StackContext (&SuperTP, 
322                       &SubTP, 
323                       c,
324                       CTX_ICAL,
325                       0,
326                       SuperTP.Tokens);
327         FlushStrBuf(Mime->Data);
328 ///     DoTemplate(HKEY("ical_attachment_display"), Mime->Data, &SubTP);
329         DoTemplate(HKEY("ical_edit"), Mime->Data, &SubTP);
330
331         /*/ cal_process_object(Mime->Data, cal, 0, Mime->msgnum, ChrPtr(Mime->PartNum)); */
332
333         /* Free the memory we obtained from libical's constructor */
334         StrBufPlain(Mime->ContentType, HKEY("text/html"));
335         StrBufAppendPrintf(WC->trailing_javascript,
336                 "eventEditAllDay();             \n"
337                 "RecurrenceShowHide();          \n"
338                 "EnableOrDisableCheckButton();  \n"
339         );
340
341         UnStackContext(&SuperTP);
342         UnStackContext(&SubTP);
343         icalcomponent_free(cal);
344 }
345 void CreateIcalComponendKindLookup(void)
346 {
347         int i = 0;
348
349         IcalComponentMap = NewHash (1, NULL);
350         while (icalproperty_kind_map[i].NameLen != 0) {
351                 RegisterNS(icalproperty_kind_map[i].Name, 
352                            icalproperty_kind_map[i].NameLen, 
353                            0, 
354                            10, 
355                            tmplput_ICalItem,
356                            NULL, 
357                            CTX_ICAL);
358                 Put(IcalComponentMap, 
359                     icalproperty_kind_map[i].Name, 
360                     icalproperty_kind_map[i].NameLen, 
361                     &icalproperty_kind_map[i],
362                     reference_free_handler);
363                            
364                            
365                 i++;
366         }
367 }
368
369
370
371
372 int cond_ICalIsMethod(StrBuf *Target, WCTemplputParams *TP)
373 {
374         icalproperty_method *the_method = (icalproperty_method *) CTX(CTX_ICALMETHOD);
375         icalproperty_method which_method;
376
377         which_method = GetTemplateTokenNumber(Target, TP, 2, ICAL_METHOD_X);
378         return *the_method == which_method;
379 }
380
381
382 typedef struct CalendarConflict
383 {
384         long is_update;
385         long existing_msgnum;
386         StrBuf *conflict_event_uid;
387         StrBuf *conflict_event_summary;
388 }CalendarConflict;
389 void DeleteConflict(void *vConflict)
390 {
391         CalendarConflict *c = (CalendarConflict *) vConflict;
392
393         FreeStrBuf(&c->conflict_event_uid);
394         FreeStrBuf(&c->conflict_event_summary);
395         free(c);
396 }
397 HashList *iterate_FindConflict(StrBuf *Target, WCTemplputParams *TP)
398 {
399         StrBuf *Line;
400         HashList *Conflicts = NULL;
401         CalendarConflict *Conflict;
402         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
403
404         serv_printf("ICAL conflicts|%ld|%s|", Mime->msgnum, ChrPtr(Mime->PartNum));
405
406         Line = NewStrBuf();
407         StrBuf_ServGetln(Line);
408         if (GetServerStatus(Line, NULL) == 1)
409         {
410                 const char *Pos = NULL;
411                 int Done = 0;
412                 int n = 0;
413                 Conflicts = NewHash(1, Flathash);
414                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
415                         if ( (StrLength(Line)==3) && 
416                              !strcmp(ChrPtr(Line), "000")) 
417                         {
418                                 Done = 1;
419                         }
420                         else {
421                                 Conflict = (CalendarConflict *) malloc(sizeof(CalendarConflict));
422                                 Conflict->conflict_event_uid = NewStrBufPlain(NULL, StrLength(Line));
423                                 Conflict->conflict_event_summary = NewStrBufPlain(NULL, StrLength(Line));
424
425                                 Conflict->existing_msgnum = StrBufExtractNext_long(Line, &Pos, '|');
426                                 StrBufSkip_NTokenS(Line, &Pos, '|', 1);
427                                 StrBufExtract_NextToken(Conflict->conflict_event_uid, Line, &Pos, '|');
428                                 StrBufExtract_NextToken(Conflict->conflict_event_summary, Line, &Pos, '|');
429                                 Conflict->is_update = StrBufExtractNext_long(Line, &Pos, '|');
430
431                                 Put(Conflicts, IKEY(n), Conflict, DeleteConflict);
432                                 n++;
433                                 Pos = NULL;
434                         }
435         }
436         FreeStrBuf(&Line);
437         syslog(LOG_DEBUG, "...done.\n");
438         return Conflicts;
439 }
440
441
442
443 void tmplput_ConflictEventMsgID(StrBuf *Target, WCTemplputParams *TP)
444 {
445         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
446         char buf[sizeof(long) * 16];
447
448         snprintf(buf, sizeof(buf), "%ld", C->existing_msgnum);
449         StrBufAppendTemplateStr(Target, TP, buf, 0);
450 }
451 void tmplput_ConflictEUID(StrBuf *Target, WCTemplputParams *TP)
452 {
453         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
454         
455         StrBufAppendTemplate(Target, TP, C->conflict_event_uid, 0);
456 }
457 void tmplput_ConflictSummary(StrBuf *Target, WCTemplputParams *TP)
458 {
459         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
460
461         StrBufAppendTemplate(Target, TP, C->conflict_event_summary, 0);
462 }
463 int cond_ConflictIsUpdate(StrBuf *Target, WCTemplputParams *TP)
464 {
465         CalendarConflict *C = (CalendarConflict *) CTX(CTX_ICALCONFLICT);
466         return C->is_update;
467 }
468
469 typedef struct CalAttendee
470 {
471         StrBuf *AttendeeStr;
472         icalparameter_partstat partstat;
473 } CalAttendee;
474
475 void DeleteAtt(void *vAtt)
476 {
477         CalAttendee *att = (CalAttendee*) vAtt;
478         FreeStrBuf(&att->AttendeeStr);
479         free(vAtt);
480 }
481
482 HashList *iterate_get_ical_attendees(StrBuf *Target, WCTemplputParams *TP)
483 {
484         icalcomponent *cal = (icalcomponent *) CTX(CTX_ICAL);
485         icalparameter *partstat_param;
486         icalproperty *p;
487         CalAttendee *Att;
488         HashList *Attendees = NULL;
489         const char *ch;
490         int n = 0;
491
492         /* If the component has attendees, iterate through them. */
493         for (p = icalcomponent_get_first_property(cal, ICAL_ATTENDEE_PROPERTY); 
494              (p != NULL); 
495              p = icalcomponent_get_next_property(cal, ICAL_ATTENDEE_PROPERTY)) {
496                 ch = icalproperty_get_attendee(p);
497                 if ((ch != NULL) && !strncasecmp(ch, "MAILTO:", 7)) {
498                         Att = (CalAttendee*) malloc(sizeof(CalAttendee));
499
500                         /** screen name or email address */
501                         Att->AttendeeStr = NewStrBufPlain(ch + 7, -1);
502                         StrBufTrim(Att->AttendeeStr);
503
504                         /** participant status */
505                         partstat_param = icalproperty_get_first_parameter(
506                                 p,
507                                 ICAL_PARTSTAT_PARAMETER
508                                 );
509                         if (partstat_param == NULL) {
510                                 Att->partstat = ICAL_PARTSTAT_X;
511                         }
512                         else {
513                                 Att->partstat = icalparameter_get_partstat(partstat_param);
514                         }
515                         if (Attendees == NULL)
516                                 Attendees = NewHash(1, Flathash);
517                         Put(Attendees, IKEY(n), Att, DeleteAtt);
518                         n++;
519                 }
520         }
521         return Attendees;
522 }
523
524 void tmplput_ICalAttendee(StrBuf *Target, WCTemplputParams *TP)
525 {
526         CalAttendee *Att = (CalAttendee*) CTX(CTX_ICALATTENDEE);
527         StrBufAppendTemplate(Target, TP, Att->AttendeeStr, 0);
528 }
529 int cond_ICalAttendeeState(StrBuf *Target, WCTemplputParams *TP)
530 {
531         CalAttendee *Att = (CalAttendee*) CTX(CTX_ICALATTENDEE);
532         icalparameter_partstat which_partstat;
533
534         which_partstat = GetTemplateTokenNumber(Target, TP, 2, ICAL_PARTSTAT_X);
535         return Att->partstat == which_partstat;
536 }
537         /* If the component has subcomponents, recurse through them. * /
538         for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
539              (c != 0);
540              c = icalcomponent_get_next_component(cal, ICAL_ANY_COMPONENT)) {
541                 /* Recursively process subcomponent * /
542                 cal_process_object(Target, c, recursion_level+1, msgnum, cal_partnum);
543         }
544         */
545
546
547 void 
548 InitModule_ICAL_SUBST
549 (void)
550 {
551         RegisterCTX(CTX_ICAL);
552 /*
553         RegisterMimeRenderer(HKEY("text/calendar"), render_MIME_ICS_TPL, 1, 501);
554         RegisterMimeRenderer(HKEY("application/ics"), render_MIME_ICS_TPL, 1, 500);
555 */
556
557         CreateIcalComponendKindLookup ();
558         RegisterConditional("COND:ICAL:PROPERTY", 1, cond_ICalHaveItem, CTX_ICAL);
559         RegisterConditional("COND:ICAL:IS:A", 1, cond_ICalIsA, CTX_ICAL);
560
561
562         RegisterIterator("ICAL:CONFLICT", 0, NULL, iterate_FindConflict, 
563                          NULL, DeleteHash, CTX_MIME_ATACH, CTX_ICALCONFLICT, IT_NOFLAG);
564         RegisterNamespace("ICAL:CONFLICT:MSGID", 0, 1, tmplput_ConflictEventMsgID, NULL, CTX_ICALCONFLICT);
565         RegisterNamespace("ICAL:CONFLICT:EUID", 0, 1, tmplput_ConflictEUID, NULL, CTX_ICALCONFLICT);
566         RegisterNamespace("ICAL:CONFLICT:SUMMARY", 0, 1, tmplput_ConflictSummary, NULL, CTX_ICALCONFLICT);
567         RegisterConditional("ICAL:CONFLICT:IS:UPDATE", 0, cond_ConflictIsUpdate, CTX_ICALCONFLICT);
568
569
570         RegisterCTX(CTX_ICALATTENDEE);
571         RegisterIterator("ICAL:ATTENDEES", 0, NULL, iterate_get_ical_attendees, 
572                          NULL, DeleteHash, CTX_ICALATTENDEE, CTX_ICAL, IT_NOFLAG);
573         RegisterNamespace("ICAL:ATTENDEE", 1, 2, tmplput_ICalAttendee, NULL, CTX_ICALATTENDEE);
574         RegisterConditional("COND:ICAL:ATTENDEE", 1, cond_ICalAttendeeState, CTX_ICALATTENDEE);
575
576         RegisterCTX(CTX_ICALPROPERTY);
577         RegisterNamespace("ICAL:ITEM", 1, 2, tmplput_ICalItem, NULL, CTX_ICAL);
578         RegisterNamespace("ICAL:PROPERTY:STR", 0, 1, tmplput_CtxICalProperty, NULL, CTX_ICALPROPERTY);
579         RegisterNamespace("ICAL:PROPERTY:DATE", 0, 1, tmplput_CtxICalPropertyDate, NULL, CTX_ICALPROPERTY);
580
581         RegisterCTX(CTX_ICALMETHOD);
582         RegisterConditional("COND:ICAL:METHOD", 1, cond_ICalIsMethod, CTX_ICALMETHOD);
583
584
585         RegisterCTX(CTX_ICALTIME);
586         RegisterConditional("COND:ICAL:DT:PROPERTY", 1, cond_ICalHaveTimeItem, CTX_ICAL);
587         RegisterConditional("COND:ICAL:DT:ISDATE", 0, cond_ICalTimeIsDate, CTX_ICALTIME);
588         RegisterNamespace("ICAL:DT:DATE", 0, 1, tmplput_ICalTime_Date, NULL, CTX_ICALTIME);
589         RegisterNamespace("ICAL:DT:DATETIME", 0, 1, tmplput_ICalTime_Time, NULL, CTX_ICALTIME);
590 }
591
592 void 
593 ServerShutdownModule_ICAL
594 (void)
595 {
596         DeleteHash(&IcalComponentMap);
597 }