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

📄 deliver.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted provided * that: (1) source distributions retain this entire copyright notice and * comment, and (2) distributions including binaries display the following * acknowledgement:  ``This product includes software developed by the * University of California, Berkeley and its contributors'' in the * documentation or other materials provided with the distribution and in * all advertising materials mentioning features or use of this software. * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */# include "sendmail.h"# include <signal.h># include <sys/stat.h># include <errno.h># include <vfork.h>SCCSID(@(#)deliver.c 1.1 92/07/30 SMI); /* from UCB 5.21 5/5/88 */static struct mxinfo *mx;	/* "current" mx record information */# ifndef MXDOMAINstruct mxinfo dummy_mx;		/* dummy mx info when not used */# endif MXDOMAIN/***  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;	int sizeleft;			/* Bytes of argv left to work with */	int buflen;			/* Temp */	register char **mvp;	register char *p;	register MAILER *m;		/* mailer for this recipient */	ADDRESS *ctladdr;	register ADDRESS *to = firstto;	bool clever = FALSE;		/* running user smtp to this mailer */	ADDRESS *tochain = NULL;	/* chain of users in this mailer call */	int rcode;			/* response code */	char *pv[MAXPV+1];	char tobuf[MAXLINE-50];		/* text line of to people */	char buf[MAXNAME];	char tfrombuf[MAXNAME];		/* translated from person */	extern bool checkcompat();	extern ADDRESS *getctladdr();	extern char *remotename();	errno = 0;	if (bitset(QDONTSEND, to->q_flags))		return (0);	m = to->q_mailer;	host = to->q_host;# ifdef DEBUG	if (tTd(10, 1))		printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",			m->m_mno, host, to->q_user);# endif DEBUG	/*	**  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.	**		This should be on a per-mailer basis.	*/	if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) &&	    !Verbose)	{		for (; to != NULL; to = to->q_next)		{			if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m)				continue;			to->q_flags |= QQUEUEUP|QDONTSEND;			e->e_to = to->q_paddr;			message(Arpa_Info, "queued");			if (LogLevel > 4)				logdelivery("queued");		}		e->e_to = NULL;		return (0);	}	/*	**  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 */	expand("\001f", buf, &buf[sizeof buf - 1], e);	(void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE));	define('g', tfrombuf, e);		/* translated sender address */	define('h', host, e);			/* to host */	Errors = 0;	pvp = pv;	sizeleft = m->m_argvsize - 10;		/* Leave some slop */	*pvp++ = m->m_argv[0];	sizeleft -= strlen(m->m_argv[0]) + 1;	/* insert -f or -r flag as appropriate */	if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags)))	{		if (bitnset(M_FOPT, m->m_flags))			*pvp++ = "-f";		else			*pvp++ = "-r";		expand("\001g", buf, &buf[sizeof buf - 1], e);		*pvp++ = newstr(buf);		sizeleft -= strlen(buf) + 1 + 2 + 1;	}	/*	**  Append the other fixed parts of the argv.  These run	**  up to the first entry containing "$u".  There can only	**  be one of these, and there are only a few more slots	**  in the pv after it.	*/	for (mvp = m->m_argv; (p = *++mvp) != NULL; )	{		while ((p = index(p, '\001')) != NULL)			if (*++p == 'u')				break;		if (p != NULL)			break;		/* this entry is safe -- go ahead and process it */		expand(*mvp, buf, &buf[sizeof buf - 1], e);		*pvp++ = newstr(buf);		sizeleft -= strlen(buf) + 1;		if (pvp >= &pv[MAXPV - 3])		{			syserr("Too many parameters to %s before $u", pv[0]);			return (-1);		}	}	/*	**  If we have no substitution for the user name in the argument	**  list, we know that we must supply the names otherwise -- and	**  SMTP is the answer!!	*/	if (*mvp == NULL)	{		/* running SMTP */# ifdef SMTP		clever = TRUE;		*pvp = NULL;# else SMTP		/* oops!  we don't implement SMTP */		syserr("SMTP style mailer");		return (EX_SOFTWARE);# endif SMTP	}	/*	**  At this point *mvp points to the argument with $u.  We	**  run through our address list and append all the addresses	**  we can.  If we run out of space, do not fret!  We can	**  always send another copy later.	*/	tobuf[0] = '\0';	e->e_to = tobuf;	ctladdr = NULL;	for (; to != NULL; to = to->q_next)	{		/* avoid sending multiple recipients to dumb mailers */		if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))			break;		/* if already sent or not for this host, don't send */		if (bitset(QDONTSEND, to->q_flags) ||		    strcmp(to->q_host, host) != 0 ||		    to->q_mailer != firstto->q_mailer)			continue;		/* avoid overflowing tobuf */		if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0)			break;# ifdef DEBUG		if (tTd(10, 1))		{			printf("\nsend to ");			printaddr(to, FALSE);		}# endif DEBUG		/* compute effective uid/gid when sending */		if (to->q_mailer == ProgMailer)			ctladdr = getctladdr(to);		user = to->q_user;		e->e_to = to->q_paddr;		/*		**  Check to see that these people are allowed to		**  talk to each other.		*/		if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)		{			NoReturn = TRUE;			usrerr("Message is too large; %ld bytes max", m->m_maxsize);			giveresponse(EX_UNAVAILABLE, m, e);			to->q_flags |= QDONTSEND;			continue;		}		if (!checkcompat(to))		{			giveresponse(EX_UNAVAILABLE, m, e);			to->q_flags |= QDONTSEND;			continue;		}		/*		**  Strip quote bits from names if the mailer is dumb		**	about them.		*/		if (bitnset(M_STRIPQ, m->m_flags))		{			stripquotes(user, TRUE);			stripquotes(host, TRUE);		}		else		{			stripquotes(user, FALSE);			stripquotes(host, FALSE);		}		/* hack attack -- delivermail compatibility */		if (m == ProgMailer && *user == '|')			user++;		/*		**  If an error message has already been given, don't		**	bother to send to this address.		**		**	>>>>>>>>>> This clause assumes that the local mailer		**	>> NOTE >> cannot do any further aliasing; that		**	>>>>>>>>>> function is subsumed by sendmail.		*/		if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) {			to->q_flags |= QDONTSEND;			continue;		}		/*		**  Expand out this user and see if it fits in argv.		**  By definition, the first user always fits, else		**  we would loop here for rather a long time.		*/		define('u', user, e);		/* to user */		define('z', to->q_home, e);	/* user's home */		expand(*mvp, buf, &buf[sizeof buf - 1], e);		buflen = strlen(buf);		if (buflen > sizeleft && tobuf[0] != '\0')			break;		/* Stop argv here */		/*		**  We have decided that we are sending the message to		**  this user now.  First mark it to avoid resending		**  later.		*/		to->q_flags |= QDONTSEND;		/*		**  See if this user name is "special".		**	If the user name has a slash in it, assume that this		**	is a file -- send it off without further ado.  Note		**	that this type of addresses is not processed along		**	with the others, so we fudge on the To person.		*/		if (m == LocalMailer)		{			if (user[0] == '/')			{				rcode = mailfile(user, getctladdr(to));				giveresponse(rcode, m, e);				markstats(e, to);				continue;			}		}		/*		**  Add this user to mailer argv, and add it		**  to the print list of recipients.		*/		/* link together the chain of recipients */		to->q_tchain = tochain;		tochain = to;		/* create list of users for error messages */		(void) strcat(tobuf, ",");		(void) strcat(tobuf, to->q_paddr);		if (!clever)		{			*pvp++ = newstr(buf);			sizeleft -= buflen + 1;			if (pvp >= &pv[MAXPV - 2])			{				/* allow some space for trailing parms */				break;			}		}	}	/* see if any addresses still exist */	if (tobuf[0] == '\0')	{		define('g', (char *) NULL, e);		return (0);	}	/* print out messages as full list */	e->e_to = tobuf + 1;	/*	**  Fill out any parameters after the $u parameter.	**  Note that these are not checked against "sizeleft", thus are	**  not counted in the mailer L= option.  The L= value just has	**  to subtract off the max length of any trailing parameters,	**  or figure out how to move them to the front instead.	*/	while (!clever && *++mvp != NULL)	{		expand(*mvp, buf, &buf[sizeof buf - 1], e);		*pvp++ = newstr(buf);		if (pvp >= &pv[MAXPV])			syserr("deliver: pv overflow after $u for %s", pv[0]);	}	*pvp++ = NULL;	/*	**  Call the mailer.	**	The argument vector gets built, pipes	**	are created as necessary, and we fork & exec as	**	appropriate.	**	If we are running SMTP, we just need to clean up.	*/	message(Arpa_Info, "Connecting to %s via %s...", host, m->m_name);	if (ctladdr == NULL)		ctladdr = &e->e_from;# ifdef SMTP	if (clever)	{# ifdef MXDOMAIN		extern struct mxinfo *getmxrr();/* * Should make this dependent on some flag, or at least * if strcmp(m->m_mailer,"[TCP]") == 0  * or certainly host[0] != '\0' */		mx = getmxrr(host, MyHostName, &rcode);		if (mx->mx_number >= 0)			rcode = EX_OK;#else MXDOMAIN		mx = &dummy_mx;		mx->mx_number = 1;		mx->mx_hosts[0] = host;		rcode = EX_OK;#endif		/* send the initial SMTP protocol */		if (rcode == EX_OK)			rcode = smtpinit(m, pv);		if (rcode == EX_OK)		{			/* send the recipient list */			tobuf[0] = '\0';			for (to = tochain; to != NULL; to = to->q_tchain)			{				int i;				e->e_to = to->q_paddr;				i = smtprcpt(to, m);				if (i != EX_OK)				{					markfailure(e, to, i);					giveresponse(i, m, e);				}				else				{					(void) strcat(tobuf, ",");					(void) strcat(tobuf, to->q_paddr);				}			}			/* now send the data */			if (tobuf[0] == '\0')				e->e_to = NULL;			else			{				e->e_to = tobuf + 1;				rcode = smtpdata(m, e);			}			/* now close the connection */			smtpquit(m);		}	}	else# endif SMTP		rcode = sendoff(e, m, pv, ctladdr);	/*	**  Do final status disposal.	**	We check for something in tobuf for the SMTP case.	**	If we got a temporary failure, arrange to queue the	**		addressees.	*/	if (tobuf[0] != '\0')		giveresponse(rcode, m, e);	if (rcode != EX_OK)	{		for (to = tochain; to != NULL; to = to->q_tchain)			markfailure(e, to, rcode);	} else for (to = tochain; to != NULL; to = to->q_tchain)		markstats(e, to);	errno = 0;	define('g', (char *) NULL, e);	return (rcode);}/***  MARKFAILURE -- mark a failure on a specific address.****	Parameters:**		e -- the envelope we are sending.**		q -- the address to mark.**		rcode -- the code signifying the particular failure.****	Returns:**		none.****	Side Effects:**		marks the address (and possibly the envelope) with the**			failure so that an error will be returned or**			the message will be queued, as appropriate.*/markfailure(e, q, rcode)	register ENVELOPE *e;	register ADDRESS *q;	int rcode;{	if (rcode == EX_OK)		return;	else if (rcode != EX_TEMPFAIL && rcode != EX_OSERR && 	         rcode !=EX_IOERR)		q->q_flags |= QBADADDR;	else if (curtime() > e->e_ctime + TimeOut)	{		extern char *pintvl();		char buf[MAXLINE];		if (!bitset(EF_TIMEOUT, e->e_flags))		{			(void) sprintf(buf, "Cannot send message for %s",				pintvl(TimeOut, FALSE));			if (e->e_message != NULL)				free(e->e_message);			e->e_message = newstr(buf);			message(Arpa_Info, buf);		}		q->q_flags |= QBADADDR;		e->e_flags |= EF_TIMEOUT;	}	else		q->q_flags |= QQUEUEUP;}/***  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.**

⌨️ 快捷键说明

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