diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /sqwebmail/folder.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'sqwebmail/folder.c')
| -rw-r--r-- | sqwebmail/folder.c | 3769 | 
1 files changed, 3769 insertions, 0 deletions
| diff --git a/sqwebmail/folder.c b/sqwebmail/folder.c new file mode 100644 index 0000000..896e711 --- /dev/null +++ b/sqwebmail/folder.c @@ -0,0 +1,3769 @@ +/* +** Copyright 1998 - 2011 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +/* +*/ +#include	"config.h" +#include	<stdio.h> +#include	<string.h> +#include	<ctype.h> +#include	<fcntl.h> +#include	<stdlib.h> +#include	"sqwebmail.h" +#include	"maildir/maildirmisc.h" +#include	"maildir/maildircreate.h" +#include	"maildir/maildirnewshared.h" +#include	"maildir/maildirinfo.h" +#include	"maildir/maildiraclt.h" + +#include	"rfc822/rfc822.h" +#include	"rfc822/rfc2047.h" +#include	"rfc2045/rfc2045.h" +#include	"md5/md5.h" +#include	"gpglib/gpglib.h" +#include	"maildir.h" +#include	"mailfilter.h" +#include	"maildir/maildirquota.h" +#include	"maildir/maildirgetquota.h" +#include	"maildir/maildirinfo.h" +#include	"numlib/numlib.h" +#include	"courierauth.h" +#include	"folder.h" +#include	"addressbook.h" +#include	"cgi/cgi.h" +#include	"pref.h" +#include	"token.h" +#include	"filter.h" +#include	"buf.h" +#include	"pref.h" +#include	"newmsg.h" +#include	"htmllibdir.h" +#include	"gpg.h" +#include	"acl.h" +#include	"auth.h" + +#include	"msg2html.h" + +#if	HAVE_LOCALE_H +#if	HAVE_SETLOCALE +#include	<locale.h> +#endif +#endif + +#if	TIME_WITH_SYS_TIME +#include	<sys/time.h> +#include	<time.h> +#else +#if	HAVE_SYS_TIME_H +#include	<sys/time.h> +#else +#include	<time.h> +#endif +#endif +#if	HAVE_SYS_STAT_H +#include	<sys/stat.h> +#endif +#include	<errno.h> + +#include	"unicode/unicode.h" + +#include	<unistd.h> +#if HAVE_WCHAR_H +#include	<wchar.h> +#endif + +#include	"strftime.h" + +extern FILE *open_langform(const char *lang, const char *formname, +			   int print_header); + +extern const char *sqwebmail_content_language; +extern char sqwebmail_folder_rights[]; +extern const char *sqwebmail_mailboxid; +extern char *get_imageurl(); +extern const char *sqwebmail_content_locale; +extern void print_attrencodedlen(const char *, size_t, int, FILE *); + +extern const char *showsize(unsigned long); +extern void maildir_cleanup(); +extern const char *nonloginscriptptr(); +extern int pref_flagpagesize; +extern int ishttps(); +extern const char *sqwebmail_content_charset; +extern int verify_shared_index_file; + +extern time_t rfc822_parsedt(const char *); +static time_t	current_time; + +static const char *folder_err_msg=0; + +extern const char *sqwebmail_folder; + +extern void output_scriptptrget(); +extern void output_scriptptr(); +extern void output_scriptptrpostinfo(); +extern void output_attrencoded(const char *); +extern void output_urlencoded(const char *); +extern char *scriptptrget(); + +void print_safe_len(const char *p, size_t n, void (*func)(const char *, size_t)) +{ +char	buf[10]; +const	char *q=p; + +	while (n) +	{ +		--n; +		if (*p == '<')	strcpy(buf, "<"); +		else if (*p == '>') strcpy(buf, ">"); +		else if (*p == '&') strcpy(buf, "&"); +		else if (*p == ' ') strcpy(buf, " "); +		else if (*p == '\n') strcpy(buf, "<br />"); +		else if (ISCTRL(*p)) +			sprintf(buf, "&#%d;", (int)(unsigned char)*p); +		else +		{ +			p++; +			continue; +		} + +		(*func)(q, p-q); +		(*func)(buf, strlen(buf)); +		p++; +		q=p; +	} +	(*func)(q, p-q); +} + +static void print_safe_to_stdout(const char *p, size_t cnt) +{ +	if (cnt == 0) +		return; + +	if (fwrite(p, cnt, 1, stdout) != 1) +		exit(1); +} + +void print_safe(const char *p) +{ +	print_safe_len(p, strlen(p), print_safe_to_stdout); +} + +void call_print_safe_to_stdout(const char *p, size_t cnt) +{ +	print_safe_len(p, cnt, print_safe_to_stdout); +} +	 +void folder_contents_title() +{ +const char *lab; +const char *f; +const char *inbox_lab, *drafts_lab, *trash_lab, *sent_lab; +int in_utf8; + +	lab=getarg("FOLDERTITLE"); + +	if (*cgi("search")) +		lab=getarg("SEARCHRESULTSTITLE"); + +	inbox_lab=getarg("INBOX"); +	drafts_lab=getarg("DRAFTS"); +	trash_lab=getarg("TRASH"); +	sent_lab=getarg("SENT"); + +	f=sqwebmail_folder; +	in_utf8=1; + +	if (strcmp(f, INBOX) == 0)	f=inbox_lab; +	else if (strcmp(f, INBOX "." DRAFTS) == 0)	f=drafts_lab; +	else if (strcmp(f, INBOX "." SENT) == 0)	f=sent_lab; +	else if (strcmp(f, INBOX "." TRASH) == 0)	f=trash_lab; +	else in_utf8=0; + +	if (lab) +	{ +		char *ff, *origff; + +		printf("%s", lab); + +		origff=ff=in_utf8 ? +			libmail_u_convert_fromutf8(f, +						   sqwebmail_content_charset, +						   NULL) +			: folder_fromutf7(f); + +		if (strcmp(ff, NEWSHAREDSP) == 0 || +		    strncmp(ff, NEWSHAREDSP ".", sizeof(NEWSHAREDSP)) == 0) +		{ +			printf("%s", getarg("PUBLICFOLDERS")); +			ff=strchr(ff, '.'); +			if (!ff) +				ff=""; +		} +		output_attrencoded(ff); +		free(origff); +	} +} + +static int group_movedel(const char *folder, +			int (*func)(const char *, const char *, size_t)) +{ +struct cgi_arglist *arg; + +	if (*cgi("SELECTALL"))	/* Everything is selected */ +	{ +		for (arg=cgi_arglist; arg; arg=arg->next) +		{ +		const	char *f; + +			if (strncmp(arg->argname, "MOVEFILE-", 9)) continue; +			f=cgi(arg->argname); +			CHECKFILENAME(f); +			if ((*func)(folder, f, atol(arg->argname+9))) +				return (-1); +		} +		return (0); +	} + +	for (arg=cgi_arglist; arg; arg=arg->next) +	{ +	unsigned long l; +	char	movedel[MAXLONGSIZE+10]; +	const	char *f; + +		if (strncmp(arg->argname, "MOVE-", 5))	continue; +		l=atol(arg->argname+5); +		sprintf(movedel, "MOVEFILE-%lu", l); +		f=cgi(movedel); +		CHECKFILENAME(f); +		if ((*func)(folder, f, l)) +			return (-1); +	} +	return (0); +} + +static int groupdel(const char *folder, const char *file, size_t pos) +{ +	maildir_msgdeletefile(folder, file, pos); +	return (0); +} + +static int groupmove(const char *folder, const char *file, size_t pos) +{ +	return (maildir_msgmovefile(folder, file, cgi("moveto"), pos)); +} + +static const char *do_folder_delmsgs(const char *dir, size_t pos) +{ +	int	rc=0; +	char	buf[2]; +	char	*cur; + +	strcpy(buf, ACL_DELETEMSGS); +	acl_computeRightsOnFolder(dir, buf); + +#if 0 +	{ +		FILE *fp=fopen("/tmp/pid", "w"); + +		if (fp) +		{ +			fprintf(fp, "%d", (int)getpid()); +			fclose(fp); +			sleep(10); +		} +	} +#endif + +	if (buf[0] == 0) +		return "nodel"; + +	if (*cgi("cmddel")) +	{ +		rc=group_movedel( dir, &groupdel ); +		maildir_savefoldermsgs(dir); +	}  +	else if (*cgi("cmdpurgeall"))  +	{ +	    char *deldir; +	    struct maildir_info minfo; + +	    if (maildir_info_imap_find(&minfo, dir, login_returnaddr())<0)  +		    return "othererror"; + +	    if ((deldir=maildir_name2dir(minfo.homedir, minfo.maildir)) == NULL) +	    { +		maildir_info_destroy(&minfo); +		return "othererror"; +	    } +	     +	    cur = malloc(strlen(deldir)+5); +	    strcpy(cur, deldir); +	    strcat(cur, "/cur"); + +	    rc=maildir_del_content(cur); +	    maildir_quota_recalculate("."); + +	    maildir_info_destroy(&minfo); +	    free(deldir); +	    free(cur); +	     +	} +	else if (*cgi("cmdmove")) +	{ +		const char *p=cgi("moveto"); + +		CHECKFILENAME(p); +		strcpy(buf, ACL_INSERT); +		acl_computeRightsOnFolder(p, buf); +		if (buf[0] == 0) +			return "noinsert"; + +		rc=group_movedel( dir, &groupmove ); +		maildir_savefoldermsgs(dir); +	} + +	maildir_cleanup(); + +	return rc ? "quota":""; +} + +void folder_delmsgs(const char *dir, size_t pos) +{ +	const char *status=do_folder_delmsgs(dir, pos); +	 +	if (*cgi("search")) +		http_redirect_argsss("&error=%s&form=folder&pos=%s&search=1&" +				     SEARCHRESFILENAME "=%s", status, +				     cgi("pos"), cgi(SEARCHRESFILENAME)); +	else +		http_redirect_argss("&error=%s&form=folder&pos=%s", status, +				    cgi("pos")); +} + +static void savepath(const char *path, const char *maildir) +{ +	char buf[BUFSIZ]; +	FILE *ofp; +	FILE *fp; +	struct maildir_tmpcreate_info createInfo; + +	maildir_tmpcreate_init(&createInfo); + +	createInfo.maildir="."; +	createInfo.uniq="sharedpath"; +	createInfo.doordie=1; + +	ofp=maildir_tmpcreate_fp(&createInfo); + +	fp=fopen(SHAREDPATHCACHE, "r"); + +	if (fp) +	{ +		int cnt=0; + +		while (cnt < 1) +		{ +			char *p; + +			if (fgets(buf, sizeof(buf), fp) == NULL) +				break; + +			if ((p=strchr(buf, '\n')) != NULL) *p=0; + +			if (strcmp(buf, maildir) == 0) +			{ +				if (fgets(buf, sizeof(buf), fp) == NULL) +					break; +				continue; +			} + +			fprintf(ofp, "%s\n", buf); + +			if (fgets(buf, sizeof(buf), fp) == NULL) +				strcpy(buf, ""); +			if ((p=strchr(buf, '\n')) != NULL) *p=0; +			fprintf(ofp, "%s\n", buf); + +			++cnt; +		} +		fclose(fp); +	} + +	fprintf(ofp, "%s\n%s\n", maildir, path); +	fclose(ofp); +	rename(createInfo.tmpname, SHAREDPATHCACHE); +	maildir_tmpcreate_free(&createInfo); +} + +void folder_search(const char *dir, size_t pos) +{ +	maildir_reload(dir); +	maildir_search(dir, +		       pos, +		       cgi("searchtxt"), +		       sqwebmail_content_charset, +		       pref_flagpagesize); + +	http_redirect_argss("&search=1&form=folder&pos=%s&" +			    SEARCHRESFILENAME "=%s", cgi("pos"), +			    cgi(SEARCHRESFILENAME)); +} + +static void folder_msg_link(const char *, int, size_t, char); +static void folder_msg_unlink(const char *, int, size_t, char); + +static char *truncate_at(const char *, const char *, size_t); + +static void show_msg(const char *dir, +		     MSGINFO *msg, +		     MATCHEDSTR *matches, +		     int row, +		     const char *charset); + +void folder_contents(const char *dir, size_t pos) +{ +MSGINFO	**contents; +MATCHEDSTR **matches; +int	i, found; +int	morebefore, moreafter; +const char	*nomsg, *selectalllab; + const char	*unselectalllab; +const char	*qerrmsg; +long highend; +unsigned long last_message_searched=0; +unsigned long *last_message_searched_ptr=NULL; + +	qerrmsg=getarg("PERMERR"); + +	if (strcmp(cgi("error"), "quota") == 0) +		printf("%s", qerrmsg); + +	if (strcmp(cgi("error"), "nodel") == 0) +		printf("%s", getarg("NODELPERM")); + +	if (strcmp(cgi("error"), "noinsert") == 0) +		printf("%s", getarg("NOINSERTPERM")); + +	if (strcmp(cgi("error"), "othererror") == 0) +		printf("%s", getarg("OTHERERROR")); + +	if (strchr(sqwebmail_folder_rights, ACL_READ[0]) == NULL) +	{ +		printf("%s", getarg("ACL")); +		return; +	} + +	maildir_reload(dir); + +	if (*cgi("search")) +	{ +#if 0 +	{ +		FILE *fp=fopen("/tmp/pid", "w"); + +		if (fp) +		{ +			fprintf(fp, "%d", (int)getpid()); +			fclose(fp); +			sleep(10); +		} +	} +#endif + +		morebefore=0; +		moreafter=0; +		maildir_loadsearch(pref_flagpagesize, &contents, &matches, +				   &last_message_searched); + +		for (i=0; i<pref_flagpagesize; i++) +		{ +			if (contents[i] == 0)	continue; + +			last_message_searched_ptr= &last_message_searched; +			break; +		} +	} +	else +	{ +		contents=maildir_read(dir, pref_flagpagesize, &pos, +				      &morebefore, &moreafter); +		matches=NULL; +	} + +	time(¤t_time); +	nomsg=getarg("NOMESSAGES"); +	selectalllab=getarg("SELECTALL"); +	unselectalllab=getarg("UNSELECTALL"); + +	if (maildir_countof(dir) <= pos + pref_flagpagesize - 1) +		highend = (long)(maildir_countof(dir) - 1); +	else +		highend = (long)(pos + pref_flagpagesize - 1); +	if (highend < 0) highend = 0; + +	if (!qerrmsg)	qerrmsg=""; + +	folder_navigate(dir, pos, highend, morebefore, moreafter, +			last_message_searched_ptr); + +	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", +		getarg("NUM"), +		getarg("DATE"), +		(strncmp(dir, INBOX "." SENT, sizeof(INBOX)+sizeof(SENT)-1) && +		 strncmp(dir, INBOX "." DRAFTS, sizeof(INBOX)+sizeof(DRAFTS)-1)) +			? getarg("FROM") : getarg("TO"), +		getarg("SUBJECT"), +		getarg("SIZE")); + +	found=0; +	for (i=0; i<pref_flagpagesize; i++) +	{ +		if (contents[i] == 0)	continue; +		found=1; + +		show_msg(dir, contents[i], matches ? matches[i]:NULL, i, +			 sqwebmail_content_charset); +	} + +	if (found) +	{ +		puts("<tr class=\"folder-index-bg-1\"><td colspan=\"6\"><hr /></td></tr>"); +		puts("<tr class=\"folder-index-bg-2\"><td> </td>"); +		puts("<td colspan=\"5\">"); + +		puts("<script type=\"text/javascript\">"); +		puts("/* <![CDATA[ */"); +		puts("function setAll(input, chk) {"); +		printf("for (i = %ld; i <= %ld; i++) {\n", +			(long)pos, highend); +		puts("if (document.getElementById) e = document.getElementById('MOVE-' + i);"); +		puts("else if (document.all) e = document['MOVE-' + i];"); +		puts("if (e != null) { e.checked = chk; e.onchange(); }} }"); +		puts("/* ]]> */"); +		puts("</script>\n"); + +		puts("<script type=\"text/javascript\">"); +		puts("/* <![CDATA[ */"); +		printf("document.write('<button type=\"button\" onclick=\"setAll(this, true); return false;\">%s<\\/button>\\n ');\n", +			selectalllab); +		printf("document.write('<button type=\"button\" onclick=\"setAll(this, false); return false;\">%s<\\/button>\\n');\n", +			unselectalllab); +		puts("/* ]]> */"); +		puts("</script>\n"); + +		printf("<noscript><label><input type=\"checkbox\" name=\"SELECTALL\" /> %s</label></noscript>\n", +			selectalllab); +		puts("</td></tr>"); + +		printf("</table>\n"); +		folder_navigate(dir, pos, highend, morebefore, moreafter, +				last_message_searched_ptr); +	} +	if (!found && nomsg) +	{ +		puts("<tr class=\"folder-index-bg-1\"><td colspan=\"6\" align=\"left\"><p>"); +		puts(nomsg); +		puts("<br /></p></td></tr>"); +		printf("</table>\n"); +	} + +	maildir_free(contents, pref_flagpagesize); +	if (matches) +		matches_free(matches, pref_flagpagesize); +} + + +static int folder_searchlink() +{ +	if (*cgi("search") == 0) +		return 0; + +	printf("&search=1&" SEARCHRESFILENAME "="); +	output_urlencoded(cgi(SEARCHRESFILENAME)); +	return 1; +} + +static void show_msg_match_str(const char *prefix, +			       const char *utf8match, +			       const char *suffix, +			       const char *classname); + +static void show_msg(const char *dir, +		     MSGINFO *msg, +		     MATCHEDSTR *matches, +		     int row, +		     const char *charset) +{ +	const char *date, *from, *subj, *size; +	char	*froms, *subjs; +	const char *p, *q; +	size_t l; +	char type[8]; +	char *folder_index_entry_start, *folder_index_entry_end; + +	size_t msgnum=msg->msgnum; + +	date=MSGINFO_DATE(msg); +	from=MSGINFO_FROM(msg); +	subj=MSGINFO_SUBJECT(msg); +	size=MSGINFO_SIZE(msg); + +	type[0]=maildirfile_type(MSGINFO_FILENAME(msg)); +	type[1]='\0'; +	if (type[0] == '\0')	strcpy(type, " "); + +	folder_index_entry_start="<span class=\"read-message\">"; +	folder_index_entry_end="</span>"; + +	if (type[0] == MSGTYPE_NEW) +	{ +		folder_index_entry_start="<strong class=\"unread-message\">"; +		folder_index_entry_end="</strong>"; +	} + +	p=MSGINFO_FILENAME(msg); + +	if ((q=strrchr(p, '/')) != 0) +		p=q+1; + +	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", +	       (row & 1)+1, +	       row, +	       folder_index_entry_start, +	       (long)(msgnum+1), +	       folder_index_entry_end, +	       (long) (msgnum), +	       (long) (msgnum)); +	printf("\" onchange=\"setsel('MOVE-%ld', 'row%d', 'folder-index-bg-%d');\"%s /><input type=\"hidden\" name=\"MOVEFILE-%ld\" value=\"", +	       (long)(msgnum), row, (row & 1)+1, +	       (type[0] == MSGTYPE_DELETED ? " disabled=\"disabled\"":""), +	       (long)(msgnum)); +	output_attrencoded(p); +	printf("\" /> %s%s%s</td><td class=\"message-date\">%s", +	       folder_index_entry_start, +	       type, +	       folder_index_entry_end, + +	       folder_index_entry_start +	       ); +	if (!*date)	date=" "; +	folder_msg_link(dir, row, msgnum, type[0]); +	print_safe(date); +	folder_msg_unlink(dir, row, msgnum, type[0]); +	printf("%s</td><td class=\"message-from\">%s", folder_index_entry_end, +	       folder_index_entry_start); +	if (!*from)	from=" "; +	folder_msg_link(dir, row, msgnum, type[0]); + + +	froms=truncate_at(from, charset, 30); + +	if (froms == 0)	enomem(); + +	print_safe(froms); +	free(froms); +	folder_msg_unlink(dir, row, msgnum, type[0]); +	printf("%s<br /></td><td class=\"message-subject\">%s", folder_index_entry_end, +	       folder_index_entry_start); + +	folder_msg_link(dir, row, msgnum, type[0]); + +#if 0 +	{ +		static int foo=0; if (foo++ == 0) +	{ +		FILE *fp=fopen("/tmp/pid", "w"); + +		if (fp) +		{ +			fprintf(fp, "%d", (int)getpid()); +			fclose(fp); +			sleep(10); +		} +	} +	} +#endif + +	subjs=truncate_at(subj, charset, 40); + +	if (subjs == 0)	enomem(); + +	print_safe(subjs); +	l=strlen(subjs); +	while (l++ < 8) +		printf(" "); +	free(subjs); + +	folder_msg_unlink(dir, row, msgnum, type[0]); +	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); + +	while (matches && matches->match) +	{ +		printf("<tr class=\"folder-index-bg-%d\"><td align=\"right\" class=\"message-number\" colspan=\"3\"> </td><td class=\"message-searchmatch\" colspan=\"3\">", (row & 1)+1); +		show_msg_match_str("...", +				   matches->prefix, "", "searchmatch-affix"); +		show_msg_match_str("", matches->match, "", "searchmatch"); +		show_msg_match_str("", matches->suffix, +				   "...", "searchmatch-affix"); +		printf("</td></tr>\n"); +		++matches; +	} +} + +static void show_msg_match_str(const char *prefix, +			       const char *utf8match, +			       const char *suffix, +			       const char *classname) +{ +	char *p; + +	p=libmail_u_convert_fromutf8(utf8match, sqwebmail_content_charset, +				     NULL); + +	if (p) +	{ +		printf("<span class=\"%s\">%s", classname, prefix); +		output_attrencoded(p); +		free(p); +		printf("%s</span>", suffix); +	} +} + +static void do_folder_navigate(const char *dir, size_t pos, long highend, +			       int morebefore, int moreafter) +{ +	const char	*firstlab, *lastlab; +	const char	*beforelab, *afterlab; +	const char	*showncountlab, *jumplab, *golab; + +	time(¤t_time); +	showncountlab=getarg("SHOWNCOUNT"); +	jumplab=getarg("JUMPTO"); +	golab=getarg("GO"); +	firstlab=getarg("FIRSTPAGE"); +	beforelab=getarg("PREVPAGE"); +	afterlab=getarg("NEXTPAGE"); +	lastlab=getarg("LASTPAGE"); + +	printf("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-nextprev-buttons\"><tr><td>"); + +	if (morebefore) +	{ +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&form=folder&pos=0\" style=\"text-decoration: none\">"); +	} +	printf("%s", firstlab); +	if (morebefore) +		printf("</a>"); + +	puts(" "); + +	if (morebefore) +	{ +	size_t	beforepos; + +		if (pos < pref_flagpagesize)	beforepos=0; +		else	beforepos=pos-pref_flagpagesize; + +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&form=folder&pos=%ld\" style=\"text-decoration: none\">", +			(long)beforepos); +	} +	printf("%s", beforelab); +	if (morebefore) +		printf("</a>"); + +	printf("</td></tr></table>\n"); + +	if (maildir_countof(dir) > 0) { +		puts("</td><td align=\"center\">\n"); +		puts("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-message-count\"><tr><td>\n"); +		printf(showncountlab, (long)(pos+1), (long)(highend+1), (long)maildir_countof(dir)); +		puts("</td></tr></table>"); + +		puts("<script type=\"text/javascript\">"); +		puts("/* <![CDATA[ */"); +		puts("document.write('<\\/td><td align=\"center\">' +"); + +		puts("'<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-jumpto-field\"><tr><td>' +"); +		printf("'%s <input type=\"text\" name=\"jumpto\" size=\"3\" value=\"%ld\" onchange=\"this.form.pos.value = this.value - 1;\" />' +\n", +			jumplab, (long)(pos+1)); +		printf("'<button type=\"button\" onclick=\"this.form.submit();\">%s<\\/button>' +\n", +			golab); +		puts("'<\\/td><\\/tr><\\/table>');"); +		puts("/* ]]> */"); +		puts("</script>"); +	} + +	printf("</td><td align=\"right\">\n"); + +	printf("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"folder-nextprev-buttons\"><tr><td>"); +	if (moreafter) +	{ +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&form=folder&pos=%ld\" style=\"text-decoration: none\">", +			(long)(pos+pref_flagpagesize)); +	} +	printf("%s", afterlab); +	if (moreafter) +		printf("</a>"); + +	puts(" "); + +	if (moreafter) +	{ +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&form=folder&pos=%ld\" style=\"text-decoration: none\">", +			(long)(maildir_countof(dir)-pref_flagpagesize)); +	} +	printf("%s", lastlab); +	if (moreafter) +		printf("</a>"); + +	printf("</td></tr></table>\n"); +} + +void folder_navigate(const char *dir, size_t pos, long highend, +		     int morebefore, int moreafter, +		     unsigned long *last_message_searched_ptr) +{ +	printf("<table width=\"100%%\" class=\"folder-nextprev-background\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>"); + +	if (*cgi("search")) +	{ +		printf("<td class=\"folder-return-link\">"); +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&form=folder&pos=%ld\">%s</a>", +		       (long)pos, getarg("RETURNTOFOLDER")); +		printf("</td>"); + +		printf("<td class=\"folder-last-message-searched\">"); +		if (last_message_searched_ptr) +		{ +			printf(getarg("LASTMESSAGESEARCHED"), +			       *last_message_searched_ptr+1); +		} +		else +		{ +			printf(" "); +		} +		printf("</td>"); +	} +	else +	{ +		printf("<td align=\"left\">"); +		do_folder_navigate(dir, pos, highend, morebefore, moreafter); +		printf("</td>"); +	} + +	printf("</tr></table>"); +} + +static void folder_msg_link(const char *dir, int row, size_t pos, char t) +{ +#if 0 +	if (t == MSGTYPE_DELETED) +	{ +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&form=folder&pos=%s\">", cgi("pos")); +		return; +	} +#endif + +	printf("<a href=\""); +	if (strcmp(dir, INBOX "." DRAFTS)) +	{ +		output_scriptptrget(); +		if (folder_searchlink()) +			printf("&searchrow=%d", row); + +		printf("&form=readmsg&pos=%ld\">", (long)pos); +	} +	else +	{ +	size_t	mpos=pos; +	char	*filename=maildir_posfind(dir, &mpos); +	char	*basename=filename ? maildir_basename(filename):NULL; + +		output_scriptptrget(); +		printf("&form=open-draft&draft="); +		output_urlencoded(basename); +		printf("\">"); +		if (basename)	free(basename); +		if (filename)	free(filename); +	} +} + +static void folder_msg_unlink(const char *dir, int row, size_t pos, char t) +{ +	printf("</a>"); +} + +size_t	msg_pos, msg_count; +static char	*msg_posfile; +static int	msg_hasprev, msg_hasnext; +static size_t	msg_searchpos; +static long	msg_prevpos, msg_prev_searchpos; +static long	msg_nextpos, msg_next_searchpos; + +static const char	*msg_nextlab=0, *msg_prevlab=0, *msg_deletelab=0, +		*msg_purgelab=0, *msg_folderlab=0; +static char	msg_type; + +static const char	*msg_replylab=0; +static const char	*msg_replyalllab=0; +static const char	*msg_replylistlab=0; +static const char	*msg_forwardlab=0; +static const char	*msg_forwardattlab=0; +static const char	*msg_fullheaderlab=0; +static const char	*msg_movetolab=0; +static const char	*msg_print=0; + +static const char	*folder_inbox=0; +static const char	*folder_drafts=0; +static const char	*folder_trash=0; +static const char	*folder_sent=0; +static const char	*msg_golab=0; + +static const char *msg_msglab; +static const char *msg_add=0; + +static int	initnextprevcnt; + +void folder_initnextprev(const char *dir, size_t pos) +{ +	MSGINFO	**info; +	const	char *p; +	const	char *msg_numlab, *msg_numnewlab; +	static char *filename=0; +	int fd; + +	MSGINFO *recp; +	MSGINFO **search_contents=NULL; +	MATCHEDSTR **search_matches=NULL; +	unsigned long last_message_searched=0; + +	cgi_put(MIMEGPGFILENAME, ""); + +	if (filename) +		free(filename); +	filename=0; + + +	if (*cgi("mimegpg") && (filename=maildir_posfind(dir, &pos)) != 0) +	{ +		char *tptr; +		int nfd; + +		fd=maildir_semisafeopen(filename, O_RDONLY, 0); + +		if (fd >= 0) +		{ +			struct maildir_tmpcreate_info createInfo; + +			maildir_purgemimegpg(); + +			maildir_tmpcreate_init(&createInfo); + +			createInfo.uniq=":mimegpg:"; +			createInfo.doordie=1; + +			if ((nfd=maildir_tmpcreate_fd(&createInfo)) < 0) +			{ +				free(filename); +				error("Can't create new file."); +			} + +			tptr=createInfo.tmpname; +			createInfo.tmpname=NULL; +			maildir_tmpcreate_free(&createInfo); + +			chmod(tptr, 0600); + +			/* +			** Decrypt/check message into a temporary file +			** that's immediately marked as deleted, so that it +			** gets purged at the next sweep. +			*/ + +			if (gpgdecode(fd, nfd) < 0) +			{ +				close(nfd); +				unlink(tptr); +				free(tptr); +			} +			else +			{ +				close(fd); +				free(filename); +				filename=tptr; +				fd=nfd; + +				cgi_put(MIMEGPGFILENAME, +					strrchr(filename, '/')+1); +			} +			close(fd); +		} +	} + +	initnextprevcnt=0; +	msg_nextlab=getarg("NEXTLAB"); +	msg_prevlab=getarg("PREVLAB"); +	msg_deletelab=getarg("DELETELAB"); +	msg_purgelab=getarg("PURGELAB"); + +	msg_folderlab=getarg("FOLDERLAB"); + +	msg_replylab=getarg("REPLY"); +	msg_replyalllab=getarg("REPLYALL"); +	msg_replylistlab=getarg("REPLYLIST"); + +	msg_forwardlab=getarg("FORWARD"); +	msg_forwardattlab=getarg("FORWARDATT"); + +	msg_numlab=getarg("MSGNUM"); +	msg_numnewlab=getarg("MSGNEWNUM"); + +	msg_fullheaderlab=getarg("FULLHDRS"); + +	msg_movetolab=getarg("MOVETO"); +	msg_print=getarg("PRINT"); + +	folder_inbox=getarg("INBOX"); +	folder_drafts=getarg("DRAFTS"); +	folder_trash=getarg("TRASH"); +	folder_sent=getarg("SENT"); + +	p=getarg("CREATEFAIL"); +	if (strcmp(cgi("error"),"quota") == 0) +		printf("%s", p); + +	msg_golab=getarg("GOLAB"); +	msg_add=getarg("QUICKADD"); + +	msg_searchpos=atol(cgi("searchrow")); + +	info=maildir_read(dir, 1, &pos, &msg_hasprev, &msg_hasnext); + +	recp=info[0]; +	msg_pos=pos; +	msg_prevpos=msg_pos-1; +	msg_nextpos=msg_pos+1; +	msg_prev_searchpos=msg_prevpos; +	msg_next_searchpos=msg_nextpos; + +	if (*cgi("search")) +		maildir_loadsearch(pref_flagpagesize, +				   &search_contents, +				   &search_matches, +				   &last_message_searched); + + +	if (search_contents) +	{ +		if (msg_searchpos < pref_flagpagesize && +		    search_contents[msg_searchpos]) +		{ +			recp=search_contents[msg_searchpos]; + +			msg_pos=recp->msgnum; +			if ((msg_hasprev=msg_searchpos > 0 && +			     search_contents[msg_searchpos-1]) != 0) +			{ +				msg_prevpos=search_contents +					[msg_searchpos-1]->msgnum; +				msg_prev_searchpos=msg_searchpos-1; +			} + +			if ((msg_hasnext=msg_searchpos + 1 < +			     pref_flagpagesize && +			     search_contents[msg_searchpos+1]) != 0) +			{ +				msg_nextpos=search_contents +					[msg_searchpos+1]->msgnum; +				msg_next_searchpos=msg_searchpos+1; +			} + +		} +	} + +	p=strrchr(MSGINFO_FILENAME(recp), '/'); +	if (p)	p++; +	else	p=MSGINFO_FILENAME(recp); +	msg_posfile=strdup(p); +	if (!msg_posfile)	enomem(); + +	if ((msg_type=maildirfile_type(MSGINFO_FILENAME(recp))) +		== MSGTYPE_NEW) msg_numlab=msg_numnewlab; + +	msg_msglab=msg_numlab; +	msg_count=maildir_countof(dir); +	maildir_free(info, 1); +	if (search_contents) +		maildir_free(search_contents, pref_flagpagesize); +	if (search_matches) +		matches_free(search_matches, pref_flagpagesize); +} + +char *get_msgfilename(const char *folder, size_t *pos) +{ +	char *filename; + +	if (*cgi(MIMEGPGFILENAME)) +	{ +		const char *p=cgi(MIMEGPGFILENAME); + +		CHECKFILENAME(p); + +		filename=malloc(sizeof("tmp/")+strlen(p)); +		if (!filename) +			enomem(); +		strcat(strcpy(filename, "tmp/"), p); +	} +	else +		filename=maildir_posfind(folder, pos); + +	if (!filename)	error("Message not found."); + +	return (filename); +} + +void output_mimegpgfilename() +{ +	if (*cgi(MIMEGPGFILENAME)) +	{ +		printf("&" MIMEGPGFILENAME "="); +		output_urlencoded(cgi(MIMEGPGFILENAME)); +	} +} + +void folder_nextprev() +{ +	printf("<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"message-menu-background\"><tr valign=\"middle\">"); + +	printf("<td align=\"left\"><table border=\"0\" cellspacing=\"4\" cellpadding=\"4\"><tr valign=\"top\">"); + +	/* PREV */ + +	printf("<td class=\"message-menu-button\">"); + +	if (msg_hasprev) +	{ +		printf("<a href=\""); +		output_scriptptrget(); + +		if (folder_searchlink()) +			printf("&searchrow=%ld", msg_prev_searchpos); + +		printf("&form=readmsg&pos=%ld\">", +		       msg_prevpos); +	} + +	printf("%s", msg_prevlab ? msg_prevlab:""); + +	if (msg_hasprev) +	{ +		printf("</a>"); +	} +	printf("</td>"); + +	/* NEXT */ + +	printf("<td class=\"message-menu-button\">"); + +	if (msg_hasnext) +	{ +		printf("<a href=\""); +		output_scriptptrget(); + +		if (folder_searchlink()) +			printf("&searchrow=%ld", msg_next_searchpos); + +		printf("&form=readmsg&pos=%ld\">", +		       msg_nextpos); +	} + +	printf("%s", msg_nextlab ? msg_nextlab:""); + +	if (msg_hasnext) +	{ +		printf("</a>"); +	} +	printf("</td>"); + +	/* DEL */ + +	printf("<td class=\"message-menu-button\">"); +	if (msg_type != MSGTYPE_DELETED) +	{ +		printf("<a href=\""); +		output_scriptptrget(); +		tokennewget(); +		folder_searchlink(); +		printf("&posfile="); +		output_urlencoded(msg_posfile); +		printf("&form=delmsg&pos=%ld\">", +			(long)msg_pos); +	} +	printf("%s", strcmp(sqwebmail_folder, INBOX "." TRASH) == 0 +		? msg_purgelab : msg_deletelab); + +	if (msg_type != MSGTYPE_DELETED) +		printf("</a>"); + +	printf("</td>\n"); + +	/* FOLDER */ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	folder_searchlink(); +	printf("&pos=%ld&form=folder\">%s</a></td>\n", +		(long)( (msg_pos/pref_flagpagesize)*pref_flagpagesize ), +		msg_folderlab); + +	/* REPLY */ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); +	printf("&pos=%ld&reply=1&form=newmsg\">%s</a></td>\n", +		(long)msg_pos, +		msg_replylab); + +	/* REPLY ALL */ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); +	printf("&pos=%ld&replyall=1&form=newmsg\">%s</a></td>\n", +		(long)msg_pos, +		msg_replyalllab); + +	/* REPLY LIST */ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); +	printf("&pos=%ld&replylist=1&form=newmsg\">%s</a></td>\n", +		(long)msg_pos, +		msg_replylistlab); + +	if (auth_getoptionenvint("wbnoimages")) +		printf("<td width=\"100%%\"></td></tr></table><table border=\"0\" cellspacing=\"4\" cellpadding=\"4\"><tr>"); + +	/* FORWARD */ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); +	printf("&pos=%ld&forward=1&form=newmsg\">%s</a></td>\n", +		(long)msg_pos, +		msg_forwardlab); + +	/* FORWARD AS ATTACHMENT*/ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); +	printf("&pos=%ld&forwardatt=1&form=newmsg\">%s</a></td>\n", +		(long)msg_pos, +		msg_forwardattlab); + +	/* FULL HEADERS */ + +	if (!pref_flagfullheaders && !*cgi("fullheaders")) +	{ +		printf("<td class=\"message-menu-button\"><a href=\""); +		output_scriptptrget(); +		folder_searchlink(); +		output_mimegpgfilename(); +		printf("&pos=%ld&form=readmsg&fullheaders=1\">%s</a></td>\n", +			(long)msg_pos, msg_fullheaderlab); +	} + +	/* PRINT MESSAGE */ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); + +	printf("&pos=%ld&form=print&setcookie=1%s\" target=\"_blank\">%s</a></td>\n", +		(long)msg_pos, +		((pref_flagfullheaders || *cgi("fullheaders")) ? "&fullheaders=1" : ""), +		msg_print); + +	/* SAVE MESSAGE */ + +	printf("<td class=\"message-menu-button\"><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); + +	printf("&pos=%ld&form=fetch&download=1\">%s</a></td>", (long)msg_pos, +	       getarg("SAVEMESSAGE")); + +    printf("<td width=\"100%%\"></td></tr></table></td><td align=\"right\" valign=\"middle\">"); + +	printf("<table border=\"0\" cellspacing=\"4\"><tr><td class=\"message-x-of-y\"> "); +	printf(msg_msglab, (int)msg_pos+1, (int)msg_count); +	printf(" </td></tr></table>"); +    printf("</td></tr></table>\n"); +} + +void list_folder(const char *p) +{ +	char *s=folder_fromutf7(p); +	print_safe(s); +	free(s); +} + +void 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) +{ +	if (strcmp(p, INBOX) == 0) +		printf("%s", n_inbox); +	else if (strcmp(p, INBOX "." DRAFTS) == 0) +		printf("%s", n_drafts); +	else if (strcmp(p, INBOX "." TRASH) == 0) +		printf("%s", n_trash); +	else if (strcmp(p, INBOX "." SENT) == 0) +		printf("%s", n_sent); +	else +		list_folder(path); +} + +static void parse_hierarchy(const char *hierarchy, +			    void (*maildir_hier_cb) +			    (const char *pfix, const char *homedir, +			     const char *path, const char *inbox_name), +			    void (*sharehier_cb) +			    (const char *sharedhier, +			     struct maildir_shindex_cache *cache)); + +static void show_transfer_dest_real(const char *, const char *, +				    const char *, const char *); +static void show_transfer_dest_fake(const char *, +				    struct maildir_shindex_cache *); +			     +static void show_transfer_dest(const char *cur_folder) +{ +	parse_hierarchy(cur_folder, show_transfer_dest_real, +			show_transfer_dest_fake); +} + +static void show_transfer_dest_fake(const char *dummy1, +				    struct maildir_shindex_cache *dummy2) +{ +} + +static void show_transfer_dest_real1(const char *inbox_pfix, +				     const char *homedir, +				     const char *cur_folder, +				     const char *inbox_name); + +static void show_transfer_dest_real(const char *inbox_pfix, +				    const char *homedir, +				    const char *cur_folder, +				    const char *inbox_name) +{ +	FILE *fp; +	char buf1[BUFSIZ]; +	char buf2[BUFSIZ]; + +	show_transfer_dest_real1(inbox_pfix, homedir, cur_folder, inbox_name); + +	if ((fp=fopen(SHAREDPATHCACHE, "r")) != NULL) +	{ +		while (fgets(buf1, sizeof(buf1), fp) && +		       fgets(buf2, sizeof(buf2), fp)) +		{ +			char *p; + +			p=strchr(buf1, '\n'); +			if (p) *p=0; +			p=strchr(buf2, '\n'); +			if (p) *p=0; + +			if (homedir == NULL || strcmp(buf1, homedir)) +			{ +				show_transfer_dest_real1(buf2, buf1, +							 cur_folder, +							 inbox_name); +			} +		} +		fclose(fp); +	} +} + +static void show_transfer_dest_real1(const char *inbox_pfix, +				     const char *homedir, +				     const char *cur_folder, +				     const char *inbox_name) +{ +	char	**folders; +	size_t	i; +	const	char *p; +	int	has_shared=0; + +	maildir_listfolders(inbox_pfix, homedir, &folders); +	for (i=0; folders[i]; i++) +	{ +		char acl_buf[2]; + +		strcpy(acl_buf, ACL_INSERT); +		acl_computeRightsOnFolder(folders[i], acl_buf); + +		if (acl_buf[0] == 0) +			continue; + +		/* Transferring TO drafts is prohibited */ + +		if (cur_folder == NULL || strcmp(cur_folder, +						 INBOX "." DRAFTS)) +		{ +			if (strcmp(folders[i], INBOX "." DRAFTS) == 0) +				continue; +		} +		else +		{ +			if (strncmp(folders[i], SHARED ".", +				    sizeof(SHARED)) && +			    strcmp(folders[i], INBOX "." TRASH)) +				continue; +		} + +		if (cur_folder && strcmp(cur_folder, folders[i]) == 0) +			continue; + +		p=folders[i]; + +		if (strcmp(p, INBOX) == 0) +			p=folder_inbox; +		else if (strcmp(p, INBOX "." DRAFTS) == 0) +			p=folder_drafts; +		else if (strcmp(p, INBOX "." TRASH) == 0) +			p=folder_trash; +		else if (strcmp(p, INBOX "." SENT) == 0) +			p=folder_sent; +		if (!p)	p=folders[i]; + +		if (strncmp(folders[i], SHARED ".", sizeof(SHARED)) == 0) +		{ +		char	*d=maildir_shareddir(".", strchr(folders[i], '.')+1); +		struct	stat	stat_buf; + +			if (!d) +			{ +				maildir_freefolders(&folders); +				enomem(); +			} +			if (stat(d, &stat_buf))	/* Not subscribed */ +			{ +				free(d); +				continue; +			} +			free(d); + +			if (!has_shared) +			{ +				printf("<option value=\"\"></option>\n"); +				has_shared=1; +			} +		} + +		printf("<option value=\""); +		output_attrencoded(folders[i]); +		printf("\">"); + +		if (strncmp(folders[i], NEWSHARED, sizeof(NEWSHARED)-1) == 0) +		{ +			printf("%s.", getarg("PUBLICFOLDERS")); +		} + +		p=strchr(folders[i], '.'); + +		list_folder(p ? p+1:folders[i]); +		printf("</option>\n"); +	} +	maildir_freefolders(&folders); +} + +void folder_msgmove() +{ +	++initnextprevcnt; +	printf("<table border=\"0\" class=\"box-small-outer\"><tr><td>\n"); +	printf("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td class=\"folder-move-background\"> %s <select name=\"list%d\">\n", msg_movetolab, initnextprevcnt); + +	show_transfer_dest(sqwebmail_folder); + +	printf("</select><input type=\"submit\"%s name=\"move%d\" value=\"%s\" /></td></tr></table>\n", +		(msg_type == MSGTYPE_DELETED ? " disabled":""), +		initnextprevcnt, +		msg_golab ? msg_golab:""); +	printf("<input type=\"hidden\" name=\"pos\" value=\"%s\" />", cgi("pos")); +	printf("<input type=\"hidden\" name=\"posfile\" value=\""); +	output_attrencoded(msg_posfile ? msg_posfile:""); +	printf("\" /></td></tr></table>\n"); +} + +void folder_delmsg(size_t pos) +{ +MSGINFO	**info; +int	dummy; +const	char *f=cgi("posfile"); +size_t	newpos; +int	rc=0; +char nbuf[MAXLONGSIZE+10]; + +	CHECKFILENAME(f); + +	if (*cgi("move1")) +	{ +		rc=maildir_msgmovefile(sqwebmail_folder, f, cgi("list1"), pos); +		maildir_savefoldermsgs(sqwebmail_folder); +	} +	else if (*cgi("move2")) +	{ +		rc=maildir_msgmovefile(sqwebmail_folder, f, cgi("list2"), pos); +		maildir_savefoldermsgs(sqwebmail_folder); +	} +	else +	{ +		maildir_msgdeletefile(sqwebmail_folder, f, pos); +		maildir_savefoldermsgs(sqwebmail_folder); +	} + +	if (rc) +	{ +		http_redirect_argu("&form=readmsg&pos=%s&error=quota", +			(unsigned long)pos); +		return; +	} + +	newpos=pos+1; +	info=maildir_read(sqwebmail_folder, 1, &newpos, &dummy, &dummy); + +	if (info[0] && newpos != pos) +	{ +		sprintf(nbuf, "%lu", (unsigned long)newpos); +	} +	else +	{ +		sprintf(nbuf, "%lu", (unsigned long)pos); +	} + +	maildir_free(info, 1); + +	if (*cgi("search")) +	{ +		http_redirect_argss("&form=readmsg&pos=%s&search=1&" +				    SEARCHRESFILENAME "=%s", nbuf, +				    cgi(SEARCHRESFILENAME)); +	} +	else +	{ +		http_redirect_argss("&form=readmsg&pos=%s", nbuf, ""); +	} +} + +static int is_preview_mode() +{ +	/* We're in new message window, and we're previewing a draft */ + +	return (*cgi("showdraft")); +} + +static void dokeyimport(FILE *, struct rfc2045 *, int); + +static void charset_warning(const char *mime_charset, void *arg) +{ +	char charset_buf[32]; +	char *p; + +	charset_buf[0]=0; +	strncat(charset_buf, mime_charset, sizeof(charset_buf)-1); + +	for (p=charset_buf; *p; p++) +		if (*p < ' ' || *p > 0x7f || +		    *p == '<' || *p == '>' || *p == '&') +			*p=' '; + +	printf(getarg("CHSET"), charset_buf, sqwebmail_content_charset); +} + +static void html_warning() +{ +	printf("%s", getarg("HTML")); +} + +static void init_smileys(struct msg2html_info *info) +{ +	FILE *fp=open_langform(sqwebmail_content_language, "smileys.txt", 0); +	char buf[1024]; + +	char imgbuf[1024]; + +	if (!fp) +		return; + +	while (fgets(buf, sizeof(buf), fp) != NULL) +	{ +		char *p=strchr(buf, '#'); +		char *code; +		char *img; +		char *attr; + +		if (p) *p=0; + +		code=buf; + +		for (p=buf; *p && !isspace(*p); p++) +			; + +		if (*p) +			*p++=0; + +		while (*p && isspace(*p)) +			p++; +		img=p; + +		while (*p && !isspace(*p)) +			p++; +		if (*p) +			*p++=0; + +		while (*p && isspace(*p)) +			p++; +		attr=p; +		p=strchr(p, '\n'); +		if (p) *p=0; + +		if (!*code || !*img) +			continue; + +		snprintf(imgbuf, sizeof(imgbuf), +			 "<img src=\"%s/%s\" %s />", +			 get_imageurl(), img, attr); + +		msg2html_add_smiley(info, code, imgbuf); +	} +	fclose(fp); +} + +static void email_address_start(const char *name, const char *addr) +{ +	if (is_preview_mode()) +	    return; + +	printf("<a href=\""); +	output_scriptptrget(); +	printf("&form=quickadd&pos=%s&newname=", +	       cgi("pos")); + +	if (name) +		output_urlencoded(name); + +	printf("&newaddr="); +	if (addr) +		output_urlencoded(addr); + +	printf("\" style=\"text-decoration: none\" " +	       "onmouseover=\"window.status='%s'; return true;\" " +	       "onmouseout=\"window.status=''; return true;\" >" +	       "<span class=\"message-rfc822-header-address\">", +	       msg_add ? msg_add:""); +} + +static void email_address_end() +{ +	if (is_preview_mode()) +		return; + +	printf("</a></span>"); +} + +static void email_header(const char *h, +			 void (*cb_func)(const char *)) +{ +	char *hdrname; +	char *p; +	const char *hdrvalue; + +	if ((hdrname=malloc(sizeof("DSPHDR_")+strlen(h))) == NULL) +		enomem(); + +	strcpy (hdrname, "DSPHDR_"); +	strcat (hdrname, h); + +	for (p=hdrname; *p; p++) +		*p=toupper((int)(unsigned char)*p); + +	hdrvalue = getarg (hdrname); + +	(*cb_func)(hdrvalue && *hdrvalue ? hdrvalue:h); + +	free(hdrname); +} + +static const char *email_header_date_fmt(const char *def) +{ +	const char *date_fmt = getarg ("DSPFMT_DATE"); + +	if (date_fmt && *date_fmt) +		def=date_fmt; +	return def; +} + +static void buf_cat_esc_amp(struct buf *b, const char *url) +{ +	for (; *url; ++url) +	{ +		char	c[2]; + +		if (*url == '&') +		{ +			buf_cat(b, "&"); +		} +		else if (*url == '<') +		{ +			buf_cat(b, "<"); +		} +		else if (*url == '>') +		{ +			buf_cat(b, ">"); +		} +		else if (*url == '"') +		{ +			buf_cat(b, """); +		} +		else +		{ +			c[0]=*url; +			c[1]=0; +			buf_cat(b, c); +		} +	} +} + +extern const char *redirect_hash(const char *timestamp); + +static char *get_textlink(const char *s, void *arg) +{ +char	*t; +struct buf b; + +	buf_init(&b); + +	if (strncmp(s, "mailto:", 7) == 0) +	{ +	int	i; + +		buf_cat(&b, "<a href=\""); + +		{ +			char *p=scriptptrget(); + +			buf_cat(&b, p); +			free(p); +		} + +		buf_cat(&b, "&form=newmsg&to="); + +		for (i=7; s[i]; i++) +		{ +		char	c[2]; + +			c[1]=0; +			if ((c[0]=s[i]) == '?') +				c[0]='&'; + 			else if (c[0] == '&') +			{ +				buf_cat(&b, "&"); +			} +			else if (c[0] == '<') +			{ +				buf_cat(&b, "<"); +			} +			else if (c[0] == '>') +			{ +				buf_cat(&b, ">"); +			} +			else if (c[0] == '"') +			{ +				buf_cat(&b, """); +			} +			else +			{ +				buf_cat(&b, c); +			} +		} +		buf_cat(&b, "\">" +			"<span class=\"message-text-plain-mailto-link\">"); +		buf_cat_esc_amp(&b, s); +		buf_cat(&b, "</span></a>"); +	} +	else if (strncmp(s, "http:", 5) == 0 || strncmp(s, "https:", 6) == 0) +	{ +		char buffer[NUMBUFSIZE]; +		time_t now; +		char *hash; +		const char *n; + +		time(&now); +		libmail_str_time_t(now, buffer); + +		hash=cgiurlencode(redirect_hash(buffer)); + +		t=cgiurlencode(s); +		buf_cat(&b, "<a href=\""); + +		n=getenv("SCRIPT_NAME"); +		if (!n || !*n) n="/"; + +		buf_cat(&b, n); +		buf_cat(&b, "?redirect="); +		buf_cat(&b, t); +		buf_cat(&b, "&timestamp="); +		buf_cat(&b, buffer); +		buf_cat(&b, "&md5="); +		if (hash) +		{ +			buf_cat(&b, hash); +			free(hash); +		} +		buf_cat(&b, "\" target=\"_blank\">" +			"<span class=\"message-text-plain-http-link\">"); +		buf_cat_esc_amp(&b, s); +		buf_cat(&b, "</span></a>"); +		free(t); +	} +	t=strdup(b.ptr ? b.ptr:""); +	if (!t)	enomem(); +	buf_free(&b); +	return (t); +} + +static void message_rfc822_action(struct rfc2045id *idptr) +{ +	if (is_preview_mode()) +		return; + +	printf("<tr valign=\"top\"><td> </td><td align=\"left\" valign=\"top\">"); + +	printf("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td><a href=\""); +	output_scriptptrget(); +	output_mimegpgfilename(); +	msg2html_showmimeid(idptr, NULL); +	printf("&pos=%ld&reply=1&form=newmsg\"><font size=\"-1\">%s</font></a> </td><td> <a href=\"", +		(long)msg_pos, msg_replylab); + +	output_scriptptrget(); +	output_mimegpgfilename(); +	msg2html_showmimeid(idptr, NULL); +	printf("&pos=%ld&replyall=1&form=newmsg\"><font size=\"-1\">%s</font></a> </td><td> <a href=\"", +		(long)msg_pos, msg_replyalllab); +	output_scriptptrget(); +	output_mimegpgfilename(); +	msg2html_showmimeid(idptr, NULL); +	printf("&pos=%ld&forward=1&form=newmsg\"><font size=\"-1\">%s</font></a> </td><td> <a href=\"", +		(long)msg_pos, msg_forwardlab); + +	output_scriptptrget(); +	output_mimegpgfilename(); +	msg2html_showmimeid(idptr, NULL); +	printf("&pos=%ld&forwardatt=1&form=newmsg\"><font size=\"-1\">%s</font></a></td></tr></table>\n", +		(long)msg_pos, msg_forwardattlab); + +	printf("</td></tr>\n"); +} + +static void output_mimeurl(struct rfc2045id *id, const char *form) +{ +	output_scriptptrget(); +	printf("&form=%s&pos=%ld", form, (long)msg_pos); +	msg2html_showmimeid(id, NULL); + +	output_mimegpgfilename(); +} + +static void inline_image_action(struct rfc2045id *id, const char *content_type, +				void *arg) +{ +	if (!is_preview_mode()) +	{ +		printf("<a href=\""); +		output_mimeurl(id, "fetch"); +		printf("\" target=\"_blank\">"); +	} +	printf("<img src=\""); +	output_mimeurl(id, "fetch"); +	printf("\" alt=\"Inline picture: "); +	output_attrencoded(content_type); +	printf("\" />%s\n", +	       is_preview_mode() ? "":"</a>"); +} + + +static void showattname(const char *fmt, const char *name, +	const char *content_type) +{ +char	*t; + +	if (!name || !*name)	name=content_type; +	if (!name)	name=""; + +	t=malloc(strlen(name)+strlen(fmt)+100); +	if (!t) +		return; + +	sprintf(t, fmt, name); +	output_attrencoded(t); +	free(t); +} + +static void unknown_attachment_action(struct rfc2045id *id, +				      const char *content_type, +				      const char *content_name, +				      off_t size, +				      void *arg) +{ +	printf("<table border=\"0\" cellpadding=\"1\" cellspacing=\"0\" class=\"box-small-outer\"><tr><td>"); +	printf("<table border=\"0\" cellpadding=\"4\" cellspacing=\"0\" class=\"message-download-attachment\"><tr><td>"); + +	if (strcmp(cgi("form"), "print") == 0) +	{ +		showattname(getarg("ATTSTUB"), content_name, content_type); + +		printf(" ("); +		output_attrencoded(content_type); +		printf(")"); +	} +	else +	{ +		printf("<div align=\"center\"><span class=\"message-attachment-header\">"); +		showattname(getarg("ATTACHMENT"), content_name, content_type); + +		printf(" ("); +		output_attrencoded(content_type); +		printf("; %s)</span></div>", +		       showsize(size)); +		printf("<br /><div align=\"center\">"); + +		if (!is_preview_mode()) +		{ +			printf("<a href=\""); +			output_mimeurl(id, "fetch"); +			printf("\" style=\"text-decoration: none\" target=\"_blank\">"); +			printf("%s</a> / ", getarg("DISPATT")); +			printf("<a href=\""); +			output_mimeurl(id, "fetch"); +			printf("&download=1\" style=\"text-decoration: none\">"); +			printf("%s</a>", getarg("DOWNATT")); +		} + +		printf("</div>\n"); +	} + +	printf("</td></tr></table>\n"); +	printf("</td></tr></table>\n"); +} + +static int is_gpg_enabled() +{ +	return *cgi(MIMEGPGFILENAME) && !is_preview_mode(); +} + +static void application_pgp_keys_action(struct rfc2045id *id) +{ +	printf("<table border=\"0\" cellpadding=\"8\" cellspacing=\"1\" class=\"box-small-outer\"><tr><td>"); +	printf("<table border=\"0\" cellpadding=\"4\" cellspacing=\"4\" class=\"message-application-pgpkeys\"><tr><td>"); + +	if (strcmp(cgi("form"), "print") == 0 || is_preview_mode()) +	{ +		printf("%s", getarg("KEY")); +	} +	else +	{ +		printf("<div align=\"center\"><a href=\""); +		output_scriptptrget(); +		printf("&form=keyimport&pos=%ld", (long)msg_pos); +		printf("&pubkeyimport=1"); +		output_mimegpgfilename(); +		msg2html_showmimeid(id, "&keymimeid="); +		printf("\" style=\"text-decoration: none\" class=\"message-application-pgpkeys\">"); +		printf("%s", getarg("PUBKEY")); +		printf("</a></div>"); + +		printf("<hr width=\"100%%\" />\n"); + +		printf("<div align=\"center\"><a href=\""); +		output_scriptptrget(); +		printf("&form=keyimport&pos=%ld", (long)msg_pos); +		printf("&privkeyimport=1"); +		output_mimegpgfilename(); +		msg2html_showmimeid(id, "&keymimeid="); +		printf("\" style=\"text-decoration: none\" class=\"message-application-pgpkeys\">"); +		printf("%s", getarg("PRIVKEY")); +		printf("</a></div>"); +	} + +	printf("</td></tr></table>\n"); +	printf("</td></tr></table>\n<br />\n"); +} + +static void gpg_message_action() +{ +	printf("<form method=\"post\" action=\""); +	output_scriptptr(); +	printf("\">"); +	output_scriptptrpostinfo(); +	printf("<input type=\"hidden\" name=\"form\" value=\"readmsg\" />"); +	printf("<input type=\"hidden\" name=\"pos\" value=\"%s\" />", +	       cgi("pos")); +	printf("<input type=\"hidden\" name=\"mimegpg\" value=\"1\" />\n"); + +	printf("<table border=\"0\" cellpadding=\"1\"" +	       " width=\"100%%\" class=\"box-outer\">" +	       "<tr><td><table width=\"100%%\" border=\"0\" cellspacing=\"0\"" +	       " cellpadding=\"0\" class=\"box-white-outer\"><tr><td>"); + +	if ( *cgi(MIMEGPGFILENAME)) +	{ +		printf("%s", getarg("NOTCOMPACTGPG")); +	} +	else +	{ +		printf("%s\n", getarg("MIMEGPGNOTICE")); + +		if (ishttps()) +			printf("%s\n", getarg("PASSPHRASE")); + +		printf("%s", getarg("DECRYPT")); +	} +	printf("</td><tr></table></td></tr></table></form><br />\n"); +} + +const char *redirect_hash(const char *timestamp) +{ +	struct stat stat_buf; + +	char buffer[NUMBUFSIZE*2+10]; +	const char *p=getenv("SQWEBMAIL_RANDSEED"); + +	if (strlen(timestamp) >= NUMBUFSIZE) +		return ""; + +	strcat(strcpy(buffer, timestamp), " "); + +	if (p && *p) +		strncat(buffer, p, NUMBUFSIZE); +	else +	{ +		if (stat(SENDITSH, &stat_buf) < 0) +			return ""; + +		libmail_str_ino_t(stat_buf.st_ino, buffer+strlen(buffer)); +	} + +	return md5_hash_courier(buffer); +} + +static char *get_url_to_mime_part(const char *mimeid, void *arg) +{ +	const char *mimegpgfilename=cgi(MIMEGPGFILENAME); +	const char *pos; +	char *p, *q; + +	p=scriptptrget(); +	pos=cgi("pos"); + +	q=malloc(strlen(p)+strlen(pos) + +		 strlen(mimegpgfilename)+ +		 strlen(mimeid)+ +		 sizeof("&mimeid=&pos=&form=fetch&mimegpgfilename=")); +	if (!q)	enomem(); +	strcpy(q, p); +	strcat(q, "&form=fetch&pos="); +	strcat(q, pos); +	strcat(q, "&mimeid="); +	strcat(q, mimeid); + +	if (*mimegpgfilename) +		strcat(strcat(q, "&mimegpgfilename="), mimegpgfilename); + +	return (q); +} + +void folder_showmsg(const char *dir, size_t pos) +{ +	char	*filename; +	FILE	*fp; +	struct	rfc2045 *rfc; +	char	buf[BUFSIZ]; +	int	n; +	int	fd; + +	struct msg2html_info *info; + +	const char *script_name=nonloginscriptptr(); + + +	if (*cgi("addnick")) +	{ +		const char *name=cgi("newname"); +		const char *addr=cgi("newaddr"); + +		const char *nick1=cgi("newnick1"); +		const char *nick2=cgi("newnick2"); + +		while (*nick1 && isspace((int)(unsigned char)*nick1)) +		       ++nick1; + +		while (*nick2 && isspace((int)(unsigned char)*nick2)) +		       ++nick2; + +		if (*nick2) +			nick1=nick2; + +		if (*nick1) +		{ +			ab_add(name, addr, nick1); +		} +	} + +	filename=get_msgfilename(dir, &pos); + +	fp=0; +	fd=maildir_semisafeopen(filename, O_RDONLY, 0); +	if (fd >= 0) +	{ +		if ((fp=fdopen(fd, "r")) == 0) +			close(fd); +	} + +	if (!fp) +	{ +		free(filename); +		return; +	} + +	msg_pos=pos; +	rfc=rfc2045_alloc(); + +	while ((n=fread(buf, 1, sizeof(buf), fp)) > 0) +		rfc2045_parse(rfc, buf, n); +	rfc2045_parse_partial(rfc); + +	info=script_name ? msg2html_alloc(sqwebmail_content_charset):NULL; + +	if (info) +	{ +		char nowbuffer[NUMBUFSIZE]; +		time_t now; +		char *hash; +		char *washpfix; +		char *washpfixmailto; +		char *scriptnameget=scriptptrget(); +		static const char formbuf[]="&form=newmsg&to="; + +		info->mimegpgfilename=cgi(MIMEGPGFILENAME); +		if (*info->mimegpgfilename) +			CHECKFILENAME(info->mimegpgfilename); + +		info->gpgdir=GPGDIR; +		info->fullheaders=pref_flagfullheaders || *cgi("fullheaders"); +		info->noflowedtext=pref_noflowedtext; +		info->showhtml=pref_showhtml; + +		info->charset_warning=charset_warning; +		info->html_content_follows=html_warning; +		info->get_url_to_mime_part=get_url_to_mime_part; + +		time(&now); +		libmail_str_time_t(now, nowbuffer); + +		hash=cgiurlencode(redirect_hash(nowbuffer)); + +		washpfix=malloc(strlen(script_name) +				+ strlen(hash ? hash:"") + strlen(nowbuffer) +				+ 100); +		if (!washpfix)	enomem(); + +		strcat(strcat(strcat(strcat(strcat(strcpy(washpfix, +							  script_name), +						   "?timestamp="), +					    nowbuffer), +				     "&md5="), +			      (hash ? hash:"")), +		       "&redirect="); + +		if (hash) +			free(hash); + +		washpfixmailto=malloc(strlen(scriptnameget)+sizeof(formbuf)); +		if (!washpfixmailto)	enomem(); +		strcat(strcpy(washpfixmailto, scriptnameget), formbuf); +		free(scriptnameget); + +		info->wash_http_prefix=washpfix; +		info->wash_mailto_prefix=washpfixmailto; + +		init_smileys(info); + +		info->email_address_start=email_address_start; +		info->email_address_end=email_address_end; +		info->email_header=email_header; +		info->email_header_date_fmt=email_header_date_fmt; +		info->get_textlink=get_textlink; +		info->message_rfc822_action=message_rfc822_action; +		info->inline_image_action=inline_image_action; +		info->unknown_attachment_action=unknown_attachment_action; +		info->application_pgp_keys_action= +			application_pgp_keys_action; +		info->gpg_message_action=gpg_message_action; + +		info->is_gpg_enabled=is_gpg_enabled(); +		info->is_preview_mode=is_preview_mode(); + +		msg2html(fp, rfc, info); +		msg2html_free(info); + +		free(washpfix); +		free(washpfixmailto); +	} + +	rfc2045_free(rfc); +	fclose(fp); +	if (*cgi(MIMEGPGFILENAME) == 0) +		maildir_markread(dir, pos); +	free(filename); +} + +void folder_keyimport(const char *dir, size_t pos) +{ +	char	*filename; +	FILE	*fp; +	struct	rfc2045 *rfc; +	int	fd; + +	filename=get_msgfilename(dir, &pos); + +	fp=0; +	fd=maildir_semisafeopen(filename, O_RDONLY, 0); +	if (fd >= 0) +	{ +		if ((fp=fdopen(fd, "r")) == 0) +			close(fd); +	} + +	if (!fp) +	{ +		free(filename); +		return; +	} + +	rfc=rfc2045_fromfp(fp); + + +	if (libmail_gpg_has_gpg(GPGDIR) == 0) +	{ +		struct rfc2045 *part; + +		if (*cgi("pubkeyimport") +		    && (part=rfc2045_find(rfc, cgi("keymimeid"))) != 0) +		{ +			dokeyimport(fp, part, 0); +		} +		else if (*cgi("privkeyimport") +		    && (part=rfc2045_find(rfc, cgi("keymimeid"))) != 0) +		{ +			dokeyimport(fp, part, 1); +		} +	} +	rfc2045_free(rfc); +	fclose(fp); +	free(filename); + +	printf("<p><a href=\""); +	output_scriptptrget(); +	printf("&form=readmsg&pos=%s", cgi("pos")); +	printf("\">%s</a>", getarg("KEYIMPORT")); +} + +static int importkey_func(const char *p, size_t cnt, void *voidptr); +static int importkeyin_func(const char *p, size_t cnt, void *voidptr); + +static void dokeyimport(FILE *fp, struct rfc2045 *rfcp, int issecret) +{ +	off_t	start_pos, end_pos, start_body, ldummy; +	char buf[BUFSIZ]; +	int cnt; + +	static const char start_str[]= +		"<table width=\"100%%\" border=\"0\" class=\"box-outer\"><tr><td>" +		"<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\"" +		" class=\"box-white-outer\"><tr><td>%s<pre>\n"; + +	static const char end_str[]= +		"</pre></td></tr></table></td></tr></table><br />\n"; + +	if (libmail_gpg_import_start(GPGDIR, issecret)) +		return; + +	printf(start_str, getarg("IMPORTHDR")); + +	rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, +		&ldummy, &ldummy); +	if (fseek(fp, start_body, SEEK_SET) < 0) +	{ +		error("Seek error."); +		libmail_gpg_import_finish(&importkey_func, NULL); +		printf("%s", end_str); +		return; +	} + +	rfc2045_cdecode_start(rfcp, &importkeyin_func, 0); + +	while (start_body < end_pos) +	{ +		cnt=sizeof(buf); +		if (cnt > end_pos-start_body) +			cnt=end_pos-start_body; +		cnt=fread(buf, 1, cnt, fp); +		if (cnt <= 0)	break; +		start_body += cnt; +		if (rfc2045_cdecode(rfcp, buf, cnt)) +		{ +			rfc2045_cdecode_end(rfcp); +			printf("%s", end_str); +			return; +		} +	} + +	if (rfc2045_cdecode_end(rfcp) == 0) +	{ +		libmail_gpg_import_finish(&importkey_func, NULL); +	} + +	printf("%s", end_str); +} + +static int importkeyin_func(const char *p, size_t cnt, void *voidptr) +{ +	return (libmail_gpg_import_do(p, cnt, &importkey_func, NULL)); +} + +static int importkey_func(const char *p, size_t cnt, void *voidptr) +{ +	print_attrencodedlen(p, cnt, 1, stdout); +	return (0); +} + + +/* +** If we're currently showing (INBOX|shared|#shared).foo.bar hierarchy, return +** "x.foo".  If we're currently showing (INBOX|shared|#shared).foo, return +** an empty string. +*/ +static char *get_parent_folder(const char *p) +{ +	const char *q; + +	q=strrchr(p, '.'); + +	if (q) +	{ +		char	*s; + +		s=malloc(q-p+1); +		if (!s)	enomem(); +		memcpy(s, p, q-p); +		s[q-p]=0; +		return (s); +	} +	return (strdup("")); +} + +static int checkrename(const char *origfolder, +		       const char *newfolder) +{ +	char acl_buf[2]; +	char *p, *q; + +	strcpy(acl_buf, ACL_DELETEFOLDER); +	acl_computeRightsOnFolder(origfolder, acl_buf); +	if (acl_buf[0] == 0) +	{ +		folder_err_msg=getarg("RENAME"); +		return -1; +	} + +	strcpy(acl_buf, ACL_CREATE); +	p=strdup(newfolder); + +	if (!p || !(q=strrchr(p, '.')) || +	    (*q=0, +	     acl_computeRightsOnFolder(p, acl_buf), +	     acl_buf[0]) == 0) +	{ +		if (p) +			free(p); + +		folder_err_msg=getarg("RENAME"); +		return -1; +	} +	free(p); + +	return 0; +} + +static void dorename(const char *origfolder, +		     struct maildir_info *mifrom, +		     struct maildir_info *mito, +		     const char *err_invalid, +		     const char *err_cantdelete, +		     const char *err_exists) +{ +	char *s; +	char *t; +	char *u; + +	const char *p; +	struct	stat	stat_buf; + +	if (mifrom->homedir == NULL || +	    mifrom->maildir == NULL || +	    mito->homedir == NULL || +	    mito->maildir == NULL || +	    strcmp(mifrom->homedir, mito->homedir)) +	{ +		folder_err_msg=err_invalid; +		return; +	} + +	s=maildir_name2dir(".", mifrom->maildir); +	t=maildir_name2dir(".", mito->maildir); + +	if (!s || !t) +	{ +		if (s) free(s); +		if (t) free(t); +		folder_err_msg=err_invalid; +		return; +	} + +	p=s; +	if (strncmp(p, "./", 2) == 0) p += 2; + +	if (strcmp(p, ".") == 0 || +	    strcmp(p, "." SENT) == 0 || +	    strcmp(p, "." DRAFTS) == 0 || +	    strcmp(p, "." TRASH) == 0) +	{ +		free(s); +		free(t); +		folder_err_msg=err_invalid; +		return; +	} + +	u=maildir_name2dir(mito->homedir, mito->maildir); +	if (!u) +	{ +		free(s); +		free(t); +		folder_err_msg=err_invalid; +		return; +	} + +	if (stat(u, &stat_buf) == 0) +	{ +		free(s); +		free(t); +		folder_err_msg=err_exists; +		return; +	} +	free(u); + +	if (mailfilter_folderused(origfolder)) +	{ +		free(s); +		free(t); +		folder_err_msg=err_cantdelete; +		return; +	} + +	if (maildir_rename(mifrom->homedir, +			   strncmp(s, "./", 2) == 0 ? s+2:s, +			   strncmp(t, "./", 2) == 0 ? t+2:t, +			   MAILDIR_RENAME_FOLDER, NULL)) +		folder_err_msg=err_cantdelete; + +	free(s); +	free(t); +} + +struct publicfolderlist_helper { +	char *name; +	char *homedir; +	char *maildir; +}; + +static void freeph(struct publicfolderlist_helper *ph) +{ +	if (ph->name) +		free(ph->name); +	if (ph->homedir) +		free(ph->homedir); +	if (ph->maildir) +		free(ph->maildir); +	memset(ph, 0, sizeof(*ph)); +} + +static void do_folderlist(const char *pfix, const char *homedir, +			  const char *path, const char *inbox_name); +static void do_sharedhierlist(const char *sharedhier, +			      struct maildir_shindex_cache *cache); + +static int checkcreate(const char *f, int isrec) +{ +	char *s=strdup(f); +	char *q; +	char buf[2]; +	struct maildir_info minfo; + +	if (!s) +	{ +		folder_err_msg=getarg("CREATEPERMS"); +		return -1; +	} + +	if (isrec) +	{ +		if ((q=strrchr(s, '.')) == NULL || +		    (*q=0, checkcreate(s, 0)) < 0) +		{ +			free(s); +			folder_err_msg=getarg("CREATEPERMS"); +			return -1; +		} +		*q='.'; +	} + +	if (maildir_info_imap_find(&minfo, s, login_returnaddr()) < 0) +	{ +		free(s); +		folder_err_msg=getarg("CREATEPERMS"); +		return -1; +	} + +	if (strchr(minfo.maildir, '.') == NULL) +	{ +		free(s); +		folder_err_msg=getarg("CREATEPERMS"); +		return -1; +	} + +	maildir_acl_delete(minfo.homedir, +			   strchr(minfo.maildir, '.')); + +	maildir_info_destroy(&minfo); + +	strcpy(buf, ACL_CREATE); + +	if ((q=strrchr(s, '.')) == NULL || +	    (*q=0, +	     acl_computeRightsOnFolder(s, buf), +	     buf[0]) == 0) +	{ +		free(s); +		folder_err_msg=getarg("CREATEPERMS"); +		return -1; +	} +	free(s); +	return 0; +} + +void folder_list() +{ +	const char	*err_invalid; +	const char	*err_exists; +	const char	*err_cantdelete; +	const char	*msg_hasbeensent; + +	err_invalid=getarg("INVALID"); +	err_exists=getarg("EXISTS"); +	err_cantdelete=getarg("DELETE"); +	msg_hasbeensent=getarg("WASSENT"); + +	folder_err_msg=0; + +	if (strcmp(cgi("foldermsg"), "sent") == 0) +		folder_err_msg=msg_hasbeensent; + +	if (*cgi("do.create")) +	{ +		const char	*newfoldername=trim_spaces(cgi("foldername")); +		const char	*newdirname=trim_spaces(cgi("dirname")); +		const char	*folderdir=cgi("folderdir"); +		char	*futf7; +		char	*dutf7; + +		/* +		** New folder names cannot contain .s, and must be considered +		** as valid by maildir_folderpath. +		*/ + +		if (!*folderdir) +			folderdir=INBOX; + +		futf7=folder_toutf7(newfoldername); +		dutf7=folder_toutf7(newdirname);; + +		if (!*newfoldername || +		    strchr(futf7, '.') || +		    strchr(dutf7, '.')) +		{ +			free(futf7); +			free(dutf7); +			folder_err_msg=err_invalid; +		} +		else +		{ +			char	*p; +			struct maildir_info minfo; +			char *q; + +			p=malloc(strlen(folderdir)+strlen(futf7) +				 +strlen(dutf7)+3); + +			if (!p)	enomem(); +			strcpy(p, folderdir); +			if (*dutf7) +			{ +				if (*p)	strcat(p, "."); +				strcat(p, dutf7); +			} +			if (*p)	strcat(p, "."); +			strcat(p, futf7); + +			free(futf7); +			free(dutf7); + +			if (maildir_info_imap_find(&minfo, p, +						   login_returnaddr()) < 0) +			{ +				folder_err_msg=err_invalid; +			} +			else if (minfo.homedir == NULL || +				 minfo.maildir == NULL || +				 (q=maildir_name2dir(minfo.homedir, +						     minfo.maildir)) == NULL) +			{ +				maildir_info_destroy(&minfo); +				folder_err_msg=err_invalid; +			} +			else if (access(q, 0) == 0) +			{ +				free(q); +				maildir_info_destroy(&minfo); +				folder_err_msg=err_exists; +			} +			else +			{ +				if (checkcreate(p, *newdirname != 0) == 0) +				{ +					if (maildir_make(q, 0700, 0700, 1)) +						folder_err_msg=err_exists; +					else +					{ +						char buf[1]; + +						buf[0]=0; +						acl_computeRightsOnFolder(p, +									  buf); +						/* Initialize ACLs correctly */ +					} +				} +				free(q); +				maildir_info_destroy(&minfo); +			} +		} +	} + +	if (*cgi("do.delete")) +	{ +		const char *p=cgi("DELETE"); +		char acl_buf[2]; + +		strcpy(acl_buf, ACL_DELETEFOLDER); +		acl_computeRightsOnFolder(p, acl_buf); +		if (acl_buf[0] == 0) +			folder_err_msg=getarg("DELETEPERMS"); +		else if (mailfilter_folderused(p)) +			folder_err_msg=err_cantdelete; +		else if (maildir_delete(p, *cgi("deletecontent"))) +			folder_err_msg=err_cantdelete; +		else +			maildir_quota_recalculate("."); +	} + +	if (*cgi("do.subunsub")) +	{ +		const char *p=cgi("DELETE"); +		char	*pp=strdup(p); +		char *d; + +		if (pp && strncmp(pp, SHARED ".", sizeof(SHARED)) == 0 && +		    (d=maildir_shareddir(".", pp+sizeof(SHARED))) != 0) +		{ +		struct stat	stat_buf; + +			if (stat(d, &stat_buf) == 0) +				maildir_shared_unsubscribe(".", +							   pp+sizeof(SHARED)); +			else +				maildir_shared_subscribe(".", +							 pp+sizeof(SHARED)); +			free(d); +		} + +		if (pp) +			free(pp); +	} + +	if (*cgi("do.rename")) +	{ +		const char *p=cgi("DELETE"); +		char	*pp=strdup(p); +		struct maildir_info mifrom, mito; +		const char *qutf7=cgi("renametofolder"); +		const char *r=trim_spaces(cgi("renametoname")); +		char	*s; +		char	*rutf7; + +		rutf7=folder_toutf7(r); + +		s=malloc(strlen(qutf7)+strlen(rutf7)+1); + +		if (!s)	enomem(); + +		strcat(strcpy(s, qutf7), rutf7); + +		if (strchr(r, '.') == NULL +		    && maildir_info_imap_find(&mifrom, pp, +					      login_returnaddr()) == 0) +		{ +			if (maildir_info_imap_find(&mito, s, +						   login_returnaddr()) == 0) +			{ +				if (checkrename(pp, s) == 0) +					dorename(pp, &mifrom, &mito, +						 err_invalid, +						 err_cantdelete, +						 err_exists); +				maildir_info_destroy(&mifrom); +			} +			else +			{ +				folder_err_msg=err_invalid; +			} +			maildir_info_destroy(&mito); +		} +		else +		{ +			folder_err_msg=err_invalid; +		} +		free(rutf7); +		free(pp); +		free(s); +		maildir_quota_recalculate("."); +	} + +	parse_hierarchy(cgi("folderdir"), +			    do_folderlist, +			    do_sharedhierlist); +} + +static int do_publicfolderlist_cb(struct maildir_newshared_enum_cb *cb) +{ +	struct publicfolderlist_helper *h= +		(struct publicfolderlist_helper *)cb->cb_arg; + +	h->name=strdup(cb->name); +	if (cb->homedir) +		h->homedir=strdup(cb->homedir); +	h->maildir=strdup(cb->maildir); +	return 0; +} + +static void 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)) +{ +	struct maildir_shindex_cache *index; +	const char *indexfile; +	const char *subhierarchy; +	const char *p; +	const char *q; +	size_t l; +	size_t n; +	struct publicfolderlist_helper ph; +	int eof; + +	if (strchr(folderdir, '/')) +		enomem(); +		 +	if (strncmp(folderdir, NEWSHAREDSP, sizeof(NEWSHAREDSP)-1) == 0) +		switch (folderdir[sizeof(NEWSHAREDSP)-1]) { +		case 0: +			verify_shared_index_file=1; +			/* FALLTHRU */ +		case '.': +			break; +		default: +			(*maildir_hier_cb)(INBOX, NULL, folderdir, INBOX); +			return; +		} +	else +	{ +		(*maildir_hier_cb)(INBOX, NULL, folderdir, INBOX); +		return; +	} + +	index=NULL; +	indexfile=NULL; +	subhierarchy=NULL; +	p=folderdir; + +	memset(&ph, 0, sizeof(ph)); + +	while ((index=maildir_shared_cache_read(index, indexfile, +						subhierarchy)) != NULL) +	{ +		q=strchr(p, '.'); +		if (!q) +			break; + +		p=q+1; + +		if ((q=strchr(p, '.')) != NULL) +			l=q-p; +		else +			l=strlen(p); + +		for (n=0; n<index->nrecords; n++) +		{ +			char *m=maildir_info_imapmunge(index->records[n].name); + +			if (!m) +				continue; + +			if (strlen(m) == l && +			    strncmp(m, p, l) == 0) +			{ +				free(m); +				break; +			} +			free(m); +		} + +		if (n >= index->nrecords) +		{ +			index=NULL; +			break; +		} + +		index->indexfile.startingpos=index->records[n].offset; +		freeph(&ph); +		if (maildir_newshared_nextAt(&index->indexfile, &eof, +					     &do_publicfolderlist_cb, &ph) || +		    eof) +		{ +			index=NULL; +			break; +		} + +		if (ph.homedir) +		{ +			char *loc=maildir_location(ph.homedir, +						   ph.maildir); +			char *m_path; +			char *m_inbox; + +			if (loc) +			{ +				while (*p) +				{ +					if (*p == '.') +						break; +					++p; +				} + +				m_path=malloc(p-folderdir+1); +				if (!m_path) +					enomem(); +				memcpy(m_path, folderdir, p-folderdir); +				m_path[p-folderdir]=0; + +				m_inbox=malloc(strlen(m_path)+1+strlen(p)); +				if (!m_inbox) +					enomem(); + +				strcat(strcpy(m_inbox, m_path), p); + +				savepath(m_path, loc); +				(*maildir_hier_cb)(m_path, loc, m_inbox, +						  m_path); +				free(loc); +				free(m_path); +				free(m_inbox); +			} +			freeph(&ph); +			return; +		} + +		indexfile=ph.maildir; +		subhierarchy=index->records[n].name; +	} + +	freeph(&ph); + +	(*sharedhier_cb)(folderdir, index); +} + +static void do_sharedhierlist(const char *folderdir, +			      struct maildir_shindex_cache *index) +{ +	const char *p; +	const char *q; +	size_t n; +	struct publicfolderlist_helper ph; +	const char *folders_img; +	const char *name_inbox; +	int eof; +	char *url, *url2; + +	p=strrchr(folderdir, '.'); + +	if (p) +		++p; +	else p=folderdir; + +	folders_img=getarg("FOLDERSICON"); +	name_inbox=getarg("INBOX"); + +	memset(&ph, 0, sizeof(ph)); + +       	printf("<table width=\"100%%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" class=\"folderlist\">\n" +	       "<tr><td align=\"left\" " +	       "class=\"folderparentdir\">%s<<< ", +	       folders_img); + +	if (strcmp(folderdir, NEWSHAREDSP) == 0) +	{ +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&form=folders&folder=INBOX\">"); +		print_safe(name_inbox); +		printf("</a>"); +	} +	else +	{ +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&folderdir="); +		output_urlencoded(NEWSHAREDSP); +		printf("&form=folders&folder=INBOX\">%s</a>", +		       getarg("PUBLICFOLDERS")); +	} + +	for (q=folderdir; q<p; ) +	{ +		const char *r; +		char *s; + +		if (*q == '.') +		{ +			++q; +			continue; +		} + +		for (r=q; *r; r++) +			if (*r == '.') +				break; + +		if (q != folderdir) +		{ +			printf(".<a href=\""); +			output_scriptptrget(); +			printf("&form=folders&folder=INBOX&folderdir="); + + +			s=malloc(r-folderdir+1); +			if (!s) +				enomem(); + +			memcpy(s, folderdir, r-folderdir); +			s[r-folderdir]=0; + +			output_urlencoded(s); +			printf("\">"); +			free(s); + +			s=malloc(r-q+1); +			if (!s) +				enomem(); +			memcpy(s, q, r-q); +			s[r-q]=0; +			list_folder(s); +			free(s); +			printf("</a>"); +		} +		q=r; +	} + +	printf("</td></tr>\n"); + + +	while (*q && *q != '.') +		++q; + +	url=malloc(q-folderdir+1); +	if (!url) +		enomem(); +	memcpy(url, folderdir, q-folderdir); +	url[q-folderdir]=0; + +	for (n=0; index && n<index->nrecords; n++) +	{ +		freeph(&ph); + +		if (n == 0) +			index->indexfile.startingpos=0; + +		if ((n == 0 ? &maildir_newshared_nextAt: +		     &maildir_newshared_next)(&index->indexfile, &eof, +					      &do_publicfolderlist_cb, &ph) || +		    eof) +		{ +			break; +		} + +		if (ph.homedir) +		{ +			char *d=maildir_location(ph.homedir, ph.maildir); + +			if (d) +			{ +				if (maildir_info_suppress(d)) +				{ +					free(d); +					continue; +				} +				free(d); +			} +		} + +		printf("<tr class=\"foldersubdir\"><td align=\"left\">%s" +		       ">>> <a href=\"", folders_img); +		output_scriptptrget(); +		printf("&form=folders&folder=INBOX&folderdir="); + +		output_urlencoded(url); + +		url2=maildir_info_imapmunge(ph.name); + +		if (!url2) +			enomem(); +		printf("."); +		output_urlencoded(url2); + +		printf("\">"); +		list_folder(url2); +		free(url2); +		printf("</a></td></tr>\n"); +	} +	free(url); +	freeph(&ph); +	printf("</table>\n"); +} + +static void do_folderlist(const char *inbox_pfix, +			  const char *homedir, +			  const char *folderdir, +			  const char *inbox_name) +{ +	const char	*name_inbox; +	const char	*name_drafts; +	const char	*name_sent; +	const char	*name_trash; +	const char	*folder_img; +	const char	*folders_img; +	const char	*unread_label; +	const char	*acl_img; +	char acl_buf[2]; +	char	**folders; +	size_t	i; +	unsigned nnew, nother; +	size_t folderdir_l; + +	name_inbox=getarg("INBOX"); +	name_drafts=getarg("DRAFTS"); +	name_sent=getarg("SENT"); +	name_trash=getarg("TRASH"); +	folder_img=getarg("FOLDERICON"); +	folders_img=getarg("FOLDERSICON"); +	sqwebmail_folder=0; +	unread_label=getarg("UNREAD"); +	acl_img=maildir_newshared_disabled ? NULL : getarg("ACLICON"); + +       	printf("<table width=\"100%%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" class=\"folderlist\">\n"); + +	maildir_listfolders(inbox_pfix, homedir, &folders); + +	if (*folderdir && strcmp(folderdir, INBOX)) +	{ +		char *parentfolder; +		size_t	i; +		char *q, *r; +		const char *c; + +		if (strncmp(folderdir, SHARED ".", sizeof(SHARED)) == 0) +		{ +			for (c=folderdir; *c; c++) +				if (*c == '.') +					break; + +			r=malloc(strlen(inbox_pfix)+strlen(c)+1); +			if (!r) +				enomem(); +			strcat(strcpy(r, inbox_pfix), c); + +			parentfolder=get_parent_folder(r); +			free(r); +		} +		else +			parentfolder=get_parent_folder(folderdir); + +		for (q=parentfolder; *q; q++) +			if (*q == '.') +				break; + +		printf("<tr><td align=\"left\" colspan=\"2\" class=\"folderparentdir\">%s", folders_img); +		printf("<<< "); + +#if 0 +		printf("<a href=\""); +		output_scriptptrget(); +		printf("&folderdir="); +		output_urlencoded(inbox_pfix); +		printf("&form=folders&folder=INBOX\">"); +		print_safe(inbox_name); +		printf("</a>"); +#endif + +		i=0; +		while (parentfolder[i]) +		{ +		char	*p=strchr(parentfolder+i, '.'); +		int	c; + +			if (!p)	p=parentfolder+strlen(parentfolder); +			c= *p; +			*p=0; + +			if (strchr(parentfolder, '.')) +				printf("."); +			printf("<a href=\""); +			output_scriptptrget(); +			printf("&form=folders&folder=INBOX&folderdir="); +			output_urlencoded(parentfolder); +			printf("\">"); +			if (strcmp(parentfolder, NEWSHAREDSP) == 0) +				printf("%s", getarg("PUBLICFOLDERS")); +			else +				list_folder_xlate(parentfolder, +						  parentfolder+i, +						  name_inbox, +						  name_drafts, +						  name_sent, +						  name_trash); +			printf("</a>"); +			if ( (*p=c) != 0)	++p; +			i=p-parentfolder; +		} +		printf("</td></tr>\n"); +		free(parentfolder); +	} +	else if (strcmp(inbox_pfix, INBOX)) +	{ +		size_t i; +		char *p; +		char *q; + +		printf("<tr><td align=\"left\" colspan=\"2\" class=\"folderparentdir\">%s<<< ", folders_img); + +		p=strdup(inbox_pfix); +		if (!p) +			enomem(); + +		if ((q=strrchr(p, '.')) != 0) +			*q=0; + +		for (i=0; p[i]; ) +		{ +			size_t j; +			char save_ch; + +			for (j=i; p[j]; j++) +				if (p[j] == '.') +					break; + + +			save_ch=p[j]; +			p[j]=0; + +			if (i) +				printf("."); + +			printf("<a href=\""); +			output_scriptptrget(); +			printf("&form=folders&folder=INBOX&folderdir="); +			output_urlencoded(p); +			printf("\">"); + +			if (strcmp(p, NEWSHAREDSP) == 0) +				printf("%s", getarg("PUBLICFOLDERS")); +			else +				list_folder(p+i); +			printf("</a>"); + +			p[j]=save_ch; + +			if (save_ch) +				++j; +			i=j; +		} +		printf("</td></tr>\n"); +		free(p); +	} + + +	if (!folderdir || strchr(folderdir, '.') == 0) +	{ +		folderdir=inbox_pfix; +	} + +	folderdir_l=strlen(folderdir); + +	for (i=0; folders[i]; i++) +	{ +		const	char *p; +		const	char *shortname=folders[i]; + +		size_t	j; +		const char *pfix; +		int isunsubscribed=0; +		const char	*img=folder_img; + +		pfix=">>>"; + +		if (strncmp(shortname, SHARED ".", +			    sizeof(SHARED)) == 0) +		{ +			char	*dir; +			struct	stat	stat_buf; + +			pfix="+++"; + +			dir=maildir_shareddir(".", +					      shortname+sizeof(SHARED)); +			if (!dir)	continue; +			if (stat(dir, &stat_buf)) +				isunsubscribed=1; +			free(dir); +		} + +		if (strcmp(shortname, inbox_name) == 0 && +		    strcmp(folderdir, inbox_name) == 0) +		{ +			/* List INBOX at the top level */ + +			strcpy(acl_buf, ACL_LOOKUP); +			acl_computeRightsOnFolder(shortname, acl_buf); +			if (acl_buf[0] == 0) +				continue; +		} +		else +		{ +			if (strcmp(folderdir, INBOX) == 0 && +			    strncmp(shortname, SHARED ".", sizeof(SHARED)) == 0) +			{ +				shortname += sizeof(SHARED); +			} +			else +			{ +				if (memcmp(shortname, folderdir, folderdir_l) || +				    shortname[folderdir_l] != '.') +				{ +					continue; +				} + +				strcpy(acl_buf, ACL_LOOKUP); +				acl_computeRightsOnFolder(shortname, acl_buf); +				if (acl_buf[0] == 0) +					continue; + +				shortname += folderdir_l; +				++shortname; +			} + +			if ((p=strchr(shortname, '.')) != 0) +			{ +				char *s; +				char	*t; +				unsigned tot_nnew, tot_nother; + +				s=malloc(p-folders[i]+1); +				if (!s) +					enomem(); +				memcpy(s, folders[i], p-folders[i]); +				s[p-folders[i]]=0; + +				printf("<tr class=\"foldersubdir\"><td align=\"left\">"); +				if (acl_img) +				{ +					printf("<a href=\""); +					output_scriptptrget(); +					printf("&form=acl&folder="); +					output_urlencoded(s); +					printf("\">%s</a> ", acl_img); +				} +				printf("%s%s <a href=\"", +				       folders_img, pfix); + +				output_scriptptrget(); +				printf("&form=folders&folder=INBOX&folderdir="); +				output_urlencoded(s); +				printf("\">"); +				free(s); + +				t=malloc(p-shortname+1); +				if (!t)	enomem(); +				memcpy(t, shortname, p-shortname); +				t[p-shortname]=0; +				list_folder_xlate(folders[i], +						  t, +						  name_inbox, +						  name_drafts, +						  name_sent, +						  name_trash); +				free(t); +				printf("</a>"); + +				tot_nnew=0; +				tot_nother=0; + +				j=i; +				while (folders[j] && memcmp(folders[j], folders[i], +							    p-folders[i]+1) == 0) +				{ +					strcpy(acl_buf, ACL_LOOKUP); +					acl_computeRightsOnFolder(folders[j], +								  acl_buf); +					if (acl_buf[0] == 0) +						continue; + +					maildir_count(folders[j], &nnew, ¬her); +					++j; +					tot_nnew += nnew; +					tot_nother += nother; +				} +				i=j-1; +				if (tot_nnew) +				{ +					printf(" <span class=\"subfolderlistunread\">"); +					printf(unread_label, tot_nnew); +					printf("</span>"); +				} +				printf("</td><td align=\"right\" valign=\"top\"><span class=\"subfoldercnt\">%d</span>  </td></tr>\n\n", +				       tot_nnew + tot_nother); +				continue; +			} +		} + +		nnew=0; +		nother=0; + +		if (!isunsubscribed) +			maildir_count(folders[i], &nnew, ¬her); + +		printf("<tr%s><td align=\"left\" valign=\"top\">", +			isunsubscribed ? " class=\"folderunsubscribed\"":""); + +		if (acl_img) +		{ +			printf("<a href=\""); +			output_scriptptrget(); +			printf("&form=acl&folder="); +			output_urlencoded(folders[i]); +			printf("\">%s</a> ", acl_img); +		} + +		printf("%s <input type=\"radio\" name=\"DELETE\" value=\"", img); +		output_attrencoded(folders[i]); +		printf("\" /> "); +		if (!isunsubscribed) +		{ +			printf("<a class=\"folderlink\" href=\""); +			output_scriptptrget(); +			printf("&form=folder&folder="); +			output_urlencoded(folders[i]); +			printf("\">"); +		} + +		list_folder_xlate(folders[i], +				  strcmp(folders[i], inbox_name) == 0 +				  ? INBOX:shortname, +				  name_inbox, +				  name_drafts, +				  name_sent, +				  name_trash); +		if (!isunsubscribed) +			printf("</a>"); +		if (nnew) +		{ +			printf(" <span class=\"folderlistunread\">"); +			printf(unread_label, nnew); +			printf("</span>"); +		} +		printf("</td><td align=\"right\" valign=\"top\">"); + +		if (!isunsubscribed) +		{ +			printf("<span class=\"foldercnt\">%d</span>  ", +			       nnew + nother); +		} +		else +		printf(" \n"); +		printf("</td></tr>\n\n"); +	} +	maildir_freefolders(&folders); + +	if (strcmp(folderdir, INBOX) == 0 && !maildir_newshared_disabled) +	{ +		char *sp=cgiurlencode(NEWSHAREDSP); + +		printf("<tr class=\"foldersubdir\"><td align=\"left\">%s>>> <a href=\"", folders_img); +		output_scriptptrget(); +		printf("&form=folders&folder=INBOX&folderdir=" +		       "%s\">%s</a>" +		       "</td><td> </td></tr>\n\n", +		       sp, +		       getarg("PUBLICFOLDERS")); +		free(sp); +	} +	printf("</table>\n"); +} + +void folder_list2() +{ +	if (folder_err_msg) +	{ +		printf("%s\n", folder_err_msg); +	} +} + +static void folder_rename_dest_fake(const char *dummy1, +				    struct maildir_shindex_cache *dummy2); +static void folder_rename_dest_real(const char *inbox_pfix, +				    const char *homedir, +				    const char *cur_folder, +				    const char *inbox_name); + +void folder_rename_list() +{ +	parse_hierarchy(cgi("folderdir"), folder_rename_dest_real, +			folder_rename_dest_fake); +} + +static void folder_rename_dest_fake(const char *dummy1, +				    struct maildir_shindex_cache *dummy2) +{ +} + +static void folder_rename_dest_real(const char *inbox_pfix, +				    const char *homedir, +				    const char *cur_folder, +				    const char *inbox_name) +{ +	char	**folders; +	int	i; +	size_t pl=strlen(inbox_pfix); + +	printf("<select name=\"renametofolder\">\n"); +	printf("<option value=\"%s.\">", inbox_pfix); +	printf("( ... )"); +	printf("</option>\n"); + +	maildir_listfolders(inbox_pfix, homedir, &folders); +	for (i=0; folders[i]; i++) +	{ +		const char *p=folders[i]; +		char	*q; +		size_t	ql; +		char acl_buf[2]; + +		if (strncmp(p, inbox_pfix, pl) == 0) +			switch (p[pl]) { +			case '.': +				break; +			default: +				continue; +			} +		else +			continue; + +		p += pl+1; + +		p=strrchr(p, '.'); +		if (!p)	continue; +		q=malloc(p-folders[i]+1); +		if (!q)	enomem(); +		memcpy(q, folders[i], p-folders[i]); +		q[p-folders[i]]=0; +		strcpy(acl_buf, ACL_CREATE); +		acl_computeRightsOnFolder(q, acl_buf); +		if (acl_buf[0]) +		{ +			printf("<option value=\""); +			output_attrencoded(q); +			printf(".\"%s>", +			       strcmp(q, cgi("folderdir")) == 0 +			       ? " selected='selected'":""); +			list_folder(strchr(q, '.')+1); +			printf(".</option>\n"); +		} +		ql=strlen(q); +		while (folders[++i]) +		{ +			if (memcmp(folders[i], q, ql) || +				folders[i][ql] != '.' || +				strchr(folders[i]+ql+1, '.'))	break; +		} +		--i; +		free(q); +	} +	maildir_freefolders(&folders); +	printf("</select>\n"); +} + +void folder_download(const char *folder, size_t pos, const char *mimeid) +{ +	char	*filename; +	FILE *fp=NULL; +	int	fd; + +	filename=get_msgfilename(folder, &pos); + +	fd=maildir_semisafeopen(filename, O_RDONLY, 0); +	if (fd >= 0) +	{ +		if ((fp=fdopen(fd, "r")) == 0) +			close(fd); +	} + +	if (!fp) +	{ +		free(filename); +		error("Message not found."); +		return; +	} +	free(filename); + +	cginocache(); +	msg2html_download(fp, mimeid, *cgi("download") == '1', +			  sqwebmail_content_charset); + +	fclose(fp); +} + +void folder_showtransfer() +{ +	const char	*deletelab, *purgelab, *movelab, *golab; + +	deletelab=getarg("DELETE"); +	purgelab=getarg("PURGE"); +	movelab=getarg("ORMOVETO"); +	golab=getarg("GO"); +	folder_inbox=getarg("INBOX"); +	folder_drafts=getarg("DRAFTS"); +	folder_trash=getarg("TRASH"); +	folder_sent=getarg("SENT"); + +	printf("<input type=\"hidden\" name=\"pos\" value=\"%s\" />", cgi("pos")); + +	if (*cgi("search")) +	{ +		printf("<input type=\"hidden\" name=\"search\" value=\"1\" />" +		       "<input type=\"hidden\" name=\"" SEARCHRESFILENAME +		       "\" value=\""); +		output_attrencoded(cgi(SEARCHRESFILENAME)); +		printf("\" />"); +	} + +	if ((strcmp(sqwebmail_folder, INBOX "." TRASH) == 0) && (strlen(getarg("PURGEALL")))) +	    printf("<input type=\"submit\" name=\"cmdpurgeall\" value=\"%s\" onclick=\"javascript: return deleteAll();\" />",  +		getarg("PURGEALL")); +	printf("<input type=\"submit\" name=\"cmddel\" value=\"%s\" />%s<select name=\"moveto\">", +		strcmp(sqwebmail_folder, INBOX "." TRASH) == 0 +		? purgelab:deletelab, +		movelab); + +	show_transfer_dest(sqwebmail_folder); +	printf("</select><input type=\"submit\" name=\"cmdmove\" value=\"%s\" />\n", +		golab); +} + +void folder_showquota() +{ +	const char	*quotamsg; +	struct maildirsize quotainfo; + +	quotamsg=getarg("QUOTAUSAGE"); + +	if (maildir_openquotafile("ainfo, ".")) +		return; + +	if (quotainfo.quota.nmessages != 0 || +	    quotainfo.quota.nbytes != 0) +		printf(quotamsg, maildir_readquota("ainfo)); + +	maildir_closequotafile("ainfo); +} + +void +folder_cleanup() +{ +	msg_purgelab=0; +	msg_folderlab=0; +	folder_drafts=0; +	folder_inbox=0; +	folder_sent=0; +	folder_trash=0; +	msg_forwardattlab=0; +	msg_forwardlab=0; +	msg_fullheaderlab=0; +	msg_golab=0; +	msg_movetolab=0; +	msg_nextlab=0; +	msg_prevlab=0; +	msg_deletelab=0; +	msg_posfile=0; +	msg_replyalllab=0; +	msg_replylistlab=0; +	msg_replylab=0; +	folder_err_msg=0; +	msg_msglab=0; +	msg_add=0; + +	msg_type=0; +	initnextprevcnt=0; +	msg_hasprev=0; +	msg_hasnext=0; +	msg_pos=0; +	msg_count=0; +} + + +/* +** Unicode-aware truncation of text at a specified column, if text length +** exceeds the given # of characters. +*/ + +static char *truncate_at(const char *str, +			 const char *charset, +			 size_t ncols) +{ +	unicode_char *uc; +	size_t n; +	size_t cols, tp=0; +	char *retbuf; +	libmail_u_convert_handle_t h; +	int chopped=0; + +	if (!str) +		return NULL; + +	h=libmail_u_convert_tou_init("utf-8", &uc, &n, 1); + +	if (h) +	{ +		libmail_u_convert(h, str, strlen(str)); +		libmail_u_convert_deinit(h, NULL); +	} +	else +	{ +		uc=NULL; +	} + +	if (!uc) +		return NULL; + +	for (cols=0, n=0; uc[n]; n++) { + +		cols += unicode_wcwidth(uc[n]); + +		tp = n; +		if (cols > ncols-3 && n > 0 && +		    unicode_grapheme_break(uc[n-1], uc[n])) +		{ +			chopped=1; +			break; +		} +		++tp; +	} + +	if (chopped) +	{ +		uc = realloc(uc, sizeof(unicode_char) * (tp+4)); +		if (uc == 0) enomem(); +		uc[tp]='.'; +		uc[tp+1]='.'; +		uc[tp+2]='.'; +		tp += 3; +	} + +	h=libmail_u_convert_fromu_init(charset, &retbuf, &cols, 1); + +	if (h) +	{ +		libmail_u_convert_uc(h, uc, tp); +		libmail_u_convert_deinit(h, NULL); +	} +	else +	{ +		retbuf=NULL; +	} + +	free(uc); +	return retbuf; +} | 
