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