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