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

📄 parseaddr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 "errno.h"SCCSID(@(#)parseaddr.c 1.1 92/07/30 SMI); /* from UCB 5.8 3/13/88 *//***  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	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 (m != NULL && !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';			/* kludge \! for naive users (violates RFC 822) */			if ((c == '!') && bslashmode)				bslashmode = FALSE;							if (bslashmode)			{				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 == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS ||		 c == MATCHYELLOW || c == MATCHNYELLOW)		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 */	char tokbuf[MAXNAME+1];		/* for concatenated class tokens */	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;				char **oldavp;			  case MATCHNCLASS:				/* match any single token not in a class */				s = stab(ap, ST_CLASS, ST_FIND);				if (s != NULL && bitnset(rp[1], s->s_class))					goto backup;				/* match exactly one token */				mlp->first = avp;				mlp->last = avp++;				mlp++;				break;			  case MATCHCLASS:				/* match any token in a class */				/* from lel@ida.liu.se */				oldavp = avp;				*tokbuf = NULL;				do				{					if (*avp == NULL)					{						avp = oldavp;						goto backup;					}					(void) strcat(tokbuf, *avp++);					s = stab(tokbuf, ST_CLASS, ST_FIND);				} while (s == NULL ||					!bitnset(rp[1], s->s_class));				mlp->first = oldavp;				mlp->last = avp-1;				mlp++;				break;			  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;# ifdef YELLOW			  case MATCHNYELLOW:			  case MATCHYELLOW:				/* match any token in (not in) a NIS map. */				if (yellowmatch(ap,rp[1]))				{					if (*rp == MATCHNYELLOW)						goto backup;				}				else if (*rp == MATCHYELLOW)					goto backup;				mlp->first = avp;				mlp->last = avp++;				mlp++;				break;# endif YELLOW			  default:				/* must have exact match */				if (strcasecmp(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 == MATCHCLASS) {	                          register STAB *s;	                          char **oldavp; 	                          /* attempt to extend binding */	                          /* slow, concat version by lel@ida.liu.se */ 	                          oldavp = avp;	                          *tokbuf = NULL;	                          for (avp = mlp[-1].first;	                               avp <= mlp[-1].last; avp++)	                            (void)strcat(tokbuf, *avp); 	                          do {	                            if (*avp == NULL) {	                              /* back out binding */	                              avp = oldavp;	                              mlp--;	                              goto cantextend;

⌨️ 快捷键说明

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