diff options
Diffstat (limited to 'maildrop/deliver.C')
| -rw-r--r-- | maildrop/deliver.C | 292 | 
1 files changed, 292 insertions, 0 deletions
diff --git a/maildrop/deliver.C b/maildrop/deliver.C new file mode 100644 index 0000000..82d3108 --- /dev/null +++ b/maildrop/deliver.C @@ -0,0 +1,292 @@ +/* +** Copyright 1998 - 2008 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#include	"config.h" +#include	"funcs.h" +#include	"deliverdotlock.h" +#include	"mio.h" +#include	"formatmbox.h" +#include	"xconfig.h" +#include	"varlist.h" +#include	"pipefds.h" +#include	"log.h" +#include	"exittrap.h" +#include	"maildir.h" +#include	"filelock.h" +#include	"setgroupid.h" +#include	<sys/types.h> +#if HAVE_SYS_STAT_H +#include	<sys/stat.h> +#endif +#if HAVE_SYS_FILE_H +#include	<sys/file.h> +#endif +#include	"mywait.h" +#include	<signal.h> +#include	<stdlib.h> +#include	<stdio.h> +#if HAVE_FCNTL_H +#include	<fcntl.h> +#endif +#if HAVE_UNISTD_H +#include	<unistd.h> +#endif +#include	<errno.h> + + +/////////////////////////////////////////////////////////////////////////// +// +//  Deliver to a mailbox, a file, or a maildir. +// +//  If there was a delivery error, error message is printed, and we +//  return -1. +// +//  If delivery was succesfull, 0 is returned. +// +/////////////////////////////////////////////////////////////////////////// + +int delivery(const char *mailbox) +{ +FormatMbox	format_mbox; + +	if (format_mbox.HasMsg())	return (0); + +DeliverDotLock	dotlock; +Buffer	b; + +	if ( *mailbox == '!' || *mailbox == '|' ) +	{ +	Buffer	cmdbuf; + +		if (*mailbox == '!') +		{ +			b="SENDMAIL"; + +		const char *sendmail=GetVarStr(b); + +			cmdbuf=sendmail; + +			cmdbuf += " -f '' "; +			cmdbuf += mailbox+1; +		} +		else +			cmdbuf= mailbox+1; + +		cmdbuf += '\0'; + +		if (VerboseLevel() > 0) +			merr << "maildrop: Delivering to |" << +				(const char *)cmdbuf << "\n"; + +	PipeFds	pipe; + +		if (pipe.Pipe()) +			throw "Cannot create pipe."; + +	pid_t	pid=fork(); + +		if (pid < 0) +			throw "Cannot fork."; + +		if (pid == 0) +		{ +			pipe.close1(); +			dup2(pipe.fds[0], 0); +			pipe.close0(); + +			try +			{ +				subshell(cmdbuf); +			} +			catch (const char *p) +			{ +				if (write(2, p, strlen(p)) < 0 || +				    write(2, "\n", 1) < 0) +					; /* ignored */ +				_exit(100); +			} +#if NEED_NONCONST_EXCEPTIONS +			catch (char *p) +			{ +				if (write(2, p, strlen(p)) < 0 || +				    write(2, "\n", 1) < 0) +					; /* ignored */ +				_exit(100); +			} +#endif +			catch (...) +			{ +				_exit(100); +			} +		} + +	Mio	pipemio; + +		pipe.close0(); +		pipemio.fd(pipe.fds[1]); +		pipe.fds[1]= -1; +		format_mbox.Init(0); + +	int	rc=format_mbox.DeliverTo(pipemio); +	int	wait_stat; + +		while (wait(&wait_stat) != pid) +			; + +		if (wait_stat == 0) +			rc=0; + +		log(mailbox, rc || wait_stat, format_mbox); + +		{ +		Buffer	name, val; + +			if (rc)	wait_stat= -1; +			else wait_stat= WIFEXITED(wait_stat) +				? WEXITSTATUS(wait_stat):-1; + +			val.append( (unsigned long)wait_stat); +			name="EXITCODE"; +			SetVar(name, val); +		} + +		if (rc)	return (-1); +	} +	else if (Maildir::IsMaildir(mailbox)) +	{ +	Maildir	deliver_maildir; +	Mio	deliver_file; + +		if ( deliver_maildir.MaildirOpen(mailbox, deliver_file, +			maildrop.msgptr->MessageSize()) < 0) +		{ +#if HAVE_COURIER +			throw 75; +#else +			throw 77; +#endif +		} + +		format_mbox.Init(0); +		if (format_mbox.DeliverTo(deliver_file)) +		{ +			log(mailbox, -1, format_mbox); +			return (-1); +		} +		deliver_maildir.MaildirSave(); +		log(mailbox, 0, format_mbox); +	} +	else		// Delivering to a mailbox (hopefully) +	{ +		if (VerboseLevel() > 0) +			merr << "maildrop: Delivering to " << mailbox << "\n"; + +#if	USE_DOTLOCK +		dotlock.LockMailbox(mailbox); +#endif + +		struct	stat	stat_buf; +		Mio	mio; +		Buffer name_buf; + +		name_buf="UMASK"; +		const char *um=GetVarStr(name_buf); +		unsigned int umask_val=077; + +		sscanf(um, "%o", &umask_val); + +		umask_val=umask(umask_val); + +		if (mio.Open(mailbox, O_CREAT | O_WRONLY, 0666) < 0) +		{ +			umask_val=umask(umask_val); +			throw "Unable to open mailbox."; +		} +		umask_val=umask(umask_val); + +		if (fstat(mio.fd(), &stat_buf) < 0) +			throw "Unable to open mailbox."; + +#if	USE_FLOCK + +		if (VerboseLevel() > 4) +			merr << "maildrop: Flock()ing " << mailbox << ".\n"; + +		FileLock::do_filelock(mio.fd()); +#endif +		if (S_ISREG(stat_buf.st_mode)) +		{ +			if (mio.seek(0L, SEEK_END) < 0) +				throw "Seek error on mailbox."; +			dotlock.trap_truncate(mio.fd(), stat_buf.st_size); +		} + +		if (VerboseLevel() > 4) +			merr << "maildrop: Appending to " << mailbox << ".\n"; + +		try +		{ +			format_mbox.Init(1); + +			if ((stat_buf.st_size > 0 && +			     mio.write( +#if	CRLF_TERM +				       "\r\n", 2 +#else +				       "\n", 1 +#endif +				       ) < 0) || +			    format_mbox.DeliverTo(mio)) +			{ +				dotlock.truncate(); +				log(mailbox, -1, format_mbox); +				return (-1); +			} +		} +		catch (...) +		{ +			dotlock.truncate(); +			log(mailbox, -1, format_mbox); +			throw; +		} +		log(mailbox, 0, format_mbox); +	} + +	if (VerboseLevel() > 4) +		merr << "maildrop: Delivery complete.\n"; + +	return (0); +} + +void	subshell(const char *cmd) +{ +Buffer	b; + +	b="SHELL"; + +const char *shell=GetVarStr(b); + +const char *p, *q; + +	for (p=q=shell; *p; p++) +		if (*p == SLASH_CHAR)	q=p+1; + +char	**env=ExportEnv(); + +int	n; + +	for (n=0; n<NSIG; n++) +		signal(n, SIG_DFL); + +	setgroupid(getgid());	// Just in case. +	setuid(getuid()); +	ExitTrap::onfork(); +	execle(shell, q, "-c", cmd, (const char *)0, env); +	if (write (2, "Unable to execute ", 18) < 0 || +	    write (2, shell, strlen(shell)) < 0 || +	    write (2, "\n", 1) < 0) +		; /* ignored */ +	_exit(100); +}  | 
