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/newmsg_create.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/newmsg_create.c')
| -rw-r--r-- | sqwebmail/newmsg_create.c | 1433 | 
1 files changed, 1433 insertions, 0 deletions
| diff --git a/sqwebmail/newmsg_create.c b/sqwebmail/newmsg_create.c new file mode 100644 index 0000000..5053d47 --- /dev/null +++ b/sqwebmail/newmsg_create.c @@ -0,0 +1,1433 @@ +/* +** Copyright 1998 - 2009 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +/* +*/ +#include	"config.h" +#include	"cgi/cgi.h" +#include	"sqconfig.h" +#include	"sqwebmail.h" +#include	"auth.h" +#include	"maildir.h" +#include	"newmsg.h" +#include	"folder.h" +#include	"filter.h" +#include	"pref.h" +#include	"gpg.h" +#include	"addressbook.h" +#include	"maildir/maildirmisc.h" +#include	"rfc822/rfc822.h" +#include	"rfc2045/rfc2045.h" +#include	"rfc822/rfc2047.h" +#include	"rfc822/encode.h" +#include	"rfc822/rfc822hdr.h" +#include	"msg2html.h" +#include	"gpglib/gpglib.h" +#include	"http11/http11.h" +#include	"htmllibdir.h" +#include	"unicode/unicode.h" +#include	"courierauth.h" + +#include	<stdlib.h> +#if HAVE_UNISTD_H +#include	<unistd.h> +#endif +#include	<ctype.h> +#include	<fcntl.h> + +#define HASTEXTPLAIN(q) (rfc2045_searchcontenttype((q), "text/plain") != NULL) +/* Also in attachments.c */ + +extern const char *rfc822_mkdt(time_t); + +extern const char *sqwebmail_content_charset; +extern const char *sqwebmail_content_language; + +int newdraftfd; +extern const char *sqwebmail_mailboxid; + +const char mimemsg[]="This is a MIME-formatted message.  If you see this text it means that your\nmail software cannot handle MIME-formatted messages.\n\n"; + +char *newmsg_createdraft_do(const char *, const char *, int); + +/* Save message in a draft file */ + +char *newmsg_createdraft(const char *curdraft) +{ +	if (curdraft && *curdraft) +	{ +	char	*base=maildir_basename(curdraft); +	char	*filename=maildir_find(INBOX "." DRAFTS, base); + +		if (filename) +		{ +		char	*p=newmsg_createdraft_do(filename, cgi("message"), 0); + +			free(filename); +			free(base); +			return (p); +		} +		free(base); +	} +	return (newmsg_createdraft_do(0, cgi("message"), 0)); +} + +static void create_draftheader_do(const char *hdrname, const char *p, +	int isrfc822addr); + +static void create_draftheader(const char *hdrname, const char *p, +			       const char *q, int isrfc822addr) +{ +	if (q && *q)	/* Add from address book */ +	{ +	char	*nick=cgi_multiple("nick", ","); +	char	*s; + +		if (nick) +		{ +			s=malloc(strlen(p)+strlen(nick)+2); + +			if (s) +			{ +				strcpy(s, p); +				if (*s && *nick)	strcat(s, ","); +				strcat(s, nick); +				create_draftheader_do(hdrname, s, isrfc822addr); +				free(s); +				free(nick); +				return; +			} +			free(nick); +		} + +	} +	create_draftheader_do(hdrname, p, isrfc822addr); +} + +#define	ISLWS(c)	((c)=='\t' || (c)=='\r' || (c)=='\n' || (c)==' ') + +static void header_wrap(const char *name, const char *hdr, +			char *outbuf, size_t *outcnt) +{ +char	*pfix; +size_t	offset=strlen(name); + +	*outcnt=0; +	pfix=""; + +	while (*hdr) +	{ +	size_t i; +	size_t spc; + +		for (spc=0, i=0; hdr[i]; i++) +		{ +			if (i + offset >= 75 && spc) +			{ +			        i = spc; +				offset = 0; +				break; +			} + +			if (ISLWS(hdr[i])) +			{ +				spc = i; +				while (ISLWS(hdr[i+1])) +					++i; +			} +		} + +		if (outbuf) +		{ +			strcpy(outbuf, pfix); +			outbuf += strlen(pfix); +		} +		*outcnt += strlen(pfix); + +		if (outbuf) +		{ +		size_t j; +			for (j=0; j < i; j++) +			{ +				if (ISLWS(hdr[j])) +				{ +					*(outbuf++) = ' '; +					while (ISLWS(hdr[j+1])) +						++j; +				} +				else +					*(outbuf++) = hdr[j]; +			} +		} +		*outcnt += i; +		pfix="\n  "; +		hdr += i; +		while (ISLWS(*hdr)) +			++hdr; +	} +	if (outbuf) +		*outbuf=0; +	++*outcnt; +} +			 +static void create_draftheader_do(const char *hdrname, const char *p, +	int isrfc822addr) +{ +char	*s, *t; +size_t	l; + +	if (!*p)	return; + +	if (!isrfc822addr) +	{ +		s=rfc2047_encode_str(p, sqwebmail_content_charset, +				     rfc2047_qp_allow_any); +	} +	else +	{ +		s=rfc2047_encode_header_tobuf("to", p, +					      sqwebmail_content_charset); +	} + +	header_wrap(hdrname, s, NULL, &l); +	if (l) +	{ +		if (!(t=malloc(l))) enomem(); +		header_wrap(hdrname, s, t, &l); +		if (*t) +		{ +			free(s); +			s = t; +		} +		else +			free(t); +	} + +	if (!s) +	{ +		close(newdraftfd); +		enomem(); +	} +	maildir_writemsgstr(newdraftfd, hdrname); +	maildir_writemsgstr(newdraftfd, s); +	maildir_writemsgstr(newdraftfd, "\n"); +	free(s); +} + +void newmsg_create_multipart(int newdraftfd, const char *charset, +			const char *multipart_boundary) +{ +	maildir_writemsgstr(newdraftfd, +		"Mime-version: 1.0\n" +		"Content-Type: multipart/mixed; boundary=\""); +	maildir_writemsgstr(newdraftfd, multipart_boundary); +	maildir_writemsgstr(newdraftfd, "\"; charset=\""); +	maildir_writemsgstr(newdraftfd, charset); +	maildir_writemsgstr(newdraftfd,  +					"\"\n\n"); + +	maildir_writemsgstr(newdraftfd, mimemsg); +} + + +static char	*newmsg_multipart_boundary(FILE *, const char *); +static void newmsg_copy_attachments(struct rfc2045 *, FILE *, const char *); + +void newmsg_copy_nonmime_headers(FILE *fp) +{ +char	*header, *value; +char	*q; + +	while ((header=maildir_readheader(fp, &value, 1)) != NULL) +	{ +		if (strcmp(header, "mime-version") == 0 || +			strncmp(header, "content-", 8) == 0)	continue; + +		/* Fluff - capitalize header names */ + +		for (q=header; *q; q++) +		{ +			for (*q=toupper(*q); *q; q++) +				if (*q == '-')	break; +			if (!*q) +				break; +		} + +		maildir_writemsgstr(newdraftfd, header); +		maildir_writemsgstr(newdraftfd, ": "); +		maildir_writemsgstr(newdraftfd, value); +		maildir_writemsgstr(newdraftfd, "\n"); +	} +} + +void newmsg_copy_content_headers(FILE *fp) +{ +char	*header, *value; +char	*q; + +	while ((header=maildir_readheader(fp, &value, 1)) != NULL) +	{ +		if (strncmp(header, "content-", 8)) continue; + +		for (q=header; *q; q++) +		{ +			for (*q=toupper(*q); *q; q++) +				if (*q == '-')	break; +			if (!*q) +				break; +		} + +		maildir_writemsgstr(newdraftfd, header); +		maildir_writemsgstr(newdraftfd, ": "); +		maildir_writemsgstr(newdraftfd, value); +		maildir_writemsgstr(newdraftfd, "\n"); +	} +} + +void wrap_text_init(struct wrap_info *uw, +		    const char *output_chset, +		    void (*output_func)(const char *p, size_t l, void *arg), +		    void *arg) +{ +	memset(uw, 0, sizeof(*uw)); +	uw->output_func=output_func; +	uw->output_chset=output_chset; +	uw->arg=arg; +} + +static void do_save_u_line(struct wrap_info *uw, +			   const unicode_char *uc, +			   size_t ucsize, +			   int flowed) +{ +	char *cbuf; +	size_t csize; + +	libmail_u_convert_handle_t h= +		libmail_u_convert_fromu_init(uw->output_chset, +					     &cbuf, +					     &csize, +					     0); + +	if (h) +	{ +		if (ucsize) +		{ +			if (uc[0] == ' ') +				libmail_u_convert_uc(h, uc, 1); +			/* Space stuff */ + +			libmail_u_convert_uc(h, uc, ucsize); +		} +		if (flowed) +		{ +			unicode_char spc=' '; +			libmail_u_convert_uc(h, &spc, 1); +		} + +		{ +			unicode_char nl='\n'; +			libmail_u_convert_uc(h, &nl, 1); +		} + +		if (libmail_u_convert_deinit(h, NULL)) +			cbuf=NULL; +	} +	else +		cbuf=NULL; + +	if (cbuf) +	{ +		(*uw->output_func)(cbuf, csize, uw->arg); +		free(cbuf); +	} +} + +static void flush_line(struct wrap_info *uw, int flowed) +{ +	do_save_u_line(uw, uw->uc + uw->line_start, +		       uw->word_start - uw->line_start, flowed); + +	uw->line_start=uw->word_start; +	uw->line_width=0; +} + +static void add_word(struct wrap_info *uw) +{ +	if (uw->line_start < uw->word_start && +	    uw->line_width + uw->word_width > MYLINESIZE) +		flush_line(uw, 1); + +	uw->line_width += uw->word_width; + +	uw->word_start=uw->cur_index; +	uw->word_width=0; +} + +static int do_save_u_process_lb(int type, void *arg) +{ +	struct wrap_info *uw=(struct wrap_info *)arg; + +	if (uw->cur_index >= uw->ucsize) +		enomem(); + +	if (type != UNICODE_LB_NONE) +	{ +		add_word(uw); +		if (type == UNICODE_LB_MANDATORY) +			flush_line(uw, 0); +	} + + +	if (uw->word_width >= MYLINESIZE && +	    uw->cur_index > 0 && +	    unicode_grapheme_break(uw->uc[uw->cur_index-1], +				   uw->uc[uw->cur_index])) +		add_word(uw); + +	uw->word_width += unicode_wcwidth(uw->uc[uw->cur_index]); +	++uw->cur_index; +	return 0; +} + +static void do_wrap_u_line(struct wrap_info *uw, +			   const unicode_char *uc, +			   size_t ucsize) +{ +	unicode_lb_info_t lb; + +	while (ucsize && uc[ucsize-1] == ' ') +		--ucsize; + +	uw->uc=uc; +	uw->ucsize=ucsize; +	uw->cur_index=0; +	uw->word_start=0; +	uw->word_width=0; + +	uw->line_start=0; +	uw->line_width=0; +	if ((lb=unicode_lb_init(do_save_u_process_lb, uw)) != NULL) +	{ +		unicode_lb_set_opts(lb, +				    UNICODE_LB_OPT_PRBREAK +				    | UNICODE_LB_OPT_SYBREAK); +		unicode_lb_next_cnt(lb, uc, ucsize); +		unicode_lb_end(lb); +		add_word(uw); +		flush_line(uw, 0); +	} +} + +static void save_textplain(const char *p, size_t l, void *dummy) +{ +	maildir_writemsg(newdraftfd, p, l); +} + +void wrap_text(struct wrap_info *uw, +	       const char *newmsg, +	       size_t newmsg_size) +{ +	size_t i=0, j; + +	while (i < newmsg_size) +	{ +		unicode_char *uc; +		size_t ucsize; +		libmail_u_convert_handle_t h; + +		j=i; + +		while (i<newmsg_size && newmsg[i] != '\n') +			++i; + +		h=libmail_u_convert_tou_init(sqwebmail_content_charset, +					     &uc, &ucsize, 0); + +		if (h) +		{ +			libmail_u_convert(h, newmsg+j, i-j); + +			if (libmail_u_convert_deinit(h, NULL)) +				uc=NULL; +		} +		else +		{ +			uc=NULL; +		} + +		if (uc) +		{ +			size_t i, j; + +			/* Get rid of any CRs that sneak in */ + +			for (i=j=0; i<ucsize; ++i) +			{ +				if (uc[i] == '\r') +					continue; + +				uc[j]=uc[i]; +				++j; +			} + +			if (j && *uc == '>') +				do_save_u_line(uw, uc, j, 0); +			else +				do_wrap_u_line(uw, uc, j); + +			free(uc); +		} + +		if (i < newmsg_size) +			++i; +	} +} + +static void convert_text2html(const char *p, size_t l, void *arg) +{ +	struct msg2html_textplain_info *info= +		(struct msg2html_textplain_info *)arg; + +	msg2html_textplain(info, p, l); +} + +static char *mkurl(const char *url, void *dummy) +{ +	char *buf=malloc(strlen(url)*2+100); + +	if (!buf) +		return NULL; + +	/* msg2html guarantees that the characters in url are "safe" */ + +	sprintf(buf, "<a href=\"%s\">%s</a>", url, url); +	return buf; +} + +char *newmsg_createdraft_do(const char *curdraft, const char *newmsg, +	int keepheader) +{ +char	*draftfilename; +FILE	*fp=0; +char	*multipart_boundary; +const char *content_type; +const char *content_transfer_encoding; +const char *charset; +unsigned long prev_size=0; +off_t	transferencodingpos; +off_t	transferencoding2pos; +int is_newevent=strcmp(cgi("form"), "newevent") == 0; +struct	rfc2045	*rfcp; +int has_attachments=0; +size_t newmsg_size; +char *sig, *footer; + +/* +** Trim extra newlines. +*/ +	newmsg_size=strlen(newmsg); + +	while (newmsg_size && newmsg[newmsg_size-1] == '\n') +		--newmsg_size; + +/* We're on the 'new event' screen */ + + 	if (curdraft)	/* Reuse a draft filename */ +		newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, curdraft, &draftfilename); +	else +		newdraftfd=maildir_createmsg(INBOX "." DRAFTS, 0, &draftfilename); +	if (newdraftfd < 0)	enomem(); + +	pref_wikifmt=0; +	if (strcmp(cgi("textformat"), "wiki") == 0) +		pref_wikifmt=1; +	pref_update(); + +	fp=NULL; +	if (curdraft) +	{ +	int	x=maildir_safeopen(curdraft, O_RDONLY, 0); + +		if (x >= 0) +			if ((fp=fdopen(x, "r")) == 0) +				close(x); +	} + +	if (fp) +	{ +	char	*header, *value; +	struct	stat	stat_buf; + +		if (fstat(fileno(fp), &stat_buf)) +		{ +			fclose(fp); +			enomem(); +		} +		prev_size=stat_buf.st_size; + +		while ((header=maildir_readheader(fp, &value, 1)) != NULL) +		{ +			if (keepheader == NEWMSG_SQISPELL) +			{ +				if (strcasecmp(header, "mime-version") == 0 || +				    strncasecmp(header, "content-", 8) == 0) +					continue; +			} +			else if (keepheader == NEWMSG_PCP) +			{ +				if (strcasecmp(header, "mime-version") == 0 || +				    strncasecmp(header, "content-", 8) == 0 || +				    strcasecmp(header, "date") == 0 || +				    strcasecmp(header, "from") == 0 || +				    strcasecmp(header, "subject") == 0) +					continue; +			} +			else +			{ +				if (strcmp(header, "in-reply-to") && +					strcmp(header, "references") && +					strncmp(header, "x-", 2))	continue; +				/* Do not discard these headers */ +			} + +			if (strcasecmp(header, "x-sqwebmail-wikifmt") == 0) +				continue; + +			maildir_writemsgstr(newdraftfd, header); +			maildir_writemsgstr(newdraftfd, ": "); +			maildir_writemsgstr(newdraftfd, value); +			maildir_writemsgstr(newdraftfd, "\n"); +		} +	} +	else if (is_newevent) +		maildir_writemsgstr(newdraftfd, "X-Event: 1\n"); + +	if (!keepheader +	    || keepheader == NEWMSG_PCP) +	/* Coming back from msg edit, set headers */ +	{ +	const	char *p=cgi("headerfrom"); + +		if (!*p)	p=pref_from; +		if (!p || !*p || auth_getoptionenvint("wbnochangingfrom")) +			p=login_fromhdr(); + +		create_draftheader("From: ", p, 0, 1); + +		if (!pref_from || strcmp(p, pref_from)) +			pref_setfrom(p); + +/* sam ???? +	create_draftheader("In-Reply-To: ", cgi("headerin-reply-to")); +*/ +		if (!is_newevent) +		{ +#if 0 +			{ +				FILE *fp; +				fp=fopen("/tmp/pid", "w"); +				fprintf(fp, "%d", getpid()); +				fclose(fp); +				sleep(10); +			} +#endif + +			create_draftheader("To: ", cgi("headerto"), +					   cgi("addressbook_to"), 1); +			create_draftheader("Cc: ", cgi("headercc"), +					   cgi("addressbook_cc"), 1); +			create_draftheader("Bcc: ", cgi("headerbcc"), +					   cgi("addressbook_bcc"), 1); +			create_draftheader("Reply-To: ", cgi("headerreply-to"), 0, 1); +		} +	} + +	if (pref_wikifmt) +		create_draftheader("x-sqwebmail-wikifmt: ", "1", 0, 0); + +	if (!keepheader || keepheader == NEWMSG_PCP) +	{ +	time_t	t; + +		create_draftheader("Subject: ", cgi("headersubject"), 0, 0); + +		time(&t); +		create_draftheader("Date: ", rfc822_mkdate(t), 0, 0); +	} + +	/* If the message has attachments, calculate multipart boundary */ + +	rfcp=NULL; + +	if (fp) +	{ +		rfcp=rfc2045_fromfp(fp); +		if (!rfcp) +		{ +			close(newdraftfd); +			fclose(fp); +			enomem(); +		} +	} + +	multipart_boundary=newmsg_multipart_boundary(fp, newmsg); + +	if (rfcp && rfcp->firstpart && +	    strcmp((rfc2045_mimeinfo(rfcp, &content_type, +			      &content_transfer_encoding, &charset), +		    content_type), "multipart/mixed") == 0) +	{ +		has_attachments=1; +		newmsg_create_multipart(newdraftfd, +			sqwebmail_content_charset, multipart_boundary); + +		maildir_writemsgstr(newdraftfd, "--"); +		maildir_writemsgstr(newdraftfd, multipart_boundary); +		maildir_writemsgstr(newdraftfd,"\n"); +	} +	else +	{ +		maildir_writemsgstr(newdraftfd, "Mime-Version: 1.0\n"); +	} + +	if (pref_wikifmt) +	{ +		++multipart_boundary[strlen(multipart_boundary)-1]; + +		maildir_writemsgstr(newdraftfd, +				    "Content-Type: multipart/alternative;" +				    " boundary=\""); +		maildir_writemsgstr(newdraftfd, multipart_boundary); +		maildir_writemsgstr(newdraftfd, "\"\n" +				    "\n" +				    "\n" +				    "--"); +		maildir_writemsgstr(newdraftfd, multipart_boundary); +		maildir_writemsgstr(newdraftfd, "\n"); +	} + +	maildir_writemsgstr(newdraftfd, +			    "Content-Type: text/plain; format=flowed; delsp=yes;" +			    " charset=\""); +	maildir_writemsgstr(newdraftfd, sqwebmail_content_charset); +	maildir_writemsgstr(newdraftfd, "\"\n"); + +	maildir_writemsgstr(newdraftfd, "Content-Transfer-Encoding: "); +	transferencoding2pos=transferencodingpos=writebufpos; +	maildir_writemsgstr(newdraftfd, "7bit\n\n"); + +	/*	maildir_writemsgstr(newdraftfd, "\n"); */ + +	sig=pref_getsig(); +	footer=pref_getfile(http11_open_langfile(get_templatedir(), +						 sqwebmail_content_language, +						 "footer")); + +	while (newmsg_size && +	       (newmsg[newmsg_size-1] == '\r' || +		newmsg[newmsg_size-1] == '\n')) +		--newmsg_size; + +	{ +		struct wrap_info uw; + +		wrap_text_init(&uw, sqwebmail_content_charset, +			       save_textplain, NULL); + +		wrap_text(&uw, newmsg, newmsg_size); + +		if ((sig && *sig) || (footer && *footer)) +		{ +			static const unicode_char sig_line[]={'-', '-', ' '}; + +			do_save_u_line(&uw, sig_line, 0, 0); +			do_save_u_line(&uw, sig_line, 3, 0); +		} + +		if (sig && *sig) +			wrap_text(&uw, sig, strlen(sig)); + +		if (footer && *footer) +		{ +			do_save_u_line(&uw, NULL, 0, 0); +			maildir_writemsg(newdraftfd, footer, strlen(footer)); +		} + +	} + +	if (pref_wikifmt) +	{ +		struct msg2html_textplain_info *info; + +		maildir_writemsgstr(newdraftfd, "\n" +				    "--"); +		maildir_writemsgstr(newdraftfd, multipart_boundary); +		maildir_writemsgstr(newdraftfd, "\n" +				    "Content-Type: text/html; charset=\""); +		maildir_writemsgstr(newdraftfd, sqwebmail_content_charset); +		maildir_writemsgstr(newdraftfd, "\"\n" +				    "Content-Transfer-Encoding: "); +		transferencoding2pos=writebufpos; +		maildir_writemsgstr(newdraftfd, "7bit\n\n"); + +		info=msg2html_textplain_start(sqwebmail_content_charset, +					      sqwebmail_content_charset, +					      1, +					      1, +					      0, +					      mkurl, NULL, +					      NULL, +					      NULL, +					      1, +					      save_textplain, +					      NULL); + +		if (info) +		{ +			struct wrap_info uw; + +			wrap_text_init(&uw, sqwebmail_content_charset, +				       convert_text2html, info); + +			wrap_text(&uw, newmsg, newmsg_size); +			msg2html_textplain_end(info); +		} + +		if ((sig && *sig) || (footer && *footer)) +			save_textplain("<hr />\n", 7, NULL); + +		if (sig && *sig) +		{ + +			info=msg2html_textplain_start(sqwebmail_content_charset, +						      sqwebmail_content_charset, +						      1, +						      1, +						      0, +						      mkurl, NULL, +						      NULL, +						      NULL, +						      1, +						      save_textplain, +						      NULL); + +			if (info) +			{ +				struct wrap_info uw; + +				wrap_text_init(&uw, sqwebmail_content_charset, +					       convert_text2html, info); + +				wrap_text(&uw, sig, strlen(sig)); +				msg2html_textplain_end(info); +			} +		} + +		if (footer && *footer) +		{ +			save_textplain("<br />\n", 7, NULL); + +			info=msg2html_textplain_start(sqwebmail_content_charset, +						      sqwebmail_content_charset, +						      1, +						      1, +						      0, +						      mkurl, NULL, +						      NULL, +						      NULL, +						      1, +						      save_textplain, +						      NULL); + +			if (info) +			{ +				msg2html_textplain(info, footer, +						   strlen(footer)); +				msg2html_textplain_end(info); +			} +		} + +		maildir_writemsgstr(newdraftfd, "\n" +				    "--"); +		maildir_writemsgstr(newdraftfd, multipart_boundary); +		maildir_writemsgstr(newdraftfd, "--\n"); +		--multipart_boundary[strlen(multipart_boundary)-1]; + +	} + +	if (sig) +		free(sig); + +	if (footer) +		free(footer); + +	if ( multipart_boundary && rfcp && has_attachments) +	{ +		newmsg_copy_attachments(rfcp, fp, multipart_boundary); +		maildir_writemsgstr(newdraftfd, "\n--"); +		maildir_writemsgstr(newdraftfd, multipart_boundary); +		maildir_writemsgstr(newdraftfd, "--\n"); +		free(multipart_boundary); +	} +	if (fp)	fclose(fp); +	if (rfcp) +		rfc2045_free(rfcp); + +	if ( maildir_writemsg_flush(newdraftfd) == 0 && writebuf8bit) +	{ +		if (lseek(newdraftfd, transferencodingpos, SEEK_SET) < 0 || +			write(newdraftfd, "8", 1) != 1 || +		    lseek(newdraftfd, transferencoding2pos, SEEK_SET) < 0 || +			write(newdraftfd, "8", 1) != 1) +		{ +			close(newdraftfd); +			enomem(); +		} +	} + +	if ( maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, -1, prev_size)) +		cgi_put("error", "quota"); + +	return(draftfilename); +} + +static void sentmsg_copy(FILE *f, struct rfc2045 *p) +{ +	off_t start_pos, end_pos, start_body; +	char buf[BUFSIZ]; +	int n; +	off_t   dummy; + +        rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, &dummy, &dummy); +        if (fseek(f, start_pos, SEEK_SET) == -1) +        { +                fclose(f); +                close(newdraftfd); +                enomem(); +        } + +        while (start_pos < end_pos) +        { +        int     cnt=sizeof(buf); + +                if (cnt > end_pos - start_pos) +                        cnt=end_pos - start_pos; + +                if ((n=fread(buf, 1, cnt, f)) <= 0) +                { +                        fclose(f);       +                        close(newdraftfd); +                        enomem(); +                } + +                maildir_writemsg(newdraftfd, buf, n); +                start_pos += n; +        } +} + + +/* Create message in the sent folder */ + +static void header_uc(char *h) +{ +	while (*h) +	{ +		*h=toupper( (int)(unsigned char) *h); +		while (*h) +		{ +			if (*h++ == '-')	break; +		} +	} +} + +struct lookup_buffers { +	struct lookup_buffers *next; +	char *buf; +	char *buf2; +	} ; + +static int lookup_addressbook_do(const char *header, const char *value, +	struct lookup_buffers **lookup_buffer_list) +{ +	struct	rfc822t *t; +	struct	rfc822a *a; +	int	i; +	char	*newbuf; +	struct lookup_buffers *ptr; +	int	expanded=0; + +	t=rfc822t_alloc_new(value, NULL, NULL); +	if (!t)	enomem(); +	a=rfc822a_alloc(t); +	if (!a) +	{ +		rfc822t_free(t); +		enomem(); +	} + +	for (i=0; i<a->naddrs; i++) +	{ +		char	*p; +		char	*s; +		const	char *q; +		struct lookup_buffers *r; + +		if (a->addrs[i].tokens == 0) +			continue; +		if (a->addrs[i].name) +			continue;	/* Can't be a nickname */ + +		p=rfc822_getaddr(a, i); +		if (!p) +		{ +			rfc822a_free(a); +			rfc822t_free(t); +			free(p); +			return (-1); +		} + +		for (ptr= *lookup_buffer_list; ptr; ptr=ptr->next) +			if (strcmp(ptr->buf2, p) == 0) +				break; + +		if (ptr)	/* Address book loop */ +		{ +		int	j; + +			for (j=i+1; j<a->naddrs; j++) +				a->addrs[j-1]=a->addrs[j]; +			--a->naddrs; +			--i; +			free(p); +			continue; +		} + +		s=rfc822_display_addr_str_tobuf(p, "utf-8"); + +		if (s == NULL || (q=ab_find(s)) == 0) +		{ +			if (s) +				free(s); +			free(p); +			continue; +		} +		free(s); + +		r=malloc(sizeof(struct lookup_buffers)); +		if (r)	r->buf=r->buf2=0; + +		if (!r || !(r->buf=strdup(q)) || !(r->buf2=strdup(p))) +		{ +			free(p); +			if (r && r->buf)	free(r->buf); +			if (r)	free(r); +			rfc822a_free(a); +			rfc822t_free(t); +			return (-1); +		} +		free(p); +		r->next= *lookup_buffer_list; +		*lookup_buffer_list=r; +		a->addrs[i].tokens->next=0; +		a->addrs[i].tokens->token=0; +		a->addrs[i].tokens->ptr=r->buf; +		a->addrs[i].tokens->len=strlen(r->buf); +		expanded=1; +	} + +	newbuf=rfc822_getaddrs_wrap(a, 70); +	rfc822a_free(a); +	rfc822t_free(t); +	if (!newbuf)	return (-1); + +	if (expanded)	/* Look through the address book again */ +	{ +	int	rc=lookup_addressbook_do(header, newbuf, lookup_buffer_list); + +		free(newbuf); +		return (rc); +	} + +	create_draftheader_do(header, newbuf, 1); +	free(newbuf); +	return (0); +} + +static void lookup_addressbook(const char *header, const char *value) +{ +	struct lookup_buffers *lookup_buffer_list=0; +	int	rc; +	char *header_cpy; +	char *value_cpy; +	/* +	** header & value may be pointing to buffer allocated by +	** maildir_readheader. +	** lookup_addressbook_do may call it again. +	*/ + +	header_cpy=strdup(header); +	if (!header_cpy) +		enomem(); + +	value_cpy=strdup(value); +	if (!value_cpy) +	{ +		free(header_cpy); +		enomem(); +	} + +	rc=lookup_addressbook_do(header_cpy, value_cpy, &lookup_buffer_list); +	free(header_cpy); + +	while (lookup_buffer_list) +	{ +	struct lookup_buffers *p=lookup_buffer_list; + +		lookup_buffer_list=p->next; +		free(p->buf); +		free(p->buf2); +		free(p); +	} +	if (rc)	enomem(); +} + +char *newmsg_createsentmsg(const char *draftname, int *isgpgerr) +{ +char	*filename=maildir_find(INBOX "." DRAFTS, draftname); +FILE	*fp; +char	*sentname; +char	*header, *value; +struct	rfc2045 *rfcp; +int	x; + +	*isgpgerr=0; +  +	if (!filename)	return (0); + +	fp=0; + +	x=maildir_safeopen(filename, O_RDONLY, 0); +	if (x >= 0) +		if ((fp=fdopen(x, "r")) == 0) +			close(x); + +	if (fp == 0) +	{ +		free(filename); +		enomem(); +	} + +	rfcp=rfc2045_fromfp(fp); +	if (!rfcp || fseek(fp, 0L, SEEK_SET) < 0) +	{ +		fclose(fp); +		close(newdraftfd); +		enomem(); +	} + +	newdraftfd=maildir_createmsg(INBOX "." SENT, 0, &sentname); +	if (newdraftfd < 0) +	{ +		rfc2045_free(rfcp); +		free(filename); +		fclose(fp); +		enomem(); +	} +	/* First, copy all headers except X- headers */ + +	while ((header=maildir_readheader(fp, &value, 1)) != 0) +	{ +		if (strncmp(header, "x-", 2) == 0)	continue; +		header_uc(header); +		if (rfc822hdr_namecmp(header, "To") == 0) +		{ +			lookup_addressbook("To: ", value); +			continue; +		} + +		if (rfc822hdr_namecmp(header, "Cc") == 0) +		{ +			lookup_addressbook("Cc: ", value); +			continue; +		} + +		if (rfc822hdr_namecmp(header, "Bcc") == 0) +		{ +			lookup_addressbook("Bcc: ", value); +			continue; +		} + +		maildir_writemsgstr(newdraftfd, header); +		maildir_writemsgstr(newdraftfd, ": "); +		maildir_writemsgstr(newdraftfd, value); +		maildir_writemsgstr(newdraftfd, "\n"); +	} +	if (auth_getoptionenvint("wbusexsender")) +	{ +		maildir_writemsgstr(newdraftfd, "X-Sender: "); +		maildir_writemsgstr(newdraftfd, login_returnaddr()); +		maildir_writemsgstr(newdraftfd, "\n"); +	} + +	maildir_writemsgstr(newdraftfd, "\n"); + +	{ +		off_t start_pos, end_pos, start_body; +		char buf[BUFSIZ]; +		int n; +		off_t   dummy; +		 +		rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, +				&dummy, &dummy); + +		if (fseek(fp, start_body, SEEK_SET) == -1) +		{ +			fclose(fp); +			close(newdraftfd); +			enomem(); +		} + +		while (start_body < end_pos) +		{ +			int     cnt=sizeof(buf); + +			if (cnt > end_pos - start_pos) +				cnt=end_pos - start_pos; + +			if ((n=fread(buf, 1, cnt, fp)) <= 0) +			{ +				fclose(fp);       +				close(newdraftfd); +				enomem(); +			} + +			maildir_writemsg(newdraftfd, buf, n); +			start_body += n; +		} +	} + + +	if ( maildir_writemsg_flush(newdraftfd)) +	{ +		free(sentname); +		return (0); +	} + +#if 0 +	if (writebuf8bit) +	{ +		if (lseek(newdraftfd, transferencodingpos, SEEK_SET) < 0 || +			write(newdraftfd, "8", 1) != 1) +		{ +			free(sentname); +			return (0); +		} +	} +#endif + +	if ( maildir_writemsg_flush(newdraftfd)) +	{ +		maildir_closemsg(newdraftfd, INBOX "." SENT, sentname, 0, 0); +		free(sentname); +		return (0); +	} + +	if (libmail_gpg_has_gpg(GPGDIR) == 0) +	{ +		char dosign= *cgi("sign"); +		char doencrypt= *cgi("encrypt"); +		const char *signkey= cgi("signkey"); +		char *encryptkeys=cgi_multiple("encryptkey", " "); + +		if (!encryptkeys) +			enomem(); + +		if (gpgbadarg(encryptkeys) || !*encryptkeys) +		{ +			free(encryptkeys); +			encryptkeys=0; +		} + +		if (gpgbadarg(signkey) || !*signkey) +		{ +			signkey=0; +		} + +		if (!encryptkeys) +			doencrypt=0; + +		if (!signkey) +			dosign=0; + +		if (lseek(newdraftfd, 0L, SEEK_SET) < 0) +		{ +			maildir_closemsg(newdraftfd, INBOX "." SENT, +					 sentname, 0, 0); +			free(sentname); +			return (0); +		} + +		if (!dosign) +			signkey=0; +		if (!doencrypt) +			encryptkeys=0; + +		if (dosign || doencrypt) +		{ +			/* +			** What we do is create another draft, then substitute +			** it for newdraftfd/sentname.  Sneaky. +			*/ + +			char *newnewsentname; +			int newnewdraftfd=maildir_createmsg(INBOX "." SENT, 0, +							    &newnewsentname); + +			if (newnewdraftfd < 0) +			{ +				maildir_closemsg(newdraftfd, INBOX "." SENT, +						 sentname, 0, 0); +				free(sentname); +				free(encryptkeys); +				return (0); +			} + +			if (gpgdomsg(newdraftfd, newnewdraftfd, +				     signkey, encryptkeys)) +			{ +				maildir_closemsg(newnewdraftfd, INBOX "." SENT, +						 newnewsentname, 0, 0); +				free(newnewsentname); +				maildir_closemsg(newdraftfd, INBOX "." SENT, +						 sentname, 0, 0); +				free(sentname); +				free(encryptkeys); +				*isgpgerr=1; +				return (0); +			} + +			maildir_closemsg(newdraftfd, INBOX "." SENT, sentname, 0, 0); +			free(sentname); +			sentname=newnewsentname; +			newdraftfd=newnewdraftfd; + +		} +		free(encryptkeys); +	} + +	if ( maildir_closemsg(newdraftfd, INBOX "." SENT, sentname, 1, 0)) +	{ +		free(sentname); +		return (0); +	} +	return (sentname); +} + +/* ---------------------------------------------------------------------- */ + +/* Create a potential multipart boundary separator tag */ + +char *multipart_boundary_create() +{ +char	pidbuf[MAXLONGSIZE]; +char	timebuf[MAXLONGSIZE]; +time_t	t; +char	cntbuf[MAXLONGSIZE]; +static unsigned long cnt=0; +char	*p; + +	sprintf(pidbuf, "%lu", (unsigned long)getpid()); +	time(&t); +	sprintf(timebuf, "%lu", (unsigned long)t); +	sprintf(cntbuf, "%lu", cnt++); +	p=malloc(strlen(pidbuf)+strlen(timebuf) +strlen(cntbuf)+20); +	sprintf(p, "=_%s_%s_%s_000", cntbuf, pidbuf, timebuf); +	return (p); +} + +/* Search for the boundary tag in a string buffer - this is the new message +** we're creating.  We should really look for the tag at the beginning of the +** line, however, the text is not yet linewrapped, besides, why make your +** life hard? +*/ + +int multipart_boundary_checks(const char *boundary, const char *msg) +{ +size_t	boundarylen=strlen(boundary); + +	while (*msg) +	{ +		if (msg[0] == '-' && msg[1] == '-' && msg[2] != '-' && +			strncasecmp(msg+2, boundary, boundarylen) == 0) +				return (-1); +		++msg; +	} +	return (0); +} + +/* Again, just look for it at the beginning of the line -- why make your +** life hard? */ + +int multipart_boundary_checkf(const char *boundary, FILE *f) +{ +size_t	boundarylen=strlen(boundary); +const char *line; + +	if (fseek(f, 0L, SEEK_SET) == -1) +	{ +		fclose(f); +		close(newdraftfd); +		enomem(); +	} + +	while ((line=maildir_readline(f)) != 0) +		if (line[0] == '-' && line[1] == '-' && +			strncasecmp(line+2, boundary, boundarylen) == 0) +				return (-1); +	return (0); +} + +/* ---------------------------------------------------------------------- */ + +/* Copy existing attachments into the new draft message */ + +/* multipart_boundary - determine if current draft has attachments */ + +static char	*newmsg_multipart_boundary(FILE *f, const char *msg) +{ +	char	*p=0; + +	do +	{ +		if (p)	free(p); +		p=multipart_boundary_create(); +	} while (multipart_boundary_checks(p, msg) +		 || (f && multipart_boundary_checkf(p, f))); +	return (p); +} + +static void	newmsg_copy_attachments(struct rfc2045 *rfcp, +					FILE *f, const char *boundary) +{ +struct	rfc2045 *p; +int	foundtextplain=0; + +	for (p=rfcp->firstpart; p; p=p->next) +	{ +		if (p->isdummy)	continue; +		if (!foundtextplain && HASTEXTPLAIN(p)) +		{	/* Previous version of this message */ + +			foundtextplain=1; +			continue; +		} +		maildir_writemsgstr(newdraftfd, "\n--"); +		maildir_writemsgstr(newdraftfd, boundary); +		maildir_writemsgstr(newdraftfd, "\n"); +		sentmsg_copy(f, p);	/* Reuse some code */ +	} +} | 
