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

📄 deliver.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
 * Copyright (c) 1988, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 */

#ifndef lint
static char id[] = "@(#)$Id: deliver.c,v 8.600.2.1.2.44 2000/09/21 21:52:17 ca Exp $";
#endif /* ! lint */

#include <sendmail.h>


#if HASSETUSERCONTEXT
# include <login_cap.h>
#endif /* HASSETUSERCONTEXT */

#if STARTTLS || (SASL && SFIO)
# include "sfsasl.h"
#endif /* STARTTLS || (SASL && SFIO) */

static int	deliver __P((ENVELOPE *, ADDRESS *));
static void	dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
static void	mailfiletimeout __P((void));
static void	markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
static int	parse_hostsignature __P((char *, char **, MAILER *));
static void	sendenvelope __P((ENVELOPE *, int));
static char	*hostsignature __P((MAILER *, char *));

#if SMTP
# if STARTTLS
static int	starttls __P((MAILER *, MCI *, ENVELOPE *));
# endif /* STARTTLS */
#endif /* SMTP */

/*
**  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.
*/

void
sendall(e, mode)
	ENVELOPE *e;
	int mode;
{
	register ADDRESS *q;
	char *owner;
	int otherowners;
	int save_errno;
	register ENVELOPE *ee;
	ENVELOPE *splitenv = NULL;
	int oldverbose = Verbose;
	bool somedeliveries = FALSE, expensive = FALSE;
	pid_t pid;

	/*
	**  If this message is to be discarded, don't bother sending
	**  the message at all.
	*/

	if (bitset(EF_DISCARD, e->e_flags))
	{
		if (tTd(13, 1))
			dprintf("sendall: discarding id %s\n", e->e_id);
		e->e_flags |= EF_CLRQUEUE;
		if (LogLevel > 4)
			sm_syslog(LOG_INFO, e->e_id, "discarded");
		markstats(e, NULL, TRUE);
		return;
	}

	/*
	**  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 */
	if (mode == SM_DEFAULT)
	{
		mode = e->e_sendmode;
		if (mode != SM_VERIFY && mode != SM_DEFER &&
		    shouldqueue(e->e_msgpriority, e->e_ctime))
			mode = SM_QUEUE;
	}

	if (tTd(13, 1))
	{
		dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
			mode, e->e_id);
		printaddr(&e->e_from, FALSE);
		dprintf("\te_flags = ");
		printenvflags(e);
		dprintf("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 (tTd(62, 1))
		checkfds(NULL);

	if (e->e_hopcount > MaxHopCount)
	{
		errno = 0;
#if QUEUE
		queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
#endif /* QUEUE */
		e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
		ExitStat = EX_UNAVAILABLE;
		syserr("554 5.0.0 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);
		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
		{
			if (QS_IS_DEAD(q->q_state))
				continue;
			q->q_state = QS_BADADDR;
			q->q_status = "5.4.6";
		}
		return;
	}

	/*
	**  Do sender deletion.
	**
	**	If the sender should be queued up, 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) &&
	    !QS_IS_QUEUEUP(e->e_from.q_state))
	{
		if (tTd(13, 5))
		{
			dprintf("sendall: QS_SENDER ");
			printaddr(&e->e_from, FALSE);
		}
		e->e_from.q_state = QS_SENDER;
		(void) recipient(&e->e_from, &e->e_sendqueue, 0, 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 &&
		    !QS_IS_DEAD(q->q_state) &&
		    strcmp(q->q_owner, e->e_from.q_paddr) == 0)
			q->q_owner = NULL;
	}

	if (tTd(13, 25))
	{
		dprintf("\nAfter first owner pass, sendq =\n");
		printaddr(e->e_sendqueue, TRUE);
	}

	owner = "";
	otherowners = 1;
	while (owner != NULL && otherowners > 0)
	{
		if (tTd(13, 28))
			dprintf("owner = \"%s\", otherowners = %d\n",
				owner, otherowners);
		owner = NULL;
		otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;

		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
		{
			if (tTd(13, 30))
			{
				dprintf("Checking ");
				printaddr(q, FALSE);
			}
			if (QS_IS_DEAD(q->q_state))
			{
				if (tTd(13, 30))
					dprintf("    ... QS_IS_DEAD\n");
				continue;
			}
			if (tTd(13, 29) && !tTd(13, 30))
			{
				dprintf("Checking ");
				printaddr(q, FALSE);
			}

			if (q->q_owner != NULL)
			{
				if (owner == NULL)
				{
					if (tTd(13, 40))
						dprintf("    ... First owner = \"%s\"\n",
							q->q_owner);
					owner = q->q_owner;
				}
				else if (owner != q->q_owner)
				{
					if (strcmp(owner, q->q_owner) == 0)
					{
						if (tTd(13, 40))
							dprintf("    ... Same owner = \"%s\"\n",
								owner);

						/* make future comparisons cheap */
						q->q_owner = owner;
					}
					else
					{
						if (tTd(13, 40))
							dprintf("    ... Another owner \"%s\"\n",
								q->q_owner);
						otherowners++;
					}
					owner = q->q_owner;
				}
				else if (tTd(13, 40))
					dprintf("    ... Same owner = \"%s\"\n",
						owner);
			}
			else
			{
				if (tTd(13, 40))
					dprintf("    ... Null owner\n");
				otherowners++;
			}

			if (QS_IS_BADADDR(q->q_state))
			{
				if (tTd(13, 30))
					dprintf("    ... QS_IS_BADADDR\n");
				continue;
			}

			if (QS_IS_QUEUEUP(q->q_state))
			{
				MAILER *m = q->q_mailer;

				/*
				**  If we have temporary address failures
				**  (e.g., dns failure) and a fallback MX is
				**  set, send directly to the fallback MX host.
				*/

				if (FallBackMX != NULL &&
				    !wordinclass(FallBackMX, 'w') &&
				    mode != SM_VERIFY &&
				    (strcmp(m->m_mailer, "[IPC]") == 0 ||
				     strcmp(m->m_mailer, "[TCP]") == 0) &&
				    m->m_argv[0] != NULL &&
				    (strcmp(m->m_argv[0], "TCP") == 0 ||
				     strcmp(m->m_argv[0], "IPC") == 0))
				{
					int len;
					char *p;

					if (tTd(13, 30))
						dprintf("    ... FallBackMX\n");

					len = strlen(FallBackMX) + 3;
					p = xalloc(len);
					snprintf(p, len, "[%s]", FallBackMX);
					q->q_state = QS_OK;
					q->q_host = p;
				}
				else
				{
					if (tTd(13, 30))
						dprintf("    ... QS_IS_QUEUEUP\n");
					continue;
				}
			}

			/*
			**  If this mailer is expensive, and if we don't
			**  want to make connections now, just mark these
			**  addresses and return.  This is useful if we
			**  want to batch connections to reduce load.  This
			**  will cause the messages to be queued up, and a
			**  daemon will come along to send the messages later.
			*/

			if (NoConnect && !Verbose &&
			    bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
			{
				if (tTd(13, 30))
					dprintf("    ... expensive\n");
				q->q_state = QS_QUEUEUP;
				expensive = TRUE;
			}
			else if (bitnset(M_HOLD, q->q_mailer->m_flags) &&
				 QueueLimitId == NULL &&
				 QueueLimitSender == NULL &&
				 QueueLimitRecipient == NULL)
			{
				if (tTd(13, 30))
					dprintf("    ... hold\n");
				q->q_state = QS_QUEUEUP;
				expensive = TRUE;
			}
			else
			{
				if (tTd(13, 30))
					dprintf("    ... deliverable\n");
				somedeliveries = TRUE;
			}
		}

		if (owner != NULL && otherowners > 0)
		{
			/*
			**  Split this envelope into two.
			*/

			ee = (ENVELOPE *) xalloc(sizeof *ee);
			*ee = *e;
			ee->e_message = NULL;
			ee->e_id = NULL;
			assign_queueid(ee);

			if (tTd(13, 1))
				dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n",
					e->e_id, ee->e_id, owner, otherowners);

			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|EF_RET_PARAM);
			ee->e_flags |= EF_NORECEIPT;
			setsender(owner, ee, NULL, '\0', TRUE);
			if (tTd(13, 5))
			{
				dprintf("sendall(split): QS_SENDER ");
				printaddr(&ee->e_from, FALSE);
			}
			ee->e_from.q_state = QS_SENDER;
			ee->e_dfp = NULL;
			ee->e_lockfp = NULL;
			ee->e_xfp = NULL;
			ee->e_queuedir = e->e_queuedir;
			ee->e_errormode = EM_MAIL;
			ee->e_sibling = splitenv;
			ee->e_statmsg = NULL;
			splitenv = ee;

			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
			{
				if (q->q_owner == owner)
				{
					q->q_state = QS_CLONED;
					if (tTd(13, 6))
						dprintf("\t... stripping %s from original envelope\n",
							q->q_paddr);
				}
			}
			for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
			{
				if (q->q_owner != owner)
				{
					q->q_state = QS_CLONED;
					if (tTd(13, 6))
						dprintf("\t... dropping %s from cloned envelope\n",
							q->q_paddr);
				}
				else
				{
					/* clear DSN parameters */
					q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
					q->q_flags |= DefaultNotify & ~QPINGONSUCCESS;
					if (tTd(13, 6))
						dprintf("\t... moving %s to cloned envelope\n",
							q->q_paddr);
				}
			}

			if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
				dup_queue_file(e, ee, 'd');

			/*
			**  Give the split envelope access to the parent
			**  transcript file for errors obtained while
			**  processing the recipients (done before the
			**  envelope splitting).
			*/

			if (e->e_xfp != NULL)
				ee->e_xfp = bfdup(e->e_xfp);

			/* failed to dup e->e_xfp, start a new transcript */
			if (ee->e_xfp == NULL)
				openxscript(ee);

			if (mode != SM_VERIFY && LogLevel > 4)
				sm_syslog(LOG_INFO, ee->e_id,
					  "clone %s, owner=%s",
					  e->e_id, owner);
		}
	}

	if (owner != NULL)
	{
		setsender(owner, e, NULL, '\0', TRUE);
		if (tTd(13, 5))
		{
			dprintf("sendall(owner): QS_SENDER ");
			printaddr(&e->e_from, FALSE);
		}
		e->e_from.q_state = QS_SENDER;
		e->e_errormode = EM_MAIL;
		e->e_flags |= EF_NORECEIPT;
		e->e_flags &= ~EF_FATALERRS;
	}

	/* if nothing to be delivered, just queue up everything */
	if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER &&
	    mode != SM_VERIFY)
	{
		if (tTd(13, 29))
			dprintf("No deliveries: auto-queuing\n");
		mode = SM_QUEUE;

		/* treat this as a delivery in terms of counting tries */
		e->e_dtime = curtime();
		if (!expensive)
			e->e_ntries++;
		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
		{
			ee->e_dtime = curtime();
			if (!expensive)
				ee->e_ntries++;
		}
	}

#if QUEUE
	if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK ||
	     (mode != SM_VERIFY && SuperSafe)) &&
	    (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
	{
		/*
		**  Be sure everything is instantiated in the queue.
		**  Split envelopes first in case the machine crashes.
		**  If the original were done first, we may lose
		**  recipients.
		*/

		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
			queueup(ee, mode == SM_QUEUE || mode == SM_DEFER);
		queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
	}
#endif /* QUEUE */

	if (tTd(62, 10))
		checkfds("after envelope splitting");

	/*
	**  If we belong in background, fork now.
	*/

	if (tTd(13, 20))
	{
		dprintf("sendall: final mode = %c\n", mode);
		if (tTd(13, 21))
		{
			dprintf("\n================ Final Send Queue(s) =====================\n");
			dprintf("\n  *** Envelope %s, e_from=%s ***\n",
				e->e_id, e->e_from.q_paddr);
			printaddr(e->e_sendqueue, TRUE);
			for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
			{
				dprintf("\n  *** Envelope %s, e_from=%s ***\n",
					ee->e_id, ee->e_from.q_paddr);
				printaddr(ee->e_sendqueue, TRUE);
			}
			dprintf("==========================================================\n\n");
		}
	}
	switch (mode)
	{
	  case SM_VERIFY:
		Verbose = 2;
		break;

	  case SM_QUEUE:
	  case SM_DEFER:
#if HASFLOCK
  queueonly:
#endif /* HASFLOCK */
		if (e->e_nrcpts > 0)
			e->e_flags |= EF_INQUEUE;
		dropenvelope(e, splitenv != NULL);
		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
		{
			if (ee->e_nrcpts > 0)

⌨️ 快捷键说明

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