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