⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 deliver.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)deliver.c	8.82 (Berkeley) 4/18/94";#endif /* not lint */#include "sendmail.h"#include <netdb.h>#include <errno.h>#if NAMED_BIND#include <arpa/nameser.h>#include <resolv.h>extern int	h_errno;#endifextern char	SmtpError[];/***  SENDALL -- actually send all the messages.****	Parameters:**		e -- the envelope to send.**		mode -- the delivery mode to use.  If SM_DEFAULT, use**			the current e->e_sendmode.****	Returns:**		none.****	Side Effects:**		Scans the send lists and sends everything it finds.**		Delivers any appropriate error messages.**		If we are running in a non-interactive mode, takes the**			appropriate action.*/sendall(e, mode)	ENVELOPE *e;	char mode;{	register ADDRESS *q;	char *owner;	int otherowners;	register ENVELOPE *ee;	ENVELOPE *splitenv = NULL;	bool announcequeueup;	/*	**  If we have had global, fatal errors, don't bother sending	**  the message at all if we are in SMTP mode.  Local errors	**  (e.g., a single address failing) will still cause the other	**  addresses to be sent.	*/	if (bitset(EF_FATALERRS, e->e_flags) &&	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))	{		e->e_flags |= EF_CLRQUEUE;		return;	}	/* determine actual delivery mode */	CurrentLA = getla();	if (mode == SM_DEFAULT)	{		mode = e->e_sendmode;		if (mode != SM_VERIFY &&		    shouldqueue(e->e_msgpriority, e->e_ctime))			mode = SM_QUEUE;		announcequeueup = mode == SM_QUEUE;	}	else		announcequeueup = FALSE;	if (tTd(13, 1))	{		printf("\n===== SENDALL: mode %c, id %s, e_from ",			mode, e->e_id);		printaddr(&e->e_from, FALSE);		printf("sendqueue:\n");		printaddr(e->e_sendqueue, TRUE);	}	/*	**  Do any preprocessing necessary for the mode we are running.	**	Check to make sure the hop count is reasonable.	**	Delete sends to the sender in mailing lists.	*/	CurEnv = e;	if (e->e_hopcount > MaxHopCount)	{		errno = 0;		e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;		syserr("554 too many hops %d (%d max): from %s via %s, to %s",			e->e_hopcount, MaxHopCount, e->e_from.q_paddr,			RealHostName == NULL ? "localhost" : RealHostName,			e->e_sendqueue->q_paddr);		return;	}	/*	**  Do sender deletion.	**	**	If the sender has the QQUEUEUP flag set, skip this.	**	This can happen if the name server is hosed when you	**	are trying to send mail.  The result is that the sender	**	is instantiated in the queue as a recipient.	*/	if (!bitset(EF_METOO, e->e_flags) &&	    !bitset(QQUEUEUP, e->e_from.q_flags))	{		if (tTd(13, 5))		{			printf("sendall: QDONTSEND ");			printaddr(&e->e_from, FALSE);		}		e->e_from.q_flags |= QDONTSEND;		(void) recipient(&e->e_from, &e->e_sendqueue, e);	}	/*	**  Handle alias owners.	**	**	We scan up the q_alias chain looking for owners.	**	We discard owners that are the same as the return path.	*/	for (q = e->e_sendqueue; q != NULL; q = q->q_next)	{		register struct address *a;		for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias)			continue;		if (a != NULL)			q->q_owner = a->q_owner;						if (q->q_owner != NULL &&		    !bitset(QDONTSEND, q->q_flags) &&		    strcmp(q->q_owner, e->e_from.q_paddr) == 0)			q->q_owner = NULL;	}			owner = "";	otherowners = 1;	while (owner != NULL && otherowners > 0)	{		owner = NULL;		otherowners = 0;		for (q = e->e_sendqueue; q != NULL; q = q->q_next)		{			if (bitset(QDONTSEND, q->q_flags))				continue;			if (q->q_owner != NULL)			{				if (owner == NULL)					owner = q->q_owner;				else if (owner != q->q_owner)				{					if (strcmp(owner, q->q_owner) == 0)					{						/* make future comparisons cheap */						q->q_owner = owner;					}					else					{						otherowners++;					}					owner = q->q_owner;				}			}			else			{				otherowners++;			}		}		if (owner != NULL && otherowners > 0)		{			extern HDR *copyheader();			extern ADDRESS *copyqueue();			/*			**  Split this envelope into two.			*/			ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE));			*ee = *e;			ee->e_id = NULL;			(void) queuename(ee, '\0');			if (tTd(13, 1))				printf("sendall: split %s into %s\n",					e->e_id, ee->e_id);			ee->e_header = copyheader(e->e_header);			ee->e_sendqueue = copyqueue(e->e_sendqueue);			ee->e_errorqueue = copyqueue(e->e_errorqueue);			ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT);			ee->e_flags |= EF_NORECEIPT;			setsender(owner, ee, NULL, TRUE);			if (tTd(13, 5))			{				printf("sendall(split): QDONTSEND ");				printaddr(&ee->e_from, FALSE);			}			ee->e_from.q_flags |= QDONTSEND;			ee->e_dfp = NULL;			ee->e_xfp = NULL;			ee->e_df = NULL;			ee->e_errormode = EM_MAIL;			ee->e_sibling = splitenv;			splitenv = ee;						for (q = e->e_sendqueue; q != NULL; q = q->q_next)				if (q->q_owner == owner)				{					q->q_flags |= QDONTSEND;					q->q_flags &= ~QQUEUEUP;				}			for (q = ee->e_sendqueue; q != NULL; q = q->q_next)				if (q->q_owner != owner)				{					q->q_flags |= QDONTSEND;					q->q_flags &= ~QQUEUEUP;				}			if (e->e_df != NULL && mode != SM_VERIFY)			{				ee->e_dfp = NULL;				ee->e_df = queuename(ee, 'd');				ee->e_df = newstr(ee->e_df);				if (link(e->e_df, ee->e_df) < 0)				{					syserr("sendall: link(%s, %s)",						e->e_df, ee->e_df);				}			}#ifdef LOG			if (LogLevel > 4)				syslog(LOG_INFO, "%s: clone %s, owner=%s",					ee->e_id, e->e_id, owner);#endif		}	}	if (owner != NULL)	{		setsender(owner, e, NULL, TRUE);		if (tTd(13, 5))		{			printf("sendall(owner): QDONTSEND ");			printaddr(&e->e_from, FALSE);		}		e->e_from.q_flags |= QDONTSEND;		e->e_errormode = EM_MAIL;		e->e_flags |= EF_NORECEIPT;	}# ifdef QUEUE	if ((mode == SM_QUEUE || mode == SM_FORK ||	     (mode != SM_VERIFY && SuperSafe)) &&	    !bitset(EF_INQUEUE, e->e_flags))	{		/* be sure everything is instantiated in the queue */		queueup(e, TRUE, announcequeueup);		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)			queueup(ee, TRUE, announcequeueup);	}#endif /* QUEUE */	if (splitenv != NULL)	{		if (tTd(13, 1))		{			printf("\nsendall: Split queue; remaining queue:\n");			printaddr(e->e_sendqueue, TRUE);		}		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)		{			CurEnv = ee;			if (mode != SM_VERIFY)				openxscript(ee);			sendenvelope(ee, mode);			dropenvelope(ee);		}		CurEnv = e;	}	sendenvelope(e, mode);}sendenvelope(e, mode)	register ENVELOPE *e;	char mode;{	bool oldverbose;	int pid;	register ADDRESS *q;	char *qf;	char *id;	/*	**  If we have had global, fatal errors, don't bother sending	**  the message at all if we are in SMTP mode.  Local errors	**  (e.g., a single address failing) will still cause the other	**  addresses to be sent.	*/	if (bitset(EF_FATALERRS, e->e_flags) &&	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))	{		e->e_flags |= EF_CLRQUEUE;		return;	}	oldverbose = Verbose;	switch (mode)	{	  case SM_VERIFY:		Verbose = TRUE;		break;	  case SM_QUEUE:  queueonly:		e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;		return;	  case SM_FORK:		if (e->e_xfp != NULL)			(void) fflush(e->e_xfp);# if !HASFLOCK		/*		**  Since fcntl locking has the interesting semantic that		**  the lock is owned by a process, not by an open file		**  descriptor, we have to flush this to the queue, and		**  then restart from scratch in the child.		*/		/* save id for future use */		id = e->e_id;		/* now drop the envelope in the parent */		e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;		dropenvelope(e);		/* and reacquire in the child */		(void) dowork(id, TRUE, FALSE, e);		return;# else /* HASFLOCK */		pid = fork();		if (pid < 0)		{			goto queueonly;		}		else if (pid > 0)		{			/* be sure we leave the temp files to our child */			/* can't call unlockqueue to avoid unlink of xfp */			if (e->e_lockfp != NULL)				(void) xfclose(e->e_lockfp, "sendenvelope", "lockfp");			e->e_lockfp = NULL;			/* close any random open files in the envelope */			closexscript(e);			if (e->e_dfp != NULL)				(void) xfclose(e->e_dfp, "sendenvelope", e->e_df);			e->e_dfp = NULL;			e->e_id = e->e_df = NULL;			/* catch intermediate zombie */			(void) waitfor(pid);			return;		}		/* double fork to avoid zombies */		pid = fork();		if (pid > 0)			exit(EX_OK);		/* be sure we are immune from the terminal */		disconnect(1, e);		/* prevent parent from waiting if there was an error */		if (pid < 0)		{			e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;			finis();		}		/*		**  Close any cached connections.		**		**	We don't send the QUIT protocol because the parent		**	still knows about the connection.		**		**	This should only happen when delivering an error		**	message.		*/		mci_flush(FALSE, NULL);# endif /* HASFLOCK */		break;	}	/*	**  Run through the list and send everything.	**	**	Set EF_GLOBALERRS so that error messages during delivery	**	result in returned mail.	*/	e->e_nsent = 0;	e->e_flags |= EF_GLOBALERRS;	/* now run through the queue */	for (q = e->e_sendqueue; q != NULL; q = q->q_next)	{#ifdef XDEBUG		char wbuf[MAXNAME + 20];		(void) sprintf(wbuf, "sendall(%s)", q->q_paddr);		checkfd012(wbuf);#endif		if (mode == SM_VERIFY)		{			e->e_to = q->q_paddr;			if (!bitset(QDONTSEND|QBADADDR, q->q_flags))			{				if (q->q_host != NULL && q->q_host[0] != '\0')					message("deliverable: mailer %s, host %s, user %s",						q->q_mailer->m_name,						q->q_host,						q->q_user);				else					message("deliverable: mailer %s, user %s",						q->q_mailer->m_name,						q->q_user);			}		}		else if (!bitset(QDONTSEND|QBADADDR, q->q_flags))		{# ifdef QUEUE			/*			**  Checkpoint the send list every few addresses			*/			if (e->e_nsent >= CheckpointInterval)			{				queueup(e, TRUE, FALSE);				e->e_nsent = 0;			}# endif /* QUEUE */			(void) deliver(e, q);		}	}	Verbose = oldverbose;#ifdef XDEBUG	checkfd012("end of sendenvelope");#endif	if (mode == SM_FORK)		finis();}/***  DOFORK -- do a fork, retrying a couple of times on failure.****	This MUST be a macro, since after a vfork we are running**	two processes on the same stack!!!****	Parameters:**		none.****	Returns:**		From a macro???  You've got to be kidding!****	Side Effects:**		Modifies the ==> LOCAL <== variable 'pid', leaving:**			pid of child in parent, zero in child.**			-1 on unrecoverable error.****	Notes:**		I'm awfully sorry this looks so awful.  That's**		vfork for you.....*/# define NFORKTRIES	5# ifndef FORK# define FORK	fork# endif# define DOFORK(fORKfN) \{\	register int i;\\	for (i = NFORKTRIES; --i >= 0; )\	{\		pid = fORKfN();\		if (pid >= 0)\			break;\		if (i > 0)\			sleep((unsigned) NFORKTRIES - i);\	}\}/***  DOFORK -- simple fork interface to DOFORK.****	Parameters:**		none.****	Returns:**		pid of child in parent.**		zero in child.**		-1 on error.****	Side Effects:**		returns twice, once in parent and once in child.*/dofork(){	register int pid;	DOFORK(fork);	return (pid);}/***  DELIVER -- Deliver a message to a list of addresses.****	This routine delivers to everyone on the same host as the**	user on the head of the list.  It is clever about mailers**	that don't handle multiple users.  It is NOT guaranteed**	that it will deliver to all these addresses however -- so**	deliver should be called once for each address on the**	list.****	Parameters:**		e -- the envelope to deliver.**		firstto -- head of the address list to deliver to.****	Returns:**		zero -- successfully delivered.**		else -- some failure, see ExitStat for more info.****	Side Effects:**		The standard input is passed off to someone.*/deliver(e, firstto)	register ENVELOPE *e;	ADDRESS *firstto;{	char *host;			/* host being sent to */	char *user;			/* user being sent to */	char **pvp;	register char **mvp;	register char *p;	register MAILER *m;		/* mailer for this recipient */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -