* shortcut notation to tokens for hashkeys; TKEY(n) will make str,len for Hash access
[citadel.git] / webcit / msg_renderers.c
1 /*----------------------------------------------------------------------------*/
2 #include "webcit.h"
3 #include "webserver.h"
4
5 /**
6  * message index functions
7  */
8
9
10 void DestroyMimeParts(wc_mime_attachment *Mime)
11 {
12         FreeStrBuf(&Mime->Name);
13         FreeStrBuf(&Mime->FileName);
14         FreeStrBuf(&Mime->PartNum);
15         FreeStrBuf(&Mime->Disposition);
16         FreeStrBuf(&Mime->ContentType);
17         FreeStrBuf(&Mime->Charset);
18         FreeStrBuf(&Mime->Data);
19 }
20
21 void DestroyMime(void *vMime)
22 {
23         wc_mime_attachment *Mime = (wc_mime_attachment*)vMime;
24         DestroyMimeParts(Mime);
25         free(Mime);
26 }
27
28 void DestroyMessageSummary(void *vMsg)
29 {
30         message_summary *Msg = (message_summary*) vMsg;
31
32         FreeStrBuf(&Msg->from);
33         FreeStrBuf(&Msg->to);
34         FreeStrBuf(&Msg->subj);
35         FreeStrBuf(&Msg->reply_inreplyto);
36         FreeStrBuf(&Msg->reply_references);
37         FreeStrBuf(&Msg->cccc);
38         FreeStrBuf(&Msg->hnod);
39         FreeStrBuf(&Msg->AllRcpt);
40         FreeStrBuf(&Msg->Room);
41         FreeStrBuf(&Msg->Rfca);
42         FreeStrBuf(&Msg->OtherNode);
43
44         FreeStrBuf(&Msg->reply_to);
45
46         DeleteHash(&Msg->Attachments);  /**< list of Accachments */
47         DeleteHash(&Msg->Submessages);
48         DeleteHash(&Msg->AttachLinks);
49         DeleteHash(&Msg->AllAttach);
50         free(Msg);
51 }
52
53
54
55 void RegisterMsgHdr(const char *HeaderName, long HdrNLen, ExamineMsgHeaderFunc evaluator, int type)
56 {
57         headereval *ev;
58         ev = (headereval*) malloc(sizeof(headereval));
59         ev->evaluator = evaluator;
60         ev->Type = type;
61         Put(MsgHeaderHandler, HeaderName, HdrNLen, ev, NULL);
62 }
63
64 void RegisterMimeRenderer(const char *HeaderName, long HdrNLen, RenderMimeFunc MimeRenderer)
65 {
66         Put(MimeRenderHandler, HeaderName, HdrNLen, MimeRenderer, reference_free_handler);
67         
68 }
69
70 /*----------------------------------------------------------------------------*/
71
72 /*
73  *  comparator for two longs in descending order.
74  */
75 int longcmp_r(const void *s1, const void *s2) {
76         long l1;
77         long l2;
78
79         l1 = *(long *)GetSearchPayload(s1);
80         l2 = *(long *)GetSearchPayload(s2);
81
82         if (l1 > l2) return(-1);
83         if (l1 < l2) return(+1);
84         return(0);
85 }
86
87 /*
88  *  comparator for longs; descending order.
89  */
90 int qlongcmp_r(const void *s1, const void *s2) {
91         long l1 = (long) s1;
92         long l2 = (long) s2;
93
94         if (l1 > l2) return(-1);
95         if (l1 < l2) return(+1);
96         return(0);
97 }
98
99  
100 /*
101  * comparator for message summary structs by ascending subject.
102  */
103 int summcmp_subj(const void *s1, const void *s2) {
104         message_summary *summ1;
105         message_summary *summ2;
106         
107         summ1 = (message_summary *)GetSearchPayload(s1);
108         summ2 = (message_summary *)GetSearchPayload(s2);
109         return strcasecmp(ChrPtr(summ1->subj), ChrPtr(summ2->subj));
110 }
111
112 /*
113  * comparator for message summary structs by descending subject.
114  */
115 int summcmp_rsubj(const void *s1, const void *s2) {
116         message_summary *summ1;
117         message_summary *summ2;
118         
119         summ1 = (message_summary *)GetSearchPayload(s1);
120         summ2 = (message_summary *)GetSearchPayload(s2);
121         return strcasecmp(ChrPtr(summ2->subj), ChrPtr(summ1->subj));
122 }
123
124 /*
125  * comparator for message summary structs by ascending sender.
126  */
127 int summcmp_sender(const void *s1, const void *s2) {
128         message_summary *summ1;
129         message_summary *summ2;
130         
131         summ1 = (message_summary *)GetSearchPayload(s1);
132         summ2 = (message_summary *)GetSearchPayload(s2);
133         return strcasecmp(ChrPtr(summ1->from), ChrPtr(summ2->from));
134 }
135
136 /*
137  * comparator for message summary structs by descending sender.
138  */
139 int summcmp_rsender(const void *s1, const void *s2) {
140         message_summary *summ1;
141         message_summary *summ2;
142         
143         summ1 = (message_summary *)GetSearchPayload(s1);
144         summ2 = (message_summary *)GetSearchPayload(s2);
145         return strcasecmp(ChrPtr(summ2->from), ChrPtr(summ1->from));
146 }
147
148 /*
149  * comparator for message summary structs by ascending date.
150  */
151 int summcmp_date(const void *s1, const void *s2) {
152         message_summary *summ1;
153         message_summary *summ2;
154         
155         summ1 = (message_summary *)GetSearchPayload(s1);
156         summ2 = (message_summary *)GetSearchPayload(s2);
157
158         if (summ1->date < summ2->date) return -1;
159         else if (summ1->date > summ2->date) return +1;
160         else return 0;
161 }
162
163 /*
164  * comparator for message summary structs by descending date.
165  */
166 int summcmp_rdate(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
173         if (summ1->date < summ2->date) return +1;
174         else if (summ1->date > summ2->date) return -1;
175         else return 0;
176 }
177
178 /*----------------------------------------------------------------------------*/
179 /* Don't wanna know... or? */
180 void examine_pref(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) {return;}
181 void examine_suff(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) {return;}
182 void examine_path(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) {return;}
183 void examine_content_encoding(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
184 {
185 ////TODO: do we care?
186 }
187
188 void examine_nhdr(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
189 {
190         Msg->nhdr = 0;
191         if (!strncasecmp(ChrPtr(HdrLine), "yes", 8))
192                 Msg->nhdr = 1;
193 }
194 int Conditional_ANONYMOUS_MESSAGE(WCTemplateToken *Tokens, void *Context, int ContextType)
195 {
196         message_summary *Msg = (message_summary*) Context;
197         return Msg->nhdr != 0;
198 }
199
200
201 void examine_type(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
202 {
203         Msg->format_type = StrToi(HdrLine);
204                         
205 }
206
207 void examine_from(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
208 {
209         FreeStrBuf(&Msg->from);
210         Msg->from = NewStrBufPlain(NULL, StrLength(HdrLine));
211         StrBuf_RFC822_to_Utf8(Msg->from, HdrLine, WC->DefaultCharset, FoundCharset);
212 }
213 void tmplput_MAIL_SUMM_FROM(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
214 {
215         message_summary *Msg = (message_summary*) Context;
216         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->from, 0);
217 }
218
219
220
221 void examine_subj(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
222 {
223         FreeStrBuf(&Msg->subj);
224         Msg->subj = NewStrBufPlain(NULL, StrLength(HdrLine));
225         StrBuf_RFC822_to_Utf8(Msg->subj, HdrLine, WC->DefaultCharset, FoundCharset);
226 }
227 void tmplput_MAIL_SUMM_SUBJECT(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
228 {/////TODO: Fwd: and RE: filter!!
229         message_summary *Msg = (message_summary*) Context;
230         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->subj, 0);
231 }
232
233
234 void examine_msgn(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
235 {
236         FreeStrBuf(&Msg->reply_inreplyto);
237         Msg->reply_inreplyto = NewStrBufPlain(NULL, StrLength(HdrLine));
238         StrBuf_RFC822_to_Utf8(Msg->reply_inreplyto, HdrLine, WC->DefaultCharset, FoundCharset);
239 }
240 void tmplput_MAIL_SUMM_INREPLYTO(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
241 {
242         message_summary *Msg = (message_summary*) Context;
243         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->reply_inreplyto, 0);
244 }
245
246 int Conditional_MAIL_SUMM_UNREAD(WCTemplateToken *Tokens, void *Context, int ContextType)
247 {
248         message_summary *Msg = (message_summary*) Context;
249         return Msg->is_new != 0;
250 }
251
252 void examine_wefw(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
253 {
254         FreeStrBuf(&Msg->reply_references);
255         Msg->reply_references = NewStrBufPlain(NULL, StrLength(HdrLine));
256         StrBuf_RFC822_to_Utf8(Msg->reply_references, HdrLine, WC->DefaultCharset, FoundCharset);
257 }
258 void tmplput_MAIL_SUMM_REFIDS(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
259 {
260         message_summary *Msg = (message_summary*) Context;
261         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->reply_references, 0);
262 }
263
264
265 void examine_cccc(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
266 {
267         FreeStrBuf(&Msg->cccc);
268         Msg->cccc = NewStrBufPlain(NULL, StrLength(HdrLine));
269         StrBuf_RFC822_to_Utf8(Msg->cccc, HdrLine, WC->DefaultCharset, FoundCharset);
270         if (Msg->AllRcpt == NULL)
271                 Msg->AllRcpt = NewStrBufPlain(NULL, StrLength(HdrLine));
272         if (StrLength(Msg->AllRcpt) > 0) {
273                 StrBufAppendBufPlain(Msg->AllRcpt, HKEY(", "), 0);
274         }
275         StrBufAppendBuf(Msg->AllRcpt, Msg->cccc, 0);
276 }
277 void tmplput_MAIL_SUMM_CCCC(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
278 {
279         message_summary *Msg = (message_summary*) Context;
280         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->cccc, 0);
281 }
282
283
284 void examine_room(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
285 {
286         if ((StrLength(HdrLine) > 0) &&
287             (strcasecmp(ChrPtr(HdrLine), WC->wc_roomname))) {
288                 FreeStrBuf(&Msg->Room);
289                 Msg->Room = NewStrBufDup(HdrLine);              
290         }
291 }
292 void tmplput_MAIL_SUMM_ORGROOM(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
293 {
294         message_summary *Msg = (message_summary*) Context;
295         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->Room, 0);
296 }
297
298
299 void examine_rfca(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
300 {
301         FreeStrBuf(&Msg->Rfca);
302         Msg->Rfca = NewStrBufDup(HdrLine);
303 }
304 void tmplput_MAIL_SUMM_RFCA(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
305 {
306         message_summary *Msg = (message_summary*) Context;
307         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->Rfca, 0);
308 }
309 int Conditional_MAIL_SUMM_RFCA(WCTemplateToken *Tokens, void *Context, int ContextType)
310 {
311         message_summary *Msg = (message_summary*) Context;
312         return StrLength(Msg->Rfca) > 0;
313 }
314
315 void examine_node(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
316 {
317         if ( (StrLength(HdrLine) > 0) &&
318              ((WC->room_flags & QR_NETWORK)
319               || ((strcasecmp(ChrPtr(HdrLine), serv_info.serv_nodename)
320                    && (strcasecmp(ChrPtr(HdrLine), serv_info.serv_fqdn)))))) {
321                 FreeStrBuf(&Msg->OtherNode);
322                 Msg->OtherNode = NewStrBufDup(HdrLine);
323         }
324 }
325 void tmplput_MAIL_SUMM_OTHERNODE(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
326 {
327         message_summary *Msg = (message_summary*) Context;
328         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->OtherNode, 0);
329 }
330 int Conditional_MAIL_SUMM_OTHERNODE(WCTemplateToken *Tokens, void *Context, int ContextType)
331 {
332         message_summary *Msg = (message_summary*) Context;
333         return StrLength(Msg->OtherNode) > 0;
334 }
335
336
337 void examine_rcpt(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
338 {
339         FreeStrBuf(&Msg->to);
340         Msg->to = NewStrBufPlain(NULL, StrLength(HdrLine));
341         StrBuf_RFC822_to_Utf8(Msg->to, HdrLine, WC->DefaultCharset, FoundCharset);
342         if (Msg->AllRcpt == NULL)
343                 Msg->AllRcpt = NewStrBufPlain(NULL, StrLength(HdrLine));
344         if (StrLength(Msg->AllRcpt) > 0) {
345                 StrBufAppendBufPlain(Msg->AllRcpt, HKEY(", "), 0);
346         }
347         StrBufAppendBuf(Msg->AllRcpt, Msg->to, 0);
348 }
349 void tmplput_MAIL_SUMM_TO(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
350 {
351         message_summary *Msg = (message_summary*) Context;
352         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->to, 0);
353 }
354 void tmplput_MAIL_SUMM_ALLRCPT(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
355 {
356         message_summary *Msg = (message_summary*) Context;
357         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->AllRcpt, 0);
358 }
359
360
361 HashList *iterate_get_mailsumm_All(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
362 {
363         return WC->summ;
364 }
365
366 void examine_time(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
367 {
368         Msg->date = StrTol(HdrLine);
369 }
370 void tmplput_MAIL_SUMM_DATE_STR(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
371 {
372         char datebuf[64];
373         message_summary *Msg = (message_summary*) Context;
374         webcit_fmt_date(datebuf, Msg->date, 1);
375         StrBufAppendBufPlain(Target, datebuf, -1, 0);
376 }
377 void tmplput_MAIL_SUMM_DATE_NO(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
378 {
379         message_summary *Msg = (message_summary*) Context;
380         StrBufAppendPrintf(Target, "%ld", Msg->date, 0);
381 }
382
383
384
385 void render_MAIL(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *FoundCharset)
386 {
387         Mime->Data = NewStrBufPlain(NULL, Mime->length);
388         read_message(Mime->Data, HKEY("view_submessage"), Mime->msgnum, 0, Mime->PartNum);
389 /*
390         if ( (!IsEmptyStr(mime_submessages)) && (!section[0]) ) {
391                 for (i=0; i<num_tokens(mime_submessages, '|'); ++i) {
392                         extract_token(buf, mime_submessages, i, '|', sizeof buf);
393                         / ** use printable_view to suppress buttons * /
394                         wprintf("<blockquote>");
395                         read_message(Mime->msgnum, 1, ChrPtr(Mime->Section));
396                         wprintf("</blockquote>");
397                 }
398         }
399 */
400 }
401
402 void render_MIME_VCard(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *FoundCharset)
403 {
404         MimeLoadData(Mime);
405         if (StrLength(Mime->Data) > 0) {
406                 StrBuf *Buf;
407                 Buf = NewStrBuf();
408                 /** If it's my vCard I can edit it */
409                 if (    (!strcasecmp(WC->wc_roomname, USERCONFIGROOM))
410                         || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM))
411                         || (WC->wc_view == VIEW_ADDRESSBOOK)
412                         ) {
413                         StrBufAppendPrintf(Buf, "<a href=\"edit_vcard?msgnum=%ld&partnum=%s\">",
414                                 Mime->msgnum, ChrPtr(Mime->PartNum));
415                         StrBufAppendPrintf(Buf, "[%s]</a>", _("edit"));
416                 }
417
418                 /* In all cases, display the full card */
419                 display_vcard(Buf, ChrPtr(Mime->Data), 0, 1, NULL, Mime->msgnum);
420                 FreeStrBuf(&Mime->Data);
421                 Mime->Data = Buf;
422         }
423
424 }
425 void render_MIME_ICS(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *FoundCharset)
426 {
427         MimeLoadData(Mime);
428         if (StrLength(Mime->Data) > 0) {
429                 cal_process_attachment(Mime);
430         }
431 }
432
433
434
435 void examine_mime_part(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
436 {
437         wc_mime_attachment *Mime;
438         StrBuf *Buf;
439         
440         Mime = (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
441         memset(Mime, 0, sizeof(wc_mime_attachment));
442         Mime->msgnum = Msg->msgnum;
443         Buf = NewStrBuf();
444
445         Mime->Name = NewStrBuf();
446         StrBufExtract_token(Buf, HdrLine, 0, '|');
447         StrBuf_RFC822_to_Utf8(Mime->Name, Buf, WC->DefaultCharset, FoundCharset);
448         StrBufTrim(Mime->Name);
449
450         StrBufExtract_token(Buf, HdrLine, 1, '|');
451         Mime->FileName = NewStrBuf();
452         StrBuf_RFC822_to_Utf8(Mime->FileName, Buf, WC->DefaultCharset, FoundCharset);
453         StrBufTrim(Mime->FileName);
454
455         Mime->PartNum = NewStrBuf();
456         StrBufExtract_token(Mime->PartNum, HdrLine, 2, '|');
457         StrBufTrim(Mime->PartNum);
458         if (strchr(ChrPtr(Mime->PartNum), '.') != NULL)
459                 Mime->level = 2;
460         else
461                 Mime->level = 1;
462
463         Mime->Disposition = NewStrBuf();
464         StrBufExtract_token(Mime->Disposition, HdrLine, 3, '|');
465
466         Mime->ContentType = NewStrBuf();
467         StrBufExtract_token(Mime->ContentType, HdrLine, 4, '|');
468         StrBufTrim(Mime->ContentType);
469         StrBufLowerCase(Mime->ContentType);
470
471         Mime->length = StrBufExtract_int(HdrLine, 5, '|');
472
473         if ( (StrLength(Mime->FileName) == 0) && (StrLength(Mime->Name) > 0) ) {
474                 StrBufAppendBuf(Mime->FileName, Mime->Name, 0);
475         }
476
477         if (StrLength(Msg->PartNum) > 0) {
478                 StrBuf *tmp;
479                 StrBufPrintf(Buf, "%s.%s", ChrPtr(Msg->PartNum), ChrPtr(Mime->PartNum));
480                 tmp = Mime->PartNum;
481                 Mime->PartNum = Buf;
482                 Buf = tmp;
483         }
484
485         if (Msg->AllAttach == NULL)
486                 Msg->AllAttach = NewHash(1,NULL);
487         Put(Msg->AllAttach, SKEY(Mime->PartNum), Mime, DestroyMime);
488         FreeStrBuf(&Buf);
489 }
490
491
492 void evaluate_mime_part(message_summary *Msg, wc_mime_attachment *Mime)
493 {
494         void *vMimeRenderer;
495
496         /* just print the root-node */
497         if ((Mime->level == 1) &&
498             GetHash(MimeRenderHandler, SKEY(Mime->ContentType), &vMimeRenderer) &&
499             vMimeRenderer != NULL)
500         {
501                 Mime->Renderer = (RenderMimeFunc) vMimeRenderer;
502                 if (Msg->Submessages == NULL)
503                         Msg->Submessages = NewHash(1,NULL);
504                 Put(Msg->Submessages, SKEY(Mime->PartNum), Mime, reference_free_handler);
505         }
506         else if ((Mime->level == 1) &&
507                  (!strcasecmp(ChrPtr(Mime->Disposition), "inline"))
508                  && (!strncasecmp(ChrPtr(Mime->ContentType), "image/", 6)) ){
509                 if (Msg->AttachLinks == NULL)
510                         Msg->AttachLinks = NewHash(1,NULL);
511                 Put(Msg->AttachLinks, SKEY(Mime->PartNum), Mime, reference_free_handler);
512         }
513         else if ((Mime->level == 1) &&
514                  (StrLength(Mime->ContentType) > 0) &&
515                   ( (!strcasecmp(ChrPtr(Mime->Disposition), "attachment")) 
516                     || (!strcasecmp(ChrPtr(Mime->Disposition), "inline"))
517                     || (!strcasecmp(ChrPtr(Mime->Disposition), ""))))
518         {               
519                 if (Msg->AttachLinks == NULL)
520                         Msg->AttachLinks = NewHash(1,NULL);
521                 Put(Msg->AttachLinks, SKEY(Mime->PartNum), Mime, reference_free_handler);
522                 if ((strcasecmp(ChrPtr(Mime->ContentType), "application/octet-stream") == 0) && 
523                     (StrLength(Mime->FileName) > 0)) {
524                         FlushStrBuf(Mime->ContentType);
525                         StrBufAppendBufPlain(Mime->ContentType,
526                                              GuessMimeByFilename(SKEY(Mime->FileName)),
527                                              -1, 0);
528                 }
529         }
530 }
531
532 void tmplput_MAIL_SUMM_NATTACH(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
533 {
534         message_summary *Msg = (message_summary*) Context;
535         StrBufAppendPrintf(Target, "%ld", GetCount(Msg->Attachments));
536 }
537
538
539 void examine_hnod(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
540 {
541         FreeStrBuf(&Msg->hnod);
542         Msg->hnod = NewStrBufPlain(NULL, StrLength(HdrLine));
543         StrBuf_RFC822_to_Utf8(Msg->hnod, HdrLine, WC->DefaultCharset, FoundCharset);
544 }
545 void tmplput_MAIL_SUMM_H_NODE(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
546 {
547         message_summary *Msg = (message_summary*) Context;
548         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->hnod, 0);
549 }
550 int Conditional_MAIL_SUMM_H_NODE(WCTemplateToken *Tokens, void *Context, int ContextType)
551 {
552         message_summary *Msg = (message_summary*) Context;
553         return StrLength(Msg->hnod) > 0;
554 }
555
556
557
558 void examine_text(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
559 {
560         Msg->MsgBody->Data = NewStrBuf();
561 }
562
563 void examine_msg4_partnum(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
564 {
565         Msg->MsgBody->PartNum = NewStrBufDup(HdrLine);
566         StrBufTrim(Msg->MsgBody->PartNum);
567 }
568
569
570 void examine_content_lengh(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
571 {
572         Msg->MsgBody->length = StrTol(HdrLine);
573         Msg->MsgBody->size_known = 1;
574 }
575
576 void examine_content_type(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
577 {
578         void *vHdr;
579         headereval *Hdr;
580         StrBuf *Token;
581         StrBuf *Value;
582         const char* sem;
583         const char *eq;
584         int len;
585         StrBufTrim(HdrLine);
586         Msg->MsgBody->ContentType = NewStrBufDup(HdrLine);
587         sem = strchr(ChrPtr(HdrLine), ';');
588
589         if (sem != NULL) {
590                 Token = NewStrBufPlain(NULL, StrLength(HdrLine));
591                 Value = NewStrBufPlain(NULL, StrLength(HdrLine));
592                 len = sem - ChrPtr(HdrLine);
593                 StrBufCutAt(Msg->MsgBody->ContentType, len, NULL);
594                 while (sem != NULL) {
595                         while (isspace(*(sem + 1)))
596                                 sem ++;
597                         StrBufCutLeft(HdrLine, sem - ChrPtr(HdrLine));
598                         sem = strchr(ChrPtr(HdrLine), ';');
599                         if (sem != NULL)
600                                 len = sem - ChrPtr(HdrLine);
601                         else
602                                 len = StrLength(HdrLine);
603                         FlushStrBuf(Token);
604                         FlushStrBuf(Value);
605                         StrBufAppendBufPlain(Token, ChrPtr(HdrLine), len, 0);
606                         eq = strchr(ChrPtr(Token), '=');
607                         if (eq != NULL) {
608                                 len = eq - ChrPtr(Token);
609                                 StrBufAppendBufPlain(Value, eq + 1, StrLength(Token) - len - 1, 0); 
610                                 StrBufCutAt(Token, len, NULL);
611                                 StrBufTrim(Value);
612                         }
613                         StrBufTrim(Token);
614
615                         if (GetHash(MsgHeaderHandler, SKEY(Token), &vHdr) &&
616                             (vHdr != NULL)) {
617                                 Hdr = (headereval*)vHdr;
618                                 Hdr->evaluator(Msg, Value, FoundCharset);
619                         }
620                         else lprintf(1, "don't know how to handle content type sub-header[%s]\n", ChrPtr(Token));
621                 }
622                 FreeStrBuf(&Token);
623                 FreeStrBuf(&Value);
624         }
625 }
626
627 void tmplput_MAIL_SUMM_N(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
628 {
629         message_summary *Msg = (message_summary*) Context;
630         StrBufAppendPrintf(Target, "%ld", Msg->msgnum);
631 }
632
633
634
635 int Conditional_MAIL_MIME_ALL(WCTemplateToken *Tokens, void *Context, int ContextType)
636 {
637         message_summary *Msg = (message_summary*) Context;
638         return GetCount(Msg->Attachments) > 0;
639 }
640
641 int Conditional_MAIL_MIME_SUBMESSAGES(WCTemplateToken *Tokens, void *Context, int ContextType)
642 {
643         message_summary *Msg = (message_summary*) Context;
644         return GetCount(Msg->Submessages) > 0;
645 }
646
647 int Conditional_MAIL_MIME_ATTACHLINKS(WCTemplateToken *Tokens, void *Context, int ContextType)
648 {
649         message_summary *Msg = (message_summary*) Context;
650         return GetCount(Msg->AttachLinks) > 0;
651 }
652
653 int Conditional_MAIL_MIME_ATTACH(WCTemplateToken *Tokens, void *Context, int ContextType)
654 {
655         message_summary *Msg = (message_summary*) Context;
656         return GetCount(Msg->AllAttach) > 0;
657 }
658
659
660
661 /*----------------------------------------------------------------------------*/
662 void tmplput_QUOTED_MAIL_BODY(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
663 {
664         long MsgNum;
665         StrBuf *Buf;
666
667         MsgNum = LBstr(TKEY(0));
668         Buf = NewStrBuf();
669         read_message(Buf, HKEY("view_message_replyquote"), MsgNum, 0, NULL);
670         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Buf, 1);
671         FreeStrBuf(&Buf);
672 }
673
674 void tmplput_MAIL_BODY(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
675 {
676         message_summary *Msg = (message_summary*) Context;
677         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Msg->MsgBody->Data, 0);
678 }
679
680
681 void render_MAIL_variformat(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *FoundCharset)
682 {
683         /* Messages in legacy Citadel variformat get handled thusly... */
684         StrBuf *Target = NewStrBufPlain(NULL, StrLength(Mime->Data));
685         FmOut(Target, "JUSTIFY", Mime->Data);
686         FreeStrBuf(&Mime->Data);
687         Mime->Data = Target;
688 }
689
690 void render_MAIL_text_plain(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *FoundCharset)
691 {
692         StrBuf *cs = NULL;
693         const char *ptr, *pte;
694         const char *BufPtr = NULL;
695         StrBuf *Line;
696         StrBuf *Line1;
697         StrBuf *Line2;
698         StrBuf *Target;
699
700         int ConvertIt = 1;
701         int bn = 0;
702         int bq = 0;
703         int i, n, done = 0;
704         long len;
705 #ifdef HAVE_ICONV
706         iconv_t ic = (iconv_t)(-1) ;
707 #endif
708
709         if ((StrLength(Mime->Data) == 0) && (Mime->length > 0)) {
710                 FreeStrBuf(&Mime->Data);
711                 Mime->Data = NewStrBufPlain(NULL, Mime->length);
712                 if (!read_message(Mime->Data, HKEY("view_submessage"), Mime->msgnum, 0, Mime->PartNum))
713                         return;
714         }
715
716         /* Boring old 80-column fixed format text gets handled this way... */
717         if ((strcasecmp(ChrPtr(Mime->Charset), "us-ascii") == 0) &&
718             (strcasecmp(ChrPtr(Mime->Charset), "UTF-8") == 0))
719                 ConvertIt = 0;
720
721 #ifdef HAVE_ICONV
722         if (ConvertIt) {
723                 if (StrLength(Mime->Charset) != 0)
724                         cs = Mime->Charset;
725                 else if (StrLength(FoundCharset) > 0)
726                         cs = FoundCharset;
727                 else if (StrLength(WC->DefaultCharset) > 0)
728                         cs = WC->DefaultCharset;
729                 if (cs == NULL) {
730                         ConvertIt = 0;
731                 }
732                 else {
733                         ctdl_iconv_open("UTF-8", ChrPtr(cs), &ic);
734                         if (ic == (iconv_t)(-1) ) {
735                                 lprintf(5, "%s:%d iconv_open(UTF-8, %s) failed: %s\n",
736                                         __FILE__, __LINE__, ChrPtr(Mime->Charset), strerror(errno));
737                         }
738                 }
739         }
740 #endif
741         Line = NewStrBuf();
742         Line1 = NewStrBuf();
743         Line2 = NewStrBuf();
744         Target = NewStrBufPlain(NULL, StrLength(Mime->Data));
745
746         while ((n = StrBufSipLine(Line, Mime->Data, &BufPtr), n >= 0) && !done)
747         {
748                 done = n == 0;
749                 bq = 0;
750                 i = 0;
751                 ptr = ChrPtr(Line);
752                 len = StrLength(Line);
753                 pte = ptr + len;
754                 
755                 while ((ptr < pte) &&
756                        ((*ptr == '>') ||
757                         isspace(*ptr)))
758                 {
759                         if (*ptr == '>')
760                                 bq++;
761                         ptr ++;
762                         i++;
763                 }
764                 if (i > 0) StrBufCutLeft(Line, i);
765                 
766                 if (StrLength(Line) == 0)
767                         continue;
768
769                 for (i = bn; i < bq; i++)                               
770                         StrBufAppendBufPlain(Target, HKEY("<blockquote>"), 0);
771                 for (i = bq; i < bn; i++)                               
772                         StrBufAppendBufPlain(Target, HKEY("</blockquote>"), 0);
773
774                 if (ConvertIt == 1) {
775                         StrBufConvert(Line, Line1, &ic);
776                 }
777
778                 StrBufAppendBufPlain(Target, HKEY("<tt>"), 0);
779                 UrlizeText(Line1, Line, Line2);
780
781                 StrEscAppend(Target, Line1, NULL, 0, 0);
782                 StrBufAppendBufPlain(Target, HKEY("</tt><br />\n"), 0);
783                 bn = bq;
784         }
785
786         for (i = 0; i < bn; i++)                                
787                 StrBufAppendBufPlain(Target, HKEY("</blockquote>"), 0);
788
789         StrBufAppendBufPlain(Target, HKEY("</i><br />"), 0);
790 #ifdef HAVE_ICONV
791         if (ic != (iconv_t)(-1) ) {
792                 iconv_close(ic);
793         }
794 #endif
795         FreeStrBuf(&Mime->Data);
796         Mime->Data = Target;
797         FreeStrBuf(&Line);
798         FreeStrBuf(&Line1);
799         FreeStrBuf(&Line2);
800 }
801
802 void render_MAIL_html(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *FoundCharset)
803 {
804         StrBuf *Buf;
805         /* HTML is fun, but we've got to strip it first */
806         if (StrLength(Mime->Data) == 0)
807                 return;
808
809         Buf = NewStrBufPlain(NULL, StrLength(Mime->Data));
810
811         output_html(ChrPtr(Mime->Charset), 
812                     (WC->wc_view == VIEW_WIKI ? 1 : 0), 
813                     StrToi(Mime->PartNum), 
814                     Mime->Data, Buf);
815         FreeStrBuf(&Mime->Data);
816         Mime->Data = Buf;
817 }
818
819 void render_MAIL_UNKNOWN(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *FoundCharset)
820 {
821         /* Unknown weirdness */
822         FlushStrBuf(Mime->Data);
823         StrBufAppendBufPlain(Mime->Data, _("I don't know how to display "), -1, 0);
824         StrBufAppendBuf(Mime->Data, Mime->ContentType, 0);
825         StrBufAppendBufPlain(Mime->Data, HKEY("<br />\n"), 0);
826 }
827
828
829
830
831
832
833 HashList *iterate_get_mime_All(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
834 {
835         message_summary *Msg = (message_summary*) Context;
836         return Msg->Attachments;
837 }
838 HashList *iterate_get_mime_Submessages(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
839 {
840         message_summary *Msg = (message_summary*) Context;
841         return Msg->Submessages;
842 }
843 HashList *iterate_get_mime_AttachLinks(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
844 {
845         message_summary *Msg = (message_summary*) Context;
846         return Msg->AttachLinks;
847 }
848 HashList *iterate_get_mime_Attachments(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
849 {
850         message_summary *Msg = (message_summary*) Context;
851         return Msg->AllAttach;
852 }
853
854 void tmplput_MIME_Name(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
855 {
856         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
857         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, mime->Name, 0);
858 }
859
860 void tmplput_MIME_FileName(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
861 {
862         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
863         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, mime->FileName, 0);
864 }
865
866 void tmplput_MIME_PartNum(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
867 {
868         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
869         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, mime->PartNum, 0);
870 }
871
872 void tmplput_MIME_MsgNum(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
873 {
874         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
875         StrBufAppendPrintf(Target, "%ld", mime->msgnum);
876 }
877
878 void tmplput_MIME_Disposition(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
879 {
880         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
881         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, mime->Disposition, 0);
882 }
883
884 void tmplput_MIME_ContentType(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
885 {
886         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
887         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, mime->ContentType, 0);
888 }
889
890 void examine_charset(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
891 {
892         Msg->MsgBody->Charset = NewStrBufDup(HdrLine);
893 }
894
895 void tmplput_MIME_Charset(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
896 {
897         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
898         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, mime->Charset, 0);
899 }
900
901 void tmplput_MIME_Data(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
902 {
903         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
904         if (mime->Renderer != NULL)
905                 mime->Renderer(mime, NULL, NULL);
906         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, mime->Data, 0);
907  /// TODO: check whether we need to load it now?
908 }
909
910 void tmplput_MIME_LoadData(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
911 {
912         wcsession *WCC = WC;    
913         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
914         wc_mime_attachment *att;
915         
916         if ( (!strcasecmp(ChrPtr(mime->Disposition), "inline"))||
917              (!strcasecmp(ChrPtr(mime->Disposition), "attachment")) ) 
918         {
919                 
920                 int n;
921                 char N[64];
922                 /* steal this mime part... */
923                 att = malloc(sizeof(wc_mime_attachment));
924                 memcpy(att, mime, sizeof(wc_mime_attachment));
925                 memset(mime, 0, sizeof(wc_mime_attachment));
926
927                 if (att->Data == NULL) 
928                         MimeLoadData(att);
929
930                 if (WCC->attachments == NULL)
931                         WCC->attachments = NewHash(1, NULL);
932                 /* And add it to the list. */
933                 n = snprintf(N, sizeof N, "%d", GetCount(WCC->attachments) + 1);
934                 Put(WCC->attachments, N, n, att, DestroyMime);
935         }
936 }
937
938 void tmplput_MIME_Length(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
939 {
940         wc_mime_attachment *mime = (wc_mime_attachment*) Context;
941         StrBufAppendPrintf(Target, "%ld", mime->length);
942 }
943
944 HashList *iterate_get_registered_Attachments(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
945 {
946         return WC->attachments;
947 }
948
949 void servcmd_do_search(char *buf, long bufsize)
950 {
951         snprintf(buf, bufsize, "MSGS SEARCH|%s", bstr("query"));
952 }
953
954 void servcmd_headers(char *buf, long bufsize)
955 {
956         snprintf(buf, bufsize, "MSGS ALL");
957 }
958
959 void servcmd_readfwd(char *buf, long bufsize)
960 {
961         snprintf(buf, bufsize, "MSGS ALL");
962 }
963
964 void servcmd_readnew(char *buf, long bufsize)
965 {
966         snprintf(buf, bufsize, "MSGS NEW");
967 }
968
969 void servcmd_readold(char *buf, long bufsize)
970 {
971         snprintf(buf, bufsize, "MSGS OLD");
972 }
973
974
975 readloop_struct rlid[] = {
976         { {HKEY("do_search")}, servcmd_do_search},
977         { {HKEY("headers")},   servcmd_headers},
978         { {HKEY("readfwd")},   servcmd_readfwd},
979         { {HKEY("readnew")},   servcmd_readnew},
980         { {HKEY("readold")},   servcmd_readold}
981 };
982
983
984
985
986                 
987
988
989
990
991 void 
992 InitModule_MSGRENDERERS
993 (void)
994 {
995         RegisterSortFunc(HKEY("date"), 
996                          NULL, 0,
997                          summcmp_date,
998                          summcmp_rdate,
999                          CTX_MAILSUM);
1000         RegisterSortFunc(HKEY("subject"), 
1001                          NULL, 0,
1002                          summcmp_subj,
1003                          summcmp_rsubj,
1004                          CTX_MAILSUM);
1005         RegisterSortFunc(HKEY("sender"),
1006                          NULL, 0,
1007                          summcmp_sender,
1008                          summcmp_rsender,
1009                          CTX_MAILSUM);
1010
1011         /* iterate over all known mails in WC->summ */
1012         RegisterIterator("MAIL:SUMM:MSGS", 0, NULL, iterate_get_mailsumm_All,
1013                          NULL,NULL, CTX_MAILSUM, CTX_NONE);
1014
1015         /* render parts of the message struct */
1016         RegisterNamespace("MAIL:SUMM:DATESTR", 0, 0, tmplput_MAIL_SUMM_DATE_STR, CTX_MAILSUM);
1017         RegisterNamespace("MAIL:SUMM:DATENO",  0, 0, tmplput_MAIL_SUMM_DATE_NO,  CTX_MAILSUM);
1018         RegisterNamespace("MAIL:SUMM:N",       0, 0, tmplput_MAIL_SUMM_N,        CTX_MAILSUM);
1019         RegisterNamespace("MAIL:SUMM:FROM",    0, 2, tmplput_MAIL_SUMM_FROM,     CTX_MAILSUM);
1020         RegisterNamespace("MAIL:SUMM:TO",      0, 2, tmplput_MAIL_SUMM_TO,       CTX_MAILSUM);
1021         RegisterNamespace("MAIL:SUMM:SUBJECT", 0, 4, tmplput_MAIL_SUMM_SUBJECT,  CTX_MAILSUM);
1022         RegisterNamespace("MAIL:SUMM:NTATACH", 0, 0, tmplput_MAIL_SUMM_NATTACH,  CTX_MAILSUM);
1023         RegisterNamespace("MAIL:SUMM:CCCC", 0, 2, tmplput_MAIL_SUMM_CCCC,  CTX_MAILSUM);
1024         RegisterNamespace("MAIL:SUMM:H_NODE", 0, 2, tmplput_MAIL_SUMM_H_NODE,  CTX_MAILSUM);
1025         RegisterNamespace("MAIL:SUMM:ALLRCPT", 0, 2, tmplput_MAIL_SUMM_ALLRCPT,  CTX_MAILSUM);
1026         RegisterNamespace("MAIL:SUMM:ORGROOM", 0, 2, tmplput_MAIL_SUMM_ORGROOM,  CTX_MAILSUM);
1027         RegisterNamespace("MAIL:SUMM:RFCA", 0, 2, tmplput_MAIL_SUMM_RFCA,  CTX_MAILSUM);
1028         RegisterNamespace("MAIL:SUMM:OTHERNODE", 2, 0, tmplput_MAIL_SUMM_OTHERNODE,  CTX_MAILSUM);
1029         RegisterNamespace("MAIL:SUMM:REFIDS", 0, 0, tmplput_MAIL_SUMM_REFIDS,  CTX_MAILSUM);
1030         RegisterNamespace("MAIL:SUMM:INREPLYTO", 0, 2, tmplput_MAIL_SUMM_INREPLYTO,  CTX_MAILSUM);
1031         RegisterNamespace("MAIL:BODY", 0, 2, tmplput_MAIL_BODY,  CTX_MAILSUM);
1032         RegisterNamespace("MAIL:QUOTETEXT", 1, 2, tmplput_QUOTED_MAIL_BODY,  CTX_NONE);
1033
1034         RegisterConditional(HKEY("COND:MAIL:SUMM:RFCA"), 0, Conditional_MAIL_SUMM_RFCA,  CTX_MAILSUM);
1035         RegisterConditional(HKEY("COND:MAIL:SUMM:UNREAD"), 0, Conditional_MAIL_SUMM_UNREAD, CTX_MAILSUM);
1036         RegisterConditional(HKEY("COND:MAIL:SUMM:H_NODE"), 0, Conditional_MAIL_SUMM_H_NODE, CTX_MAILSUM);
1037         RegisterConditional(HKEY("COND:MAIL:SUMM:OTHERNODE"), 0, Conditional_MAIL_SUMM_OTHERNODE, CTX_MAILSUM);
1038         RegisterConditional(HKEY("COND:MAIL:ANON"), 0, Conditional_ANONYMOUS_MESSAGE, CTX_MAILSUM);
1039
1040
1041         /* do we have mimetypes to iterate over? */
1042         RegisterConditional(HKEY("COND:MAIL:MIME:ATTACH"), 0, Conditional_MAIL_MIME_ALL, CTX_MAILSUM);
1043         RegisterConditional(HKEY("COND:MAIL:MIME:ATTACH:SUBMESSAGES"), 0, Conditional_MAIL_MIME_SUBMESSAGES, CTX_MAILSUM);
1044         RegisterConditional(HKEY("COND:MAIL:MIME:ATTACH:LINKS"), 0, Conditional_MAIL_MIME_ATTACHLINKS, CTX_MAILSUM);
1045         RegisterConditional(HKEY("COND:MAIL:MIME:ATTACH:ATT"), 0, Conditional_MAIL_MIME_ATTACH, CTX_MAILSUM);
1046         RegisterIterator("MAIL:MIME:ATTACH", 0, NULL, iterate_get_mime_All, 
1047                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM);
1048         RegisterIterator("MAIL:MIME:ATTACH:SUBMESSAGES", 0, NULL, iterate_get_mime_Submessages, 
1049                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM);
1050         RegisterIterator("MAIL:MIME:ATTACH:LINKS", 0, NULL, iterate_get_mime_AttachLinks, 
1051                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM);
1052         RegisterIterator("MAIL:MIME:ATTACH:ATT", 0, NULL, iterate_get_mime_Attachments, 
1053                          NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM);
1054
1055         /* Parts of a mime attachent */
1056         RegisterNamespace("MAIL:MIME:NAME", 0, 2, tmplput_MIME_Name, CTX_MIME_ATACH);
1057         RegisterNamespace("MAIL:MIME:FILENAME", 0, 2, tmplput_MIME_FileName, CTX_MIME_ATACH);
1058         RegisterNamespace("MAIL:MIME:PARTNUM", 0, 2, tmplput_MIME_PartNum, CTX_MIME_ATACH);
1059         RegisterNamespace("MAIL:MIME:MSGNUM", 0, 2, tmplput_MIME_MsgNum, CTX_MIME_ATACH);
1060         RegisterNamespace("MAIL:MIME:DISPOSITION", 0, 2, tmplput_MIME_Disposition, CTX_MIME_ATACH);
1061         RegisterNamespace("MAIL:MIME:CONTENTTYPE", 0, 2, tmplput_MIME_ContentType, CTX_MIME_ATACH);
1062         RegisterNamespace("MAIL:MIME:CHARSET", 0, 2, tmplput_MIME_Charset, CTX_MIME_ATACH);
1063         RegisterNamespace("MAIL:MIME:LENGTH", 0, 2, tmplput_MIME_Length, CTX_MIME_ATACH);
1064         RegisterNamespace("MAIL:MIME:DATA", 0, 2, tmplput_MIME_Data, CTX_MIME_ATACH);
1065         /* load the actual attachment into WC->attachments; no output!!! */
1066         RegisterNamespace("MAIL:MIME:LOADDATA", 0, 0, tmplput_MIME_LoadData, CTX_MIME_ATACH);
1067
1068         /* iterate the WC->attachments; use the above tokens for their contents */
1069         RegisterIterator("MSG:ATTACHNAMES", 0, NULL, iterate_get_registered_Attachments, 
1070                          NULL, NULL, CTX_MIME_ATACH, CTX_NONE);
1071
1072         /* mime renderers translate an attachment into webcit viewable html text */
1073         RegisterMimeRenderer(HKEY("message/rfc822"), render_MAIL);
1074         RegisterMimeRenderer(HKEY("text/x-vcard"), render_MIME_VCard);
1075         RegisterMimeRenderer(HKEY("text/vcard"), render_MIME_VCard);
1076         RegisterMimeRenderer(HKEY("text/calendar"), render_MIME_ICS);
1077         RegisterMimeRenderer(HKEY("application/ics"), render_MIME_ICS);
1078         RegisterMimeRenderer(HKEY("text/x-citadel-variformat"), render_MAIL_variformat);
1079         RegisterMimeRenderer(HKEY("text/plain"), render_MAIL_text_plain);
1080         RegisterMimeRenderer(HKEY("text"), render_MAIL_text_plain);
1081         RegisterMimeRenderer(HKEY("text/html"), render_MAIL_html);
1082         RegisterMimeRenderer(HKEY(""), render_MAIL_UNKNOWN);
1083
1084         /* these headers are citserver replies to MSG4 and friends. one evaluator for each */
1085         RegisterMsgHdr(HKEY("nhdr"), examine_nhdr, 0);
1086         RegisterMsgHdr(HKEY("type"), examine_type, 0);
1087         RegisterMsgHdr(HKEY("from"), examine_from, 0);
1088         RegisterMsgHdr(HKEY("subj"), examine_subj, 0);
1089         RegisterMsgHdr(HKEY("msgn"), examine_msgn, 0);
1090         RegisterMsgHdr(HKEY("wefw"), examine_wefw, 0);
1091         RegisterMsgHdr(HKEY("cccc"), examine_cccc, 0);
1092         RegisterMsgHdr(HKEY("hnod"), examine_hnod, 0);
1093         RegisterMsgHdr(HKEY("room"), examine_room, 0);
1094         RegisterMsgHdr(HKEY("rfca"), examine_rfca, 0);
1095         RegisterMsgHdr(HKEY("node"), examine_node, 0);
1096         RegisterMsgHdr(HKEY("rcpt"), examine_rcpt, 0);
1097         RegisterMsgHdr(HKEY("time"), examine_time, 0);
1098         RegisterMsgHdr(HKEY("part"), examine_mime_part, 0);
1099         RegisterMsgHdr(HKEY("text"), examine_text, 1);
1100         /* these are the content-type headers we get infront of a message; put it into the same hash since it doesn't clash. */
1101         RegisterMsgHdr(HKEY("X-Citadel-MSG4-Partnum"), examine_msg4_partnum, 0);
1102         RegisterMsgHdr(HKEY("Content-type"), examine_content_type, 0);
1103         RegisterMsgHdr(HKEY("Content-length"), examine_content_lengh, 0);
1104         RegisterMsgHdr(HKEY("Content-transfer-encoding"), examine_content_encoding, 0); /* do we care? */
1105         RegisterMsgHdr(HKEY("charset"), examine_charset, 0);
1106
1107         /* Don't care about these... */
1108         RegisterMsgHdr(HKEY("pref"), examine_pref, 0);
1109         RegisterMsgHdr(HKEY("suff"), examine_suff, 0);
1110         RegisterMsgHdr(HKEY("path"), examine_path, 0);
1111 }