Removed from WebCit Classic all code which handles display of legacy CitaNet node...
[citadel.git] / webcit / msg_renderers.c
1 #include "webcit.h"
2 #include "webserver.h"
3 #include "dav.h"
4
5 CtxType CTX_MAILSUM = CTX_NONE;
6 CtxType CTX_MIME_ATACH = CTX_NONE;
7
8 HashList *MsgHeaderHandler = NULL;
9 HashList *DflMsgHeaderHandler = NULL;
10 HashList *DflEnumMsgHeaderHandler = NULL;
11
12
13 static inline void CheckConvertBufs(struct wcsession *WCC)
14 {
15         if (WCC->ConvertBuf1 == NULL)
16                 WCC->ConvertBuf1 = NewStrBuf();
17         if (WCC->ConvertBuf2 == NULL)
18                 WCC->ConvertBuf2 = NewStrBuf();
19 }
20
21 /*
22  * message index functions
23  */
24
25
26 void DestroyMimeParts(wc_mime_attachment *Mime)
27 {
28         FreeStrBuf(&Mime->Name);
29         FreeStrBuf(&Mime->FileName);
30         FreeStrBuf(&Mime->PartNum);
31         FreeStrBuf(&Mime->Disposition);
32         FreeStrBuf(&Mime->ContentType);
33         FreeStrBuf(&Mime->Charset);
34         FreeStrBuf(&Mime->Data);
35 }
36
37 void DestroyMime(void *vMime)
38 {
39         wc_mime_attachment *Mime = (wc_mime_attachment*)vMime;
40         DestroyMimeParts(Mime);
41         free(Mime);
42 }
43
44 void DestroyMessageSummary(void *vMsg)
45 {
46         message_summary *Msg = (message_summary*) vMsg;
47
48         FreeStrBuf(&Msg->from);
49         FreeStrBuf(&Msg->to);
50         FreeStrBuf(&Msg->subj);
51         FreeStrBuf(&Msg->reply_inreplyto);
52         FreeStrBuf(&Msg->reply_references);
53         FreeStrBuf(&Msg->cccc);
54         FreeStrBuf(&Msg->ReplyTo);
55         FreeStrBuf(&Msg->hnod);
56         FreeStrBuf(&Msg->AllRcpt);
57         FreeStrBuf(&Msg->Room);
58         FreeStrBuf(&Msg->Rfca);
59         FreeStrBuf(&Msg->EnvTo);
60         FreeStrBuf(&Msg->OtherNode);
61
62         DeleteHash(&Msg->Attachments);  /* list of Attachments */
63         DeleteHash(&Msg->Submessages);
64         DeleteHash(&Msg->AttachLinks);
65         DeleteHash(&Msg->AllAttach);
66         free(Msg);
67 }
68
69 int EvaluateMsgHdrEnum(eMessageField f, message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
70 {
71         void *vHdr;
72         headereval* Hdr = NULL;
73         if (GetHash(DflEnumMsgHeaderHandler, IKEY(f), &vHdr) &&
74             (vHdr != NULL)) {
75                 Hdr = (headereval*)vHdr;
76         }
77         if (Hdr == NULL)
78                 return -1;
79         Hdr->evaluator(Msg, HdrLine, FoundCharset);
80         return Hdr->Type;
81 }
82
83 int EvaluateMsgHdr(const char *HeaderName, long HdrNLen, message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
84 {
85         void *vHdr;
86         headereval* Hdr = NULL;
87         if (HdrNLen == 4) {
88                 if (GetHash(DflMsgHeaderHandler, HeaderName, HdrNLen, &vHdr) &&
89                     (vHdr != NULL)) {
90                         Hdr = (headereval*)vHdr;
91                 }
92         }
93         if (Hdr == NULL && GetHash(MsgHeaderHandler, HeaderName, HdrNLen, &vHdr) &&
94             (vHdr != NULL)) {
95                 Hdr = (headereval*)vHdr;
96         }
97         if (Hdr == NULL)
98                 return -1;
99         Hdr->evaluator(Msg, HdrLine, FoundCharset);
100         return Hdr->Type;
101 }
102
103 void RegisterMsgHdr(const char *HeaderName, long HdrNLen, ExamineMsgHeaderFunc evaluator, int type)
104 {
105         headereval *ev;
106         ev = (headereval*) malloc(sizeof(headereval));
107         ev->evaluator = evaluator;
108         ev->Type = type;
109
110         if (HdrNLen == 4) {
111                 eMessageField f;
112                 if (GetFieldFromMnemonic(&f, HeaderName)) {
113                         Put(DflMsgHeaderHandler, HeaderName, HdrNLen, ev, NULL);
114                         Put(DflEnumMsgHeaderHandler, IKEY(f), ev, reference_free_handler);
115                         return;
116                 }
117         }
118         Put(MsgHeaderHandler, HeaderName, HdrNLen, ev, NULL);
119 }
120
121 void RegisterMimeRenderer(const char *HeaderName, long HdrNLen, 
122                           RenderMimeFunc MimeRenderer,
123                           int InlineRenderable,
124                           int Priority)
125 {
126         RenderMimeFuncStruct *f;
127
128         f = (RenderMimeFuncStruct*) malloc(sizeof(RenderMimeFuncStruct));
129         f->f = MimeRenderer;
130         Put(MimeRenderHandler, HeaderName, HdrNLen, f, NULL);
131         if (InlineRenderable)
132                 RegisterEmbeddableMimeType(HeaderName, HdrNLen, 10000 - Priority);
133 }
134
135 /*----------------------------------------------------------------------------*/
136
137 /*
138  *  comparator for two longs in descending order.
139  */
140 int longcmp_r(const void *s1, const void *s2) {
141         long l1;
142         long l2;
143
144         l1 = *(long *)GetSearchPayload(s1);
145         l2 = *(long *)GetSearchPayload(s2);
146
147         if (l1 > l2) return(-1);
148         if (l1 < l2) return(+1);
149         return(0);
150 }
151
152 /*
153  *  comparator for longs; descending order.
154  */
155 int qlongcmp_r(const void *s1, const void *s2) {
156         long l1 = (long) s1;
157         long l2 = (long) s2;
158
159         if (l1 > l2) return(-1);
160         if (l1 < l2) return(+1);
161         return(0);
162 }
163
164  
165 /*
166  * comparator for message summary structs by ascending subject.
167  */
168 int summcmp_subj(const void *s1, const void *s2) {
169         message_summary *summ1;
170         message_summary *summ2;
171         
172         summ1 = (message_summary *)GetSearchPayload(s1);
173         summ2 = (message_summary *)GetSearchPayload(s2);
174         return strcasecmp(ChrPtr(summ1->subj), ChrPtr(summ2->subj));
175 }
176
177 /*
178  * comparator for message summary structs by descending subject.
179  */
180 int summcmp_rsubj(const void *s1, const void *s2) {
181         message_summary *summ1;
182         message_summary *summ2;
183         
184         summ1 = (message_summary *)GetSearchPayload(s1);
185         summ2 = (message_summary *)GetSearchPayload(s2);
186         return strcasecmp(ChrPtr(summ2->subj), ChrPtr(summ1->subj));
187 }
188 /*
189  * comparator for message summary structs by descending subject.
190  */
191 int groupchange_subj(const void *s1, const void *s2) {
192         message_summary *summ1;
193         message_summary *summ2;
194         
195         summ1 = (message_summary *)s1;
196         summ2 = (message_summary *)s2;
197         return ChrPtr(summ2->subj)[0] != ChrPtr(summ1->subj)[0];
198 }
199
200 /*
201  * comparator for message summary structs by ascending sender.
202  */
203 int summcmp_sender(const void *s1, const void *s2) {
204         message_summary *summ1;
205         message_summary *summ2;
206         
207         summ1 = (message_summary *)GetSearchPayload(s1);
208         summ2 = (message_summary *)GetSearchPayload(s2);
209         return strcasecmp(ChrPtr(summ1->from), ChrPtr(summ2->from));
210 }
211
212 /*
213  * comparator for message summary structs by descending sender.
214  */
215 int summcmp_rsender(const void *s1, const void *s2) {
216         message_summary *summ1;
217         message_summary *summ2;
218         
219         summ1 = (message_summary *)GetSearchPayload(s1);
220         summ2 = (message_summary *)GetSearchPayload(s2);
221         return strcasecmp(ChrPtr(summ2->from), ChrPtr(summ1->from));
222 }
223 /*
224  * comparator for message summary structs by descending sender.
225  */
226 int groupchange_sender(const void *s1, const void *s2) {
227         message_summary *summ1;
228         message_summary *summ2;
229         
230         summ1 = (message_summary *)s1;
231         summ2 = (message_summary *)s2;
232         return strcasecmp(ChrPtr(summ2->from), ChrPtr(summ1->from)) != 0;
233
234 }
235
236 /*
237  * comparator for message summary structs by ascending date.
238  */
239 int summcmp_date(const void *s1, const void *s2) {
240         message_summary *summ1;
241         message_summary *summ2;
242         
243         summ1 = (message_summary *)GetSearchPayload(s1);
244         summ2 = (message_summary *)GetSearchPayload(s2);
245
246         if (summ1->date < summ2->date) return -1;
247         else if (summ1->date > summ2->date) return +1;
248         else return 0;
249 }
250
251 /*
252  * comparator for message summary structs by descending date.
253  */
254 int summcmp_rdate(const void *s1, const void *s2) {
255         message_summary *summ1;
256         message_summary *summ2;
257         
258         summ1 = (message_summary *)GetSearchPayload(s1);
259         summ2 = (message_summary *)GetSearchPayload(s2);
260
261         if (summ1->date < summ2->date) return +1;
262         else if (summ1->date > summ2->date) return -1;
263         else return 0;
264 }
265
266 /*
267  * comparator for message summary structs by descending date.
268  */
269 const long DAYSECONDS = 24 * 60 * 60;
270 int groupchange_date(const void *s1, const void *s2) {
271         message_summary *summ1;
272         message_summary *summ2;
273         
274         summ1 = (message_summary *)s1;
275         summ2 = (message_summary *)s2;
276
277         return (summ1->date % DAYSECONDS) != (summ2->date %DAYSECONDS);
278 }
279
280
281 /*----------------------------------------------------------------------------*/
282 /* Don't wanna know... or? */
283 void examine_pref(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) {return;}
284 void examine_suff(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) {return;}
285 void examine_path(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) {return;}
286 void examine_content_encoding(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
287 {
288 /* TODO: do we care? */
289 }
290
291
292 void examine_exti(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
293 {
294         /* we don't care */
295 }
296
297 void examine_nhdr(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
298 {
299         Msg->nhdr = 0;
300         if (!strncasecmp(ChrPtr(HdrLine), "yes", 8))
301                 Msg->nhdr = 1;
302 }
303 int Conditional_ANONYMOUS_MESSAGE(StrBuf *Target, WCTemplputParams *TP)
304 {
305         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
306         return Msg->nhdr != 0;
307 }
308
309 void examine_type(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
310 {
311         Msg->format_type = StrToi(HdrLine);
312                         
313 }
314
315 void examine_from(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
316 {
317         wcsession *WCC = WC;
318
319         CheckConvertBufs(WCC);
320         FreeStrBuf(&Msg->from);
321         Msg->from = NewStrBufPlain(NULL, StrLength(HdrLine));
322         StrBuf_RFC822_2_Utf8(Msg->from, 
323                              HdrLine, 
324                              WCC->DefaultCharset, 
325                              FoundCharset,
326                              WCC->ConvertBuf1,
327                              WCC->ConvertBuf2);
328 }
329 void tmplput_MAIL_SUMM_FROM(StrBuf *Target, WCTemplputParams *TP)
330 {
331         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
332         StrBufAppendTemplate(Target, TP, Msg->from, 0);
333 }
334
335 void examine_subj(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
336 {
337         wcsession *WCC = WC;
338
339         CheckConvertBufs(WCC);
340         FreeStrBuf(&Msg->subj);
341         Msg->subj = NewStrBufPlain(NULL, StrLength(HdrLine));
342         StrBuf_RFC822_2_Utf8(Msg->subj, 
343                              HdrLine, 
344                              WCC->DefaultCharset, 
345                              FoundCharset,
346                              WCC->ConvertBuf1,
347                              WCC->ConvertBuf2);
348 }
349 void tmplput_MAIL_SUMM_SUBJECT(StrBuf *Target, WCTemplputParams *TP)
350 {
351         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
352
353         if (TP->Tokens->nParameters == 4)
354         {
355                 const char *pch;
356                 long len;
357                 
358                 GetTemplateTokenString(Target, TP, 3, &pch, &len);
359                 if ((len > 0)&&
360                     (strstr(ChrPtr(Msg->subj), pch) == NULL))
361                 {
362                         GetTemplateTokenString(Target, TP, 2, &pch, &len);
363                         StrBufAppendBufPlain(Target, pch, len, 0);
364                 }
365         }
366         StrBufAppendTemplate(Target, TP, Msg->subj, 0);
367 }
368 int Conditional_MAIL_SUMM_SUBJECT(StrBuf *Target, WCTemplputParams *TP)
369 {
370         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
371
372
373         return StrLength(Msg->subj) > 0;
374 }
375
376
377 void examine_msgn(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
378 {
379         wcsession *WCC = WC;
380         long Offset = 0;
381         const char *pOffset;
382
383         CheckConvertBufs(WCC);
384         FreeStrBuf(&Msg->reply_inreplyto);
385         Msg->reply_inreplyto = NewStrBufPlain(NULL, StrLength(HdrLine));
386         pOffset = strchr(ChrPtr(HdrLine), '/');
387         if (pOffset != NULL) {
388                 Offset = pOffset - ChrPtr(HdrLine);
389         }
390         Msg->reply_inreplyto_hash = ThreadIdHashOffset(HdrLine, Offset);
391         StrBuf_RFC822_2_Utf8(Msg->reply_inreplyto, 
392                              HdrLine, 
393                              WCC->DefaultCharset,
394                              FoundCharset,
395                              WCC->ConvertBuf1,
396                              WCC->ConvertBuf2);
397 }
398 void tmplput_MAIL_SUMM_INREPLYTO(StrBuf *Target, WCTemplputParams *TP)
399 {
400         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
401         StrBufAppendTemplate(Target, TP, Msg->reply_inreplyto, 0);
402 }
403
404 int Conditional_MAIL_SUMM_UNREAD(StrBuf *Target, WCTemplputParams *TP)
405 {
406         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
407         return (Msg->Flags & MSGFLAG_READ) != 0;
408 }
409
410 void examine_wefw(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
411 {
412         wcsession *WCC = WC;
413         long Offset = 0;
414         const char *pOffset;
415
416         CheckConvertBufs(WCC);
417         FreeStrBuf(&Msg->reply_references);
418         Msg->reply_references = NewStrBufPlain(NULL, StrLength(HdrLine));
419         pOffset = strchr(ChrPtr(HdrLine), '/');
420         if (pOffset != NULL) {
421                 Offset = pOffset - ChrPtr(HdrLine);
422         }
423         Msg->reply_references_hash = ThreadIdHashOffset(HdrLine, Offset);
424         StrBuf_RFC822_2_Utf8(Msg->reply_references, 
425                              HdrLine, 
426                              WCC->DefaultCharset, 
427                              FoundCharset,
428                              WCC->ConvertBuf1,
429                              WCC->ConvertBuf2);
430 }
431 void tmplput_MAIL_SUMM_REFIDS(StrBuf *Target, WCTemplputParams *TP)
432 {
433         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
434         StrBufAppendTemplate(Target, TP, Msg->reply_references, 0);
435 }
436
437 void examine_replyto(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
438 {
439         wcsession *WCC = WC;
440
441         CheckConvertBufs(WCC);
442         FreeStrBuf(&Msg->ReplyTo);
443         Msg->ReplyTo = NewStrBufPlain(NULL, StrLength(HdrLine));
444         StrBuf_RFC822_2_Utf8(Msg->ReplyTo, 
445                              HdrLine, 
446                              WCC->DefaultCharset, 
447                              FoundCharset,
448                              WCC->ConvertBuf1,
449                              WCC->ConvertBuf2);
450         if (Msg->AllRcpt == NULL)
451                 Msg->AllRcpt = NewStrBufPlain(NULL, StrLength(HdrLine));
452         if (StrLength(Msg->AllRcpt) > 0) {
453                 StrBufAppendBufPlain(Msg->AllRcpt, HKEY(", "), 0);
454         }
455         StrBufAppendBuf(Msg->AllRcpt, Msg->ReplyTo, 0);
456 }
457 void tmplput_MAIL_SUMM_REPLYTO(StrBuf *Target, WCTemplputParams *TP)
458 {
459         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
460         StrBufAppendTemplate(Target, TP, Msg->ReplyTo, 0);
461 }
462
463 void examine_cccc(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
464 {
465         wcsession *WCC = WC;
466
467         CheckConvertBufs(WCC);
468         FreeStrBuf(&Msg->cccc);
469         Msg->cccc = NewStrBufPlain(NULL, StrLength(HdrLine));
470         StrBuf_RFC822_2_Utf8(Msg->cccc, 
471                              HdrLine, 
472                              WCC->DefaultCharset, 
473                              FoundCharset,
474                              WCC->ConvertBuf1,
475                              WCC->ConvertBuf2);
476         if (Msg->AllRcpt == NULL)
477                 Msg->AllRcpt = NewStrBufPlain(NULL, StrLength(HdrLine));
478         if (StrLength(Msg->AllRcpt) > 0) {
479                 StrBufAppendBufPlain(Msg->AllRcpt, HKEY(", "), 0);
480         }
481         StrBufAppendBuf(Msg->AllRcpt, Msg->cccc, 0);
482 }
483 void tmplput_MAIL_SUMM_CCCC(StrBuf *Target, WCTemplputParams *TP)
484 {
485         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
486         StrBufAppendTemplate(Target, TP, Msg->cccc, 0);
487 }
488
489
490 void examine_room(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
491 {
492         if ((StrLength(HdrLine) > 0) &&
493             (strcasecmp(ChrPtr(HdrLine), ChrPtr(WC->CurRoom.name)))) {
494                 FreeStrBuf(&Msg->Room);
495                 Msg->Room = NewStrBufDup(HdrLine);              
496         }
497 }
498 void tmplput_MAIL_SUMM_ORGROOM(StrBuf *Target, WCTemplputParams *TP)
499 {
500         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
501         StrBufAppendTemplate(Target, TP, Msg->Room, 0);
502 }
503
504
505 void examine_rfca(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
506 {
507         FreeStrBuf(&Msg->Rfca);
508         Msg->Rfca = NewStrBufDup(HdrLine);
509 }
510 void tmplput_MAIL_SUMM_RFCA(StrBuf *Target, WCTemplputParams *TP)
511 {
512         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
513         StrBufAppendTemplate(Target, TP, Msg->Rfca, 0);
514 }
515 int Conditional_MAIL_SUMM_RFCA(StrBuf *Target, WCTemplputParams *TP)
516 {
517         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
518         return StrLength(Msg->Rfca) > 0;
519 }
520 int Conditional_MAIL_SUMM_CCCC(StrBuf *Target, WCTemplputParams *TP)
521 {
522         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
523         return StrLength(Msg->cccc) > 0;
524 }
525 int Conditional_MAIL_SUMM_REPLYTO(StrBuf *Target, WCTemplputParams *TP)
526 {
527         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
528         return StrLength(Msg->ReplyTo) > 0;
529 }
530
531 void examine_nvto(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
532 {
533         wcsession *WCC = WC;
534
535         CheckConvertBufs(WCC);
536         FreeStrBuf(&Msg->EnvTo);
537         Msg->EnvTo = NewStrBufPlain(NULL, StrLength(HdrLine));
538         StrBuf_RFC822_2_Utf8(Msg->EnvTo, 
539                              HdrLine, 
540                              WCC->DefaultCharset, 
541                              FoundCharset,
542                              WCC->ConvertBuf1,
543                              WCC->ConvertBuf2);
544 }
545
546
547 void examine_rcpt(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
548 {
549         wcsession *WCC = WC;
550
551         CheckConvertBufs(WCC);
552         FreeStrBuf(&Msg->to);
553         Msg->to = NewStrBufPlain(NULL, StrLength(HdrLine));
554         StrBuf_RFC822_2_Utf8(Msg->to, 
555                              HdrLine, 
556                              WCC->DefaultCharset, 
557                              FoundCharset,
558                              WCC->ConvertBuf1,
559                              WCC->ConvertBuf2);
560         if (Msg->AllRcpt == NULL)
561                 Msg->AllRcpt = NewStrBufPlain(NULL, StrLength(HdrLine));
562         if (StrLength(Msg->AllRcpt) > 0) {
563                 StrBufAppendBufPlain(Msg->AllRcpt, HKEY(", "), 0);
564         }
565         StrBufAppendBuf(Msg->AllRcpt, Msg->to, 0);
566 }
567 void tmplput_MAIL_SUMM_TO(StrBuf *Target, WCTemplputParams *TP)
568 {
569         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
570         StrBufAppendTemplate(Target, TP, Msg->to, 0);
571 }
572 int Conditional_MAIL_SUMM_TO(StrBuf *Target, WCTemplputParams *TP) 
573 {
574         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
575         return StrLength(Msg->to) != 0;
576 }
577 int Conditional_MAIL_SUMM_SUBJ(StrBuf *Target, WCTemplputParams *TP) 
578 {
579         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
580         return StrLength(Msg->subj) != 0;
581 }
582 void tmplput_MAIL_SUMM_ALLRCPT(StrBuf *Target, WCTemplputParams *TP)
583 {
584         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
585         StrBufAppendTemplate(Target, TP, Msg->AllRcpt, 0);
586 }
587
588
589
590 void tmplput_SUMM_COUNT(StrBuf *Target, WCTemplputParams *TP)
591 {
592         StrBufAppendPrintf(Target, "%d", GetCount( WC->summ));
593 }
594
595 HashList *iterate_get_mailsumm_All(StrBuf *Target, WCTemplputParams *TP)
596 {
597         return WC->summ;
598 }
599 void examine_time(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
600 {
601         Msg->date = StrTol(HdrLine);
602 }
603
604 void tmplput_MAIL_SUMM_DATE_BRIEF(StrBuf *Target, WCTemplputParams *TP)
605 {
606         char datebuf[64];
607         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
608         webcit_fmt_date(datebuf, 64, Msg->date, DATEFMT_BRIEF);
609         StrBufAppendBufPlain(Target, datebuf, -1, 0);
610 }
611
612 void tmplput_MAIL_SUMM_EUID(StrBuf *Target, WCTemplputParams *TP)
613 {
614         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
615         StrBufAppendTemplate(Target, TP, Msg->euid, 0);
616 }
617
618 void tmplput_MAIL_SUMM_DATE_FULL(StrBuf *Target, WCTemplputParams *TP)
619 {
620         char datebuf[64];
621         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
622         webcit_fmt_date(datebuf, 64, Msg->date, DATEFMT_FULL);
623         StrBufAppendBufPlain(Target, datebuf, -1, 0);
624 }
625 void tmplput_MAIL_SUMM_DATE_NO(StrBuf *Target, WCTemplputParams *TP)
626 {
627         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
628         StrBufAppendPrintf(Target, "%ld", Msg->date, 0);
629 }
630
631
632
633 void render_MAIL(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset)
634 {
635         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
636         const StrBuf *TemplateMime;
637
638         if (Mime->Data == NULL) 
639                 Mime->Data = NewStrBufPlain(NULL, Mime->length);
640         else 
641                 FlushStrBuf(Mime->Data);
642         read_message(Mime->Data, HKEY("view_submessage"), Mime->msgnum, Mime->PartNum, &TemplateMime, TP);
643 /*
644         if ( (!IsEmptyStr(mime_submessages)) && (!section[0]) ) {
645                 for (i=0; i<num_tokens(mime_submessages, '|'); ++i) {
646                         extract_token(buf, mime_submessages, i, '|', sizeof buf);
647                         / ** use printable_view to suppress buttons * /
648                         wc_printf("<blockquote>");
649                         read_message(Mime->msgnum, 1, ChrPtr(Mime->Section));
650                         wc_printf("</blockquote>");
651                 }
652         }
653 */
654 }
655
656 void render_MIME_ICS(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset)
657 {
658         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
659         if (StrLength(Mime->Data) == 0) {
660                 MimeLoadData(Mime);
661         }
662         if (StrLength(Mime->Data) > 0) {
663                 cal_process_attachment(Mime);
664         }
665 }
666
667
668
669 void examine_mime_part(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
670 {
671         const char *Ptr = NULL;
672         wc_mime_attachment *Mime;
673         StrBuf *Buf;
674         wcsession *WCC = WC;
675
676         CheckConvertBufs(WCC);  
677         Mime = (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
678         memset(Mime, 0, sizeof(wc_mime_attachment));
679         Mime->msgnum = Msg->msgnum;
680         Buf = NewStrBuf();
681
682         Mime->Name = NewStrBuf();
683         StrBufExtract_NextToken(Buf, HdrLine, &Ptr, '|');
684         StrBuf_RFC822_2_Utf8(Mime->Name, 
685                              Buf, 
686                              WCC->DefaultCharset, 
687                              FoundCharset,
688                              WCC->ConvertBuf1,
689                              WCC->ConvertBuf2);
690         StrBufTrim(Mime->Name);
691
692         StrBufExtract_NextToken(Buf, HdrLine, &Ptr, '|');
693         Mime->FileName = NewStrBuf();
694         StrBuf_RFC822_2_Utf8(Mime->FileName, 
695                              Buf, 
696                              WCC->DefaultCharset, 
697                              FoundCharset,
698                              WCC->ConvertBuf1,
699                              WCC->ConvertBuf2);
700         StrBufTrim(Mime->FileName);
701
702         Mime->PartNum = NewStrBuf();
703         StrBufExtract_NextToken(Mime->PartNum, HdrLine, &Ptr, '|');
704         StrBufTrim(Mime->PartNum);
705         if (strchr(ChrPtr(Mime->PartNum), '.') != NULL) 
706                 Mime->level = 2;
707         else
708                 Mime->level = 1;
709
710         Mime->Disposition = NewStrBuf();
711         StrBufExtract_NextToken(Mime->Disposition, HdrLine, &Ptr, '|');
712
713         Mime->ContentType = NewStrBuf();
714         StrBufExtract_NextToken(Mime->ContentType, HdrLine, &Ptr, '|');
715         StrBufTrim(Mime->ContentType);
716         StrBufLowerCase(Mime->ContentType);
717         if (!strcmp(ChrPtr(Mime->ContentType), "application/octet-stream")) {
718                 StrBufPlain(Mime->ContentType, 
719                             GuessMimeByFilename(SKEY(Mime->FileName)), -1);
720         }
721
722         Mime->length = StrBufExtractNext_int(HdrLine, &Ptr, '|');
723
724         StrBufSkip_NTokenS(HdrLine, &Ptr, '|', 1);  /* cbid?? */
725
726         Mime->Charset = NewStrBuf();
727         StrBufExtract_NextToken(Mime->Charset, HdrLine, &Ptr, '|');
728
729
730         if ( (StrLength(Mime->FileName) == 0) && (StrLength(Mime->Name) > 0) ) {
731                 StrBufAppendBuf(Mime->FileName, Mime->Name, 0);
732         }
733
734         if (StrLength(Msg->PartNum) > 0) {
735                 StrBuf *tmp;
736                 StrBufPrintf(Buf, "%s.%s", ChrPtr(Msg->PartNum), ChrPtr(Mime->PartNum));
737                 tmp = Mime->PartNum;
738                 Mime->PartNum = Buf;
739                 Buf = tmp;
740         }
741
742         if (Msg->AllAttach == NULL)
743                 Msg->AllAttach = NewHash(1,NULL);
744         Put(Msg->AllAttach, SKEY(Mime->PartNum), Mime, DestroyMime);
745         FreeStrBuf(&Buf);
746 }
747
748
749 void evaluate_mime_part(StrBuf *Target, WCTemplputParams *TP)
750 {
751         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
752         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
753         void *vMimeRenderer;
754
755         /* just print the root-node */
756         if ((Mime->level >= 1) &&
757             GetHash(MimeRenderHandler, SKEY(Mime->ContentType), &vMimeRenderer) &&
758             vMimeRenderer != NULL)
759         {
760                 Mime->Renderer = (RenderMimeFuncStruct*) vMimeRenderer;
761                 if (Msg->Submessages == NULL)
762                         Msg->Submessages = NewHash(1,NULL);
763                 Put(Msg->Submessages, SKEY(Mime->PartNum), Mime, reference_free_handler);
764         }
765         else if ((Mime->level >= 1) &&
766                  (!strcasecmp(ChrPtr(Mime->Disposition), "inline"))
767                  && (!strncasecmp(ChrPtr(Mime->ContentType), "image/", 6)) ){
768                 if (Msg->AttachLinks == NULL)
769                         Msg->AttachLinks = NewHash(1,NULL);
770                 Put(Msg->AttachLinks, SKEY(Mime->PartNum), Mime, reference_free_handler);
771         }
772         else if ((Mime->level >= 1) &&
773                  (StrLength(Mime->ContentType) > 0) &&
774                   ( (!strcasecmp(ChrPtr(Mime->Disposition), "attachment")) 
775                     || (!strcasecmp(ChrPtr(Mime->Disposition), "inline"))
776                     || (!strcasecmp(ChrPtr(Mime->Disposition), ""))))
777         {               
778                 if (Msg->AttachLinks == NULL)
779                         Msg->AttachLinks = NewHash(1,NULL);
780                 Put(Msg->AttachLinks, SKEY(Mime->PartNum), Mime, reference_free_handler);
781                 if ((strcasecmp(ChrPtr(Mime->ContentType), "application/octet-stream") == 0) && 
782                     (StrLength(Mime->FileName) > 0)) {
783                         FlushStrBuf(Mime->ContentType);
784                         StrBufAppendBufPlain(Mime->ContentType,
785                                              GuessMimeByFilename(SKEY(Mime->FileName)),
786                                              -1, 0);
787                 }
788         }
789 }
790
791 void tmplput_MAIL_SUMM_NATTACH(StrBuf *Target, WCTemplputParams *TP)
792 {
793         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
794         StrBufAppendPrintf(Target, "%ld", GetCount(Msg->Attachments));
795 }
796
797 void examine_text(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
798 {
799         if (Msg->MsgBody->Data == NULL)
800                 Msg->MsgBody->Data = NewStrBufPlain(NULL, SIZ);
801         else
802                 FlushStrBuf(Msg->MsgBody->Data);
803 }
804
805 void examine_msg4_partnum(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
806 {
807         Msg->MsgBody->PartNum = NewStrBufDup(HdrLine);
808         StrBufTrim(Msg->MsgBody->PartNum);
809 }
810
811 void examine_content_lengh(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
812 {
813         Msg->MsgBody->length = StrTol(HdrLine);
814         Msg->MsgBody->size_known = 1;
815 }
816
817 void examine_content_type(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
818 {
819         StrBuf *Token;
820         StrBuf *Value;
821         const char* sem;
822         const char *eq;
823         int len;
824         StrBufTrim(HdrLine);
825         Msg->MsgBody->ContentType = NewStrBufDup(HdrLine);
826         sem = strchr(ChrPtr(HdrLine), ';');
827
828         if (sem != NULL) {
829                 Token = NewStrBufPlain(NULL, StrLength(HdrLine));
830                 Value = NewStrBufPlain(NULL, StrLength(HdrLine));
831                 len = sem - ChrPtr(HdrLine);
832                 StrBufCutAt(Msg->MsgBody->ContentType, len, NULL);
833                 while (sem != NULL) {
834                         while (isspace(*(sem + 1)))
835                                 sem ++;
836                         StrBufCutLeft(HdrLine, sem - ChrPtr(HdrLine));
837                         sem = strchr(ChrPtr(HdrLine), ';');
838                         if (sem != NULL)
839                                 len = sem - ChrPtr(HdrLine);
840                         else
841                                 len = StrLength(HdrLine);
842                         FlushStrBuf(Token);
843                         FlushStrBuf(Value);
844                         StrBufAppendBufPlain(Token, ChrPtr(HdrLine), len, 0);
845                         eq = strchr(ChrPtr(Token), '=');
846                         if (eq != NULL) {
847                                 len = eq - ChrPtr(Token);
848                                 StrBufAppendBufPlain(Value, eq + 1, StrLength(Token) - len - 1, 0); 
849                                 StrBufCutAt(Token, len, NULL);
850                                 StrBufTrim(Value);
851                         }
852                         StrBufTrim(Token);
853
854                         if (EvaluateMsgHdr(SKEY(Token), Msg, Value, FoundCharset) < 0)
855                                 syslog(LOG_WARNING, "don't know how to handle content type sub-header[%s]\n", ChrPtr(Token));
856                 }
857                 FreeStrBuf(&Token);
858                 FreeStrBuf(&Value);
859         }
860 }
861
862
863 int ReadOneMessageSummary(message_summary *Msg, StrBuf *FoundCharset, StrBuf *Buf)
864 {
865         const char *buf;
866         const char *ebuf;
867         int nBuf;
868         long len;
869         
870         serv_printf("MSG0 %ld|1", Msg->msgnum); /* ask for headers only */
871         
872         StrBuf_ServGetln(Buf);
873         if (GetServerStatus(Buf, NULL) != 1) {
874                 return 0;
875         }
876
877         while (len = StrBuf_ServGetln(Buf),
878                (len >= 0) && 
879                ((len != 3)  ||
880                 strcmp(ChrPtr(Buf), "000")))
881         {
882                 buf = ChrPtr(Buf);
883                 ebuf = strchr(ChrPtr(Buf), '=');
884                 nBuf = ebuf - buf;
885                 
886                 if (EvaluateMsgHdr(buf, nBuf, Msg, Buf, FoundCharset) < 0)
887                         syslog(LOG_INFO, "Don't know how to handle Message Headerline [%s]", ChrPtr(Buf));
888         }
889         return 1;
890 }
891
892 void tmplput_MAIL_SUMM_N(StrBuf *Target, WCTemplputParams *TP)
893 {
894         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
895         StrBufAppendPrintf(Target, "%ld", Msg->msgnum);
896 }
897
898
899 void tmplput_MAIL_SUMM_PERMALINK(StrBuf *Target, WCTemplputParams *TP)
900 {
901         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
902         StrBuf *perma_link;
903         const StrBuf *View;
904
905         perma_link = NewStrBufPlain(HKEY("/readfwd?go="));
906         StrBufUrlescAppend(perma_link, WC->CurRoom.name, NULL);
907         View = sbstr("view");
908         if (View != NULL) {
909                 StrBufAppendBufPlain(perma_link, HKEY("?view="), 0);
910                 StrBufAppendBuf(perma_link, View, 0);
911         }
912         StrBufAppendBufPlain(perma_link, HKEY("?start_reading_at="), 0);
913         StrBufAppendPrintf(perma_link, "%ld#%ld", Msg->msgnum, Msg->msgnum);
914         StrBufAppendBuf(Target, perma_link, 0);
915         FreeStrBuf(&perma_link);
916 }
917
918
919 int Conditional_MAIL_MIME_ALL(StrBuf *Target, WCTemplputParams *TP)
920 {
921         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
922         return GetCount(Msg->Attachments) > 0;
923 }
924
925 int Conditional_MAIL_MIME_SUBMESSAGES(StrBuf *Target, WCTemplputParams *TP)
926 {
927         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
928         return GetCount(Msg->Submessages) > 0;
929 }
930
931 int Conditional_MAIL_MIME_ATTACHLINKS(StrBuf *Target, WCTemplputParams *TP)
932 {
933         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
934         return GetCount(Msg->AttachLinks) > 0;
935 }
936
937 int Conditional_MAIL_MIME_ATTACH(StrBuf *Target, WCTemplputParams *TP)
938 {
939         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
940         return GetCount(Msg->AllAttach) > 0;
941 }
942
943 void tmplput_QUOTED_MAIL_BODY(StrBuf *Target, WCTemplputParams *TP)
944 {
945         const StrBuf *Mime;
946         long MsgNum;
947         StrBuf *Buf;
948
949         MsgNum = LBstr(TKEY(0));
950         Buf = NewStrBuf();
951         read_message(Buf, HKEY("view_message_replyquote"), MsgNum, NULL, &Mime, TP);
952         StrBufAppendTemplate(Target, TP, Buf, 1);
953         FreeStrBuf(&Buf);
954 }
955
956 void tmplput_EDIT_MAIL_BODY(StrBuf *Target, WCTemplputParams *TP)
957 {
958         const StrBuf *Mime;
959         long MsgNum;
960         StrBuf *Buf;
961
962         MsgNum = LBstr(TKEY(0));
963         Buf = NewStrBuf();
964         read_message(Buf, HKEY("view_message_edit"), MsgNum, NULL, &Mime, TP);
965         StrBufAppendTemplate(Target, TP, Buf, 1);
966         FreeStrBuf(&Buf);
967 }
968
969 void tmplput_EDIT_WIKI_BODY(StrBuf *Target, WCTemplputParams *TP)
970 {
971         const StrBuf *Mime;
972         long msgnum;
973         StrBuf *Buf;
974
975         /* Insert the existing content of the wiki page into the editor.  But we only want
976          * to do this the first time -- if the user is uploading an attachment we don't want
977          * to do it again.
978          */
979         if (!havebstr("attach_button")) {
980                 StrBuf *wikipage = NewStrBufDup(sbstr("page"));
981                 putbstr("format", NewStrBufPlain(HKEY("plain")));
982                 str_wiki_index(wikipage);
983                 msgnum = locate_message_by_uid(ChrPtr(wikipage));
984                 FreeStrBuf(&wikipage);
985                 if (msgnum >= 0L) {
986                         Buf = NewStrBuf();
987                         read_message(Buf, HKEY("view_message_wikiedit"), msgnum, NULL, &Mime, TP);
988                         StrBufAppendTemplate(Target, TP, Buf, 1);
989                         FreeStrBuf(&Buf);
990                 }
991         }
992 }
993
994 void tmplput_MAIL_BODY(StrBuf *Target, WCTemplputParams *TP)
995 {
996         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
997         StrBufAppendTemplate(Target, TP, Msg->MsgBody->Data, 0);
998 }
999
1000
1001 void render_MAIL_variformat(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset)
1002 {
1003         /* Messages in legacy Citadel variformat get handled thusly... */
1004         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
1005         StrBuf *TTarget = NewStrBufPlain(NULL, StrLength(Mime->Data));
1006         FmOut(TTarget, "JUSTIFY", Mime->Data);
1007         FreeStrBuf(&Mime->Data);
1008         Mime->Data = TTarget;
1009 }
1010
1011 void render_MAIL_text_plain(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset)
1012 {
1013         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
1014         const char *ptr, *pte;
1015         const char *BufPtr = NULL;
1016         StrBuf *Line;
1017         StrBuf *Line1;
1018         StrBuf *Line2;
1019         StrBuf *TTarget;
1020         long Linecount;
1021         long nEmptyLines;
1022         int bn = 0;
1023         int bq = 0;
1024         int i;
1025         long len;
1026 #ifdef HAVE_ICONV
1027         StrBuf *cs = NULL;
1028         int ConvertIt = 1;
1029         iconv_t ic = (iconv_t)(-1) ;
1030 #endif
1031
1032         if ((StrLength(Mime->Data) == 0) && (Mime->length > 0)) {
1033                 FreeStrBuf(&Mime->Data);
1034                 MimeLoadData(Mime);
1035         }
1036
1037 #ifdef HAVE_ICONV
1038         if (ConvertIt) {
1039                 if (StrLength(Mime->Charset) != 0)
1040                         cs = Mime->Charset;
1041                 else if (StrLength(FoundCharset) > 0)
1042                         cs = FoundCharset;
1043                 else if (StrLength(WC->DefaultCharset) > 0)
1044                         cs = WC->DefaultCharset;
1045                 if (cs == NULL) {
1046                         ConvertIt = 0;
1047                 }
1048                 else if (!strcasecmp(ChrPtr(cs), "utf-8")) {
1049                         ConvertIt = 0;
1050                 }
1051                 else if (!strcasecmp(ChrPtr(cs), "us-ascii")) {
1052                         ConvertIt = 0;
1053                 }
1054                 else {
1055                         ctdl_iconv_open("UTF-8", ChrPtr(cs), &ic);
1056                         if (ic == (iconv_t)(-1) ) {
1057                                 syslog(LOG_WARNING, "%s:%d iconv_open(UTF-8, %s) failed: %s\n",
1058                                         __FILE__, __LINE__, ChrPtr(Mime->Charset), strerror(errno));
1059                         }
1060                 }
1061         }
1062 #endif
1063         Line = NewStrBufPlain(NULL, SIZ);
1064         Line1 = NewStrBufPlain(NULL, SIZ);
1065         Line2 = NewStrBufPlain(NULL, SIZ);
1066         TTarget = NewStrBufPlain(NULL, StrLength(Mime->Data));
1067         Linecount = 0;
1068         nEmptyLines = 0;
1069         if (StrLength(Mime->Data) > 0) 
1070                 do 
1071                 {
1072                         StrBufSipLine(Line, Mime->Data, &BufPtr);
1073                         bq = 0;
1074                         i = 0;
1075                         ptr = ChrPtr(Line);
1076                         len = StrLength(Line);
1077                         pte = ptr + len;
1078                 
1079                         while ((ptr < pte) &&
1080                                ((*ptr == '>') ||
1081                                 isspace(*ptr)))
1082                         {
1083                                 if (*ptr == '>')
1084                                         bq++;
1085                                 ptr ++;
1086                                 i++;
1087                         }
1088                         if (i > 0) StrBufCutLeft(Line, i);
1089                 
1090                         if (StrLength(Line) == 0) {
1091                                 if (Linecount == 0)
1092                                         continue;
1093                                 StrBufAppendBufPlain(TTarget, HKEY("<tt></tt><br>\n"), 0);
1094
1095                                 nEmptyLines ++;
1096                                 continue;
1097                         }
1098                         nEmptyLines = 0;
1099                         for (i = bn; i < bq; i++)                               
1100                                 StrBufAppendBufPlain(TTarget, HKEY("<blockquote>"), 0);
1101                         for (i = bq; i < bn; i++)                               
1102                                 StrBufAppendBufPlain(TTarget, HKEY("</blockquote>"), 0);
1103 #ifdef HAVE_ICONV
1104                         if (ConvertIt) {
1105                                 StrBufConvert(Line, Line1, &ic);
1106                         }
1107 #endif
1108                         StrBufAppendBufPlain(TTarget, HKEY("<tt>"), 0);
1109                         UrlizeText(Line1, Line, Line2);
1110
1111                         StrEscAppend(TTarget, Line1, NULL, 0, 0);
1112                         StrBufAppendBufPlain(TTarget, HKEY("</tt><br>\n"), 0);
1113                         bn = bq;
1114                         Linecount ++;
1115                 }
1116         while ((BufPtr != StrBufNOTNULL) &&
1117                (BufPtr != NULL));
1118
1119         if (nEmptyLines > 0)
1120                 StrBufCutRight(TTarget, nEmptyLines * (sizeof ("<tt></tt><br>\n") - 1));
1121         for (i = 0; i < bn; i++)                                
1122                 StrBufAppendBufPlain(TTarget, HKEY("</blockquote>"), 0);
1123
1124         StrBufAppendBufPlain(TTarget, HKEY("</i><br>"), 0);
1125 #ifdef HAVE_ICONV
1126         if (ic != (iconv_t)(-1) ) {
1127                 iconv_close(ic);
1128         }
1129 #endif
1130
1131         FreeStrBuf(&Mime->Data);
1132         Mime->Data = TTarget;
1133         FlushStrBuf(Mime->ContentType);
1134         StrBufAppendBufPlain(Mime->ContentType, HKEY("text/html"), 0);
1135         FlushStrBuf(Mime->Charset);
1136         StrBufAppendBufPlain(Mime->Charset, HKEY("UTF-8"), 0);
1137         FreeStrBuf(&Line);
1138         FreeStrBuf(&Line1);
1139         FreeStrBuf(&Line2);
1140 }
1141
1142 void render_MAIL_html(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset)
1143 {
1144         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
1145         StrBuf *Buf;
1146
1147         if (StrLength(Mime->Data) == 0)
1148                 return;
1149
1150         Buf = NewStrBufPlain(NULL, StrLength(Mime->Data));
1151
1152         /* HTML is fun, but we've got to strip it first */
1153         output_html(ChrPtr(Mime->Charset), 
1154                     (WC->CurRoom.view == VIEW_WIKI ? 1 : 0), 
1155                     Mime->msgnum,
1156                     Mime->Data, Buf);
1157         FreeStrBuf(&Mime->Data);
1158         Mime->Data = Buf;
1159 }
1160
1161
1162 void render_MAIL_UNKNOWN(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset)
1163 {
1164         wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH);
1165         /* Unknown weirdness */
1166         FlushStrBuf(Mime->Data);
1167         StrBufAppendBufPlain(Mime->Data, _("I don't know how to display "), -1, 0);
1168         StrBufAppendBuf(Mime->Data, Mime->ContentType, 0);
1169         StrBufAppendBufPlain(Mime->Data, HKEY("<br>\n"), 0);
1170 }
1171
1172
1173 HashList *iterate_get_mime_All(StrBuf *Target, WCTemplputParams *TP)
1174 {
1175         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
1176         return Msg->Attachments;
1177 }
1178 HashList *iterate_get_mime_Submessages(StrBuf *Target, WCTemplputParams *TP)
1179 {
1180         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
1181         return Msg->Submessages;
1182 }
1183 HashList *iterate_get_mime_AttachLinks(StrBuf *Target, WCTemplputParams *TP)
1184 {
1185         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
1186         return Msg->AttachLinks;
1187 }
1188 HashList *iterate_get_mime_Attachments(StrBuf *Target, WCTemplputParams *TP)
1189 {
1190         message_summary *Msg = (message_summary*) CTX(CTX_MAILSUM);
1191         return Msg->AllAttach;
1192 }
1193
1194 void tmplput_MIME_Name(StrBuf *Target, WCTemplputParams *TP)
1195 {
1196         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1197         StrBufAppendTemplate(Target, TP, mime->Name, 0);
1198 }
1199
1200 void tmplput_MIME_FileName(StrBuf *Target, WCTemplputParams *TP)
1201 {
1202         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1203         StrBufAppendTemplate(Target, TP, mime->FileName, 0);
1204 }
1205
1206 void tmplput_MIME_PartNum(StrBuf *Target, WCTemplputParams *TP)
1207 {
1208         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1209         StrBufAppendTemplate(Target, TP, mime->PartNum, 0);
1210 }
1211
1212 void tmplput_MIME_MsgNum(StrBuf *Target, WCTemplputParams *TP)
1213 {
1214         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1215         StrBufAppendPrintf(Target, "%ld", mime->msgnum);
1216 }
1217
1218 void tmplput_MIME_Disposition(StrBuf *Target, WCTemplputParams *TP)
1219 {
1220         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1221         StrBufAppendTemplate(Target, TP, mime->Disposition, 0);
1222 }
1223
1224 void tmplput_MIME_ContentType(StrBuf *Target, WCTemplputParams *TP)
1225 {
1226         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1227         StrBufAppendTemplate(Target, TP, mime->ContentType, 0);
1228 }
1229
1230 void examine_charset(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
1231 {
1232         Msg->MsgBody->Charset = NewStrBufDup(HdrLine);
1233 }
1234
1235 void tmplput_MIME_Charset(StrBuf *Target, WCTemplputParams *TP)
1236 {
1237         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1238         StrBufAppendTemplate(Target, TP, mime->Charset, 0);
1239 }
1240
1241 void tmplput_MIME_Data(StrBuf *Target, WCTemplputParams *TP)
1242 {
1243         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1244         if (mime->Renderer != NULL)
1245                 mime->Renderer->f(Target, TP, NULL);
1246         StrBufAppendTemplate(Target, TP, mime->Data, 0);
1247         /* TODO: check whether we need to load it now? */
1248 }
1249
1250 void tmplput_MIME_LoadData(StrBuf *Target, WCTemplputParams *TP)
1251 {
1252         wcsession *WCC = WC;    
1253         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1254         wc_mime_attachment *att;
1255         
1256         if (( (!strcasecmp(ChrPtr(mime->Disposition), "inline"))||
1257               (!strcasecmp(ChrPtr(mime->Disposition), "attachment"))) && 
1258             (strcasecmp(ChrPtr(mime->ContentType), "application/ms-tnef")!=0))
1259         {
1260                 
1261                 int n;
1262                 char N[64];
1263                 /* steal this mime part... */
1264                 att = malloc(sizeof(wc_mime_attachment));
1265                 memcpy(att, mime, sizeof(wc_mime_attachment));
1266                 memset(mime, 0, sizeof(wc_mime_attachment));
1267
1268                 if (att->Data == NULL) 
1269                         MimeLoadData(att);
1270
1271                 if (WCC->attachments == NULL)
1272                         WCC->attachments = NewHash(1, NULL);
1273                 /* And add it to the list. */
1274                 n = snprintf(N, sizeof N, "%d", GetCount(WCC->attachments) + 1);
1275                 Put(WCC->attachments, N, n, att, DestroyMime);
1276         }
1277 }
1278
1279 void tmplput_MIME_Length(StrBuf *Target, WCTemplputParams *TP)
1280 {
1281         wc_mime_attachment *mime = (wc_mime_attachment*) CTX(CTX_MIME_ATACH);
1282         StrBufAppendPrintf(Target, "%ld", mime->length);
1283 }
1284
1285 HashList *iterate_get_registered_Attachments(StrBuf *Target, WCTemplputParams *TP)
1286 {
1287         return WC->attachments;
1288 }
1289
1290 void get_registered_Attachments_Count(StrBuf *Target, WCTemplputParams *TP)
1291 {
1292         StrBufAppendPrintf(Target, "%ld", GetCount (WC->attachments));
1293 }
1294
1295 void servcmd_do_search(char *buf, long bufsize)
1296 {
1297         snprintf(buf, bufsize, "MSGS SEARCH|%s", bstr("query"));
1298 }
1299
1300 void servcmd_headers(char *buf, long bufsize)
1301 {
1302         snprintf(buf, bufsize, "MSGS ALL");
1303 }
1304
1305 void servcmd_readfwd(char *buf, long bufsize)
1306 {
1307         snprintf(buf, bufsize, "MSGS ALL");
1308 }
1309
1310 void servcmd_readgt(char *buf, long bufsize)
1311 {
1312         snprintf(buf, bufsize, "MSGS GT|%s", bstr("gt"));
1313 }
1314
1315 void servcmd_readlt(char *buf, long bufsize)
1316 {
1317         snprintf(buf, bufsize, "MSGS LT|%s", bstr("lt"));
1318 }
1319
1320 void servcmd_readnew(char *buf, long bufsize)
1321 {
1322         snprintf(buf, bufsize, "MSGS NEW");
1323 }
1324
1325 void servcmd_readold(char *buf, long bufsize)
1326 {
1327         snprintf(buf, bufsize, "MSGS OLD");
1328 }
1329
1330
1331 /* DO NOT REORDER OR REMOVE ANY OF THESE */
1332 readloop_struct rlid[] = {
1333         { {HKEY("do_search")},  servcmd_do_search       },
1334         { {HKEY("headers")},    servcmd_headers         },
1335         { {HKEY("readfwd")},    servcmd_readfwd         },
1336         { {HKEY("readnew")},    servcmd_readnew         },
1337         { {HKEY("readold")},    servcmd_readold         },
1338         { {HKEY("readgt")},     servcmd_readgt          },
1339         { {HKEY("readlt")},     servcmd_readlt          }
1340 };
1341
1342 const char* fieldMnemonics[] = {
1343         "from", /* A -> eAuthor       */
1344         "exti", /* E -> eXclusivID    */
1345         "rfca", /* F -> erFc822Addr   */
1346         "msgn", /* I -> emessageId    */
1347         "jrnl", /* J -> eJournal      */
1348         "rep2", /* K -> eReplyTo      */
1349         "list", /* L -> eListID       */
1350         "text", /* M -> eMesageText   */
1351         "room", /* O -> eOriginalRoom */
1352         "path", /* P -> eMessagePath  */
1353         "rcpt", /* R -> eRecipient    */
1354         "spec", /* S -> eSpecialField */
1355         "time", /* T -> eTimestamp    */
1356         "subj", /* U -> eMsgSubject   */
1357         "nvto", /* V -> eenVelopeTo   */
1358         "wefw", /* W -> eWeferences   */
1359         "cccc", /* Y -> eCarbonCopY   */
1360         "nhdr", /* % -> eHeaderOnly   */
1361         "type", /* % -> eFormatType   */
1362         "part", /* % -> eMessagePart  */
1363         "suff", /* % -> eSubFolder    */
1364         "pref"  /* % -> ePevious      */
1365 };
1366 HashList *msgKeyLookup = NULL;
1367
1368 int GetFieldFromMnemonic(eMessageField *f, const char* c)
1369 {
1370         void *v = NULL;
1371         if (GetHash(msgKeyLookup, c, 4, &v)) {
1372                 *f = (eMessageField) v;
1373                 return 1;
1374         }
1375         return 0;
1376 }
1377
1378 void FillMsgKeyLookupTable(void)
1379 {
1380         long i = 0;
1381
1382         msgKeyLookup = NewHash (1, FourHash);
1383
1384         while (i != eLastHeader) {
1385                 if (fieldMnemonics[i] != NULL) {
1386                         Put(msgKeyLookup, fieldMnemonics[i], 4, (void*)i, reference_free_handler);
1387                 }
1388                 i++;
1389         }
1390 }
1391
1392
1393
1394 void 
1395 InitModule_MSGRENDERERS
1396 (void)
1397 {
1398         RegisterCTX(CTX_MAILSUM);
1399         RegisterCTX(CTX_MIME_ATACH);
1400
1401         RegisterSortFunc(HKEY("date"), 
1402                          NULL, 0,
1403                          summcmp_date,
1404                          summcmp_rdate,
1405                          groupchange_date,
1406                          CTX_MAILSUM);
1407         RegisterSortFunc(HKEY("subject"), 
1408                          NULL, 0,
1409                          summcmp_subj,
1410                          summcmp_rsubj,
1411                          groupchange_subj,
1412                          CTX_MAILSUM);
1413         RegisterSortFunc(HKEY("sender"),
1414                          NULL, 0,
1415                          summcmp_sender,
1416                          summcmp_rsender,
1417                          groupchange_sender,
1418                          CTX_MAILSUM);
1419
1420         RegisterNamespace("SUMM:COUNT", 0, 0, tmplput_SUMM_COUNT, NULL, CTX_NONE);
1421         /* iterate over all known mails in WC->summ */
1422         RegisterIterator("MAIL:SUMM:MSGS", 0, NULL, iterate_get_mailsumm_All,
1423                          NULL,NULL, CTX_MAILSUM, CTX_NONE, IT_NOFLAG);
1424
1425         RegisterNamespace("MAIL:SUMM:EUID", 0, 1, tmplput_MAIL_SUMM_EUID, NULL, CTX_MAILSUM);
1426         RegisterNamespace("MAIL:SUMM:DATEBRIEF", 0, 0, tmplput_MAIL_SUMM_DATE_BRIEF, NULL, CTX_MAILSUM);
1427         RegisterNamespace("MAIL:SUMM:DATEFULL", 0, 0, tmplput_MAIL_SUMM_DATE_FULL, NULL, CTX_MAILSUM);
1428         RegisterNamespace("MAIL:SUMM:DATENO",  0, 0, tmplput_MAIL_SUMM_DATE_NO,  NULL, CTX_MAILSUM);
1429         RegisterNamespace("MAIL:SUMM:N",       0, 0, tmplput_MAIL_SUMM_N,        NULL, CTX_MAILSUM);
1430         RegisterNamespace("MAIL:SUMM:PERMALINK", 0, 0, tmplput_MAIL_SUMM_PERMALINK, NULL, CTX_MAILSUM);
1431         RegisterNamespace("MAIL:SUMM:FROM",    0, 2, tmplput_MAIL_SUMM_FROM,     NULL, CTX_MAILSUM);
1432         RegisterNamespace("MAIL:SUMM:TO",      0, 2, tmplput_MAIL_SUMM_TO,       NULL, CTX_MAILSUM);
1433         RegisterNamespace("MAIL:SUMM:SUBJECT", 0, 4, tmplput_MAIL_SUMM_SUBJECT,  NULL, CTX_MAILSUM);
1434         RegisterNamespace("MAIL:SUMM:NTATACH", 0, 0, tmplput_MAIL_SUMM_NATTACH,  NULL, CTX_MAILSUM);
1435         RegisterNamespace("MAIL:SUMM:CCCC", 0, 2, tmplput_MAIL_SUMM_CCCC, NULL, CTX_MAILSUM);
1436         RegisterNamespace("MAIL:SUMM:REPLYTO", 0, 2, tmplput_MAIL_SUMM_REPLYTO, NULL, CTX_MAILSUM);
1437         RegisterNamespace("MAIL:SUMM:ALLRCPT", 0, 2, tmplput_MAIL_SUMM_ALLRCPT,  NULL, CTX_MAILSUM);
1438         RegisterNamespace("MAIL:SUMM:ORGROOM", 0, 2, tmplput_MAIL_SUMM_ORGROOM,  NULL, CTX_MAILSUM);
1439         RegisterNamespace("MAIL:SUMM:RFCA", 0, 2, tmplput_MAIL_SUMM_RFCA, NULL, CTX_MAILSUM);
1440         RegisterNamespace("MAIL:SUMM:REFIDS", 0, 1, tmplput_MAIL_SUMM_REFIDS,  NULL, CTX_MAILSUM);
1441         RegisterNamespace("MAIL:SUMM:INREPLYTO", 0, 2, tmplput_MAIL_SUMM_INREPLYTO,  NULL, CTX_MAILSUM);
1442         RegisterNamespace("MAIL:BODY", 0, 2, tmplput_MAIL_BODY,  NULL, CTX_MAILSUM);
1443         RegisterNamespace("MAIL:QUOTETEXT", 1, 2, tmplput_QUOTED_MAIL_BODY,  NULL, CTX_NONE);
1444         RegisterNamespace("MAIL:EDITTEXT", 1, 2, tmplput_EDIT_MAIL_BODY,  NULL, CTX_NONE);
1445         RegisterNamespace("MAIL:EDITWIKI", 1, 2, tmplput_EDIT_WIKI_BODY,  NULL, CTX_NONE);
1446         RegisterConditional("COND:MAIL:SUMM:RFCA", 0, Conditional_MAIL_SUMM_RFCA,  CTX_MAILSUM);
1447         RegisterConditional("COND:MAIL:SUMM:CCCC", 0, Conditional_MAIL_SUMM_CCCC,  CTX_MAILSUM);
1448         RegisterConditional("COND:MAIL:SUMM:REPLYTO", 0, Conditional_MAIL_SUMM_REPLYTO,  CTX_MAILSUM);
1449         RegisterConditional("COND:MAIL:SUMM:UNREAD", 0, Conditional_MAIL_SUMM_UNREAD, CTX_MAILSUM);
1450         RegisterConditional("COND:MAIL:SUMM:SUBJECT", 0, Conditional_MAIL_SUMM_SUBJECT, CTX_MAILSUM);
1451         RegisterConditional("COND:MAIL:ANON", 0, Conditional_ANONYMOUS_MESSAGE, CTX_MAILSUM);
1452         RegisterConditional("COND:MAIL:TO", 0, Conditional_MAIL_SUMM_TO, CTX_MAILSUM);  
1453         RegisterConditional("COND:MAIL:SUBJ", 0, Conditional_MAIL_SUMM_SUBJ, CTX_MAILSUM);      
1454
1455         /* do we have mimetypes to iterate over? */
1456         RegisterConditional("COND:MAIL:MIME:ATTACH", 0, Conditional_MAIL_MIME_ALL, CTX_MAILSUM);
1457         RegisterConditional("COND:MAIL:MIME:ATTACH:SUBMESSAGES", 0, Conditional_MAIL_MIME_SUBMESSAGES, CTX_MAILSUM);
1458         RegisterConditional("COND:MAIL:MIME:ATTACH:LINKS", 0, Conditional_MAIL_MIME_ATTACHLINKS, CTX_MAILSUM);
1459         RegisterConditional("COND:MAIL:MIME:ATTACH:ATT", 0, Conditional_MAIL_MIME_ATTACH, CTX_MAILSUM);
1460         RegisterIterator("MAIL:MIME:ATTACH", 0, NULL, iterate_get_mime_All, 
1461                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG);
1462         RegisterIterator("MAIL:MIME:ATTACH:SUBMESSAGES", 0, NULL, iterate_get_mime_Submessages, 
1463                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG);
1464         RegisterIterator("MAIL:MIME:ATTACH:LINKS", 0, NULL, iterate_get_mime_AttachLinks, 
1465                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG);
1466         RegisterIterator("MAIL:MIME:ATTACH:ATT", 0, NULL, iterate_get_mime_Attachments, 
1467                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG);
1468
1469         /* Parts of a mime attachent */
1470         RegisterNamespace("MAIL:MIME:NAME", 0, 2, tmplput_MIME_Name, NULL, CTX_MIME_ATACH);
1471         RegisterNamespace("MAIL:MIME:FILENAME", 0, 2, tmplput_MIME_FileName, NULL, CTX_MIME_ATACH);
1472         RegisterNamespace("MAIL:MIME:PARTNUM", 0, 2, tmplput_MIME_PartNum, NULL, CTX_MIME_ATACH);
1473         RegisterNamespace("MAIL:MIME:MSGNUM", 0, 2, tmplput_MIME_MsgNum, NULL, CTX_MIME_ATACH);
1474         RegisterNamespace("MAIL:MIME:DISPOSITION", 0, 2, tmplput_MIME_Disposition, NULL, CTX_MIME_ATACH);
1475         RegisterNamespace("MAIL:MIME:CONTENTTYPE", 0, 2, tmplput_MIME_ContentType, NULL, CTX_MIME_ATACH);
1476         RegisterNamespace("MAIL:MIME:CHARSET", 0, 2, tmplput_MIME_Charset, NULL, CTX_MIME_ATACH);
1477         RegisterNamespace("MAIL:MIME:LENGTH", 0, 2, tmplput_MIME_Length, NULL, CTX_MIME_ATACH);
1478         RegisterNamespace("MAIL:MIME:DATA", 0, 2, tmplput_MIME_Data, NULL, CTX_MIME_ATACH);
1479         /* load the actual attachment into WC->attachments; no output!!! */
1480         RegisterNamespace("MAIL:MIME:LOADDATA", 0, 0, tmplput_MIME_LoadData, NULL, CTX_MIME_ATACH);
1481
1482         /* iterate the WC->attachments; use the above tokens for their contents */
1483         RegisterIterator("MSG:ATTACHNAMES", 0, NULL, iterate_get_registered_Attachments, 
1484                          NULL, NULL, CTX_MIME_ATACH, CTX_NONE, IT_NOFLAG);
1485
1486         RegisterNamespace("MSG:NATTACH", 0, 0, get_registered_Attachments_Count,  NULL, CTX_NONE);
1487
1488         /* mime renderers translate an attachment into webcit viewable html text */
1489         RegisterMimeRenderer(HKEY("message/rfc822"), render_MAIL, 0, 150);
1490 //*
1491         RegisterMimeRenderer(HKEY("text/calendar"), render_MIME_ICS, 1, 501);
1492         RegisterMimeRenderer(HKEY("application/ics"), render_MIME_ICS, 1, 500);
1493 //*/
1494         RegisterMimeRenderer(HKEY("text/x-citadel-variformat"), render_MAIL_variformat, 1, 2);
1495         RegisterMimeRenderer(HKEY("text/plain"), render_MAIL_text_plain, 1, 3);
1496         RegisterMimeRenderer(HKEY("text"), render_MAIL_text_plain, 1, 1);
1497         RegisterMimeRenderer(HKEY("text/x-markdown"), render_MAIL_text_plain, 1, 1);
1498         RegisterMimeRenderer(HKEY("text/html"), render_MAIL_html, 1, 100);
1499         RegisterMimeRenderer(HKEY(""), render_MAIL_UNKNOWN, 0, 0);
1500
1501         /* these headers are citserver replies to MSG4 and friends. one evaluator for each */
1502         RegisterMsgHdr(HKEY("nhdr"), examine_nhdr, 0);
1503         RegisterMsgHdr(HKEY("exti"), examine_exti, 0);
1504         RegisterMsgHdr(HKEY("type"), examine_type, 0);
1505         RegisterMsgHdr(HKEY("from"), examine_from, 0);
1506         RegisterMsgHdr(HKEY("subj"), examine_subj, 0);
1507         RegisterMsgHdr(HKEY("msgn"), examine_msgn, 0);
1508         RegisterMsgHdr(HKEY("wefw"), examine_wefw, 0);
1509         RegisterMsgHdr(HKEY("cccc"), examine_cccc, 0);
1510         RegisterMsgHdr(HKEY("rep2"), examine_replyto, 0);
1511         RegisterMsgHdr(HKEY("room"), examine_room, 0);
1512         RegisterMsgHdr(HKEY("rfca"), examine_rfca, 0);
1513         RegisterMsgHdr(HKEY("rcpt"), examine_rcpt, 0);
1514         RegisterMsgHdr(HKEY("nvto"), examine_nvto, 0);
1515         RegisterMsgHdr(HKEY("time"), examine_time, 0);
1516         RegisterMsgHdr(HKEY("part"), examine_mime_part, 0);
1517         RegisterMsgHdr(HKEY("text"), examine_text, 1);
1518         /* these are the content-type headers we get infront of a message; put it into the same hash since it doesn't clash. */
1519         RegisterMsgHdr(HKEY("X-Citadel-MSG4-Partnum"), examine_msg4_partnum, 0);
1520         RegisterMsgHdr(HKEY("Content-type"), examine_content_type, 0);
1521         RegisterMsgHdr(HKEY("Content-length"), examine_content_lengh, 0);
1522         RegisterMsgHdr(HKEY("Content-transfer-encoding"), examine_content_encoding, 0); /* do we care? */
1523         RegisterMsgHdr(HKEY("charset"), examine_charset, 0);
1524
1525         /* Don't care about these... */
1526         RegisterMsgHdr(HKEY("pref"), examine_pref, 0);
1527         RegisterMsgHdr(HKEY("suff"), examine_suff, 0);
1528         RegisterMsgHdr(HKEY("path"), examine_path, 0);
1529 }
1530
1531 void 
1532 InitModule2_MSGRENDERERS
1533 (void)
1534 {
1535         /* and finalize the anouncement to the server... */
1536         CreateMimeStr();
1537 }
1538 void 
1539 ServerStartModule_MSGRENDERERS
1540 (void)
1541 {
1542         DflMsgHeaderHandler = NewHash (1, FourHash);
1543         DflEnumMsgHeaderHandler = NewHash (1, Flathash);
1544         MsgHeaderHandler = NewHash(1, NULL);
1545         MimeRenderHandler = NewHash(1, NULL);
1546         ReadLoopHandler = NewHash(1, NULL);
1547         FillMsgKeyLookupTable();
1548 }
1549
1550 void 
1551 ServerShutdownModule_MSGRENDERERS
1552 (void)
1553 {
1554         DeleteHash(&DflMsgHeaderHandler);
1555         DeleteHash(&DflEnumMsgHeaderHandler);
1556
1557
1558         DeleteHash(&MsgHeaderHandler);
1559         DeleteHash(&MimeRenderHandler);
1560         DeleteHash(&ReadLoopHandler);
1561         DeleteHash(&msgKeyLookup);
1562 }
1563
1564 void 
1565 SessionDestroyModule_MSGRENDERERS
1566 (wcsession *sess)
1567 {
1568         DeleteHash(&sess->attachments);
1569         FreeStrBuf(&sess->ConvertBuf1);
1570         FreeStrBuf(&sess->ConvertBuf2);
1571 }