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 /maildrop/filter.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 'maildrop/filter.C')
| -rw-r--r-- | maildrop/filter.C | 260 | 
1 files changed, 260 insertions, 0 deletions
| diff --git a/maildrop/filter.C b/maildrop/filter.C new file mode 100644 index 0000000..373eb47 --- /dev/null +++ b/maildrop/filter.C @@ -0,0 +1,260 @@ +/* +** Copyright 1998 - 2006 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#include	"funcs.h" +#include	"message.h" +#include	"messageinfo.h" +#include	"mio.h" +#include	"pipefds.h" +#include	"formatmbox.h" +#include	"xconfig.h" +#include	"varlist.h" +#include	"maildrop.h" +#include	"config.h" +#include	<sys/types.h> +#if HAVE_SYS_STAT_H +#include	<sys/stat.h> +#endif +#include	"mywait.h" +#include	"mytime.h" +#include	<signal.h> +#include	<errno.h> +#if	HAVE_STRINGS_H +#include	<strings.h> +#endif + + +/////////////////////////////////////////////////////////////////////////// +// +//  Filter message through an external command. +// +/////////////////////////////////////////////////////////////////////////// + +int xfilter(const char *, int); + +int filter(const char *filtercmd) +{ +	try +	{ +	int	rc=xfilter(filtercmd, 0); + +		if (rc == 0) +		{ +		Message	*ptr=maildrop.savemsgptr; + +			maildrop.savemsgptr=maildrop.msgptr; +			maildrop.msgptr=ptr; +			maildrop.msgptr->setmsgsize(); +			maildrop.msginfo.filtered(); +		} +		maildrop.savemsgptr->Init(); +		return(rc); +	} +	catch (...) +	{ +		maildrop.savemsgptr->Init(); +		throw; +	} +} + +int xfilter(const char *filtercmd, int ignorewerr) +{ +FormatMbox	format_mbox; +char	buffer[1024]; + +	maildrop.savemsgptr->Init(); + +//	if (format_mbox.HasMsg())	return (0);	// Empty +	(void)format_mbox.HasMsg(); + +Buffer	cmdbuf; + +	cmdbuf= filtercmd; +	cmdbuf += '\0'; + +PipeFds	pipe0, pipe1; + +	if (pipe0.Pipe() < 0 || pipe1.Pipe() < 0) +		throw "Cannot create pipe."; + +pid_t	pid=fork(); + +	if (pid < 0) +		throw "Cannot fork."; + +	if (pid == 0) +	{ +		try +		{ +			pipe0.close1(); +			pipe1.close0(); +			dup2(pipe0.fds[0], 0); +			pipe0.close0(); +			dup2(pipe1.fds[1], 1); +			pipe1.close1(); +			subshell(filtercmd); +		} +		catch (const char *p) +		{ +			if (write(2, p, strlen(p)) < 0 || +			    write(2, "\n", 1) < 0) +				; /* ignore */  +			_exit(100); +		} +#if NEED_NONCONST_EXCEPTIONS +		catch (char *p) +		{ +			if (write(2, p, strlen(p)) < 0 || +			    write(2, "\n", 1) < 0) +				; /* ignore */ +			_exit(100); +		} +#endif +		catch (...) +		{ +			_exit(101); +		} +	} + +	pipe0.close0(); +	pipe1.close1(); + +	format_mbox.Init(0); + +////////////////////////////////////////////////////////////////////////// +// +// Write message contents to the subprocess.  Simultaneously read process's +// output, and save it.  This is done simultaneously, via select() call. +// +////////////////////////////////////////////////////////////////////////// + +const	char	*writebufptr=0; +int		writebuflen=0; + +fd_set	readfd, writefd; + +	FD_ZERO(&readfd); +	FD_ZERO(&writefd); + +int	errflag=0; +int	maxfd=pipe1.fds[0]; + +	if (pipe0.fds[1] > maxfd) +		maxfd=pipe0.fds[1]; +	++maxfd; + +	fcntl(pipe1.fds[0], F_SETFL, O_NDELAY); +	fcntl(pipe0.fds[1], F_SETFL, O_NDELAY); + +	for (;;) +	{ +		FD_SET(pipe1.fds[0], &readfd); +		if (pipe0.fds[1] >= 0) +			FD_SET(pipe0.fds[1], &writefd); + +		if (!writebuflen && pipe0.fds[1] >= 0) +		{		// Need more to write. +		Buffer	*p=format_mbox.NextLine(); + +			if (!p) +			{ +				FD_CLR(pipe0.fds[1], &writefd); +				pipe0.close1();	// End of msg. +			} +			else +			{ +				writebufptr= *p; +				writebuflen= p->Length(); +			} +		} + +	int	n=select(maxfd, &readfd, &writefd, NULL, NULL); + +		if (n < 0) +		{ +			if (errno != EINTR) +				throw "maildrop: select() error."; +			continue; +		} + +		if (pipe0.fds[1] >= 0 && FD_ISSET(pipe0.fds[1], &writefd)) +		{ +		int	n= ::write(pipe0.fds[1], writebufptr, writebuflen); + +			if (n < 0) +			{ +				if (errno != EINTR)	// Perfectly OK +				{ +					FD_CLR(pipe0.fds[1], &writefd); +					pipe0.close1(); +					writebuflen=0; +					if (!ignorewerr) +					{ +						merr << "maildrop: error writing to filter.\n"; +						errflag=1; +						break; +					} +				} +			} +			else +			{ +				writebufptr += n; +				writebuflen -= n; +			} +		} + +		if (FD_ISSET(pipe1.fds[0], &readfd)) +		{ +		int	readbuflen=::read(pipe1.fds[0], buffer, sizeof(buffer)); + +			if (readbuflen < 0) +			{ +				if (errno != EINTR) +				{ +					merr << "maildrop: error reading from filter.\n"; +					errflag=1; +					break; +				} +				continue; +			} +			if (readbuflen == 0)	// FILTERED +			{ +				if ( (pipe0.fds[1] >= 0) && (!ignorewerr) ) +				{ +					merr << "maildrop: filter terminated prematurely.\n"; +					errflag=1;	// Not everything +					break;		// was written, though. +				} +				break; +			} + +			maildrop.savemsgptr->Init(buffer, readbuflen); +		} +	} + +	pipe0.close1(); +	pipe1.close0(); + +int	wait_stat; + +	while (wait(&wait_stat) != pid) +		; +	wait_stat= WIFEXITED(wait_stat) ? WEXITSTATUS(wait_stat):-1; + +	if (!wait_stat && errflag) +		wait_stat= -1; + +	{ +	Buffer	name, val; + +		val.append( (unsigned long)wait_stat); +		name="RETURNCODE"; +		SetVar(name, val); +	} + +	if (wait_stat) +		return (-1); +	return (0); +} | 
