diff options
Diffstat (limited to 'sqwebmail/mailfilter.c')
| -rw-r--r-- | sqwebmail/mailfilter.c | 694 | 
1 files changed, 694 insertions, 0 deletions
| diff --git a/sqwebmail/mailfilter.c b/sqwebmail/mailfilter.c new file mode 100644 index 0000000..c228061 --- /dev/null +++ b/sqwebmail/mailfilter.c @@ -0,0 +1,694 @@ +#include "config.h" +/* +*/ + +/* +** Copyright 2000-2010 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + +#include	"mailfilter.h" +#include	"sqwebmail.h" +#include	"maildir.h" +#include	"auth.h" +#include	"maildir/maildirmisc.h" +#include	"maildir/maildirfilter.h" +#include	"maildir/autoresponse.h" +#include	"numlib/numlib.h" +#include	"cgi/cgi.h" +#include	<string.h> +#include	<stdlib.h> +#include	<stdio.h> + +extern void list_folder(const char *); +extern void output_attrencoded(const char *); + +static const char *internal_err=0; + +static void clrfields() +{ +	cgi_put("currentfilternum", ""); +	cgi_put("rulename", ""); +	cgi_put("filtertype", ""); +	cgi_put("hasrecipienttype", ""); +	cgi_put("hasrecipientaddr", ""); +	cgi_put("headername", ""); +	cgi_put("headervalue", ""); +	cgi_put("headermatchtype", ""); +	cgi_put("action", ""); +	cgi_put("forwardaddy", ""); +	cgi_put("bouncemsg", ""); +	cgi_put("savefolder", ""); +	cgi_put("sizecompare", ""); +	cgi_put("bytecount", ""); +	cgi_put("continuefiltering", ""); +	cgi_put("autoresponse_choose", ""); +	cgi_put("autoresponse_dsn", ""); +	cgi_put("autoresponse_regexp", ""); +	cgi_put("autoresponse_dupe", ""); +	cgi_put("autoresponse_days", ""); +	cgi_put("autoresponse_from", ""); +	cgi_put("autoresponse_noquote", ""); +} + +void mailfilter_list() +{ +struct maildirfilter mf; +struct maildirfilterrule *r; +unsigned cnt; + +	memset(&mf, 0, sizeof(mf)); + +	if (maildir_filter_loadmaildirfilter(&mf, ".")) +	{ +		maildir_filter_freerules(&mf); +		return; +	} + +	for (cnt=0, r=mf.first; r; r=r->next, ++cnt) +	{ +		printf("<option value=\"%u\">", cnt); +		output_attrencoded(r->rulename); +		printf("</option>"); +	} +	maildir_filter_freerules(&mf); +} + +void mailfilter_init() +{ +const char *p; +unsigned n; +struct maildirfilter mf; +struct maildirfilterrule *r; + +	if (*cgi("import")) +	{ +		if (maildir_filter_importmaildirfilter(".")) +		{ +			printf("%s", getarg("BADIMPORT")); +			return; +		} +	} + +	if (*cgi("internalerr")) +	{ +	const char *p=internal_err; + +	if (*cgi("currentfilternum"))  +		printf("<input name=\"currentfilternum\"" +			" type=\"hidden\"" +			" value=\"%s\" />", cgi("currentfilternum")); +		if (p) +			printf("%s", getarg(p)); +	} +	internal_err=0; + +	if (*cgi("do.save")) +	{ +		if (maildir_filter_exportmaildirfilter(".") || +			maildir_filter_importmaildirfilter(".")) +			printf("%s", getarg("INTERNAL")); +		else +			printf("%s", getarg("UPDATED")); +		clrfields(); +	} + +	if (*cgi("do.add")) +		clrfields(); +	memset(&mf, 0, sizeof(mf)); + +	if (maildir_filter_loadmaildirfilter(&mf, ".")) +	{ +		maildir_filter_freerules(&mf); +		printf("%s", getarg("BADIMPORT")); +		return; +	} +	if (*(p=cgi("currentfilter")) == 0) +	{ +		maildir_filter_freerules(&mf); +		return; +	} +	n=atoi(p); + +	for (r=mf.first; n && r; r=r->next) +		--n; +	if (!r) +	{ +		maildir_filter_freerules(&mf); +		return; +	} + +	if (*cgi("do.moveup") && r) +	{ +		maildir_filter_ruleup(&mf, r); +		maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr()); +		clrfields(); +	} +	else if (*cgi("do.movedown") && r) +	{ +		maildir_filter_ruledown(&mf, r); +		maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr()); +		clrfields(); +	} +	else if (*cgi("do.delete") && r) +	{ +		maildir_filter_ruledel(&mf, r); +		maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr()); +		clrfields(); +	} +	else if (*cgi("do.edit")) +	{ +	static char *namebuf=0; +	static char *headernamebuf=0; +	static char *headervaluebuf=0; +	static char *actionbuf=0; +	char	numbuf[NUMBUFSIZE+1]; + +		printf("<input name=\"currentfilternum\"" +			" type=\"hidden\"" +			" value=\"%s\" />", p); + +		cgi_put("filtertype", +			r->type == startswith ||  +			r->type == endswith || +			r->type == contains ? +				r->flags & MFR_BODY ? "body":"header": +			r->type == hasrecipient +					? "hasrecipient": +			r->type == mimemultipart ? +				r->flags & MFR_DOESNOT ? +					"nothasmultipart": +					"hasmultipart": +			r->type == islargerthan ? "hassize": +			r->type == anymessage +					? "anymessage": +			r->type == textplain ? +				r->flags & MFR_DOESNOT ? +					"nothastextplain": +					"hastextplain":"" +				) ; + +		cgi_put("continuefiltering", +				r->flags & MFR_CONTINUE ? "1":""); + +		cgi_put("headermatch", +			r->type == startswith ? +				r->flags & MFR_DOESNOT ? "notstartswith":"startswith": +			r->type == endswith ? +				r->flags & MFR_DOESNOT ? "notendswith":"endswith": +			r->type == contains ? +				r->flags & MFR_DOESNOT ? "notcontains":"contains":""); + +		if (namebuf)	free(namebuf); +		p=r->rulename ? r->rulename:""; +		namebuf=malloc(strlen(p)+1); +		if (!namebuf)	enomem(); +		strcpy(namebuf, p); +		cgi_put("rulename", namebuf); + +		p=r->fieldname ? r->fieldname:""; +		if (r->type != startswith && +			r->type != endswith && +			r->type != contains)	p=""; +		if (r->flags & MFR_BODY)	p=""; + +		if (headernamebuf)	free(headernamebuf); +		headernamebuf=malloc(strlen(p)+1); +		if (!headernamebuf)	enomem(); +		strcpy(headernamebuf, p); +		cgi_put("headername", headernamebuf); + +		p=r->fieldvalue ? r->fieldvalue:""; +		if (r->type != startswith && +			r->type != endswith && +			r->type != contains && +			r->type != hasrecipient && +			r->type != islargerthan)	p=""; + +		if (r->type == islargerthan) +			p=libmail_str_size_t( atol(p)+( r->flags & MFR_DOESNOT ? 1:0), +				numbuf); + +		if (headervaluebuf)	free(headervaluebuf); + + + +		headervaluebuf=malloc(strlen(p)+1); +		if (!headervaluebuf)	enomem(); +		strcpy(headervaluebuf, p); + +		cgi_put("hasrecipientaddr", ""); +		cgi_put("headervalue", ""); +		cgi_put("bytecount", ""); +		cgi_put("sizecompare", ""); + +		cgi_put(r->type == hasrecipient ? "hasrecipientaddr": +			r->type == islargerthan ? "bytecount": +				"headervalue", headervaluebuf); + +		if (r->type == hasrecipient) +			cgi_put("hasrecipienttype", +				r->flags & MFR_DOESNOT ? "nothasrecipient": +					"hasrecipient"); +		if (r->type == islargerthan) +			cgi_put("sizecompare", +				r->flags & MFR_DOESNOT +					? "issmallerthan":"islargerthan"); +		if (actionbuf)	actionbuf=0; +		p=r->tofolder; +		if (!p)	p=""; +		actionbuf=malloc(strlen(p)+1); +		if (!actionbuf)	enomem(); +		strcpy(actionbuf, p); + +		cgi_put("bouncemsg", ""); +		cgi_put("forwardaddy", ""); +		cgi_put("savefolder", ""); + +		cgi_put("autoresponse_regexp", +			r->flags & MFR_PLAINSTRING ? "":"1"); + +		if (actionbuf[0] == '!') +		{ +			cgi_put("action", "forwardto"); +			cgi_put("forwardaddy", actionbuf+1); +		} +		else if (actionbuf[0] == '*') +		{ +			cgi_put("action", "bounce"); +			cgi_put("bouncemsg", actionbuf+1); +		} +		else if (actionbuf[0] == '+') +		{ +			struct maildir_filter_autoresp_info mfai; +			static char *autoresp_name_buf=0; +			static char days_buf[NUMBUFSIZE]; +			static char *fromhdr=0; + +			if (maildir_filter_autoresp_info_init_str(&mfai, actionbuf+1)) +				enomem(); + +			if (autoresp_name_buf) +				free(autoresp_name_buf); + +			if ((autoresp_name_buf=strdup(mfai.name)) == NULL) +				enomem(); + +			cgi_put("action", "autoresponse"); +			cgi_put("autoresponse_choose", autoresp_name_buf); +			cgi_put("autoresponse_dsn", +				mfai.dsnflag ? "1":""); +			 +			cgi_put("autoresponse_dupe", +				mfai.days > 0 ? "1":""); + +			libmail_str_size_t(mfai.days, days_buf); +			cgi_put("autoresponse_days", mfai.days ? +				days_buf:""); +			maildir_filter_autoresp_info_free(&mfai); + +			if (fromhdr) +				free(fromhdr); +			fromhdr=strdup(r->fromhdr ? r->fromhdr:""); +			if (!fromhdr) +				enomem(); +			cgi_put("autoresponse_from", fromhdr); + +			if (mfai.noquote) +				cgi_put("autoresponse_noquote", "1"); +		} +		else if (strcmp(actionbuf, "exit") == 0) +		{ +			cgi_put("action", "purge"); +		} +		else +		{ +			cgi_put("action", "savefolder"); +			cgi_put("savefolder", +				strcmp(actionbuf, ".") == 0 ? INBOX: +				*actionbuf == '.' ? actionbuf+1:actionbuf); +		} +	} +	else if (*(p=cgi("currentfilternum")) != 0) +	{ +		printf("<input name=\"currentfilternum\"" +			" type=\"hidden\"" +			" value=\"%s\" />", p); +	} +	 +	 + +	maildir_filter_freerules(&mf); +} + +void mailfilter_listfolders() +{ +char	**folders; +int	i; +const char *f=cgi("savefolder"); + +	printf("<select name=\"savefolder\">"); + +	maildir_listfolders(INBOX, ".", &folders); + +	for (i=0; folders[i]; i++) +	{ +		const char *p=folders[i]; +		int selected=0; + +		if (strcmp(p, INBOX) && +		    strncmp(p, INBOX ".", sizeof(INBOX))) +			continue; + +		printf("<option value=\""); +		output_attrencoded(p); +		if (strcmp(p, f) == 0) +			selected=1; + +		if (strcmp(p, INBOX) == 0) +		{ +			p=getarg("INBOX"); +			selected=0; +			if (strcmp(f, ".") == 0) +				selected=1; +		} +		else if (strcmp(p, INBOX "." DRAFTS) == 0) +			p=getarg("DRAFTS"); +		else if (strcmp(p, INBOX "." TRASH) == 0) +			p=getarg("TRASH"); +		else if (strcmp(p, INBOX "." SENT) == 0) +			p=getarg("SENT"); +		else +			p=strchr(p, '.')+1; + +		printf("\""); +		if (selected) +			printf(" selected='selected'"); +		printf(">"); +		list_folder(p); +		printf("</option>\n"); +	} + +	maildir_freefolders(&folders); +	printf("</select>"); +} + +void mailfilter_submit() +{ +struct maildirfilter mf; +struct maildirfilterrule *r; +const char *p; +enum maildirfiltertype type; +int flags=0; +const char *rulename=0; +const char *fieldname=0; +const char *fieldvalue=0; +char *tofolder=0; +char *fieldname_cpy; +int	err_num; +char	numbuf[NUMBUFSIZE]; +const char *autoreply_from=""; + +	memset(&mf, 0, sizeof(mf)); +	if (maildir_filter_loadmaildirfilter(&mf, ".")) +	{ +		maildir_filter_freerules(&mf); +		return; +	} + +	r=0; +	p=cgi("currentfilternum"); +	if (*p) +	{ +	unsigned n=atoi(p); + +		for (r=mf.first; r && n; r=r->next) +			--n; +	} + +	rulename=cgi("rulename"); + +	p=cgi("filtertype"); +	if (strcmp(p, "hasrecipient") == 0) +	{ +		type=hasrecipient; +		if (strcmp(cgi("hasrecipienttype"), "nothasrecipient") == 0) +			flags |= MFR_DOESNOT; + +		fieldvalue=cgi("hasrecipientaddr"); +	} +	else if (strcmp(p, "hastextplain") == 0) +	{ +		type=textplain; +	} +	else if (strcmp(p, "nothastextplain") == 0) +	{ +		type=textplain; +		flags |= MFR_DOESNOT; +	} +	else if (strcmp(p, "hasmultipart") == 0) +	{ +		type=mimemultipart; +	} +	else if (strcmp(p, "nothasmultipart") == 0) +	{ +		type=mimemultipart; +		flags |= MFR_DOESNOT; +	} +	else if (strcmp(p, "hassize") == 0) +	{ +	unsigned long n=atol(cgi("bytecount")); + +		type=islargerthan; +		if (strcmp(cgi("sizecompare"), "issmallerthan") == 0) +		{ +			flags |= MFR_DOESNOT; +			if (n)	--n; +		} +		fieldvalue=libmail_str_size_t(n, numbuf); +	} +	else if (strcmp(p, "anymessage") == 0) +	{ +		type=anymessage; +	} +	else +	{ +		if (strcmp(p, "body") == 0) +			flags |= MFR_BODY; + +		fieldname=cgi("headername"); +		p=cgi("headermatchtype"); +		type=strcmp(p, "startswith") == 0 || +			strcmp(p, "notstartswith") == 0 ? startswith: +			strcmp(p, "contains") == 0 || +			strcmp(p, "notcontains") == 0 ? contains:endswith; +		if (strncmp(p, "not", 3) == 0) +			flags |= MFR_DOESNOT; +		fieldvalue=cgi("headervalue"); +	} + +	if (*cgi("continuefiltering")) +		flags |= MFR_CONTINUE; + +	if (!*cgi("autoresponse_regexp")) +		flags |= MFR_PLAINSTRING; + +	p=cgi("action"); +	if (strcmp(p, "forwardto") == 0) +	{ +		p=cgi("forwardaddy"); +		tofolder=malloc(strlen(p)+2); +		if (!tofolder)	enomem(); +		strcat(strcpy(tofolder, "!"), p); +	} +	else if (strcmp(p, "bounce") == 0) +	{ +		p=cgi("bouncemsg"); +		tofolder=malloc(strlen(p)+2); +		if (!tofolder)	enomem(); +		strcat(strcpy(tofolder, "*"), p); +	} +	else if (strcmp(p, "autoresponse") == 0) +	{ +		struct maildir_filter_autoresp_info mfaii; +		char *q; + +		p=cgi("autoresponse_choose"); + +		if (maildir_filter_autoresp_info_init(&mfaii, p)) +		{ +			internal_err="AUTOREPLY"; +			cgi_put("internal_err", "1"); +			return; +		} + +		p=cgi("autoresponse_dsn"); + +		if (*p) +			mfaii.dsnflag=1; + +		p=cgi("autoresponse_dupe"); +		if (*p) +		{ +			p=cgi("autoresponse_days"); +			mfaii.days=atoi(p); +		} + +		p=cgi("autoresponse_noquote"); + +		if (*p) +			mfaii.noquote=1; + +		q=maildir_filter_autoresp_info_asstr(&mfaii); +		maildir_filter_autoresp_info_free(&mfaii); + +		if (!q) +			enomem(); + +		if (!(tofolder=malloc(strlen(q)+2))) +		{ +			free(q); +			enomem(); +		} + +		tofolder[0]='+'; +		strcpy(tofolder+1, q); +		free(q); +		autoreply_from=cgi("autoresponse_from"); +	} +	else if (strcmp(p, "purge") == 0) +	{ +		tofolder = strdup("exit"); +		if (!tofolder) enomem(); +	} +	else +	{ +		tofolder=strdup(cgi("savefolder")); +		if (!tofolder)	enomem(); +	} + +	fieldname_cpy=NULL; + +	if (fieldname) +	{ +		char *p; + +		fieldname_cpy=strdup(fieldname); + +		p=strrchr(fieldname_cpy, ':'); + +		if (p && p[1] == 0) +			*p=0; +	} + +	if (!r) +		r=maildir_filter_appendrule(&mf, rulename, type, flags, fieldname_cpy, +			fieldvalue, tofolder, autoreply_from, &err_num); +	else if (maildir_filter_ruleupdate(&mf, r, rulename, type, flags, fieldname_cpy, +			fieldvalue, tofolder, autoreply_from, &err_num)) +		r=0; +	free(tofolder); +	if (fieldname_cpy) +		free(fieldname_cpy); +	if (r) +	{ +		maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr()); +		maildir_filter_freerules(&mf); +		clrfields(); +		return; +	} +	maildir_filter_freerules(&mf); + +	internal_err="INTERNAL"; +	if (err_num == MF_ERR_BADRULENAME) +		internal_err= "BADRULENAME"; +	if (err_num == MF_ERR_EXISTS) +		internal_err= "EXISTS"; +	if (err_num == MF_ERR_BADRULEHEADER) +		internal_err= "BADHEADER"; +	if (err_num == MF_ERR_BADRULEVALUE) +		internal_err= "BADVALUE"; +	if (err_num == MF_ERR_BADRULEFOLDER) +		internal_err= "ERRTOFOLDER"; +	if (err_num == MF_ERR_BADFROMHDR) +		internal_err= "FROMHDR"; + +	cgi_put("internalerr", "1"); +} + +int mailfilter_folderused(const char *foldername) +{ +struct maildirfilter mf; +struct maildirfilterrule *r; +int	rc; + +	memset(&mf, 0, sizeof(mf)); +	if (maildir_filter_hasmaildirfilter(".") || +		maildir_filter_importmaildirfilter("."))	return (0); + +	rc=maildir_filter_loadmaildirfilter(&mf, "."); +	maildir_filter_endmaildirfilter("."); +	if (rc) +	{ +		maildir_filter_freerules(&mf); +		return (0); +	} + +	for (r=mf.first; r; r=r->next) +	{ +		if (r->tofolder == 0)	continue; +		if (strcmp(foldername, r->tofolder) == 0) +		{ +			maildir_filter_freerules(&mf); +			return (-1); +		} +	} +	maildir_filter_freerules(&mf); +	return (0); +} + +int mailfilter_autoreplyused(const char *autoreply) +{ +	struct maildirfilter mf; +	struct maildirfilterrule *r; +	int	rc; + +	memset(&mf, 0, sizeof(mf)); +	if (maildir_filter_hasmaildirfilter(".") || +	    maildir_filter_importmaildirfilter("."))	return (0); + +	rc=maildir_filter_loadmaildirfilter(&mf, "."); +	maildir_filter_endmaildirfilter("."); +	if (rc) +	{ +		maildir_filter_freerules(&mf); +		return (0); +	} + +	for (r=mf.first; r; r=r->next) +	{ +		struct maildir_filter_autoresp_info mfai; + +		if (r->tofolder == 0)	continue; +		if (r->tofolder[0] != '+') +			continue; + +		if (maildir_filter_autoresp_info_init_str(&mfai, r->tofolder+1)) +			enomem(); + +		if (strcmp(autoreply, mfai.name) == 0) +		{ +			maildir_filter_autoresp_info_free(&mfai); +			maildir_filter_freerules(&mf); +			return (-1); +		} +		maildir_filter_autoresp_info_free(&mfai); +	} +	maildir_filter_freerules(&mf); +	return (0); +} + +void mailfilter_cleanup() +{ +	internal_err=0; +} | 
