1 /*
2 ** Copyright 1998 - 2009 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6
7 /*
8 ** $Id: folder.c,v 1.188 2009/11/18 03:38:50 mrsam Exp $
9 */
10 #include "config.h"
11 #include <stdio.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include "sqwebmail.h"
17 #include "maildir/maildirmisc.h"
18 #include "maildir/maildircreate.h"
19 #include "maildir/maildirnewshared.h"
20 #include "maildir/maildirinfo.h"
21 #include "maildir/maildiraclt.h"
22
23 #include "rfc822/rfc822.h"
24 #include "rfc822/rfc2047.h"
25 #include "rfc2045/rfc2045.h"
26 #include "rfc2045/rfc2646.h"
27 #include "rfc2646html.h"
28 #include "md5/md5.h"
29 #include "gpglib/gpglib.h"
30 #include "maildir.h"
31 #include "mailfilter.h"
32 #include "maildir/maildirquota.h"
33 #include "maildir/maildirgetquota.h"
34 #include "maildir/maildirinfo.h"
35 #include "numlib/numlib.h"
36 #include "courierauth.h"
37 #include "folder.h"
38 #include "addressbook.h"
39 #include "cgi/cgi.h"
40 #include "pref.h"
41 #include "token.h"
42 #include "filter.h"
43 #include "buf.h"
44 #include "pref.h"
45 #include "newmsg.h"
46 #include "htmllibdir.h"
47 #include "gpg.h"
48 #include "acl.h"
49 #include "auth.h"
50
51 #include "msg2html.h"
52
53 #if HAVE_LOCALE_H
54 #if HAVE_SETLOCALE
55 #include <locale.h>
56 #endif
57 #endif
58
59 #if TIME_WITH_SYS_TIME
60 #include <sys/time.h>
61 #include <time.h>
62 #else
63 #if HAVE_SYS_TIME_H
64 #include <sys/time.h>
65 #else
66 #include <time.h>
67 #endif
68 #endif
69 #if HAVE_SYS_STAT_H
70 #include <sys/stat.h>
71 #endif
72 #include <errno.h>
73
74 #include "unicode/unicode.h"
75
76 #include <unistd.h>
77 #if HAVE_WCHAR_H
78 #include <wchar.h>
79 #endif
80
81 #include "strftime.h"
82
83 extern FILE *open_langform(const char *lang, const char *formname,
84 int print_header);
85
86 extern const char *sqwebmail_content_language;
87 extern char sqwebmail_folder_rights[];
88 extern const char *sqwebmail_mailboxid;
89 extern char *get_imageurl();
90 extern const char *sqwebmail_content_locale;
91 extern void print_attrencodedlen(const char *, size_t, int, FILE *);
92
93 extern const char *showsize(unsigned long);
94 extern void maildir_cleanup();
95 extern const char *nonloginscriptptr();
96 extern int pref_flagpagesize;
97 extern int ishttps();
98 extern const char *sqwebmail_content_charset;
99 extern int verify_shared_index_file;
100
101 extern time_t rfc822_parsedt(const char *);
102 static time_t current_time;
103
104 static const char *folder_err_msg=0;
105
106 extern const char *sqwebmail_folder;
107
108 extern void output_scriptptrget();
109 extern void output_scriptptr();
110 extern void output_scriptptrpostinfo();
111 extern void output_attrencoded(const char *);
112 extern void output_urlencoded(const char *);
113 extern char *scriptptrget();
114
print_safe_len(const char * p,size_t n,void (* func)(const char *,size_t))115 void print_safe_len(const char *p, size_t n, void (*func)(const char *, size_t))
116 {
117 char buf[10];
118 const char *q=p;
119
120 while (n)
121 {
122 --n;
123 if (*p == '<') strcpy(buf, "<");
124 else if (*p == '>') strcpy(buf, ">");
125 else if (*p == '&') strcpy(buf, "&");
126 else if (*p == ' ') strcpy(buf, " ");
127 else if (*p == '\n') strcpy(buf, "<br />");
128 else if (ISCTRL(*p))
129 sprintf(buf, "&#%d;", (int)(unsigned char)*p);
130 else
131 {
132 p++;
133 continue;
134 }
135
136 (*func)(q, p-q);
137 (*func)(buf, strlen(buf));
138 p++;
139 q=p;
140 }
141 (*func)(q, p-q);
142 }
143
print_safe_to_stdout(const char * p,size_t cnt)144 static void print_safe_to_stdout(const char *p, size_t cnt)
145 {
146 if (cnt == 0)
147 return;
148
149 if (fwrite(p, cnt, 1, stdout) != 1)
150 exit(1);
151 }
152
print_safe(const char * p)153 void print_safe(const char *p)
154 {
155 print_safe_len(p, strlen(p), print_safe_to_stdout);
156 }
157
call_print_safe_to_stdout(const char * p,size_t cnt)158 void call_print_safe_to_stdout(const char *p, size_t cnt)
159 {
160 print_safe_len(p, cnt, print_safe_to_stdout);
161 }
162
folder_contents_title()163 void folder_contents_title()
164 {
165 const char *lab;
166 const char *f;
167 const char *inbox_lab, *drafts_lab, *trash_lab, *sent_lab;
168
169 lab=getarg("FOLDERTITLE");
170 inbox_lab=getarg("INBOX");
171 drafts_lab=getarg("DRAFTS");
172 trash_lab=getarg("TRASH");
173 sent_lab=getarg("SENT");
174
175 f=sqwebmail_folder;
176 if (strcmp(f, INBOX) == 0) f=inbox_lab;
177 else if (strcmp(f, INBOX "." DRAFTS) == 0) f=drafts_lab;
178 else if (strcmp(f, INBOX "." SENT) == 0) f=sent_lab;
179 else if (strcmp(f, INBOX "." TRASH) == 0) f=trash_lab;
180
181 if (lab)
182 {
183 char *ff, *origff;
184
185 printf("%s", lab);
186
187 origff=ff=folder_fromutf7(f);
188
189 if (strcmp(ff, NEWSHAREDSP) == 0 ||
190 strncmp(ff, NEWSHAREDSP ".", sizeof(NEWSHAREDSP)) == 0)
191 {
192 printf("%s", getarg("PUBLICFOLDERS"));
193 ff=strchr(ff, '.');
194 if (!ff)
195 ff="";
196 }
197 output_attrencoded(ff);
198 free(origff);
199 }
200 }
201
group_movedel(const char * folder,int (* func)(const char *,const char *,size_t))202 static int group_movedel(const char *folder,
203 int (*func)(const char *, const char *, size_t))
204 {
205 struct cgi_arglist *arg;
206
207 if (*cgi("SELECTALL")) /* Everything is selected */
208 {
209 for (arg=cgi_arglist; arg; arg=arg->next)
210 {
211 const char *f;
212
213 if (strncmp(arg->argname, "MOVEFILE-", 9)) continue;
214 f=cgi(arg->argname);
215 CHECKFILENAME(f);
216 if ((*func)(folder, f, atol(arg->argname+9)))
217 return (-1);
218 }
219 return (0);
220 }
221
222 for (arg=cgi_arglist; arg; arg=arg->next)
223 {
224 unsigned long l;
225 char movedel[MAXLONGSIZE+10];
226 const char *f;
227
228 if (strncmp(arg->argname, "MOVE-", 5)) continue;
229 l=atol(arg->argname+5);
230 sprintf(movedel, "MOVEFILE-%lu", l);
231 f=cgi(movedel);
232 CHECKFILENAME(f);
233 if ((*func)(folder, f, l))
234 return (-1);
235 }
236 return (0);
237 }
238
groupdel(const char * folder,const char * file,size_t pos)239 static int groupdel(const char *folder, const char *file, size_t pos)
240 {
241 maildir_msgdeletefile(folder, file, pos);
242 return (0);
243 }
244
groupmove(const char * folder,const char * file,size_t pos)245 static int groupmove(const char *folder, const char *file, size_t pos)
246 {
247 return (maildir_msgmovefile(folder, file, cgi("moveto"), pos));
248 }
249
folder_delmsgs(const char * dir,size_t pos)250 void folder_delmsgs(const char *dir, size_t pos)
251 {
252 int rc=0;
253 char buf[2];
254 char *cur;
255
256 strcpy(buf, ACL_DELETEMSGS);
257 acl_computeRightsOnFolder(dir, buf);
258
259 if (buf[0] == 0)
260 {
261 http_redirect_argu("&error=nodel&form=folder&pos=%s",
262 (unsigned long)pos);
263 return;
264 }
265
266 if (*cgi("cmddel"))
267 {
268 rc=group_movedel( dir, &groupdel );
269 maildir_savefoldermsgs(dir);
270 }
271 else if (*cgi("cmdpurgeall"))
272 {
273 char *deldir;
274 struct maildir_info minfo;
275
276 if (maildir_info_imap_find(&minfo, dir, login_returnaddr())<0)
277 {
278 http_redirect_argu("&error=othererror&form=folder&pos=%s",
279 (unsigned long)pos);
280 return ;
281 }
282
283 if ((deldir=maildir_name2dir(minfo.homedir, minfo.maildir)) == NULL)
284 {
285 maildir_info_destroy(&minfo);
286 http_redirect_argu("&error=othererror&form=folder&pos=%s",
287 (unsigned long)pos);
288 return;
289 }
290
291 cur = malloc(strlen(deldir)+5);
292 strcpy(cur, deldir);
293 strcat(cur, "/cur");
294
295 rc=maildir_del_content(cur);
296 maildir_quota_recalculate(".");
297
298 maildir_info_destroy(&minfo);
299 free(deldir);
300 free(cur);
301
302 }
303 else if (*cgi("cmdmove"))
304 {
305 const char *p=cgi("moveto");
306
307 CHECKFILENAME(p);
308 strcpy(buf, ACL_INSERT);
309 acl_computeRightsOnFolder(p, buf);
310 if (buf[0] == 0)
311 {
312 http_redirect_argu("&error=noinsert&form=folder&pos=%s",
313 (unsigned long)pos);
314 return;
315 }
316
317 rc=group_movedel( dir, &groupmove );
318 maildir_savefoldermsgs(dir);
319 }
320
321 maildir_cleanup();
322
323 http_redirect_argu(
324 (rc ? "&error=quota&form=folder&pos=%s":"&form=folder&pos=%s"),
325 (unsigned long)pos);
326 }
327
328
savepath(const char * path,const char * maildir)329 static void savepath(const char *path, const char *maildir)
330 {
331 char buf[BUFSIZ];
332 FILE *ofp;
333 FILE *fp;
334 struct maildir_tmpcreate_info createInfo;
335
336 maildir_tmpcreate_init(&createInfo);
337
338 createInfo.maildir=".";
339 createInfo.uniq="sharedpath";
340 createInfo.doordie=1;
341
342 ofp=maildir_tmpcreate_fp(&createInfo);
343
344 fp=fopen(SHAREDPATHCACHE, "r");
345
346 if (fp)
347 {
348 int cnt=0;
349
350 while (cnt < 1)
351 {
352 char *p;
353
354 if (fgets(buf, sizeof(buf), fp) == NULL)
355 break;
356
357 if ((p=strchr(buf, '\n')) != NULL) *p=0;
358
359 if (strcmp(buf, maildir) == 0)
360 {
361 if (fgets(buf, sizeof(buf), fp) == NULL)
362 break;
363 continue;
364 }
365
366 fprintf(ofp, "%s\n", buf);
367
368 if (fgets(buf, sizeof(buf), fp) == NULL)
369 strcpy(buf, "");
370 if ((p=strchr(buf, '\n')) != NULL) *p=0;
371 fprintf(ofp, "%s\n", buf);
372
373 ++cnt;
374 }
375 fclose(fp);
376 }
377
378 fprintf(ofp, "%s\n%s\n", maildir, path);
379 fclose(ofp);
380 rename(createInfo.tmpname, SHAREDPATHCACHE);
381 maildir_tmpcreate_free(&createInfo);
382 }
383
384 static void folder_msg_link(const char *, size_t, char);
385 static void folder_msg_unlink(const char *, size_t, char);
386
387 static char *truncate_at(const char *, const struct unicode_info *, size_t);
388
389
folder_contents(const char * dir,size_t pos)390 void folder_contents(const char *dir, size_t pos)
391 {
392 MSGINFO **contents;
393 int i, found;
394 int morebefore, moreafter;
395 const char *nomsg, *selectalllab;
396 const char *unselectalllab, *golab;
397 const char *qerrmsg;
398 long highend;
399 const struct unicode_info *uiptr=unicode_find(sqwebmail_content_charset);
400
401 if (!uiptr)
402 uiptr=&unicode_ISO8859_1;
403
404 qerrmsg=getarg("PERMERR");
405
406 if (strcmp(cgi("error"), "quota") == 0)
407 printf("%s", qerrmsg);
408
409 if (strcmp(cgi("error"), "nodel") == 0)
410 printf("%s", getarg("NODELPERM"));
411
412 if (strcmp(cgi("error"), "noinsert") == 0)
413 printf("%s", getarg("NOINSERTPERM"));
414
415 if (strcmp(cgi("error"), "othererror") == 0)
416 printf("%s", getarg("OTHERERROR"));
417
418 if (strchr(sqwebmail_folder_rights, ACL_READ[0]) == NULL)
419 {
420 printf("%s", getarg("ACL"));
421 return;
422 }
423
424 maildir_reload(dir);
425 contents=maildir_read(dir, pref_flagpagesize, &pos,
426 &morebefore, &moreafter);
427
428 time(¤t_time);
429 nomsg=getarg("NOMESSAGES");
430 golab=getarg("GO");
431 selectalllab=getarg("SELECTALL");
432 unselectalllab=getarg("UNSELECTALL");
433
434 if (maildir_countof(dir) <= pos + pref_flagpagesize - 1)
435 highend = (long)(maildir_countof(dir) - 1);
436 else
437 highend = (long)(pos + pref_flagpagesize - 1);
438 if (highend < 0) highend = 0;
439
440 if (!qerrmsg) qerrmsg="";
441
442 folder_navigate(dir, pos, highend, morebefore, moreafter);
443
444 printf("<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\"><tr class=\"folder-index-header\"><th align=\"center\">%s</th><th> </th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n",
445 getarg("NUM"),
446 getarg("DATE"),
447 (strncmp(dir, INBOX "." SENT, sizeof(INBOX)+sizeof(SENT)-1) &&
448 strncmp(dir, INBOX "." DRAFTS, sizeof(INBOX)+sizeof(DRAFTS)-1))
449 ? getarg("FROM") : getarg("TO"),
450 getarg("SUBJECT"),
451 getarg("SIZE"));
452
453 found=0;
454 for (i=0; i<pref_flagpagesize; i++)
455 {
456 const char *date, *from, *subj, *size;
457 char *froms, *subjs;
458 const char *p, *q;
459 size_t l;
460 char type[8];
461 char *folder_index_entry_start, *folder_index_entry_end;
462
463 if (contents[i] == 0) continue;
464 found=1;
465
466 date=MSGINFO_DATE(contents[i]);
467 from=MSGINFO_FROM(contents[i]);
468 subj=MSGINFO_SUBJECT(contents[i]);
469 size=MSGINFO_SIZE(contents[i]);
470
471 type[0]=maildirfile_type(MSGINFO_FILENAME(contents[i]));
472 type[1]='\0';
473 if (type[0] == '\0') strcpy(type, " ");
474
475 folder_index_entry_start="<span class=\"read-message\">";
476 folder_index_entry_end="</span>";
477
478 if (type[0] == MSGTYPE_NEW)
479 {
480 folder_index_entry_start="<strong class=\"unread-message\">";
481 folder_index_entry_end="</strong>";
482 }
483
484 p=MSGINFO_FILENAME(contents[i]);
485
486 if ((q=strrchr(p, '/')) != 0)
487 p=q+1;
488
489 printf("<tr class=\"folder-index-bg-%d\" id=\"row%d\"><td align=\"right\" class=\"message-number\">%s%ld.%s</td><td class=\"message-status\"><input type=\"checkbox\" name=\"MOVE-%ld\" id=\"MOVE-%ld",
490 (i & 1)+1,
491 i,
492 folder_index_entry_start,
493 (long)(i+pos+1),
494 folder_index_entry_end,
495 (long) (pos+i),
496 (long) (pos+i));
497 printf("\" onchange=\"setsel('MOVE-%ld', 'row%d', 'folder-index-bg-%d');\"%s /><input type=\"hidden\" name=\"MOVEFILE-%ld\" value=\"",
498 (long)(pos+i), i, (i & 1)+1,
499 (type[0] == MSGTYPE_DELETED ? " disabled=\"disabled\"":""),
500 (long)(pos+i));
501 output_attrencoded(p);
502 printf("\" /> %s%s%s</td><td class=\"message-date\">%s",
503 folder_index_entry_start,
504 type,
505 folder_index_entry_end,
506
507 folder_index_entry_start
508 );
509 if (!*date) date=" ";
510 folder_msg_link(dir, pos+i, type[0]);
511 print_safe(date);
512 folder_msg_unlink(dir, pos+i, type[0]);
513 printf("%s</td><td class=\"message-from\">%s", folder_index_entry_end,
514 folder_index_entry_start);
515 if (!*from) from=" ";
516 folder_msg_link(dir, pos+i, type[0]);
517
518
519 froms=truncate_at(from, uiptr, 30);
520
521 if (froms == 0) enomem();
522
523 print_safe(froms);
524 free(froms);
525 folder_msg_unlink(dir, pos+i, type[0]);
526 printf("%s<br /></td><td class=\"message-subject\">%s", folder_index_entry_end,
527 folder_index_entry_start);
528
529 folder_msg_link(dir, pos+i, type[0]);
530
531
532 subjs=truncate_at(subj, uiptr, 40);
533
534 if (subjs == 0) enomem();
535
536 print_safe(subjs);
537 l=strlen(subjs);
538 while (l++ < 8)
539 printf(" ");
540 free(subjs);
541
542 folder_msg_unlink(dir, pos+i, type[0]);
543 printf("%s</td><td align=\"right\" class=\"message-size\">%s%s %s<br /></td></tr>\n", folder_index_entry_end, folder_index_entry_start, size, folder_index_entry_end);
544 }
545
546 if (found)
547 {
548 puts("<tr class=\"folder-index-bg-1\"><td colspan=\"6\"><hr /></td></tr>");
549 puts("<tr class=\"folder-index-bg-2\"><td> </td>");
550 puts("<td colspan=\"5\">");
551
552 puts("<script type=\"text/javascript\">");
553 puts("/* <![CDATA[ */");
554 puts("function setAll(input, chk) {");
555 printf("for (i = %ld; i <= %ld; i++) {\n",
556 (long)pos, highend);
557 puts("if (document.getElementById) e = document.getElementById('MOVE-' + i);");
558 puts("else if (document.all) e = document['MOVE-' + i];");
559 puts("if (e != null) { e.checked = chk; e.onchange(); }} }");
560 puts("/* ]]> */");
561 puts("</script>\n");
562
563 puts("<script type=\"text/javascript\">");
564 puts("/* <![CDATA[ */");
565 printf("document.write('<button type=\"button\" onclick=\"setAll(this, true); return false;\">%s<\\/button>\\n ');\n",
566 selectalllab);
567 printf("document.write('<button type=\"button\" onclick=\"setAll(this, false); return false;\">%s<\\/button>\\n');\n",
568 unselectalllab);
569 puts("/* ]]> */");
570 puts("</script>\n");
571
572 printf("<noscript><label><input type=\"checkbox\" name=\"SELECTALL\" /> %s</label></noscript>\n",
573 selectalllab);
574 puts("</td></tr>");
575
576 printf("</table>\n");
577 folder_navigate(dir, pos, highend, morebefore, moreafter);
578 }
579 if (!found && nomsg)
580 {
581 puts("<tr class=\"folder-index-bg-1\"><td colspan=\"6\" align=\"left\"><p>");
582 puts(nomsg);
583 puts("<br /></p></td></tr>");
584 printf("</table>\n");
585 }
586
587 maildir_free(contents, pref_flagpagesize);
588 }
589
folder_navigate(const char * dir,size_t pos,long highend,int morebefore,int moreafter)590 void folder_navigate(const char *dir, size_t pos, long highend, int morebefore, int moreafter)
591 {
592 const char *firstlab, *lastlab;
593 const char *beforelab, *afterlab;
594 const char *showncountlab, *jumplab, *golab;
595
596 time(¤t_time);
597 showncountlab=getarg("SHOWNCOUNT");
598 jumplab=getarg("JUMPTO");
599 golab=getarg("GO");
600 firstlab=getarg("FIRSTPAGE");
601 beforelab=getarg("PREVPAGE");
602 afterlab=getarg("NEXTPAGE");
603 lastlab=getarg("LASTPAGE");
604
605 printf("<table width=\"100%%\" class=\"folder-nextprev-background\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
606 printf("<tr><td align=\"left\">");
607 printf("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-nextprev-buttons\"><tr><td>");
608 if (morebefore)
609 {
610 size_t beforepos;
611
612 if (pos < pref_flagpagesize) beforepos=0;
613 else beforepos=pos-pref_flagpagesize;
614
615 printf("<a href=\"");
616 output_scriptptrget();
617 printf("&form=folder&pos=0\" style=\"text-decoration: none\">");
618 }
619 printf("%s", firstlab);
620 if (morebefore)
621 printf("</a>");
622
623 puts(" ");
624
625 if (morebefore)
626 {
627 size_t beforepos;
628
629 if (pos < pref_flagpagesize) beforepos=0;
630 else beforepos=pos-pref_flagpagesize;
631
632 printf("<a href=\"");
633 output_scriptptrget();
634 printf("&form=folder&pos=%ld\" style=\"text-decoration: none\">",
635 (long)beforepos);
636 }
637 printf("%s", beforelab);
638 if (morebefore)
639 printf("</a>");
640
641 printf("</td></tr></table>\n");
642
643 if (maildir_countof(dir) > 0) {
644 puts("</td><td align=\"center\">\n");
645 puts("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-message-count\"><tr><td>\n");
646 printf(showncountlab, (long)(pos+1), (long)(highend+1), (long)maildir_countof(dir));
647 puts("</td></tr></table>");
648
649 puts("<script type=\"text/javascript\">");
650 puts("/* <![CDATA[ */");
651 puts("document.write('<\\/td><td align=\"center\">' +");
652
653 puts("'<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-jumpto-field\"><tr><td>' +");
654 printf("'%s <input type=\"text\" name=\"jumpto\" size=\"3\" value=\"%ld\" onchange=\"this.form.pos.value = this.value - 1;\" />' +\n",
655 jumplab, (long)(pos+1));
656 printf("'<button type=\"button\" onclick=\"this.form.submit();\">%s<\\/button>' +\n",
657 golab);
658 puts("'<\\/td><\\/tr><\\/table>');");
659 puts("/* ]]> */");
660 puts("</script>");
661 }
662
663 printf("</td><td align=\"right\">\n");
664
665 printf("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-nextprev-buttons\"><tr><td>");
666 if (moreafter)
667 {
668 printf("<a href=\"");
669 output_scriptptrget();
670 printf("&form=folder&pos=%ld\" style=\"text-decoration: none\">",
671 (long)(pos+pref_flagpagesize));
672 }
673 printf("%s", afterlab);
674 if (moreafter)
675 printf("</a>");
676
677 puts(" ");
678
679 if (moreafter)
680 {
681 printf("<a href=\"");
682 output_scriptptrget();
683 printf("&form=folder&pos=%ld\" style=\"text-decoration: none\">",
684 (long)(maildir_countof(dir)-pref_flagpagesize));
685 }
686 printf("%s", lastlab);
687 if (moreafter)
688 printf("</a>");
689
690 printf("</td></tr></table>\n");
691
692 printf("</td></tr></table>");
693 }
694
folder_msg_link(const char * dir,size_t pos,char t)695 static void folder_msg_link(const char *dir, size_t pos, char t)
696 {
697 #if 0
698 if (t == MSGTYPE_DELETED)
699 {
700 printf("<a href=\"");
701 output_scriptptrget();
702 printf("&form=folder&pos=%s\">", cgi("pos"));
703 return;
704 }
705 #endif
706
707 printf("<a href=\"");
708 if (strcmp(dir, INBOX "." DRAFTS))
709 {
710 output_scriptptrget();
711 printf("&form=readmsg&pos=%ld\">", (long)pos);
712 }
713 else
714 {
715 size_t mpos=pos;
716 char *filename=maildir_posfind(dir, &mpos);
717 char *basename=filename ? maildir_basename(filename):NULL;
718
719 output_scriptptrget();
720 printf("&form=open-draft&draft=");
721 output_urlencoded(basename);
722 printf("\">");
723 if (basename) free(basename);
724 if (filename) free(filename);
725 }
726 }
727
folder_msg_unlink(const char * dir,size_t pos,char t)728 static void folder_msg_unlink(const char *dir, size_t pos, char t)
729 {
730 printf("</a>");
731 }
732
733 size_t msg_pos, msg_count;
734 static char *msg_posfile;
735 static int msg_hasprev, msg_hasnext;
736 static const char *msg_nextlab=0, *msg_prevlab=0, *msg_deletelab=0,
737 *msg_purgelab=0, *msg_folderlab=0;
738 static char msg_type;
739
740 static const char *msg_replylab=0;
741 static const char *msg_replyalllab=0;
742 static const char *msg_replylistlab=0;
743 static const char *msg_forwardlab=0;
744 static const char *msg_forwardattlab=0;
745 static const char *msg_fullheaderlab=0;
746 static const char *msg_movetolab=0;
747 static const char *msg_print=0;
748
749 static const char *folder_inbox=0;
750 static const char *folder_drafts=0;
751 static const char *folder_trash=0;
752 static const char *folder_sent=0;
753 static const char *msg_golab=0;
754
755 static const char *msg_msglab;
756 static const char *msg_add=0;
757
758 static int initnextprevcnt;
759
folder_initnextprev(const char * dir,size_t pos)760 void folder_initnextprev(const char *dir, size_t pos)
761 {
762 MSGINFO **info;
763 const char *p;
764 const char *msg_numlab, *msg_numnewlab;
765 static char *filename=0;
766 int fd;
767
768 cgi_put(MIMEGPGFILENAME, "");
769
770 if (filename)
771 free(filename);
772 filename=0;
773
774
775 if (*cgi("mimegpg") && (filename=maildir_posfind(dir, &pos)) != 0)
776 {
777 char *tptr;
778 int nfd;
779
780 fd=maildir_semisafeopen(filename, O_RDONLY, 0);
781
782 if (fd >= 0)
783 {
784 struct maildir_tmpcreate_info createInfo;
785
786 maildir_purgemimegpg();
787
788 maildir_tmpcreate_init(&createInfo);
789
790 createInfo.uniq=":mimegpg:";
791 createInfo.doordie=1;
792
793 if ((nfd=maildir_tmpcreate_fd(&createInfo)) < 0)
794 {
795 free(filename);
796 error("Can't create new file.");
797 }
798
799 tptr=createInfo.tmpname;
800 createInfo.tmpname=NULL;
801 maildir_tmpcreate_free(&createInfo);
802
803 chmod(tptr, 0600);
804
805 /*
806 ** Decrypt/check message into a temporary file
807 ** that's immediately marked as deleted, so that it
808 ** gets purged at the next sweep.
809 */
810
811 if (gpgdecode(fd, nfd) < 0)
812 {
813 close(nfd);
814 unlink(tptr);
815 free(tptr);
816 }
817 else
818 {
819 close(fd);
820 free(filename);
821 filename=tptr;
822 fd=nfd;
823
824 cgi_put(MIMEGPGFILENAME,
825 strrchr(filename, '/')+1);
826 }
827 close(fd);
828 }
829 }
830
831 initnextprevcnt=0;
832 msg_nextlab=getarg("NEXTLAB");
833 msg_prevlab=getarg("PREVLAB");
834 msg_deletelab=getarg("DELETELAB");
835 msg_purgelab=getarg("PURGELAB");
836
837 msg_folderlab=getarg("FOLDERLAB");
838
839 msg_replylab=getarg("REPLY");
840 msg_replyalllab=getarg("REPLYALL");
841 msg_replylistlab=getarg("REPLYLIST");
842
843 msg_forwardlab=getarg("FORWARD");
844 msg_forwardattlab=getarg("FORWARDATT");
845
846 msg_numlab=getarg("MSGNUM");
847 msg_numnewlab=getarg("MSGNEWNUM");
848
849 msg_fullheaderlab=getarg("FULLHDRS");
850
851 msg_movetolab=getarg("MOVETO");
852 msg_print=getarg("PRINT");
853
854 folder_inbox=getarg("INBOX");
855 folder_drafts=getarg("DRAFTS");
856 folder_trash=getarg("TRASH");
857 folder_sent=getarg("SENT");
858
859 p=getarg("CREATEFAIL");
860 if (strcmp(cgi("error"),"quota") == 0)
861 printf("%s", p);
862
863 msg_golab=getarg("GOLAB");
864 msg_add=getarg("QUICKADD");
865
866 info=maildir_read(dir, 1, &pos, &msg_hasprev, &msg_hasnext);
867 msg_pos=pos;
868
869 p=strrchr(MSGINFO_FILENAME(info[0]), '/');
870 if (p) p++;
871 else p=MSGINFO_FILENAME(info[0]);
872 msg_posfile=strdup(p);
873 if (!msg_posfile) enomem();
874
875 if ((msg_type=maildirfile_type(MSGINFO_FILENAME(info[0])))
876 == MSGTYPE_NEW) msg_numlab=msg_numnewlab;
877
878 msg_msglab=msg_numlab;
879 msg_count=maildir_countof(dir);
880 maildir_free(info, 1);
881 }
882
get_msgfilename(const char * folder,size_t * pos)883 char *get_msgfilename(const char *folder, size_t *pos)
884 {
885 char *filename;
886
887 if (*cgi(MIMEGPGFILENAME))
888 {
889 const char *p=cgi(MIMEGPGFILENAME);
890
891 CHECKFILENAME(p);
892
893 filename=malloc(sizeof("tmp/")+strlen(p));
894 if (!filename)
895 enomem();
896 strcat(strcpy(filename, "tmp/"), p);
897 }
898 else
899 filename=maildir_posfind(folder, pos);
900
901 if (!filename) error("Message not found.");
902
903 return (filename);
904 }
905
output_mimegpgfilename()906 void output_mimegpgfilename()
907 {
908 if (*cgi(MIMEGPGFILENAME))
909 {
910 printf("&" MIMEGPGFILENAME "=");
911 output_urlencoded(cgi(MIMEGPGFILENAME));
912 }
913 }
914
folder_nextprev()915 void folder_nextprev()
916 {
917 printf("<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"message-menu-background\"><tr valign=\"middle\">");
918
919 printf("<td align=\"left\"><table border=\"0\" cellspacing=\"4\" cellpadding=\"4\"><tr valign=\"top\">");
920
921 /* PREV */
922
923 printf("<td class=\"message-menu-button\">");
924
925 if (msg_hasprev)
926 {
927 printf("<a href=\"");
928 output_scriptptrget();
929 printf("&form=readmsg&pos=%ld\">",
930 (long)(msg_pos-1));
931 }
932
933 printf("%s", msg_prevlab ? msg_prevlab:"");
934
935 if (msg_hasprev)
936 {
937 printf("</a>");
938 }
939 printf("</td>");
940
941 /* NEXT */
942
943 printf("<td class=\"message-menu-button\">");
944
945 if (msg_hasnext)
946 {
947 printf("<a href=\"");
948 output_scriptptrget();
949 printf("&form=readmsg&pos=%ld\">",
950 (long)(msg_pos+1));
951 }
952
953 printf("%s", msg_nextlab ? msg_nextlab:"");
954
955 if (msg_hasnext)
956 {
957 printf("</a>");
958 }
959 printf("</td>");
960
961 /* DEL */
962
963 printf("<td class=\"message-menu-button\">");
964 if (msg_type != MSGTYPE_DELETED)
965 {
966 printf("<a href=\"");
967 output_scriptptrget();
968 tokennewget();
969 printf("&posfile=");
970 output_urlencoded(msg_posfile);
971 printf("&form=delmsg&pos=%ld\">",
972 (long)msg_pos);
973 }
974 printf("%s", strcmp(sqwebmail_folder, INBOX "." TRASH) == 0
975 ? msg_purgelab : msg_deletelab);
976
977 if (msg_type != MSGTYPE_DELETED)
978 printf("</a>");
979
980 printf("</td>\n");
981
982 /* FOLDER */
983
984 printf("<td class=\"message-menu-button\"><a href=\"");
985 output_scriptptrget();
986 printf("&pos=%ld&form=folder\">%s</a></td>\n",
987 (long)( (msg_pos/pref_flagpagesize)*pref_flagpagesize ),
988 msg_folderlab);
989
990 /* REPLY */
991
992 printf("<td class=\"message-menu-button\"><a href=\"");
993 output_scriptptrget();
994 output_mimegpgfilename();
995 printf("&pos=%ld&reply=1&form=newmsg\">%s</a></td>\n",
996 (long)msg_pos,
997 msg_replylab);
998
999 /* REPLY ALL */
1000
1001 printf("<td class=\"message-menu-button\"><a href=\"");
1002 output_scriptptrget();
1003 output_mimegpgfilename();
1004 printf("&pos=%ld&replyall=1&form=newmsg\">%s</a></td>\n",
1005 (long)msg_pos,
1006 msg_replyalllab);
1007
1008 /* REPLY LIST */
1009
1010 printf("<td class=\"message-menu-button\"><a href=\"");
1011 output_scriptptrget();
1012 output_mimegpgfilename();
1013 printf("&pos=%ld&replylist=1&form=newmsg\">%s</a></td>\n",
1014 (long)msg_pos,
1015 msg_replylistlab);
1016
1017 if (auth_getoptionenvint("wbnoimages"))
1018 printf("<td width=\"100%%\"></td></tr></table><table border=\"0\" cellspacing=\"4\" cellpadding=\"4\"><tr>");
1019
1020 /* FORWARD */
1021
1022 printf("<td class=\"message-menu-button\"><a href=\"");
1023 output_scriptptrget();
1024 output_mimegpgfilename();
1025 printf("&pos=%ld&forward=1&form=newmsg\">%s</a></td>\n",
1026 (long)msg_pos,
1027 msg_forwardlab);
1028
1029 /* FORWARD AS ATTACHMENT*/
1030
1031 printf("<td class=\"message-menu-button\"><a href=\"");
1032 output_scriptptrget();
1033 output_mimegpgfilename();
1034 printf("&pos=%ld&forwardatt=1&form=newmsg\">%s</a></td>\n",
1035 (long)msg_pos,
1036 msg_forwardattlab);
1037
1038 /* FULL HEADERS */
1039
1040 if (!pref_flagfullheaders && !*cgi("fullheaders"))
1041 {
1042 printf("<td class=\"message-menu-button\"><a href=\"");
1043 output_scriptptrget();
1044 output_mimegpgfilename();
1045 printf("&pos=%ld&form=readmsg&fullheaders=1\">%s</a></td>\n",
1046 (long)msg_pos, msg_fullheaderlab);
1047 }
1048
1049 /* PRINT MESSAGE */
1050
1051 printf("<td class=\"message-menu-button\"><a href=\"");
1052 output_scriptptrget();
1053 output_mimegpgfilename();
1054
1055 printf("&pos=%ld&form=print&setcookie=1%s\" target=\"_blank\">%s</a></td>\n",
1056 (long)msg_pos,
1057 ((pref_flagfullheaders || *cgi("fullheaders")) ? "&fullheaders=1" : ""),
1058 msg_print);
1059
1060 /* SAVE MESSAGE */
1061
1062 printf("<td class=\"message-menu-button\"><a href=\"");
1063 output_scriptptrget();
1064 output_mimegpgfilename();
1065
1066 printf("&pos=%ld&form=fetch&download=1\">%s</a></td>", (long)msg_pos,
1067 getarg("SAVEMESSAGE"));
1068
1069 printf("<td width=\"100%%\"></td></tr></table></td><td align=\"right\" valign=\"middle\">");
1070
1071 printf("<table border=\"0\" cellspacing=\"4\"><tr><td class=\"message-x-of-y\"> ");
1072 printf(msg_msglab, (int)msg_pos+1, (int)msg_count);
1073 printf(" </td></tr></table>");
1074 printf("</td></tr></table>\n");
1075 }
1076
list_folder(const char * p)1077 void list_folder(const char *p)
1078 {
1079 char *s=folder_fromutf7(p);
1080 print_safe(s);
1081 free(s);
1082 }
1083
list_folder_xlate(const char * p,const char * path,const char * n_inbox,const char * n_drafts,const char * n_sent,const char * n_trash)1084 void list_folder_xlate(const char *p,
1085 const char *path,
1086 const char *n_inbox,
1087 const char *n_drafts,
1088 const char *n_sent,
1089 const char *n_trash)
1090 {
1091 if (strcmp(p, INBOX) == 0)
1092 printf("%s", n_inbox);
1093 else if (strcmp(p, INBOX "." DRAFTS) == 0)
1094 printf("%s", n_drafts);
1095 else if (strcmp(p, INBOX "." TRASH) == 0)
1096 printf("%s", n_trash);
1097 else if (strcmp(p, INBOX "." SENT) == 0)
1098 printf("%s", n_sent);
1099 else
1100 list_folder(path);
1101 }
1102
1103 static void parse_hierarchy(const char *hierarchy,
1104 void (*maildir_hier_cb)
1105 (const char *pfix, const char *homedir,
1106 const char *path, const char *inbox_name),
1107 void (*sharehier_cb)
1108 (const char *sharedhier,
1109 struct maildir_shindex_cache *cache));
1110
1111 static void show_transfer_dest_real(const char *, const char *,
1112 const char *, const char *);
1113 static void show_transfer_dest_fake(const char *,
1114 struct maildir_shindex_cache *);
1115
show_transfer_dest(const char * cur_folder)1116 static void show_transfer_dest(const char *cur_folder)
1117 {
1118 parse_hierarchy(cur_folder, show_transfer_dest_real,
1119 show_transfer_dest_fake);
1120 }
1121
show_transfer_dest_fake(const char * dummy1,struct maildir_shindex_cache * dummy2)1122 static void show_transfer_dest_fake(const char *dummy1,
1123 struct maildir_shindex_cache *dummy2)
1124 {
1125 }
1126
1127 static void show_transfer_dest_real1(const char *inbox_pfix,
1128 const char *homedir,
1129 const char *cur_folder,
1130 const char *inbox_name);
1131
show_transfer_dest_real(const char * inbox_pfix,const char * homedir,const char * cur_folder,const char * inbox_name)1132 static void show_transfer_dest_real(const char *inbox_pfix,
1133 const char *homedir,
1134 const char *cur_folder,
1135 const char *inbox_name)
1136 {
1137 FILE *fp;
1138 char buf1[BUFSIZ];
1139 char buf2[BUFSIZ];
1140
1141 show_transfer_dest_real1(inbox_pfix, homedir, cur_folder, inbox_name);
1142
1143 if ((fp=fopen(SHAREDPATHCACHE, "r")) != NULL)
1144 {
1145 while (fgets(buf1, sizeof(buf1), fp) &&
1146 fgets(buf2, sizeof(buf2), fp))
1147 {
1148 char *p;
1149
1150 p=strchr(buf1, '\n');
1151 if (p) *p=0;
1152 p=strchr(buf2, '\n');
1153 if (p) *p=0;
1154
1155 if (homedir == NULL || strcmp(buf1, homedir))
1156 {
1157 show_transfer_dest_real1(buf2, buf1,
1158 cur_folder,
1159 inbox_name);
1160 }
1161 }
1162 fclose(fp);
1163 }
1164 }
1165
show_transfer_dest_real1(const char * inbox_pfix,const char * homedir,const char * cur_folder,const char * inbox_name)1166 static void show_transfer_dest_real1(const char *inbox_pfix,
1167 const char *homedir,
1168 const char *cur_folder,
1169 const char *inbox_name)
1170 {
1171 char **folders;
1172 size_t i;
1173 const char *p;
1174 int has_shared=0;
1175
1176 maildir_listfolders(inbox_pfix, homedir, &folders);
1177 for (i=0; folders[i]; i++)
1178 {
1179 char acl_buf[2];
1180
1181 strcpy(acl_buf, ACL_INSERT);
1182 acl_computeRightsOnFolder(folders[i], acl_buf);
1183
1184 if (acl_buf[0] == 0)
1185 continue;
1186
1187 /* Transferring TO drafts is prohibited */
1188
1189 if (cur_folder == NULL || strcmp(cur_folder,
1190 INBOX "." DRAFTS))
1191 {
1192 if (strcmp(folders[i], INBOX "." DRAFTS) == 0)
1193 continue;
1194 }
1195 else
1196 {
1197 if (strncmp(folders[i], SHARED ".",
1198 sizeof(SHARED)) &&
1199 strcmp(folders[i], INBOX "." TRASH))
1200 continue;
1201 }
1202
1203 if (cur_folder && strcmp(cur_folder, folders[i]) == 0)
1204 continue;
1205
1206 p=folders[i];
1207
1208 if (strcmp(p, INBOX) == 0)
1209 p=folder_inbox;
1210 else if (strcmp(p, INBOX "." DRAFTS) == 0)
1211 p=folder_drafts;
1212 else if (strcmp(p, INBOX "." TRASH) == 0)
1213 p=folder_trash;
1214 else if (strcmp(p, INBOX "." SENT) == 0)
1215 p=folder_sent;
1216 if (!p) p=folders[i];
1217
1218 if (strncmp(folders[i], SHARED ".", sizeof(SHARED)) == 0)
1219 {
1220 char *d=maildir_shareddir(".", strchr(folders[i], '.')+1);
1221 struct stat stat_buf;
1222
1223 if (!d)
1224 {
1225 maildir_freefolders(&folders);
1226 enomem();
1227 }
1228 if (stat(d, &stat_buf)) /* Not subscribed */
1229 {
1230 free(d);
1231 continue;
1232 }
1233 free(d);
1234
1235 if (!has_shared)
1236 {
1237 printf("<option value=\"\"></option>\n");
1238 has_shared=1;
1239 }
1240 }
1241
1242 printf("<option value=\"");
1243 output_attrencoded(folders[i]);
1244 printf("\">");
1245
1246 if (strncmp(folders[i], NEWSHARED, sizeof(NEWSHARED)-1) == 0)
1247 {
1248 printf("%s.", getarg("PUBLICFOLDERS"));
1249 }
1250
1251 p=strchr(folders[i], '.');
1252
1253 list_folder(p ? p+1:folders[i]);
1254 printf("</option>\n");
1255 }
1256 maildir_freefolders(&folders);
1257 }
1258
folder_msgmove()1259 void folder_msgmove()
1260 {
1261 ++initnextprevcnt;
1262 printf("<table border=\"0\" class=\"box-small-outer\"><tr><td>\n");
1263 printf("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td class=\"folder-move-background\"> %s <select name=\"list%d\">\n", msg_movetolab, initnextprevcnt);
1264
1265 show_transfer_dest(sqwebmail_folder);
1266
1267 printf("</select><input type=\"submit\"%s name=\"move%d\" value=\"%s\" /></td></tr></table>\n",
1268 (msg_type == MSGTYPE_DELETED ? " disabled":""),
1269 initnextprevcnt,
1270 msg_golab ? msg_golab:"");
1271 printf("<input type=\"hidden\" name=\"pos\" value=\"%s\" />", cgi("pos"));
1272 printf("<input type=\"hidden\" name=\"posfile\" value=\"");
1273 output_attrencoded(msg_posfile ? msg_posfile:"");
1274 printf("\" /></td></tr></table>\n");
1275 }
1276
folder_delmsg(size_t pos)1277 void folder_delmsg(size_t pos)
1278 {
1279 MSGINFO **info;
1280 int dummy;
1281 const char *f=cgi("posfile");
1282 size_t newpos;
1283 int rc=0;
1284
1285 CHECKFILENAME(f);
1286
1287 if (*cgi("move1"))
1288 {
1289 rc=maildir_msgmovefile(sqwebmail_folder, f, cgi("list1"), pos);
1290 maildir_savefoldermsgs(sqwebmail_folder);
1291 }
1292 else if (*cgi("move2"))
1293 {
1294 rc=maildir_msgmovefile(sqwebmail_folder, f, cgi("list2"), pos);
1295 maildir_savefoldermsgs(sqwebmail_folder);
1296 }
1297 else
1298 {
1299 maildir_msgdeletefile(sqwebmail_folder, f, pos);
1300 maildir_savefoldermsgs(sqwebmail_folder);
1301 }
1302
1303 if (rc)
1304 {
1305 http_redirect_argu("&form=readmsg&pos=%s&error=quota",
1306 (unsigned long)pos);
1307 return;
1308 }
1309
1310 newpos=pos+1;
1311 info=maildir_read(sqwebmail_folder, 1, &newpos, &dummy, &dummy);
1312
1313 if (info[0] && newpos != pos)
1314 {
1315 maildir_free(info, 1);
1316 http_redirect_argu("&form=readmsg&pos=%s",
1317 (unsigned long)newpos);
1318 }
1319 else
1320 {
1321 maildir_free(info, 1);
1322 http_redirect_argu("&form=folder&pos=%s",
1323 (unsigned long)pos);
1324 }
1325 }
1326
is_preview_mode()1327 static int is_preview_mode()
1328 {
1329 /* We're in new message window, and we're previewing a draft */
1330
1331 return (*cgi("showdraft"));
1332 }
1333
1334 static void dokeyimport(FILE *, struct rfc2045 *, int);
1335
charset_warning(const char * mime_charset)1336 void charset_warning(const char *mime_charset)
1337 {
1338 const struct unicode_info *u1, *u2;
1339
1340 if (strcasecmp(mime_charset, "us-ascii") == 0)
1341 return;
1342
1343 u1=unicode_find(mime_charset);
1344 u2=unicode_find(sqwebmail_content_charset);
1345
1346 if (u2 && (u2->flags & UNICODE_UTF))
1347 return;
1348
1349 if (!u1 || !u2 || strcmp(u1->chset, u2->chset))
1350 {
1351 printf(getarg("CHSET"), mime_charset,
1352 sqwebmail_content_charset);
1353 }
1354 }
1355
html_warning()1356 static void html_warning()
1357 {
1358 printf("%s", getarg("HTML"));
1359 }
1360
init_smileys(struct msg2html_info * info)1361 static void init_smileys(struct msg2html_info *info)
1362 {
1363 FILE *fp=open_langform(sqwebmail_content_language, "smileys.txt", 0);
1364 char buf[1024];
1365
1366 char imgbuf[1024];
1367
1368 if (!fp)
1369 return;
1370
1371 while (fgets(buf, sizeof(buf), fp) != NULL)
1372 {
1373 char *p=strchr(buf, '#');
1374 char *code;
1375 char *img;
1376 char *attr;
1377
1378 if (p) *p=0;
1379
1380 code=buf;
1381
1382 for (p=buf; *p && !isspace(*p); p++)
1383 ;
1384
1385 if (*p)
1386 *p++=0;
1387
1388 while (*p && isspace(*p))
1389 p++;
1390 img=p;
1391
1392 while (*p && !isspace(*p))
1393 p++;
1394 if (*p)
1395 *p++=0;
1396
1397 while (*p && isspace(*p))
1398 p++;
1399 attr=p;
1400 p=strchr(p, '\n');
1401 if (p) *p=0;
1402
1403 if (!*code || !*img)
1404 continue;
1405
1406 snprintf(imgbuf, sizeof(imgbuf),
1407 "<img src=\"%s/%s\" %s />",
1408 get_imageurl(), img, attr);
1409
1410 msg2html_add_smiley(info, code, imgbuf);
1411 }
1412 fclose(fp);
1413 }
1414
email_address_start(const char * name,const char * addr)1415 static void email_address_start(const char *name, const char *addr)
1416 {
1417 if (is_preview_mode())
1418 return;
1419
1420 printf("<a href=\"");
1421 output_scriptptrget();
1422 printf("&form=quickadd&pos=%s&newname=",
1423 cgi("pos"));
1424
1425 if (name)
1426 output_urlencoded(name);
1427
1428 printf("&newaddr=");
1429 if (addr)
1430 output_urlencoded(addr);
1431
1432 printf("\" style=\"text-decoration: none\" "
1433 "onmouseover=\"window.status='%s'; return true;\" "
1434 "onmouseout=\"window.status=''; return true;\" >"
1435 "<span class=\"message-rfc822-header-address\">",
1436 msg_add ? msg_add:"");
1437 }
1438
email_address_end()1439 static void email_address_end()
1440 {
1441 if (is_preview_mode())
1442 return;
1443
1444 printf("</a></span>");
1445 }
1446
email_header(const char * h,void (* cb_func)(const char *))1447 static void email_header(const char *h,
1448 void (*cb_func)(const char *))
1449 {
1450 char *hdrname;
1451 char *p;
1452 const char *hdrvalue;
1453
1454 if ((hdrname=malloc(sizeof("DSPHDR_")+strlen(h))) == NULL)
1455 enomem();
1456
1457 strcpy (hdrname, "DSPHDR_");
1458 strcat (hdrname, h);
1459
1460 for (p=hdrname; *p; p++)
1461 *p=toupper((int)(unsigned char)*p);
1462
1463 hdrvalue = getarg (hdrname);
1464
1465 (*cb_func)(hdrvalue && *hdrvalue ? hdrvalue:h);
1466
1467 free(hdrname);
1468 }
1469
email_header_date_fmt(const char * def)1470 static const char *email_header_date_fmt(const char *def)
1471 {
1472 const char *date_fmt = getarg ("DSPFMT_DATE");
1473
1474 if (date_fmt && *date_fmt)
1475 def=date_fmt;
1476 return def;
1477 }
1478
1479 extern const char *redirect_hash(const char *timestamp);
1480
decode_cgiurlencode(const char * s)1481 static char *decode_cgiurlencode(const char *s)
1482 {
1483 char *q=malloc(strlen(s)+1), *r;
1484 const char *t;
1485
1486 if (!q) enomem();
1487
1488 for (r=q, t=s; *t; )
1489 {
1490 if (strncmp(t, "&", 5) == 0)
1491 {
1492 *r++ = '&';
1493 t += 5;
1494 continue;
1495 }
1496 if (strncmp(t, "<", 4) == 0)
1497 {
1498 *r++ = '<';
1499 t += 4;
1500 continue;
1501 }
1502 if (strncmp(t, ">", 4) == 0)
1503 {
1504 *r++ = '>';
1505 t += 4;
1506 continue;
1507 }
1508 if (strncmp(t, """, 6) == 0)
1509 {
1510 *r++ = '"';
1511 t += 6;
1512 continue;
1513 }
1514 *r++ = *t++;
1515 }
1516 *r=0;
1517
1518 r=cgiurlencode(q);
1519 free(q);
1520 return (r);
1521 }
1522
get_textlink(const char * s,void * arg)1523 static char *get_textlink(const char *s, void *arg)
1524 {
1525 char *t;
1526 struct buf b;
1527
1528 buf_init(&b);
1529
1530 if (strncmp(s, "mailto:", 7) == 0)
1531 {
1532 int i;
1533
1534 buf_cat(&b, "<a href=\"");
1535 buf_cat(&b, scriptptrget());
1536 buf_cat(&b, "&form=newmsg&to=");
1537
1538 for (i=7; s[i]; i++)
1539 {
1540 char c[2];
1541
1542 c[1]=0;
1543 if ((c[0]=s[i]) == '?')
1544 c[0]='&';
1545 buf_cat(&b, c);
1546 }
1547 buf_cat(&b, "\">"
1548 "<span class=\"message-text-plain-mailto-link\">");
1549 buf_cat(&b, s);
1550 buf_cat(&b, "</span></a>");
1551 }
1552 else if (strncmp(s, "http:", 5) == 0 || strncmp(s, "https:", 6) == 0)
1553 {
1554 char buffer[NUMBUFSIZE];
1555 time_t now;
1556 char *hash;
1557 const char *n;
1558
1559 time(&now);
1560 libmail_str_time_t(now, buffer);
1561
1562 hash=cgiurlencode(redirect_hash(buffer));
1563
1564 t=decode_cgiurlencode(s);
1565 buf_cat(&b, "<a href=\"");
1566
1567 n=getenv("SCRIPT_NAME");
1568 if (!*n) n="/";
1569
1570 buf_cat(&b, n);
1571 buf_cat(&b, "?redirect=");
1572 buf_cat(&b, t);
1573 buf_cat(&b, "&timestamp=");
1574 buf_cat(&b, buffer);
1575 buf_cat(&b, "&md5=");
1576 if (hash)
1577 {
1578 buf_cat(&b, hash);
1579 free(hash);
1580 }
1581 buf_cat(&b, "\" target=\"_blank\">"
1582 "<span class=\"message-text-plain-http-link\">");
1583 buf_cat(&b, s);
1584 buf_cat(&b, "</span></a>");
1585 free(t);
1586 }
1587 t=strdup(b.ptr ? b.ptr:"");
1588 if (!t) enomem();
1589 buf_free(&b);
1590 return (t);
1591 }
1592
message_rfc822_action(struct rfc2045id * idptr)1593 static void message_rfc822_action(struct rfc2045id *idptr)
1594 {
1595 if (is_preview_mode())
1596 return;
1597
1598 printf("<tr valign=\"top\"><td> </td><td align=\"left\" valign=\"top\">");
1599
1600 printf("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td><a href=\"");
1601 output_scriptptrget();
1602 output_mimegpgfilename();
1603 msg2html_showmimeid(idptr, NULL);
1604 printf("&pos=%ld&reply=1&form=newmsg\"><font size=\"-1\">%s</font></a> </td><td> <a href=\"",
1605 (long)msg_pos, msg_replylab);
1606
1607 output_scriptptrget();
1608 output_mimegpgfilename();
1609 msg2html_showmimeid(idptr, NULL);
1610 printf("&pos=%ld&replyall=1&form=newmsg\"><font size=\"-1\">%s</font></a> </td><td> <a href=\"",
1611 (long)msg_pos, msg_replyalllab);
1612 output_scriptptrget();
1613 output_mimegpgfilename();
1614 msg2html_showmimeid(idptr, NULL);
1615 printf("&pos=%ld&forward=1&form=newmsg\"><font size=\"-1\">%s</font></a> </td><td> <a href=\"",
1616 (long)msg_pos, msg_forwardlab);
1617
1618 output_scriptptrget();
1619 output_mimegpgfilename();
1620 msg2html_showmimeid(idptr, NULL);
1621 printf("&pos=%ld&forwardatt=1&form=newmsg\"><font size=\"-1\">%s</font></a></td></tr></table>\n",
1622 (long)msg_pos, msg_forwardattlab);
1623
1624 printf("</td></tr>\n");
1625 }
1626
output_mimeurl(struct rfc2045id * id,const char * form)1627 static void output_mimeurl(struct rfc2045id *id, const char *form)
1628 {
1629 output_scriptptrget();
1630 printf("&form=%s&pos=%ld", form, (long)msg_pos);
1631 msg2html_showmimeid(id, NULL);
1632
1633 output_mimegpgfilename();
1634 }
1635
inline_image_action(struct rfc2045id * id,const char * content_type,void * arg)1636 static void inline_image_action(struct rfc2045id *id, const char *content_type,
1637 void *arg)
1638 {
1639 if (!is_preview_mode())
1640 {
1641 printf("<a href=\"");
1642 output_mimeurl(id, "fetch");
1643 printf("\" target=\"_blank\">");
1644 }
1645 printf("<img src=\"");
1646 output_mimeurl(id, "fetch");
1647 printf("\" alt=\"Inline picture: ");
1648 output_attrencoded(content_type);
1649 printf("\" />%s\n",
1650 is_preview_mode() ? "":"</a>");
1651 }
1652
1653
showattname(const char * fmt,const char * name,const char * content_type)1654 static void showattname(const char *fmt, const char *name,
1655 const char *content_type)
1656 {
1657 char *t;
1658
1659 if (!name || !*name) name=content_type;
1660 if (!name) name="";
1661
1662 t=malloc(strlen(name)+strlen(fmt)+100);
1663 if (!t)
1664 return;
1665
1666 sprintf(t, fmt, name);
1667 output_attrencoded(t);
1668 free(t);
1669 }
1670
unknown_attachment_action(struct rfc2045id * id,const char * content_type,const char * content_name,off_t size,void * arg)1671 static void unknown_attachment_action(struct rfc2045id *id,
1672 const char *content_type,
1673 const char *content_name,
1674 off_t size,
1675 void *arg)
1676 {
1677 printf("<table border=\"0\" cellpadding=\"1\" cellspacing=\"0\" class=\"box-small-outer\"><tr><td>");
1678 printf("<table border=\"0\" cellpadding=\"4\" cellspacing=\"0\" class=\"message-download-attachment\"><tr><td>");
1679
1680 if (strcmp(cgi("form"), "print") == 0)
1681 {
1682 showattname(getarg("ATTSTUB"), content_name, content_type);
1683
1684 printf(" (");
1685 output_attrencoded(content_type);
1686 printf(")");
1687 }
1688 else
1689 {
1690 printf("<div align=\"center\"><span class=\"message-attachment-header\">");
1691 showattname(getarg("ATTACHMENT"), content_name, content_type);
1692
1693 printf(" (");
1694 output_attrencoded(content_type);
1695 printf("; %s)</span></div>",
1696 showsize(size));
1697 printf("<br /><div align=\"center\">");
1698
1699 if (!is_preview_mode())
1700 {
1701 printf("<a href=\"");
1702 output_mimeurl(id, "fetch");
1703 printf("\" style=\"text-decoration: none\" target=\"_blank\">");
1704 printf("%s</a> / ", getarg("DISPATT"));
1705 printf("<a href=\"");
1706 output_mimeurl(id, "fetch");
1707 printf("&download=1\" style=\"text-decoration: none\">");
1708 printf("%s</a>", getarg("DOWNATT"));
1709 }
1710
1711 printf("</div>\n");
1712 }
1713
1714 printf("</td></tr></table>\n");
1715 printf("</td></tr></table>\n");
1716 }
1717
is_gpg_enabled()1718 static int is_gpg_enabled()
1719 {
1720 return *cgi(MIMEGPGFILENAME) && !is_preview_mode();
1721 }
1722
application_pgp_keys_action(struct rfc2045id * id)1723 static void application_pgp_keys_action(struct rfc2045id *id)
1724 {
1725 printf("<table border=\"0\" cellpadding=\"8\" cellspacing=\"1\" class=\"box-small-outer\"><tr><td>");
1726 printf("<table border=\"0\" cellpadding=\"4\" cellspacing=\"4\" class=\"message-application-pgpkeys\"><tr><td>");
1727
1728 if (strcmp(cgi("form"), "print") == 0 || is_preview_mode())
1729 {
1730 printf("%s", getarg("KEY"));
1731 }
1732 else
1733 {
1734 printf("<div align=\"center\"><a href=\"");
1735 output_scriptptrget();
1736 printf("&form=keyimport&pos=%ld", (long)msg_pos);
1737 printf("&pubkeyimport=1");
1738 output_mimegpgfilename();
1739 msg2html_showmimeid(id, "&keymimeid=");
1740 printf("\" style=\"text-decoration: none\" class=\"message-application-pgpkeys\">");
1741 printf("%s", getarg("PUBKEY"));
1742 printf("</a></div>");
1743
1744 printf("<hr width=\"100%%\" />\n");
1745
1746 printf("<div align=\"center\"><a href=\"");
1747 output_scriptptrget();
1748 printf("&form=keyimport&pos=%ld", (long)msg_pos);
1749 printf("&privkeyimport=1");
1750 output_mimegpgfilename();
1751 msg2html_showmimeid(id, "&keymimeid=");
1752 printf("\" style=\"text-decoration: none\" class=\"message-application-pgpkeys\">");
1753 printf("%s", getarg("PRIVKEY"));
1754 printf("</a></div>");
1755 }
1756
1757 printf("</td></tr></table>\n");
1758 printf("</td></tr></table>\n<br />\n");
1759 }
1760
gpg_message_action()1761 static void gpg_message_action()
1762 {
1763 printf("<form method=\"post\" action=\"");
1764 output_scriptptr();
1765 printf("\">");
1766 output_scriptptrpostinfo();
1767 printf("<input type=\"hidden\" name=\"form\" value=\"readmsg\" />");
1768 printf("<input type=\"hidden\" name=\"pos\" value=\"%s\" />",
1769 cgi("pos"));
1770 printf("<input type=\"hidden\" name=\"mimegpg\" value=\"1\" />\n");
1771
1772 printf("<table border=\"0\" cellpadding=\"1\""
1773 " width=\"100%%\" class=\"box-outer\">"
1774 "<tr><td><table width=\"100%%\" border=\"0\" cellspacing=\"0\""
1775 " cellpadding=\"0\" class=\"box-white-outer\"><tr><td>");
1776
1777 if ( *cgi(MIMEGPGFILENAME))
1778 {
1779 printf("%s", getarg("NOTCOMPACTGPG"));
1780 }
1781 else
1782 {
1783 printf("%s\n", getarg("MIMEGPGNOTICE"));
1784
1785 if (ishttps())
1786 printf("%s\n", getarg("PASSPHRASE"));
1787
1788 printf("%s", getarg("DECRYPT"));
1789 }
1790 printf("</td><tr></table></td></tr></table></form><br />\n");
1791 }
1792
redirect_hash(const char * timestamp)1793 const char *redirect_hash(const char *timestamp)
1794 {
1795 struct stat stat_buf;
1796
1797 char buffer[NUMBUFSIZE*2+10];
1798 const char *p=getenv("SQWEBMAIL_RANDSEED");
1799
1800 if (strlen(timestamp) >= NUMBUFSIZE)
1801 return "";
1802
1803 strcat(strcpy(buffer, timestamp), " ");
1804
1805 if (p && *p)
1806 strncat(buffer, p, NUMBUFSIZE);
1807 else
1808 {
1809 if (stat(SENDITSH, &stat_buf) < 0)
1810 return "";
1811
1812 libmail_str_ino_t(stat_buf.st_ino, buffer+strlen(buffer));
1813 }
1814
1815 return md5_hash_courier(buffer);
1816 }
1817
get_url_to_mime_part(const char * mimeid,void * arg)1818 static char *get_url_to_mime_part(const char *mimeid, void *arg)
1819 {
1820 const char *mimegpgfilename=cgi(MIMEGPGFILENAME);
1821 const char *pos;
1822 char *p, *q;
1823
1824 p=scriptptrget();
1825 pos=cgi("pos");
1826
1827 q=malloc(strlen(p)+strlen(pos) +
1828 strlen(mimegpgfilename)+
1829 strlen(mimeid)+
1830 sizeof("&mimeid=&pos=&form=fetch&mimegpgfilename="));
1831 if (!q) enomem();
1832 strcpy(q, p);
1833 strcat(q, "&form=fetch&pos=");
1834 strcat(q, pos);
1835 strcat(q, "&mimeid=");
1836 strcat(q, mimeid);
1837
1838 if (*mimegpgfilename)
1839 strcat(strcat(q, "&mimegpgfilename="), mimegpgfilename);
1840
1841 return (q);
1842 }
1843
folder_showmsg(const char * dir,size_t pos)1844 void folder_showmsg(const char *dir, size_t pos)
1845 {
1846 char *filename;
1847 FILE *fp;
1848 struct rfc2045 *rfc;
1849 char buf[BUFSIZ];
1850 int n;
1851 int fd;
1852
1853 struct msg2html_info *info;
1854
1855 const char *script_name=nonloginscriptptr();
1856
1857
1858 if (*cgi("addnick"))
1859 {
1860 const char *name=cgi("newname");
1861 const char *addr=cgi("newaddr");
1862
1863 const char *nick1=cgi("newnick1");
1864 const char *nick2=cgi("newnick2");
1865
1866 while (*nick1 && isspace((int)(unsigned char)*nick1))
1867 ++nick1;
1868
1869 while (*nick2 && isspace((int)(unsigned char)*nick2))
1870 ++nick2;
1871
1872 if (*nick2)
1873 nick1=nick2;
1874
1875 if (*nick1)
1876 {
1877 ab_add(name, addr, nick1);
1878 }
1879 }
1880
1881 filename=get_msgfilename(dir, &pos);
1882
1883 fp=0;
1884 fd=maildir_semisafeopen(filename, O_RDONLY, 0);
1885 if (fd >= 0)
1886 {
1887 if ((fp=fdopen(fd, "r")) == 0)
1888 close(fd);
1889 }
1890
1891 if (!fp)
1892 {
1893 free(filename);
1894 return;
1895 }
1896
1897 msg_pos=pos;
1898 rfc=rfc2045_alloc();
1899
1900 while ((n=fread(buf, 1, sizeof(buf), fp)) > 0)
1901 rfc2045_parse(rfc, buf, n);
1902 rfc2045_parse_partial(rfc);
1903
1904 info=script_name ? msg2html_alloc(sqwebmail_content_charset):NULL;
1905
1906 if (info)
1907 {
1908 char nowbuffer[NUMBUFSIZE];
1909 time_t now;
1910 char *hash;
1911 char *washpfix;
1912 char *washpfixmailto;
1913 char *scriptnameget=scriptptrget();
1914 static const char formbuf[]="&form=newmsg&to=";
1915
1916 info->mimegpgfilename=cgi(MIMEGPGFILENAME);
1917 if (*info->mimegpgfilename)
1918 CHECKFILENAME(info->mimegpgfilename);
1919
1920 info->gpgdir=GPGDIR;
1921 info->fullheaders=pref_flagfullheaders || *cgi("fullheaders");
1922 info->noflowedtext=pref_noflowedtext;
1923 info->showhtml=pref_showhtml;
1924
1925 info->character_set_follows=charset_warning;
1926 info->html_content_follows=html_warning;
1927 info->get_url_to_mime_part=get_url_to_mime_part;
1928
1929 time(&now);
1930 libmail_str_time_t(now, nowbuffer);
1931
1932 hash=cgiurlencode(redirect_hash(nowbuffer));
1933
1934 washpfix=malloc(strlen(script_name)
1935 + strlen(hash ? hash:"") + strlen(nowbuffer)
1936 + 100);
1937 if (!washpfix) enomem();
1938
1939 strcat(strcat(strcat(strcat(strcat(strcpy(washpfix,
1940 script_name),
1941 "?timestamp="),
1942 nowbuffer),
1943 "&md5="),
1944 (hash ? hash:"")),
1945 "&redirect=");
1946
1947 if (hash)
1948 free(hash);
1949
1950 washpfixmailto=malloc(strlen(scriptnameget)+sizeof(formbuf));
1951 if (!washpfixmailto) enomem();
1952 strcat(strcpy(washpfixmailto, scriptnameget), formbuf);
1953
1954 info->wash_http_prefix=washpfix;
1955 info->wash_mailto_prefix=washpfixmailto;
1956
1957 init_smileys(info);
1958
1959 info->email_address_start=email_address_start;
1960 info->email_address_end=email_address_end;
1961 info->email_header=email_header;
1962 info->email_header_date_fmt=email_header_date_fmt;
1963 info->get_textlink=get_textlink;
1964 info->message_rfc822_action=message_rfc822_action;
1965 info->inline_image_action=inline_image_action;
1966 info->unknown_attachment_action=unknown_attachment_action;
1967 info->application_pgp_keys_action=
1968 application_pgp_keys_action;
1969 info->gpg_message_action=gpg_message_action;
1970
1971 info->is_gpg_enabled=is_gpg_enabled;
1972 info->is_preview_mode=is_preview_mode;
1973 msg2html(fp, rfc, info);
1974 msg2html_free(info);
1975
1976 free(washpfix);
1977 free(washpfixmailto);
1978 }
1979
1980 rfc2045_free(rfc);
1981 fclose(fp);
1982 if (*cgi(MIMEGPGFILENAME) == 0)
1983 maildir_markread(dir, pos);
1984 free(filename);
1985 }
1986
folder_keyimport(const char * dir,size_t pos)1987 void folder_keyimport(const char *dir, size_t pos)
1988 {
1989 char *filename;
1990 FILE *fp;
1991 struct rfc2045 *rfc;
1992 int fd;
1993
1994 filename=get_msgfilename(dir, &pos);
1995
1996 fp=0;
1997 fd=maildir_semisafeopen(filename, O_RDONLY, 0);
1998 if (fd >= 0)
1999 {
2000 if ((fp=fdopen(fd, "r")) == 0)
2001 close(fd);
2002 }
2003
2004 if (!fp)
2005 {
2006 free(filename);
2007 return;
2008 }
2009
2010 rfc=rfc2045_fromfp(fp);
2011
2012
2013 if (libmail_gpg_has_gpg(GPGDIR) == 0)
2014 {
2015 struct rfc2045 *part;
2016
2017 if (*cgi("pubkeyimport")
2018 && (part=rfc2045_find(rfc, cgi("keymimeid"))) != 0)
2019 {
2020 dokeyimport(fp, part, 0);
2021 }
2022 else if (*cgi("privkeyimport")
2023 && (part=rfc2045_find(rfc, cgi("keymimeid"))) != 0)
2024 {
2025 dokeyimport(fp, part, 1);
2026 }
2027 }
2028 rfc2045_free(rfc);
2029 fclose(fp);
2030 free(filename);
2031
2032 printf("<p><a href=\"");
2033 output_scriptptrget();
2034 printf("&form=readmsg&pos=%s", cgi("pos"));
2035 printf("\">%s</a>", getarg("KEYIMPORT"));
2036 }
2037
2038 static int importkey_func(const char *p, size_t cnt, void *voidptr);
2039 static int importkeyin_func(const char *p, size_t cnt, void *voidptr);
2040
dokeyimport(FILE * fp,struct rfc2045 * rfcp,int issecret)2041 static void dokeyimport(FILE *fp, struct rfc2045 *rfcp, int issecret)
2042 {
2043 off_t start_pos, end_pos, start_body, ldummy;
2044 char buf[BUFSIZ];
2045 int cnt;
2046
2047 static const char start_str[]=
2048 "<table width=\"100%%\" border=\"0\" class=\"box-outer\"><tr><td>"
2049 "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\""
2050 " class=\"box-white-outer\"><tr><td>%s<pre>\n";
2051
2052 static const char end_str[]=
2053 "</pre></td></tr></table></td></tr></table><br />\n";
2054
2055 if (libmail_gpg_import_start(GPGDIR, issecret))
2056 return;
2057
2058 printf(start_str, getarg("IMPORTHDR"));
2059
2060 rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body,
2061 &ldummy, &ldummy);
2062 if (fseek(fp, start_body, SEEK_SET) < 0)
2063 {
2064 error("Seek error.");
2065 libmail_gpg_import_finish(&importkey_func, NULL);
2066 printf("%s", end_str);
2067 return;
2068 }
2069
2070 rfc2045_cdecode_start(rfcp, &importkeyin_func, 0);
2071
2072 while (start_body < end_pos)
2073 {
2074 cnt=sizeof(buf);
2075 if (cnt > end_pos-start_body)
2076 cnt=end_pos-start_body;
2077 cnt=fread(buf, 1, cnt, fp);
2078 if (cnt <= 0) break;
2079 start_body += cnt;
2080 if (rfc2045_cdecode(rfcp, buf, cnt))
2081 {
2082 rfc2045_cdecode_end(rfcp);
2083 printf("%s", end_str);
2084 return;
2085 }
2086 }
2087
2088 if (rfc2045_cdecode_end(rfcp) == 0)
2089 {
2090 libmail_gpg_import_finish(&importkey_func, NULL);
2091 }
2092
2093 printf("%s", end_str);
2094 }
2095
importkeyin_func(const char * p,size_t cnt,void * voidptr)2096 static int importkeyin_func(const char *p, size_t cnt, void *voidptr)
2097 {
2098 return (libmail_gpg_import_do(p, cnt, &importkey_func, NULL));
2099 }
2100
importkey_func(const char * p,size_t cnt,void * voidptr)2101 static int importkey_func(const char *p, size_t cnt, void *voidptr)
2102 {
2103 print_attrencodedlen(p, cnt, 1, stdout);
2104 return (0);
2105 }
2106
2107
2108 /*
2109 ** If we're currently showing (INBOX|shared|#shared).foo.bar hierarchy, return
2110 ** "x.foo". If we're currently showing (INBOX|shared|#shared).foo, return
2111 ** an empty string.
2112 */
get_parent_folder(const char * p)2113 static char *get_parent_folder(const char *p)
2114 {
2115 const char *q;
2116
2117 q=strrchr(p, '.');
2118
2119 if (q)
2120 {
2121 char *s;
2122
2123 s=malloc(q-p+1);
2124 if (!s) enomem();
2125 memcpy(s, p, q-p);
2126 s[q-p]=0;
2127 return (s);
2128 }
2129 return (strdup(""));
2130 }
2131
checkrename(const char * origfolder,const char * newfolder)2132 static int checkrename(const char *origfolder,
2133 const char *newfolder)
2134 {
2135 char acl_buf[2];
2136 char *p, *q;
2137
2138 strcpy(acl_buf, ACL_DELETEFOLDER);
2139 acl_computeRightsOnFolder(origfolder, acl_buf);
2140 if (acl_buf[0] == 0)
2141 {
2142 folder_err_msg=getarg("RENAME");
2143 return -1;
2144 }
2145
2146 strcpy(acl_buf, ACL_CREATE);
2147 p=strdup(newfolder);
2148
2149 if (!p || !(q=strrchr(p, '.')) ||
2150 (*q=0,
2151 acl_computeRightsOnFolder(p, acl_buf),
2152 acl_buf[0]) == 0)
2153 {
2154 if (p)
2155 free(p);
2156
2157 folder_err_msg=getarg("RENAME");
2158 return -1;
2159 }
2160 free(p);
2161
2162 return 0;
2163 }
2164
dorename(const char * origfolder,struct maildir_info * mifrom,struct maildir_info * mito,const char * err_invalid,const char * err_cantdelete,const char * err_exists)2165 static void dorename(const char *origfolder,
2166 struct maildir_info *mifrom,
2167 struct maildir_info *mito,
2168 const char *err_invalid,
2169 const char *err_cantdelete,
2170 const char *err_exists)
2171 {
2172 char *s;
2173 char *t;
2174 char *u;
2175
2176 const char *p;
2177 struct stat stat_buf;
2178
2179 if (mifrom->homedir == NULL ||
2180 mifrom->maildir == NULL ||
2181 mito->homedir == NULL ||
2182 mito->maildir == NULL ||
2183 strcmp(mifrom->homedir, mito->homedir))
2184 {
2185 folder_err_msg=err_invalid;
2186 return;
2187 }
2188
2189 s=maildir_name2dir(".", mifrom->maildir);
2190 t=maildir_name2dir(".", mito->maildir);
2191
2192 if (!s || !t)
2193 {
2194 if (s) free(s);
2195 if (t) free(t);
2196 folder_err_msg=err_invalid;
2197 return;
2198 }
2199
2200 p=s;
2201 if (strncmp(p, "./", 2) == 0) p += 2;
2202
2203 if (strcmp(p, ".") == 0 ||
2204 strcmp(p, "." SENT) == 0 ||
2205 strcmp(p, "." DRAFTS) == 0 ||
2206 strcmp(p, "." TRASH) == 0)
2207 {
2208 free(s);
2209 free(t);
2210 folder_err_msg=err_invalid;
2211 return;
2212 }
2213
2214 u=maildir_name2dir(mito->homedir, mito->maildir);
2215 if (!u)
2216 {
2217 free(s);
2218 free(t);
2219 folder_err_msg=err_invalid;
2220 return;
2221 }
2222
2223 if (stat(u, &stat_buf) == 0)
2224 {
2225 free(s);
2226 free(t);
2227 folder_err_msg=err_exists;
2228 return;
2229 }
2230 free(u);
2231
2232 if (mailfilter_folderused(origfolder))
2233 {
2234 free(s);
2235 free(t);
2236 folder_err_msg=err_cantdelete;
2237 return;
2238 }
2239
2240 if (maildir_rename(mifrom->homedir,
2241 strncmp(s, "./", 2) == 0 ? s+2:s,
2242 strncmp(t, "./", 2) == 0 ? t+2:t,
2243 MAILDIR_RENAME_FOLDER, NULL))
2244 folder_err_msg=err_cantdelete;
2245
2246 free(s);
2247 free(t);
2248 }
2249
2250 struct publicfolderlist_helper {
2251 char *name;
2252 char *homedir;
2253 char *maildir;
2254 };
2255
freeph(struct publicfolderlist_helper * ph)2256 static void freeph(struct publicfolderlist_helper *ph)
2257 {
2258 if (ph->name)
2259 free(ph->name);
2260 if (ph->homedir)
2261 free(ph->homedir);
2262 if (ph->maildir)
2263 free(ph->maildir);
2264 memset(ph, 0, sizeof(*ph));
2265 }
2266
2267 static void do_folderlist(const char *pfix, const char *homedir,
2268 const char *path, const char *inbox_name);
2269 static void do_sharedhierlist(const char *sharedhier,
2270 struct maildir_shindex_cache *cache);
2271
checkcreate(const char * f,int isrec)2272 static int checkcreate(const char *f, int isrec)
2273 {
2274 char *s=strdup(f);
2275 char *q;
2276 char buf[2];
2277 struct maildir_info minfo;
2278
2279 if (!s)
2280 {
2281 folder_err_msg=getarg("CREATEPERMS");
2282 return -1;
2283 }
2284
2285 if (isrec)
2286 {
2287 if ((q=strrchr(s, '.')) == NULL ||
2288 (*q=0, checkcreate(s, 0)) < 0)
2289 {
2290 free(s);
2291 folder_err_msg=getarg("CREATEPERMS");
2292 return -1;
2293 }
2294 *q='.';
2295 }
2296
2297 if (maildir_info_imap_find(&minfo, s, login_returnaddr()) < 0)
2298 {
2299 free(s);
2300 folder_err_msg=getarg("CREATEPERMS");
2301 return -1;
2302 }
2303
2304 if (strchr(minfo.maildir, '.') == NULL)
2305 {
2306 free(s);
2307 folder_err_msg=getarg("CREATEPERMS");
2308 return -1;
2309 }
2310
2311 maildir_acl_delete(minfo.homedir,
2312 strchr(minfo.maildir, '.'));
2313
2314 maildir_info_destroy(&minfo);
2315
2316 strcpy(buf, ACL_CREATE);
2317
2318 if ((q=strrchr(s, '.')) == NULL ||
2319 (*q=0,
2320 acl_computeRightsOnFolder(s, buf),
2321 buf[0]) == 0)
2322 {
2323 free(s);
2324 folder_err_msg=getarg("CREATEPERMS");
2325 return -1;
2326 }
2327 free(s);
2328 return 0;
2329 }
2330
folder_list()2331 void folder_list()
2332 {
2333 const char *err_invalid;
2334 const char *err_exists;
2335 const char *err_cantdelete;
2336 const char *msg_hasbeensent;
2337
2338 err_invalid=getarg("INVALID");
2339 err_exists=getarg("EXISTS");
2340 err_cantdelete=getarg("DELETE");
2341 msg_hasbeensent=getarg("WASSENT");
2342
2343 folder_err_msg=0;
2344
2345 if (strcmp(cgi("foldermsg"), "sent") == 0)
2346 folder_err_msg=msg_hasbeensent;
2347
2348 if (*cgi("do.create"))
2349 {
2350 const char *newfoldername=trim_spaces(cgi("foldername"));
2351 const char *newdirname=trim_spaces(cgi("dirname"));
2352 const char *folderdir=cgi("folderdir");
2353
2354 /*
2355 ** New folder names cannot contain .s, and must be considered
2356 ** as valid by maildir_folderpath.
2357 */
2358
2359 if (!*folderdir)
2360 folderdir=INBOX;
2361
2362 if (!*newfoldername ||
2363 strchr(newfoldername, '.') ||
2364 strchr(newdirname, '.'))
2365 folder_err_msg=err_invalid;
2366 else
2367 {
2368 char *p;
2369 char *futf7;
2370 char *dutf7;
2371 struct maildir_info minfo;
2372 char *q;
2373
2374 futf7=folder_toutf7(newfoldername);
2375 dutf7=folder_toutf7(newdirname);;
2376
2377 p=malloc(strlen(folderdir)+strlen(futf7)
2378 +strlen(dutf7)+3);
2379
2380 if (!p) enomem();
2381 strcpy(p, folderdir);
2382 if (*dutf7)
2383 {
2384 if (*p) strcat(p, ".");
2385 strcat(p, dutf7);
2386 }
2387 if (*p) strcat(p, ".");
2388 strcat(p, futf7);
2389
2390 free(futf7);
2391 free(dutf7);
2392
2393 if (maildir_info_imap_find(&minfo, p,
2394 login_returnaddr()) < 0)
2395 {
2396 folder_err_msg=err_invalid;
2397 }
2398 else if (minfo.homedir == NULL ||
2399 minfo.maildir == NULL ||
2400 (q=maildir_name2dir(minfo.homedir,
2401 minfo.maildir)) == NULL)
2402 {
2403 maildir_info_destroy(&minfo);
2404 folder_err_msg=err_invalid;
2405 }
2406 else if (access(q, 0) == 0)
2407 {
2408 free(q);
2409 maildir_info_destroy(&minfo);
2410 folder_err_msg=err_exists;
2411 }
2412 else
2413 {
2414 if (checkcreate(p, *newdirname != 0) == 0)
2415 {
2416 if (maildir_make(q, 0700, 0700, 1))
2417 folder_err_msg=err_exists;
2418 else
2419 {
2420 char buf[1];
2421
2422 buf[0]=0;
2423 acl_computeRightsOnFolder(p,
2424 buf);
2425 /* Initialize ACLs correctly */
2426 }
2427 }
2428 free(q);
2429 maildir_info_destroy(&minfo);
2430 }
2431 }
2432 }
2433
2434 if (*cgi("do.delete"))
2435 {
2436 const char *p=cgi("DELETE");
2437 char acl_buf[2];
2438
2439 strcpy(acl_buf, ACL_DELETEFOLDER);
2440 acl_computeRightsOnFolder(p, acl_buf);
2441 if (acl_buf[0] == 0)
2442 folder_err_msg=getarg("DELETEPERMS");
2443 else if (mailfilter_folderused(p))
2444 folder_err_msg=err_cantdelete;
2445 else if (maildir_delete(p, *cgi("deletecontent")))
2446 folder_err_msg=err_cantdelete;
2447 else
2448 maildir_quota_recalculate(".");
2449 }
2450
2451 if (*cgi("do.subunsub"))
2452 {
2453 const char *p=cgi("DELETE");
2454 char *pp=strdup(p);
2455 char *d;
2456
2457 if (pp && strncmp(pp, SHARED ".", sizeof(SHARED)) == 0 &&
2458 (d=maildir_shareddir(".", pp+sizeof(SHARED))) != 0)
2459 {
2460 struct stat stat_buf;
2461
2462 if (stat(d, &stat_buf) == 0)
2463 maildir_shared_unsubscribe(".",
2464 pp+sizeof(SHARED));
2465 else
2466 maildir_shared_subscribe(".",
2467 pp+sizeof(SHARED));
2468 free(d);
2469 }
2470
2471 if (pp)
2472 free(pp);
2473 }
2474
2475 if (*cgi("do.rename"))
2476 {
2477 const char *p=cgi("DELETE");
2478 char *pp=strdup(p);
2479 struct maildir_info mifrom, mito;
2480 const char *qutf7=cgi("renametofolder");
2481 const char *r=trim_spaces(cgi("renametoname"));
2482 char *s;
2483 char *rutf7;
2484
2485 rutf7=folder_toutf7(r);
2486
2487 s=malloc(strlen(qutf7)+strlen(rutf7)+1);
2488
2489 if (!s) enomem();
2490
2491 strcat(strcpy(s, qutf7), rutf7);
2492
2493 if (strchr(r, '.') == NULL
2494 && maildir_info_imap_find(&mifrom, pp,
2495 login_returnaddr()) == 0)
2496 {
2497 if (maildir_info_imap_find(&mito, s,
2498 login_returnaddr()) == 0)
2499 {
2500 if (checkrename(pp, s) == 0)
2501 dorename(pp, &mifrom, &mito,
2502 err_invalid,
2503 err_cantdelete,
2504 err_exists);
2505 maildir_info_destroy(&mifrom);
2506 }
2507 else
2508 {
2509 folder_err_msg=err_invalid;
2510 }
2511 maildir_info_destroy(&mito);
2512 }
2513 else
2514 {
2515 folder_err_msg=err_invalid;
2516 }
2517 free(rutf7);
2518 free(pp);
2519 free(s);
2520 maildir_quota_recalculate(".");
2521 }
2522
2523 parse_hierarchy(cgi("folderdir"),
2524 do_folderlist,
2525 do_sharedhierlist);
2526 }
2527
do_publicfolderlist_cb(struct maildir_newshared_enum_cb * cb)2528 static int do_publicfolderlist_cb(struct maildir_newshared_enum_cb *cb)
2529 {
2530 struct publicfolderlist_helper *h=
2531 (struct publicfolderlist_helper *)cb->cb_arg;
2532
2533 h->name=strdup(cb->name);
2534 if (cb->homedir)
2535 h->homedir=strdup(cb->homedir);
2536 h->maildir=strdup(cb->maildir);
2537 return 0;
2538 }
2539
parse_hierarchy(const char * folderdir,void (* maildir_hier_cb)(const char * pfix,const char * homedir,const char * path,const char * inbox_name),void (* sharedhier_cb)(const char * sharedhier,struct maildir_shindex_cache * cache))2540 static void parse_hierarchy(const char *folderdir,
2541 void (*maildir_hier_cb)
2542 (const char *pfix, const char *homedir,
2543 const char *path, const char *inbox_name),
2544 void (*sharedhier_cb)
2545 (const char *sharedhier,
2546 struct maildir_shindex_cache *cache))
2547 {
2548 struct maildir_shindex_cache *index;
2549 const char *indexfile;
2550 const char *subhierarchy;
2551 const char *p;
2552 const char *q;
2553 size_t l;
2554 size_t n;
2555 struct publicfolderlist_helper ph;
2556 int eof;
2557
2558 if (strchr(folderdir, '/'))
2559 enomem();
2560
2561 if (strncmp(folderdir, NEWSHAREDSP, sizeof(NEWSHAREDSP)-1) == 0)
2562 switch (folderdir[sizeof(NEWSHAREDSP)-1]) {
2563 case 0:
2564 verify_shared_index_file=1;
2565 /* FALLTHRU */
2566 case '.':
2567 break;
2568 default:
2569 (*maildir_hier_cb)(INBOX, NULL, folderdir, INBOX);
2570 return;
2571 }
2572 else
2573 {
2574 (*maildir_hier_cb)(INBOX, NULL, folderdir, INBOX);
2575 return;
2576 }
2577
2578 index=NULL;
2579 indexfile=NULL;
2580 subhierarchy=NULL;
2581 p=folderdir;
2582
2583 memset(&ph, 0, sizeof(ph));
2584
2585 while ((index=maildir_shared_cache_read(index, indexfile,
2586 subhierarchy)) != NULL)
2587 {
2588 q=strchr(p, '.');
2589 if (!q)
2590 break;
2591
2592 p=q+1;
2593
2594 if ((q=strchr(p, '.')) != NULL)
2595 l=q-p;
2596 else
2597 l=strlen(p);
2598
2599 for (n=0; n<index->nrecords; n++)
2600 {
2601 char *m=maildir_info_imapmunge(index->records[n].name);
2602
2603 if (!m)
2604 continue;
2605
2606 if (strlen(m) == l &&
2607 strncmp(m, p, l) == 0)
2608 {
2609 free(m);
2610 break;
2611 }
2612 free(m);
2613 }
2614
2615 if (n >= index->nrecords)
2616 {
2617 index=NULL;
2618 break;
2619 }
2620
2621 index->indexfile.startingpos=index->records[n].offset;
2622 freeph(&ph);
2623 if (maildir_newshared_nextAt(&index->indexfile, &eof,
2624 &do_publicfolderlist_cb, &ph) ||
2625 eof)
2626 {
2627 index=NULL;
2628 break;
2629 }
2630
2631 if (ph.homedir)
2632 {
2633 char *loc=maildir_location(ph.homedir,
2634 ph.maildir);
2635 char *m_path;
2636 char *m_inbox;
2637
2638 if (loc)
2639 {
2640 while (*p)
2641 {
2642 if (*p == '.')
2643 break;
2644 ++p;
2645 }
2646
2647 m_path=malloc(p-folderdir+1);
2648 if (!m_path)
2649 enomem();
2650 memcpy(m_path, folderdir, p-folderdir);
2651 m_path[p-folderdir]=0;
2652
2653 m_inbox=malloc(strlen(m_path)+1+strlen(p));
2654 if (!m_inbox)
2655 enomem();
2656
2657 strcat(strcpy(m_inbox, m_path), p);
2658
2659 savepath(m_path, loc);
2660 (*maildir_hier_cb)(m_path, loc, m_inbox,
2661 m_path);
2662 free(loc);
2663 free(m_path);
2664 free(m_inbox);
2665 }
2666 freeph(&ph);
2667 return;
2668 }
2669
2670 indexfile=ph.maildir;
2671 subhierarchy=index->records[n].name;
2672 }
2673
2674 freeph(&ph);
2675
2676 (*sharedhier_cb)(folderdir, index);
2677 }
2678
do_sharedhierlist(const char * folderdir,struct maildir_shindex_cache * index)2679 static void do_sharedhierlist(const char *folderdir,
2680 struct maildir_shindex_cache *index)
2681 {
2682 const char *p;
2683 const char *q;
2684 size_t n;
2685 struct publicfolderlist_helper ph;
2686 const char *folders_img;
2687 const char *name_inbox;
2688 int eof;
2689 char *url, *url2;
2690
2691 p=strrchr(folderdir, '.');
2692
2693 if (p)
2694 ++p;
2695 else p=folderdir;
2696
2697 folders_img=getarg("FOLDERSICON");
2698 name_inbox=getarg("INBOX");
2699
2700 memset(&ph, 0, sizeof(ph));
2701
2702 printf("<table width=\"100%%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" class=\"folderlist\">\n"
2703 "<tr><td align=\"left\" "
2704 "class=\"folderparentdir\">%s<<< ",
2705 folders_img);
2706
2707 if (strcmp(folderdir, NEWSHAREDSP) == 0)
2708 {
2709 printf("<a href=\"");
2710 output_scriptptrget();
2711 printf("&form=folders&folder=INBOX\">");
2712 print_safe(name_inbox);
2713 printf("</a>");
2714 }
2715 else
2716 {
2717 printf("<a href=\"");
2718 output_scriptptrget();
2719 printf("&folderdir=");
2720 output_urlencoded(NEWSHAREDSP);
2721 printf("&form=folders&folder=INBOX\">%s</a>",
2722 getarg("PUBLICFOLDERS"));
2723 }
2724
2725 for (q=folderdir; q<p; )
2726 {
2727 const char *r;
2728 char *s;
2729
2730 if (*q == '.')
2731 {
2732 ++q;
2733 continue;
2734 }
2735
2736 for (r=q; *r; r++)
2737 if (*r == '.')
2738 break;
2739
2740 if (q != folderdir)
2741 {
2742 printf(".<a href=\"");
2743 output_scriptptrget();
2744 printf("&form=folders&folder=INBOX&folderdir=");
2745
2746
2747 s=malloc(r-folderdir+1);
2748 if (!s)
2749 enomem();
2750
2751 memcpy(s, folderdir, r-folderdir);
2752 s[r-folderdir]=0;
2753
2754 output_urlencoded(s);
2755 printf("\">");
2756 free(s);
2757
2758 s=malloc(r-q+1);
2759 if (!s)
2760 enomem();
2761 memcpy(s, q, r-q);
2762 s[r-q]=0;
2763 list_folder(s);
2764 free(s);
2765 printf("</a>");
2766 }
2767 q=r;
2768 }
2769
2770 printf("</td></tr>\n");
2771
2772
2773 while (*q && *q != '.')
2774 ++q;
2775
2776 url=malloc(q-folderdir+1);
2777 if (!url)
2778 enomem();
2779 memcpy(url, folderdir, q-folderdir);
2780 url[q-folderdir]=0;
2781
2782 for (n=0; index && n<index->nrecords; n++)
2783 {
2784 freeph(&ph);
2785
2786 if (n == 0)
2787 index->indexfile.startingpos=0;
2788
2789 if ((n == 0 ? &maildir_newshared_nextAt:
2790 &maildir_newshared_next)(&index->indexfile, &eof,
2791 &do_publicfolderlist_cb, &ph) ||
2792 eof)
2793 {
2794 break;
2795 }
2796
2797 if (ph.homedir)
2798 {
2799 char *d=maildir_location(ph.homedir, ph.maildir);
2800
2801 if (d)
2802 {
2803 if (maildir_info_suppress(d))
2804 {
2805 free(d);
2806 continue;
2807 }
2808 free(d);
2809 }
2810 }
2811
2812 printf("<tr class=\"foldersubdir\"><td align=\"left\">%s"
2813 ">>> <a href=\"", folders_img);
2814 output_scriptptrget();
2815 printf("&form=folders&folder=INBOX&folderdir=");
2816
2817 output_urlencoded(url);
2818
2819 url2=maildir_info_imapmunge(ph.name);
2820
2821 if (!url2)
2822 enomem();
2823 printf(".");
2824 output_urlencoded(url2);
2825
2826 printf("\">");
2827 list_folder(url2);
2828 free(url2);
2829 printf("</a></td></tr>\n");
2830 }
2831 free(url);
2832 freeph(&ph);
2833 printf("</table>\n");
2834 }
2835
do_folderlist(const char * inbox_pfix,const char * homedir,const char * folderdir,const char * inbox_name)2836 static void do_folderlist(const char *inbox_pfix,
2837 const char *homedir,
2838 const char *folderdir,
2839 const char *inbox_name)
2840 {
2841 const char *name_inbox;
2842 const char *name_drafts;
2843 const char *name_sent;
2844 const char *name_trash;
2845 const char *folder_img;
2846 const char *folders_img;
2847 const char *unread_label;
2848 const char *acl_img;
2849 char acl_buf[2];
2850 char **folders;
2851 size_t i;
2852 unsigned nnew, nother;
2853 size_t folderdir_l;
2854
2855 name_inbox=getarg("INBOX");
2856 name_drafts=getarg("DRAFTS");
2857 name_sent=getarg("SENT");
2858 name_trash=getarg("TRASH");
2859 folder_img=getarg("FOLDERICON");
2860 folders_img=getarg("FOLDERSICON");
2861 sqwebmail_folder=0;
2862 unread_label=getarg("UNREAD");
2863 acl_img=maildir_newshared_disabled ? NULL : getarg("ACLICON");
2864
2865 printf("<table width=\"100%%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" class=\"folderlist\">\n");
2866
2867 maildir_listfolders(inbox_pfix, homedir, &folders);
2868
2869 if (*folderdir && strcmp(folderdir, INBOX))
2870 {
2871 char *parentfolder;
2872 size_t i;
2873 char *q, *r;
2874 const char *c;
2875
2876 if (strncmp(folderdir, SHARED ".", sizeof(SHARED)) == 0)
2877 {
2878 for (c=folderdir; *c; c++)
2879 if (*c == '.')
2880 break;
2881
2882 r=malloc(strlen(inbox_pfix)+strlen(c)+1);
2883 if (!r)
2884 enomem();
2885 strcat(strcpy(r, inbox_pfix), c);
2886
2887 parentfolder=get_parent_folder(r);
2888 free(r);
2889 }
2890 else
2891 parentfolder=get_parent_folder(folderdir);
2892
2893 for (q=parentfolder; *q; q++)
2894 if (*q == '.')
2895 break;
2896
2897 printf("<tr><td align=\"left\" colspan=\"2\" class=\"folderparentdir\">%s", folders_img);
2898 printf("<<< ");
2899
2900 #if 0
2901 printf("<a href=\"");
2902 output_scriptptrget();
2903 printf("&folderdir=");
2904 output_urlencoded(inbox_pfix);
2905 printf("&form=folders&folder=INBOX\">");
2906 print_safe(inbox_name);
2907 printf("</a>");
2908 #endif
2909
2910 i=0;
2911 while (parentfolder[i])
2912 {
2913 char *p=strchr(parentfolder+i, '.');
2914 int c;
2915
2916 if (!p) p=parentfolder+strlen(parentfolder);
2917 c= *p;
2918 *p=0;
2919
2920 if (strchr(parentfolder, '.'))
2921 printf(".");
2922 printf("<a href=\"");
2923 output_scriptptrget();
2924 printf("&form=folders&folder=INBOX&folderdir=");
2925 output_urlencoded(parentfolder);
2926 printf("\">");
2927 if (strcmp(parentfolder, NEWSHAREDSP) == 0)
2928 printf("%s", getarg("PUBLICFOLDERS"));
2929 else
2930 list_folder_xlate(parentfolder,
2931 parentfolder+i,
2932 name_inbox,
2933 name_drafts,
2934 name_sent,
2935 name_trash);
2936 printf("</a>");
2937 if ( (*p=c) != 0) ++p;
2938 i=p-parentfolder;
2939 }
2940 printf("</td></tr>\n");
2941 free(parentfolder);
2942 }
2943 else if (strcmp(inbox_pfix, INBOX))
2944 {
2945 size_t i;
2946 char *p;
2947 char *q;
2948
2949 printf("<tr><td align=\"left\" colspan=\"2\" class=\"folderparentdir\">%s<<< ", folders_img);
2950
2951 p=strdup(inbox_pfix);
2952 if (!p)
2953 enomem();
2954
2955 if ((q=strrchr(p, '.')) != 0)
2956 *q=0;
2957
2958 for (i=0; p[i]; )
2959 {
2960 size_t j;
2961 char save_ch;
2962
2963 for (j=i; p[j]; j++)
2964 if (p[j] == '.')
2965 break;
2966
2967
2968 save_ch=p[j];
2969 p[j]=0;
2970
2971 if (i)
2972 printf(".");
2973
2974 printf("<a href=\"");
2975 output_scriptptrget();
2976 printf("&form=folders&folder=INBOX&folderdir=");
2977 output_urlencoded(p);
2978 printf("\">");
2979
2980 if (strcmp(p, NEWSHAREDSP) == 0)
2981 printf("%s", getarg("PUBLICFOLDERS"));
2982 else
2983 list_folder(p+i);
2984 printf("</a>");
2985
2986 p[j]=save_ch;
2987
2988 if (save_ch)
2989 ++j;
2990 i=j;
2991 }
2992 printf("</td></tr>\n");
2993 free(p);
2994 }
2995
2996
2997 if (!folderdir || strchr(folderdir, '.') == 0)
2998 {
2999 folderdir=inbox_pfix;
3000 }
3001
3002 folderdir_l=strlen(folderdir);
3003
3004 for (i=0; folders[i]; i++)
3005 {
3006 const char *p;
3007 const char *shortname=folders[i];
3008
3009 size_t j;
3010 const char *pfix;
3011 int isshared=0;
3012 int isunsubscribed=0;
3013 const char *img=folder_img;
3014
3015 pfix=">>>";
3016
3017 if (strncmp(shortname, SHARED ".",
3018 sizeof(SHARED)) == 0)
3019 {
3020 char *dir;
3021 struct stat stat_buf;
3022
3023 isshared=1;
3024 pfix="+++";
3025
3026 dir=maildir_shareddir(".",
3027 shortname+sizeof(SHARED));
3028 if (!dir) continue;
3029 if (stat(dir, &stat_buf))
3030 isunsubscribed=1;
3031 free(dir);
3032 }
3033
3034 if (strcmp(shortname, inbox_name) == 0 &&
3035 strcmp(folderdir, inbox_name) == 0)
3036 {
3037 /* List INBOX at the top level */
3038
3039 strcpy(acl_buf, ACL_LOOKUP);
3040 acl_computeRightsOnFolder(shortname, acl_buf);
3041 if (acl_buf[0] == 0)
3042 continue;
3043 }
3044 else
3045 {
3046 if (strcmp(folderdir, INBOX) == 0 &&
3047 strncmp(shortname, SHARED ".", sizeof(SHARED)) == 0)
3048 {
3049 shortname += sizeof(SHARED);
3050 }
3051 else
3052 {
3053 if (memcmp(shortname, folderdir, folderdir_l) ||
3054 shortname[folderdir_l] != '.')
3055 {
3056 continue;
3057 }
3058
3059 strcpy(acl_buf, ACL_LOOKUP);
3060 acl_computeRightsOnFolder(shortname, acl_buf);
3061 if (acl_buf[0] == 0)
3062 continue;
3063
3064 shortname += folderdir_l;
3065 ++shortname;
3066 }
3067
3068 if ((p=strchr(shortname, '.')) != 0)
3069 {
3070 char *s;
3071 char *t;
3072 unsigned tot_nnew, tot_nother;
3073
3074 s=malloc(p-folders[i]+1);
3075 if (!s)
3076 enomem();
3077 memcpy(s, folders[i], p-folders[i]);
3078 s[p-folders[i]]=0;
3079
3080 printf("<tr class=\"foldersubdir\"><td align=\"left\">");
3081 if (acl_img)
3082 {
3083 printf("<a href=\"");
3084 output_scriptptrget();
3085 printf("&form=acl&folder=");
3086 output_urlencoded(s);
3087 printf("\">%s</a> ", acl_img);
3088 }
3089 printf("%s%s <a href=\"",
3090 folders_img, pfix);
3091
3092 output_scriptptrget();
3093 printf("&form=folders&folder=INBOX&folderdir=");
3094 output_urlencoded(s);
3095 printf("\">");
3096 free(s);
3097
3098 t=malloc(p-shortname+1);
3099 if (!t) enomem();
3100 memcpy(t, shortname, p-shortname);
3101 t[p-shortname]=0;
3102 list_folder_xlate(folders[i],
3103 t,
3104 name_inbox,
3105 name_drafts,
3106 name_sent,
3107 name_trash);
3108 free(t);
3109 printf("</a>");
3110
3111 tot_nnew=0;
3112 tot_nother=0;
3113
3114 j=i;
3115 while (folders[j] && memcmp(folders[j], folders[i],
3116 p-folders[i]+1) == 0)
3117 {
3118 strcpy(acl_buf, ACL_LOOKUP);
3119 acl_computeRightsOnFolder(folders[j],
3120 acl_buf);
3121 if (acl_buf[0] == 0)
3122 continue;
3123
3124 maildir_count(folders[j], &nnew, ¬her);
3125 ++j;
3126 tot_nnew += nnew;
3127 tot_nother += nother;
3128 }
3129 i=j-1;
3130 if (tot_nnew)
3131 {
3132 printf(" <span class=\"subfolderlistunread\">");
3133 printf(unread_label, tot_nnew);
3134 printf("</span>");
3135 }
3136 printf("</td><td align=\"right\" valign=\"top\"><span class=\"subfoldercnt\">%d</span> </td></tr>\n\n",
3137 tot_nnew + tot_nother);
3138 continue;
3139 }
3140 }
3141
3142 nnew=0;
3143 nother=0;
3144
3145 if (!isunsubscribed)
3146 maildir_count(folders[i], &nnew, ¬her);
3147
3148 printf("<tr%s><td align=\"left\" valign=\"top\">",
3149 isunsubscribed ? " class=\"folderunsubscribed\"":"");
3150
3151 if (acl_img)
3152 {
3153 printf("<a href=\"");
3154 output_scriptptrget();
3155 printf("&form=acl&folder=");
3156 output_urlencoded(folders[i]);
3157 printf("\">%s</a> ", acl_img);
3158 }
3159
3160 printf("%s <input type=\"radio\" name=\"DELETE\" value=\"", img);
3161 output_attrencoded(folders[i]);
3162 printf("\" /> ");
3163 if (!isunsubscribed)
3164 {
3165 printf("<a class=\"folderlink\" href=\"");
3166 output_scriptptrget();
3167 printf("&form=folder&folder=");
3168 output_urlencoded(folders[i]);
3169 printf("\">");
3170 }
3171
3172 list_folder_xlate(folders[i],
3173 strcmp(folders[i], inbox_name) == 0
3174 ? INBOX:shortname,
3175 name_inbox,
3176 name_drafts,
3177 name_sent,
3178 name_trash);
3179 if (!isunsubscribed)
3180 printf("</a>");
3181 if (nnew)
3182 {
3183 printf(" <span class=\"folderlistunread\">");
3184 printf(unread_label, nnew);
3185 printf("</span>");
3186 }
3187 printf("</td><td align=\"right\" valign=\"top\">");
3188
3189 if (!isunsubscribed)
3190 {
3191 printf("<span class=\"foldercnt\">%d</span> ",
3192 nnew + nother);
3193 }
3194 else
3195 printf(" \n");
3196 printf("</td></tr>\n\n");
3197 }
3198 maildir_freefolders(&folders);
3199
3200 if (strcmp(folderdir, INBOX) == 0 && !maildir_newshared_disabled)
3201 {
3202 char *sp=cgiurlencode(NEWSHAREDSP);
3203
3204 printf("<tr class=\"foldersubdir\"><td align=\"left\">%s>>> <a href=\"", folders_img);
3205 output_scriptptrget();
3206 printf("&form=folders&folder=INBOX&folderdir="
3207 "%s\">%s</a>"
3208 "</td><td> </td></tr>\n\n",
3209 sp,
3210 getarg("PUBLICFOLDERS"));
3211 free(sp);
3212 }
3213 printf("</table>\n");
3214 }
3215
folder_list2()3216 void folder_list2()
3217 {
3218 if (folder_err_msg)
3219 {
3220 printf("%s\n", folder_err_msg);
3221 }
3222 }
3223
3224 static void folder_rename_dest_fake(const char *dummy1,
3225 struct maildir_shindex_cache *dummy2);
3226 static void folder_rename_dest_real(const char *inbox_pfix,
3227 const char *homedir,
3228 const char *cur_folder,
3229 const char *inbox_name);
3230
folder_rename_list()3231 void folder_rename_list()
3232 {
3233 parse_hierarchy(cgi("folderdir"), folder_rename_dest_real,
3234 folder_rename_dest_fake);
3235 }
3236
folder_rename_dest_fake(const char * dummy1,struct maildir_shindex_cache * dummy2)3237 static void folder_rename_dest_fake(const char *dummy1,
3238 struct maildir_shindex_cache *dummy2)
3239 {
3240 }
3241
folder_rename_dest_real(const char * inbox_pfix,const char * homedir,const char * cur_folder,const char * inbox_name)3242 static void folder_rename_dest_real(const char *inbox_pfix,
3243 const char *homedir,
3244 const char *cur_folder,
3245 const char *inbox_name)
3246 {
3247 char **folders;
3248 int i;
3249 size_t pl=strlen(inbox_pfix);
3250
3251 printf("<select name=\"renametofolder\">\n");
3252 printf("<option value=\"%s.\">", inbox_pfix);
3253 printf("( ... )");
3254 printf("</option>\n");
3255
3256 maildir_listfolders(inbox_pfix, homedir, &folders);
3257 for (i=0; folders[i]; i++)
3258 {
3259 const char *p=folders[i];
3260 char *q;
3261 size_t ql;
3262 char acl_buf[2];
3263
3264 if (strncmp(p, inbox_pfix, pl) == 0)
3265 switch (p[pl]) {
3266 case '.':
3267 break;
3268 default:
3269 continue;
3270 }
3271 else
3272 continue;
3273
3274 p += pl+1;
3275
3276 p=strrchr(p, '.');
3277 if (!p) continue;
3278 q=malloc(p-folders[i]+1);
3279 if (!q) enomem();
3280 memcpy(q, folders[i], p-folders[i]);
3281 q[p-folders[i]]=0;
3282 strcpy(acl_buf, ACL_CREATE);
3283 acl_computeRightsOnFolder(q, acl_buf);
3284 if (acl_buf[0])
3285 {
3286 printf("<option value=\"");
3287 output_attrencoded(q);
3288 printf(".\"%s>",
3289 strcmp(q, cgi("folderdir")) == 0
3290 ? " selected='selected'":"");
3291 list_folder(strchr(q, '.')+1);
3292 printf(".</option>\n");
3293 }
3294 ql=strlen(q);
3295 while (folders[++i])
3296 {
3297 if (memcmp(folders[i], q, ql) ||
3298 folders[i][ql] != '.' ||
3299 strchr(folders[i]+ql+1, '.')) break;
3300 }
3301 --i;
3302 free(q);
3303 }
3304 maildir_freefolders(&folders);
3305 printf("</select>\n");
3306 }
3307
folder_download(const char * folder,size_t pos,const char * mimeid)3308 void folder_download(const char *folder, size_t pos, const char *mimeid)
3309 {
3310 char *filename;
3311 FILE *fp=NULL;
3312 int fd;
3313
3314 filename=get_msgfilename(folder, &pos);
3315
3316 fd=maildir_semisafeopen(filename, O_RDONLY, 0);
3317 if (fd >= 0)
3318 {
3319 if ((fp=fdopen(fd, "r")) == 0)
3320 close(fd);
3321 }
3322
3323 if (!fp)
3324 {
3325 free(filename);
3326 error("Message not found.");
3327 return;
3328 }
3329 free(filename);
3330
3331 cginocache();
3332 msg2html_download(fp, mimeid, *cgi("download") == '1');
3333
3334 fclose(fp);
3335 }
3336
folder_showtransfer()3337 void folder_showtransfer()
3338 {
3339 const char *deletelab, *purgelab, *movelab, *golab;
3340
3341 deletelab=getarg("DELETE");
3342 purgelab=getarg("PURGE");
3343 movelab=getarg("ORMOVETO");
3344 golab=getarg("GO");
3345 folder_inbox=getarg("INBOX");
3346 folder_drafts=getarg("DRAFTS");
3347 folder_trash=getarg("TRASH");
3348 folder_sent=getarg("SENT");
3349
3350 printf("<input type=\"hidden\" name=\"pos\" value=\"%s\" />", cgi("pos"));
3351 if ((strcmp(sqwebmail_folder, INBOX "." TRASH) == 0) && (strlen(getarg("PURGEALL"))))
3352 printf("<input type=\"submit\" name=\"cmdpurgeall\" value=\"%s\" onclick=\"javascript: return deleteAll();\" />",
3353 getarg("PURGEALL"));
3354 printf("<input type=\"submit\" name=\"cmddel\" value=\"%s\" />%s<select name=\"moveto\">",
3355 strcmp(sqwebmail_folder, INBOX "." TRASH) == 0
3356 ? purgelab:deletelab,
3357 movelab);
3358
3359 show_transfer_dest(sqwebmail_folder);
3360 printf("</select><input type=\"submit\" name=\"cmdmove\" value=\"%s\" />\n",
3361 golab);
3362 }
3363
folder_showquota()3364 void folder_showquota()
3365 {
3366 const char *quotamsg;
3367 struct maildirsize quotainfo;
3368
3369 quotamsg=getarg("QUOTAUSAGE");
3370
3371 if (maildir_openquotafile("ainfo, "."))
3372 return;
3373
3374 if (quotainfo.quota.nmessages != 0 ||
3375 quotainfo.quota.nbytes != 0)
3376 printf(quotamsg, maildir_readquota("ainfo));
3377
3378 maildir_closequotafile("ainfo);
3379 }
3380
3381 void
folder_cleanup()3382 folder_cleanup()
3383 {
3384 msg_purgelab=0;
3385 msg_folderlab=0;
3386 folder_drafts=0;
3387 folder_inbox=0;
3388 folder_sent=0;
3389 folder_trash=0;
3390 msg_forwardattlab=0;
3391 msg_forwardlab=0;
3392 msg_fullheaderlab=0;
3393 msg_golab=0;
3394 msg_movetolab=0;
3395 msg_nextlab=0;
3396 msg_prevlab=0;
3397 msg_deletelab=0;
3398 msg_posfile=0;
3399 msg_replyalllab=0;
3400 msg_replylistlab=0;
3401 msg_replylab=0;
3402 folder_err_msg=0;
3403 msg_msglab=0;
3404 msg_add=0;
3405
3406 msg_type=0;
3407 initnextprevcnt=0;
3408 msg_hasprev=0;
3409 msg_hasnext=0;
3410 msg_pos=0;
3411 msg_count=0;
3412 }
3413
3414
3415 /*
3416 ** Unicode-aware truncation of text at a specified column, if text length
3417 ** exceeds the given # of characters.
3418 */
3419
truncate_at(const char * str,const struct unicode_info * uiptr,size_t ncols)3420 static char *truncate_at(const char *str,
3421 const struct unicode_info *uiptr,
3422 size_t ncols)
3423 {
3424 unicode_char *uc;
3425 size_t n;
3426 size_t cols, tp=0;
3427 char *retbuf;
3428
3429 if (!str)
3430 return NULL;
3431
3432 uc= (*unicode_UTF8.c2u)(&unicode_UTF8, str, NULL);
3433
3434 if (!uc)
3435 return NULL;
3436
3437 for (cols=0, n=0; uc[n]; n++) {
3438
3439 cols += unicode_wcwidth(uc[n]);
3440
3441 if (!tp && cols > ncols-3)
3442 tp = n;
3443 }
3444
3445 if (cols > ncols)
3446 {
3447 uc = realloc(uc, sizeof(unicode_char) * (tp+4));
3448 if (uc == 0) enomem();
3449 uc[tp]='.';
3450 uc[tp+1]='.';
3451 uc[tp+2]='.';
3452 uc[tp+3]=0;
3453 }
3454
3455 retbuf=(*uiptr->u2c)(uiptr, uc, NULL);
3456
3457 free(uc);
3458 return retbuf;
3459 }
3460