parseaddr.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,432 行 · 第 1/2 页

C
1,432
字号
#ifndef lintstatic	char	*sccsid = "@(#)parseaddr.c	4.1	(ULTRIX)	7/2/90";#endif lint/************************************************************************ *									* *			Copyright (c) 1987, 1988 by			* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//************************************************************************ * * EDIT HISTORY * * 001	07-July-1988	Jeff Michaud in association w/John Haxby *	The recipient names in RCPT commands we were issuing were *	getting the domain of the sender tacked on if they didn't *	already have a domain and the 'C' flag for the incomming *	mailer was set.  The 'C' flag is documented to only affect *	the rewriting of the addresses in header lines, not in the *	envelope. * ***********************************************************************/# include "sendmail.h"# include <sys/svcinfo.h>/***  PARSEADDR -- Parse an address****	Parses an address and breaks it up into three parts: a**	net to transmit the message on, the host to transmit it**	to, and a user on that host.  These are loaded into an**	ADDRESS header with the values squirreled away if necessary.**	The "user" part may not be a real user; the process may**	just reoccur on that machine.  For example, on a machine**	with an arpanet connection, the address**		csvax.bill@berkeley**	will break up to a "user" of 'csvax.bill' and a host**	of 'berkeley' -- to be transmitted over the arpanet.****	Parameters:**		addr -- the address to parse.**		a -- a pointer to the address descriptor buffer.**			If NULL, a header will be created.**		copyf -- determines what shall be copied:**			-1 -- don't copy anything.  The printname**				(q_paddr) is just addr, and the**				user & host are allocated internally**				to parse.**			0 -- copy out the parsed user & host, but**				don't copy the printname.**			+1 -- copy everything.**		delim -- the character to terminate the address, passed**			to prescan.****	Returns:**		A pointer to the address descriptor header (`a' if**			`a' is non-NULL).**		NULL on error.****	Side Effects:**		none*//* following delimiters are inherent to the internal algorithms */# define DELIMCHARS	"\001()<>,;\\\"\r\n"	/* word delimiters */ADDRESS *parseaddr(addr, a, copyf, delim)	char *addr;	register ADDRESS *a;	int copyf;	char delim;{	register char **pvp;	register struct mailer *m;	char pvpbuf[PSBUFSIZE];	extern char **prescan();	extern ADDRESS *buildaddr();	/*	**  Initialize and prescan address.	*/	CurEnv->e_to = addr;# ifdef DEBUG	/* Turning on this line has strange side effects in	 * received mail when there is an unknown user error	 * when mailing to an alias.	 *	 * ie.. >>> MAIL From:<user@host>	 *      <<<	 *      >>> RCPT To:<user@host> (if .forward present)	 *	<<<	 */	if (tTd(20, 1))		printf("\n--parseaddr(%s)\n", addr);# endif DEBUG	pvp = prescan(addr, delim, pvpbuf);	if (pvp == NULL)		return (NULL);	/*	**  Apply rewriting rules.	**	Ruleset 0 does basic parsing.  It must resolve.	*/	rewrite(pvp, 3);	rewrite(pvp, 0);	/*	**  See if we resolved to a real mailer.	*/	if (pvp[0][0] != CANONNET)	{		setstat(EX_USAGE);		usrerr("cannot resolve name");		return (NULL);	}	/*	**  Build canonical address from pvp.	*/	a = buildaddr(pvp, a);	if (a == NULL)		return (NULL);	m = a->q_mailer;	/*	**  Make local copies of the host & user and then	**  transport them out.	*/	if (copyf > 0)	{		extern char *DelimChar;		char savec = *DelimChar;		*DelimChar = '\0';		a->q_paddr = newstr(addr);		*DelimChar = savec;	}	else		a->q_paddr = addr;	if (a->q_user == NULL)		a->q_user = "";	if (a->q_host == NULL)		a->q_host = "";	if (copyf >= 0)	{		a->q_host = newstr(a->q_host);		if (a->q_user != a->q_paddr)			a->q_user = newstr(a->q_user);	}	/*	**  Convert host name to lower case if requested.	**	User name will be done later.	*/	if (!bitnset(M_HST_UPPER, m->m_flags))		makelower(a->q_host);	/*	**  Compute return value.	*/# ifdef DEBUG	if (tTd(20, 1))	{		printf("parseaddr-->");		printaddr(a, FALSE);	}# endif DEBUG	return (a);}/***  LOWERADDR -- map UPPER->lower case on addresses as requested.****	Parameters:**		a -- address to be mapped.****	Returns:**		none.****	Side Effects:**		none.*/loweraddr(a)	register ADDRESS *a;{	register MAILER *m = a->q_mailer;	if (!bitnset(M_USR_UPPER, m->m_flags))		makelower(a->q_user);}/***  PRESCAN -- Prescan name and make it canonical****	Scans a name and turns it into a set of tokens.  This process**	deletes blanks and comments (in parentheses).****	This routine knows about quoted strings and angle brackets.****	There are certain subtleties to this routine.  The one that**	comes to mind now is that backslashes on the ends of names**	are silently stripped off; this is intentional.  The problem**	is that some versions of sndmsg (like at LBL) set the kill**	character to something other than @ when reading addresses;**	so people type "csvax.eric\@berkeley" -- which screws up the**	berknet mailer.****	Parameters:**		addr -- the name to chomp.**		delim -- the delimiter for the address, normally**			'\0' or ','; \0 is accepted in any case.**			If '\t' then we are reading the .cf file.**		pvpbuf -- place to put the saved text -- note that**			the pointers are static.****	Returns:**		A pointer to a vector of tokens.**		NULL on error.****	Side Effects:**		sets DelimChar to point to the character matching 'delim'.*//* states and character types */# define OPR		0	/* operator */# define ATM		1	/* atom */# define QST		2	/* in quoted string */# define SPC		3	/* chewing up spaces */# define ONE		4	/* pick up one character */# define NSTATES	5	/* number of states */# define TYPE		017	/* mask to select state type *//* meta bits for table */# define M		020	/* meta character; don't pass through */# define B		040	/* cause a break */# define MB		M|B	/* meta-break */static short StateTab[NSTATES][NSTATES] ={   /*	oldst	chtype>	OPR	ATM	QST	SPC	ONE	*/	/*OPR*/		OPR|B,	ATM|B,	QST|B,	SPC|MB,	ONE|B,	/*ATM*/		OPR|B,	ATM,	QST|B,	SPC|MB,	ONE|B,	/*QST*/		QST,	QST,	OPR,	QST,	QST,	/*SPC*/		OPR,	ATM,	QST,	SPC|M,	ONE,	/*ONE*/		OPR,	OPR,	OPR,	OPR,	OPR,};# define NOCHAR		-1	/* signal nothing in lookahead token */char	*DelimChar;		/* set to point to the delimiter */char **prescan(addr, delim, pvpbuf)	char *addr;	char delim;	char pvpbuf[];{	register char *p;	register char *q;	register int c;	char **avp;	bool bslashmode;	int cmntcnt;	int anglecnt;	char *tok;	int state;	int newstate;	static char *av[MAXATOM+1];	extern int errno;	/* make sure error messages don't have garbage on them */	errno = 0;	q = pvpbuf;	bslashmode = FALSE;	cmntcnt = 0;	anglecnt = 0;	avp = av;	state = OPR;	c = NOCHAR;	p = addr;# ifdef DEBUG	if (tTd(22, 45))	{		printf("prescan: ");		xputs(p);		(void) putchar('\n');	}# endif DEBUG	do	{		/* read a token */		tok = q;		for (;;)		{			/* store away any old lookahead character */			if (c != NOCHAR)			{				/* see if there is room */				if (q >= &pvpbuf[PSBUFSIZE - 5])				{					usrerr("Address too long");					DelimChar = p;					return (NULL);				}				/* squirrel it away */				*q++ = c;			}			/* read a new input character */			c = *p++;			if (c == '\0')				break;			c &= ~0200;# ifdef DEBUG			if (tTd(22, 101))				printf("c=%c, s=%d; ", c, state);# endif DEBUG			/* chew up special characters */			*q = '\0';			if (bslashmode)			{				/* kludge \! for naive users */				if (c != '!')					c |= 0200;				bslashmode = FALSE;			}			else if (c == '\\')			{				bslashmode = TRUE;				c = NOCHAR;			}			else if (state == QST)			{				/* do nothing, just avoid next clauses */			}			else if (c == '(')			{				cmntcnt++;				c = NOCHAR;			}			else if (c == ')')			{				if (cmntcnt <= 0)				{					usrerr("Unbalanced ')'");					DelimChar = p;					return (NULL);				}				else					cmntcnt--;			}			else if (cmntcnt > 0)				c = NOCHAR;			else if (c == '<')				anglecnt++;			else if (c == '>')			{				if (anglecnt <= 0)				{					usrerr("Unbalanced '>'");					DelimChar = p;					return (NULL);				}				anglecnt--;			}			else if (delim == ' ' && isspace(c))				c = ' ';			if (c == NOCHAR)				continue;			/* see if this is end of input */			if (c == delim && anglecnt <= 0 && state != QST)				break;			newstate = StateTab[state][toktype(c)];# ifdef DEBUG			if (tTd(22, 101))				printf("ns=%02o\n", newstate);# endif DEBUG			state = newstate & TYPE;			if (bitset(M, newstate))				c = NOCHAR;			if (bitset(B, newstate))				break;		}		/* new token */		if (tok != q)		{			*q++ = '\0';# ifdef DEBUG			if (tTd(22, 36))			{				printf("tok=");				xputs(tok);				(void) putchar('\n');			}# endif DEBUG			if (avp >= &av[MAXATOM])			{				syserr("prescan: too many tokens");				DelimChar = p;				return (NULL);			}			*avp++ = tok;		}	} while (c != '\0' && (c != delim || anglecnt > 0));	*avp = NULL;	DelimChar = --p;	if (cmntcnt > 0)		usrerr("Unbalanced '('");	else if (anglecnt > 0)		usrerr("Unbalanced '<'");	else if (state == QST)		usrerr("Unbalanced '\"'");	else if (av[0] != NULL)		return (av);	return (NULL);}/***  TOKTYPE -- return token type****	Parameters:**		c -- the character in question.****	Returns:**		Its type.****	Side Effects:**		none.*/toktype(c)	register char c;{	static char buf[50];	static bool firstime = TRUE;	if (firstime)	{		firstime = FALSE;		expand("\001o", buf, &buf[sizeof buf - 1], CurEnv);		(void) strcat(buf, DELIMCHARS);	}	if ( c == MATCHMA || c == MATCHPW || c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)		return (ONE);	if (c == '"')		return (QST);	if (!isascii(c))		return (ATM);	if (isspace(c) || c == ')')		return (SPC);	if (iscntrl(c) || index(buf, c) != NULL)		return (OPR);	return (ATM);}/***  REWRITE -- apply rewrite rules to token vector.****	This routine is an ordered production system.  Each rewrite**	rule has a LHS (called the pattern) and a RHS (called the**	rewrite); 'rwr' points the the current rewrite rule.****	For each rewrite rule, 'avp' points the address vector we**	are trying to match against, and 'pvp' points to the pattern.**	If pvp points to a special match value (MATCHZANY, MATCHANY,**	MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp**	matched is saved away in the match vector (pointed to by 'mvp').****	When a match between avp & pvp does not match, we try to**	back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS**	we must also back out the match in mvp.  If we reach a**	MATCHANY or MATCHZANY we just extend the match and start**	over again.****	When we finally match, we rewrite the address vector**	and try over again.****	Parameters:**		pvp -- pointer to token vector.****	Returns:**		none.****	Side Effects:**		pvp is modified.*/struct match{	char	**first;	/* first token matched */	char	**last;		/* last token matched */};# define MAXMATCH	9	/* max params per rewrite */rewrite(pvp, ruleset)	char **pvp;	int ruleset;{	register char *ap;		/* address pointer */	register char *rp;		/* rewrite pointer */	register char **avp;		/* address vector pointer */	register char **rvp;		/* rewrite vector pointer */	register struct match *mlp;	/* cur ptr into mlist */	register struct rewrite *rwr;	/* pointer to current rewrite rule */	struct match mlist[MAXMATCH];	/* stores match on LHS */	char *npvp[MAXATOM+1];		/* temporary space for rebuild */	extern bool sameword();	if (OpMode == MD_TEST || tTd(21, 2))	{		printf("rewrite: ruleset %2d   input:", ruleset);		printav(pvp);	}	if (pvp == NULL)		return;	/*	**  Run through the list of rewrite rules, applying	**	any that match.	*/	for (rwr = RewriteRules[ruleset]; rwr != NULL; )	{# ifdef DEBUG		if (tTd(21, 12))		{			printf("-----trying rule:");			printav(rwr->r_lhs);		}# endif DEBUG		/* try to match on this rule */		mlp = mlist;		rvp = rwr->r_lhs;		avp = pvp;		while ((ap = *avp) != NULL || *rvp != NULL)		{			rp = *rvp;# ifdef DEBUG			if (tTd(21, 35))			{				printf("ap=");				xputs(ap);				printf(", rp=");				xputs(rp);				printf("\n");			}# endif DEBUG			if (rp == NULL)			{				/* end-of-pattern before end-of-address */				goto backup;			}			if (ap == NULL && *rp != MATCHZANY)			{				/* end-of-input */				break;			}			switch (*rp)			{				register STAB *s;			  case MATCHMA:				/* See if token is in the name server				 * db for aliases.				 */				if (!in_alias_map(rvp,ap))					goto backup; /*_not found_*/				mlp->first = avp;				mlp->last = avp++;				mlp++;				break;			  case MATCHPW:				/* See if token is in the name server				 * db for user passwds.				 */				if (!in_passwd_map(rvp,ap))					goto backup; /*_not found_*/				mlp->first = avp;				mlp->last = avp++;				mlp++;				break;			  case MATCHCLASS:			  case MATCHNCLASS:				/* match any token in (not in) a class */				s = stab(ap, ST_CLASS, ST_FIND);				if (s == NULL || !bitnset(rp[1], s->s_class))				{					if (*rp == MATCHCLASS)						goto backup;				}				else if (*rp == MATCHNCLASS)					goto backup;				/* explicit fall-through */			  case MATCHONE:			  case MATCHANY:				/* match exactly one token */				mlp->first = avp;				mlp->last = avp++;				mlp++;				break;			  case MATCHZANY:				/* match zero or more tokens */				mlp->first = avp;				mlp->last = avp - 1;				mlp++;				break;			  default:				/* must have exact match */				if (!sameword(rp, ap))					goto backup;				avp++;				break;			}			/* successful match on this token */			rvp++;			continue;		  backup:			/* match failed -- back up */			while (--rvp >= rwr->r_lhs)			{				rp = *rvp;				if (*rp == MATCHANY || *rp == MATCHZANY)				{					/* extend binding and continue */					avp = ++mlp[-1].last;					avp++;					rvp++;					break;				}				avp--;				if (*rp == MATCHONE || *rp == MATCHCLASS ||				    *rp == MATCHNCLASS)				{					/* back out binding */					mlp--;				}			}			if (rvp < rwr->r_lhs)			{				/* total failure to match */				break;			}		}		/*		**  See if we successfully matched		*/		if (rvp < rwr->r_lhs || *rvp != NULL)		{# ifdef DEBUG			if (tTd(21, 10))				printf("----- rule fails\n");# endif DEBUG			rwr = rwr->r_next;			continue;		}

⌨️ 快捷键说明

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