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