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