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