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