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

📄 deliver.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
				ee->e_flags |= EF_INQUEUE;
			dropenvelope(ee, FALSE);
		}
		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 */
			char *qid = e->e_id;

			/* now drop the envelope in the parent */
			e->e_flags |= EF_INQUEUE;
			dropenvelope(e, splitenv != NULL);

			/* arrange to reacquire lock after fork */
			e->e_id = qid;
		}

		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
		{
			/* save id for future use */
			char *qid = ee->e_id;

			/* drop envelope in parent */
			ee->e_flags |= EF_INQUEUE;
			dropenvelope(ee, FALSE);

			/* and save qid for reacquisition */
			ee->e_id = qid;
		}

#endif /* !HASFLOCK */

		/*
		**  Since the delivery may happen in a child and the parent
		**  does not wait, the parent may close the maps thereby
		**  removing any shared memory used by the map.  Therefore,
		**  close the maps now so the child will dynamically open
		**  them if necessary.
		*/

		closemaps();

		pid = fork();
		if (pid < 0)
		{
			syserr("deliver: fork 1");
#if HASFLOCK
			goto queueonly;
#else /* HASFLOCK */
			e->e_id = NULL;
			for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
				ee->e_id = NULL;
			return;
#endif /* HASFLOCK */
		}
		else if (pid > 0)
		{
#if HASFLOCK
			/* be sure we leave the temp files to our child */
			/* close any random open files in the envelope */
			closexscript(e);
			if (e->e_dfp != NULL)
				(void) bfclose(e->e_dfp);
			e->e_dfp = NULL;
			e->e_flags &= ~EF_HAS_DF;

			/* can't call unlockqueue to avoid unlink of xfp */
			if (e->e_lockfp != NULL)
				(void) fclose(e->e_lockfp);
			else
				syserr("%s: sendall: null lockfp", e->e_id);
			e->e_lockfp = NULL;
#endif /* HASFLOCK */

			/* make sure the parent doesn't own the envelope */
			e->e_id = NULL;

			/* catch intermediate zombie */
			(void) waitfor(pid);
			return;
		}

		/*
		**  Since we have accepted responsbility for the message,
		**  change the SIGTERM handler.  intsig() (the old handler)
		**  would remove the envelope if this was a command line
		**  message submission.
		*/

		(void) setsignal(SIGTERM, SIG_DFL);

		/* double fork to avoid zombies */
		pid = fork();
		if (pid > 0)
			exit(EX_OK);
		save_errno = errno;

		/* be sure we are immune from the terminal */
		disconnect(2, e);
		clearstats();

		/* prevent parent from waiting if there was an error */
		if (pid < 0)
		{
			errno = save_errno;
			syserr("deliver: fork 2");
#if HASFLOCK
			e->e_flags |= EF_INQUEUE;
#else /* HASFLOCK */
			e->e_id = NULL;
#endif /* HASFLOCK */
			finis(TRUE, ExitStat);
		}

		/* be sure to give error messages in child */
		QuickAbort = FALSE;

		/*
		**  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);

#if HASFLOCK
		break;
#else /* HASFLOCK */

		/*
		**  Now reacquire and run the various queue files.
		*/

		for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
		{
			ENVELOPE *sibling = ee->e_sibling;

			(void) dowork(ee->e_queuedir, ee->e_id,
				      FALSE, FALSE, ee);
			ee->e_sibling = sibling;
		}
		(void) dowork(e->e_queuedir, e->e_id,
			      FALSE, FALSE, e);
		finis(TRUE, ExitStat);
#endif /* HASFLOCK */
	}

	sendenvelope(e, mode);
	dropenvelope(e, TRUE);
	for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
	{
		CurEnv = ee;
		if (mode != SM_VERIFY)
			openxscript(ee);
		sendenvelope(ee, mode);
		dropenvelope(ee, TRUE);
	}
	CurEnv = e;

	Verbose = oldverbose;
	if (mode == SM_FORK)
		finis(TRUE, ExitStat);
}

static void
sendenvelope(e, mode)
	register ENVELOPE *e;
	int mode;
{
	register ADDRESS *q;
	bool didany;

	if (tTd(13, 10))
		dprintf("sendenvelope(%s) e_flags=0x%lx\n",
			e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
			e->e_flags);
	if (LogLevel > 80)
		sm_syslog(LOG_DEBUG, e->e_id,
			  "sendenvelope, flags=0x%lx",
			  e->e_flags);

	/*
	**  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;
	}

	/* Don't attempt deliveries if we want to bounce now */
	if (!bitset(EF_RESPONSE, e->e_flags) &&
	    TimeOuts.to_q_return[e->e_timeoutclass] == NOW)
		return;

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

	define(macid("{envid}", NULL), e->e_envid, e);
	define(macid("{bodytype}", NULL), e->e_bodytype, e);
	didany = FALSE;

	/* now run through the queue */
	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
	{
#if XDEBUG
		char wbuf[MAXNAME + 20];

		(void) snprintf(wbuf, sizeof wbuf, "sendall(%.*s)",
			MAXNAME, q->q_paddr);
		checkfd012(wbuf);
#endif /* XDEBUG */
		if (mode == SM_VERIFY)
		{
			e->e_to = q->q_paddr;
			if (QS_IS_SENDABLE(q->q_state))
			{
				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 (QS_IS_OK(q->q_state))
		{
#if QUEUE
			/*
			**  Checkpoint the send list every few addresses
			*/

			if (CheckpointInterval > 0 &&
			    e->e_nsent >= CheckpointInterval)
			{
				queueup(e, FALSE);
				e->e_nsent = 0;
			}
#endif /* QUEUE */
			(void) deliver(e, q);
			didany = TRUE;
		}
	}
	if (didany)
	{
		e->e_dtime = curtime();
		e->e_ntries++;
	}

#if XDEBUG
	checkfd012("end of sendenvelope");
#endif /* XDEBUG */
}
/*
**  DUP_QUEUE_FILE -- duplicate a queue file into a split queue
**
**	Parameters:
**		e -- the existing envelope
**		ee -- the new envelope
**		type -- the queue file type (e.g., 'd')
**
**	Returns:
**		none
*/

static void
dup_queue_file(e, ee, type)
	struct envelope *e, *ee;
	int type;
{
	char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN];

	ee->e_dfp = NULL;
	ee->e_xfp = NULL;

	/*
	**  Make sure both are in the same directory.
	*/

	snprintf(f1buf, sizeof f1buf, "%s", queuename(e, type));
	snprintf(f2buf, sizeof f2buf, "%s", queuename(ee, type));
	if (link(f1buf, f2buf) < 0)
	{
		int save_errno = errno;

		syserr("sendall: link(%s, %s)", f1buf, f2buf);
		if (save_errno == EEXIST)
		{
			if (unlink(f2buf) < 0)
			{
				syserr("!sendall: unlink(%s): permanent",
					f2buf);
				/* NOTREACHED */
			}
			if (link(f1buf, f2buf) < 0)
			{
				syserr("!sendall: link(%s, %s): permanent",
					f1buf, f2buf);
				/* NOTREACHED */
			}
		}
	}
}
/*
**  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 /* ! FORK */

#define DOFORK(fORKfN) \
{\
	register int i;\
\
	for (i = NFORKTRIES; --i >= 0; )\
	{\
		pid = fORKfN();\
		if (pid >= 0)\
			break;\
		if (i > 0)\
			(void) 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.
*/

int
dofork()
{
	register pid_t pid = -1;

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

#ifndef NO_UID
# define NO_UID		-1
#endif /* ! NO_UID */
#ifndef NO_GID
# define NO_GID		-1
#endif /* ! NO_GID */

static int
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 */
	ADDRESS *volatile ctladdr;
	ADDRESS *volatile contextaddr = NULL;
	register MCI *volatile mci;
	register ADDRESS *to = firstto;
	volatile bool clever = FALSE;	/* running user smtp to this mailer */
	ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */
	int rcode;			/* response code */
	int lmtp_rcode = EX_OK;
	int nummxhosts = 0;		/* number of MX hosts available */
	int hostnum = 0;		/* current MX host index */
	char *firstsig;			/* signature of firstto */
	pid_t pid = -1;
	char *volatile curhost;
	register u_short port = 0;
#if NETUNIX
	char *mux_path = NULL;		/* path to UNIX domain socket */
#endif /* NETUNIX */
	time_t xstart;
	bool suidwarn;
	bool anyok;			/* at least one address was OK */
	bool goodmxfound = FALSE;	/* at least one MX was OK */
	bool ovr;
#if _FFR_DYNAMIC_TOBUF
	int strsize;
	int rcptcount;
	static int tobufsize = 0;
	static char *tobuf = NULL;
#else /* _FFR_DYNAMIC_TOBUF */
	char tobuf[TOBUFSIZE];		/* text line of to people */
#endif /* _FFR_DYNAMIC_TOBUF */
	int mpvect[2];
	int rpvect[2];
	char *mxhosts[MAXMXHOSTS + 1];
	char *pv[MAXPV + 1];
	char buf[MAXNAME + 1];
	char rpathbuf[MAXNAME + 1];	/* translated return path */

	errno = 0;
	if (!QS_IS_OK(to->q_state))
		return 0;

	suidwarn = geteuid() == 0;

	m = to->q_mailer;
	host = to->q_host;
	CurEnv = e;			/* just in case */
	e->e_statmsg = NULL;
#if SMTP
	SmtpError[0] = '\0';
#endif /* SMTP */
	xstart = curtime();

	if (tTd(10, 1))
		dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
			e->e_id, m->m_name, host, to->q_user);
	if (tTd(10, 100))
		printopenfds(FALSE);

	/*
	**  Clear $&{client_*} macros if this is a bounce message to
	**  prevent rejection by check_compat ruleset.
	*/

	if (bitset(EF_RESPONSE, e->e_flags))
	{
		define(macid("{client_name}", NULL), "", e);
		define(macid("{client_addr}", NULL), "", e);
		define(macid("{client_port}", NULL), "", e);
	}

	/*
	**  Do initial argv setup.
	**	Insert the mailer name.  Notice that $x expansion is
	**	NOT done on the mailer name.  Then, if the mailer has
	**	a picky -f flag, we insert it as appropriate.  This
	**	code does not check for 'pv' overflow; this places a
	**	manifest lower limit of 4 for MAXPV.
	**		The from address rewrite is expected to make
	**		the address relative to the other end.
	*/

	/* rewrite from address, using rewriting rules */
	rcode = EX_OK;
	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
		p = e->e_sender;
	else
		p = e->e_from.q_paddr;
	p = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
	if (strlen(p) >= (SIZE_T) sizeof rpathbuf)
	{
		p = shortenstring(p, MAXSHORTSTR);
		syserr("remotename: huge return %s", p);
	}
	snprintf(rpathbuf, sizeof rpathbuf, "%s", p);
	define('g', rpathbuf, e);		/* translated return path */
	define('h', host, e);			/* to host */
	Errors = 0;
	pvp = pv;
	*pvp++ = m->m_argv[0];

	/* insert -f or -r flag as appropriate */
	if (FromFlag &&
	    (bitnset(M_FOPT, m->m_flags) ||

⌨️ 快捷键说明

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