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

📄 parseaddr.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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[] = "@(#)parseaddr.c	8.31 (Berkeley) 4/15/94";#endif /* not lint */# include "sendmail.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.**		flags -- describe detail for parsing.  See RF_ definitions**			in sendmail.h.**		delim -- the character to terminate the address, passed**			to prescan.**		delimptr -- if non-NULL, set to the location of the**			delim character that was found.**		e -- the envelope that will contain this address.****	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	"()<>,;\r\n"	/* default word delimiters */ADDRESS *parseaddr(addr, a, flags, delim, delimptr, e)	char *addr;	register ADDRESS *a;	int flags;	int delim;	char **delimptr;	register ENVELOPE *e;{	register char **pvp;	auto char *delimptrbuf;	bool queueup;	char pvpbuf[PSBUFSIZE];	extern ADDRESS *buildaddr();	extern bool invalidaddr();	/*	**  Initialize and prescan address.	*/	e->e_to = addr;	if (tTd(20, 1))		printf("\n--parseaddr(%s)\n", addr);	if (delimptr == NULL)		delimptr = &delimptrbuf;	pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr);	if (pvp == NULL)	{		if (tTd(20, 1))			printf("parseaddr-->NULL\n");		return (NULL);	}	if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))	{		if (tTd(20, 1))			printf("parseaddr-->bad address\n");		return NULL;	}	/*	**  Save addr if we are going to have to.	**	**	We have to do this early because there is a chance that	**	the map lookups in the rewriting rules could clobber	**	static memory somewhere.	*/	if (bitset(RF_COPYPADDR, flags) && addr != NULL)	{		char savec = **delimptr;		if (savec != '\0')			**delimptr = '\0';		e->e_to = addr = newstr(addr);		if (savec != '\0')			**delimptr = savec;	}	/*	**  Apply rewriting rules.	**	Ruleset 0 does basic parsing.  It must resolve.	*/	queueup = FALSE;	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)		queueup = TRUE;	if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)		queueup = TRUE;	/*	**  Build canonical address from pvp.	*/	a = buildaddr(pvp, a, flags, e);	/*	**  Make local copies of the host & user and then	**  transport them out.	*/	allocaddr(a, flags, addr);	if (bitset(QBADADDR, a->q_flags))		return a;	/*	**  If there was a parsing failure, mark it for queueing.	*/	if (queueup)	{		char *msg = "Transient parse error -- message queued for future delivery";		if (tTd(20, 1))			printf("parseaddr: queuing message\n");		message(msg);		if (e->e_message == NULL)			e->e_message = newstr(msg);		a->q_flags |= QQUEUEUP;	}	/*	**  Compute return value.	*/	if (tTd(20, 1))	{		printf("parseaddr-->");		printaddr(a, FALSE);	}	return (a);}/***  INVALIDADDR -- check for address containing meta-characters****	Parameters:**		addr -- the address to check.****	Returns:**		TRUE -- if the address has any "wierd" characters**		FALSE -- otherwise.*/boolinvalidaddr(addr, delimptr)	register char *addr;	char *delimptr;{	char savedelim;	if (delimptr != NULL)	{		savedelim = *delimptr;		if (savedelim != '\0')			*delimptr = '\0';	}#if 0	/* for testing.... */	if (strcmp(addr, "INvalidADDR") == 0)	{		usrerr("553 INvalid ADDRess");		goto addrfailure;	}#endif	for (; *addr != '\0'; addr++)	{		if ((*addr & 0340) == 0200)			break;	}	if (*addr == '\0')	{		if (savedelim != '\0' && delimptr != NULL)			*delimptr = savedelim;		return FALSE;	}	setstat(EX_USAGE);	usrerr("553 Address contained invalid control characters");  addrfailure:	if (savedelim != '\0' && delimptr != NULL)		*delimptr = savedelim;	return TRUE;}/***  ALLOCADDR -- do local allocations of address on demand.****	Also lowercases the host name if requested.****	Parameters:**		a -- the address to reallocate.**		flags -- the copy flag (see RF_ definitions in sendmail.h**			for a description).**		paddr -- the printname of the address.****	Returns:**		none.****	Side Effects:**		Copies portions of a into local buffers as requested.*/allocaddr(a, flags, paddr)	register ADDRESS *a;	int flags;	char *paddr;{	if (tTd(24, 4))		printf("allocaddr(flags=%o, paddr=%s)\n", flags, paddr);	a->q_paddr = paddr;	if (a->q_user == NULL)		a->q_user = "";	if (a->q_host == NULL)		a->q_host = "";	if (bitset(RF_COPYPARSE, flags))	{		a->q_host = newstr(a->q_host);		if (a->q_user != a->q_paddr)			a->q_user = newstr(a->q_user);	}	if (a->q_paddr == NULL)		a->q_paddr = 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.**		pvpbsize -- size of pvpbuf.**		delimptr -- if non-NULL, set to the location of the**			terminating delimiter.****	Returns:**		A pointer to a vector of tokens.**		NULL on error.*//* 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,};/* token type table -- it gets modified with $o characters */static TokTypeTab[256] ={	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,	OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,};#define toktype(c)	((int) TokTypeTab[(c) & 0xff])# define NOCHAR		-1	/* signal nothing in lookahead token */char **prescan(addr, delim, pvpbuf, pvpbsize, delimptr)	char *addr;	char delim;	char pvpbuf[];	char **delimptr;{	register char *p;	register char *q;	register int c;	char **avp;	bool bslashmode;	int cmntcnt;	int anglecnt;	char *tok;	int state;	int newstate;	char *saveto = CurEnv->e_to;	static char *av[MAXATOM+1];	static char firsttime = TRUE;	extern int errno;	if (firsttime)	{		/* initialize the token type table */		char obuf[50];		firsttime = FALSE;		expand("\201o", obuf, &obuf[sizeof obuf - sizeof DELIMCHARS], CurEnv);		strcat(obuf, DELIMCHARS);		for (p = obuf; *p != '\0'; p++)		{			if (TokTypeTab[*p & 0xff] == ATM)				TokTypeTab[*p & 0xff] = OPR;		}	}	/* make sure error messages don't have garbage on them */	errno = 0;	q = pvpbuf;	bslashmode = FALSE;	cmntcnt = 0;	anglecnt = 0;	avp = av;	state = ATM;	c = NOCHAR;	p = addr;	CurEnv->e_to = p;	if (tTd(22, 11))	{		printf("prescan: ");		xputs(p);		(void) putchar('\n');	}	do	{		/* read a token */		tok = q;		for (;;)		{			/* store away any old lookahead character */			if (c != NOCHAR && !bslashmode)			{				/* see if there is room */				if (q >= &pvpbuf[pvpbsize - 5])				{					usrerr("553 Address too long");	returnnull:					if (delimptr != NULL)						*delimptr = p;					CurEnv->e_to = saveto;					return (NULL);				}				/* squirrel it away */				*q++ = c;			}			/* read a new input character */			c = *p++;			if (c == '\0')			{				/* diagnose and patch up bad syntax */				if (state == QST)				{					usrerr("653 Unbalanced '\"'");					c = '"';				}				else if (cmntcnt > 0)				{					usrerr("653 Unbalanced '('");					c = ')';				}				else if (anglecnt > 0)				{					c = '>';					usrerr("653 Unbalanced '<'");				}				else					break;				p--;			}			else if (c == delim && anglecnt <= 0 &&					cmntcnt <= 0 && state != QST)				break;			if (tTd(22, 101))				printf("c=%c, s=%d; ", c, state);			/* chew up special characters */			*q = '\0';			if (bslashmode)			{				bslashmode = FALSE;				/* kludge \! for naive users */				if (cmntcnt > 0)				{					c = NOCHAR;					continue;				}				else if (c != '!' || state == QST)				{					*q++ = '\\';					continue;				}			}			if (c == '\\')			{				bslashmode = TRUE;			}			else if (state == QST)			{				/* do nothing, just avoid next clauses */			}			else if (c == '(')			{				cmntcnt++;				c = NOCHAR;			}			else if (c == ')')			{				if (cmntcnt <= 0)				{					usrerr("653 Unbalanced ')'");					c = NOCHAR;				}				else					cmntcnt--;			}			else if (cmntcnt > 0)				c = NOCHAR;			else if (c == '<')				anglecnt++;			else if (c == '>')			{				if (anglecnt <= 0)				{					usrerr("653 Unbalanced '>'");					c = NOCHAR;				}				else					anglecnt--;			}			else if (delim == ' ' && isascii(c) && 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)];			if (tTd(22, 101))				printf("ns=%02o\n", newstate);			state = newstate & TYPE;			if (bitset(M, newstate))				c = NOCHAR;			if (bitset(B, newstate))				break;		}		/* new token */		if (tok != q)		{			*q++ = '\0';			if (tTd(22, 36))			{				printf("tok=");				xputs(tok);				(void) putchar('\n');			}			if (avp >= &av[MAXATOM])			{				syserr("553 prescan: too many tokens");				goto returnnull;			}			if (q - tok > MAXNAME)			{				syserr("553 prescan: token too long");				goto returnnull;			}			*avp++ = tok;		}	} while (c != '\0' && (c != delim || anglecnt > 0));	*avp = NULL;	p--;	if (delimptr != NULL)		*delimptr = p;	if (tTd(22, 12))	{		printf("prescan==>");		printav(av);	}	CurEnv->e_to = saveto;	if (av[0] == NULL)	{		if (tTd(22, 1))			printf("prescan: null leading token\n");		return (NULL);	}	return (av);}/***  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.**		ruleset -- the ruleset to use for rewriting.**		reclevel -- recursion level (to catch loops).**		e -- the current envelope.****	Returns:**		A status code.  If EX_TEMPFAIL, higher level code should**			attempt recovery.****	Side Effects:**		pvp is modified.*/struct match{	char	**first;	/* first token matched */	char	**last;		/* last token matched */	char	**pattern;	/* pointer to pattern */};# define MAXMATCH	9	/* max params per rewrite */# ifndef MAXRULERECURSION#  define MAXRULERECURSION	50	/* max recursion depth */# endifintrewrite(pvp, ruleset, reclevel, e)	char **pvp;	int ruleset;	int reclevel;	register ENVELOPE *e;

⌨️ 快捷键说明

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