1 /*
2  * Copyright (c) 1983, 1995 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)parseaddr.c	8.73 (Berkeley) 06/19/95";
11 #endif /* not lint */
12 
13 # include "sendmail.h"
14 
15 /*
16 **  PARSEADDR -- Parse an address
17 **
18 **	Parses an address and breaks it up into three parts: a
19 **	net to transmit the message on, the host to transmit it
20 **	to, and a user on that host.  These are loaded into an
21 **	ADDRESS header with the values squirreled away if necessary.
22 **	The "user" part may not be a real user; the process may
23 **	just reoccur on that machine.  For example, on a machine
24 **	with an arpanet connection, the address
25 **		csvax.bill@berkeley
26 **	will break up to a "user" of 'csvax.bill' and a host
27 **	of 'berkeley' -- to be transmitted over the arpanet.
28 **
29 **	Parameters:
30 **		addr -- the address to parse.
31 **		a -- a pointer to the address descriptor buffer.
32 **			If NULL, a header will be created.
33 **		flags -- describe detail for parsing.  See RF_ definitions
34 **			in sendmail.h.
35 **		delim -- the character to terminate the address, passed
36 **			to prescan.
37 **		delimptr -- if non-NULL, set to the location of the
38 **			delim character that was found.
39 **		e -- the envelope that will contain this address.
40 **
41 **	Returns:
42 **		A pointer to the address descriptor header (`a' if
43 **			`a' is non-NULL).
44 **		NULL on error.
45 **
46 **	Side Effects:
47 **		none
48 */
49 
50 /* following delimiters are inherent to the internal algorithms */
51 # define DELIMCHARS	"()<>,;\r\n"	/* default word delimiters */
52 
53 ADDRESS *
parseaddr(addr,a,flags,delim,delimptr,e)54 parseaddr(addr, a, flags, delim, delimptr, e)
55 	char *addr;
56 	register ADDRESS *a;
57 	int flags;
58 	int delim;
59 	char **delimptr;
60 	register ENVELOPE *e;
61 {
62 	register char **pvp;
63 	auto char *delimptrbuf;
64 	bool queueup;
65 	char pvpbuf[PSBUFSIZE];
66 	extern ADDRESS *buildaddr();
67 	extern bool invalidaddr();
68 	extern void allocaddr __P((ADDRESS *, int, char *));
69 
70 	/*
71 	**  Initialize and prescan address.
72 	*/
73 
74 	e->e_to = addr;
75 	if (tTd(20, 1))
76 		printf("\n--parseaddr(%s)\n", addr);
77 
78 	if (delimptr == NULL)
79 		delimptr = &delimptrbuf;
80 
81 	pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
82 	if (pvp == NULL)
83 	{
84 		if (tTd(20, 1))
85 			printf("parseaddr-->NULL\n");
86 		return (NULL);
87 	}
88 
89 	if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
90 	{
91 		if (tTd(20, 1))
92 			printf("parseaddr-->bad address\n");
93 		return NULL;
94 	}
95 
96 	/*
97 	**  Save addr if we are going to have to.
98 	**
99 	**	We have to do this early because there is a chance that
100 	**	the map lookups in the rewriting rules could clobber
101 	**	static memory somewhere.
102 	*/
103 
104 	if (bitset(RF_COPYPADDR, flags) && addr != NULL)
105 	{
106 		char savec = **delimptr;
107 
108 		if (savec != '\0')
109 			**delimptr = '\0';
110 		e->e_to = addr = newstr(addr);
111 		if (savec != '\0')
112 			**delimptr = savec;
113 	}
114 
115 	/*
116 	**  Apply rewriting rules.
117 	**	Ruleset 0 does basic parsing.  It must resolve.
118 	*/
119 
120 	queueup = FALSE;
121 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
122 		queueup = TRUE;
123 	if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
124 		queueup = TRUE;
125 
126 
127 	/*
128 	**  Build canonical address from pvp.
129 	*/
130 
131 	a = buildaddr(pvp, a, flags, e);
132 
133 	/*
134 	**  Make local copies of the host & user and then
135 	**  transport them out.
136 	*/
137 
138 	allocaddr(a, flags, addr);
139 	if (bitset(QBADADDR, a->q_flags))
140 		return a;
141 
142 	/*
143 	**  If there was a parsing failure, mark it for queueing.
144 	*/
145 
146 	if (queueup)
147 	{
148 		char *msg = "Transient parse error -- message queued for future delivery";
149 
150 		if (tTd(20, 1))
151 			printf("parseaddr: queuing message\n");
152 		message(msg);
153 		if (e->e_message == NULL)
154 			e->e_message = newstr(msg);
155 		a->q_flags |= QQUEUEUP;
156 		a->q_status = "4.4.3";
157 	}
158 
159 	/*
160 	**  Compute return value.
161 	*/
162 
163 	if (tTd(20, 1))
164 	{
165 		printf("parseaddr-->");
166 		printaddr(a, FALSE);
167 	}
168 
169 	return (a);
170 }
171 /*
172 **  INVALIDADDR -- check for address containing meta-characters
173 **
174 **	Parameters:
175 **		addr -- the address to check.
176 **
177 **	Returns:
178 **		TRUE -- if the address has any "wierd" characters
179 **		FALSE -- otherwise.
180 */
181 
182 bool
invalidaddr(addr,delimptr)183 invalidaddr(addr, delimptr)
184 	register char *addr;
185 	char *delimptr;
186 {
187 	char savedelim = '\0';
188 
189 	if (delimptr != NULL)
190 	{
191 		savedelim = *delimptr;
192 		if (savedelim != '\0')
193 			*delimptr = '\0';
194 	}
195 #if 0
196 	/* for testing.... */
197 	if (strcmp(addr, "INvalidADDR") == 0)
198 	{
199 		usrerr("553 INvalid ADDRess");
200 		goto addrfailure;
201 	}
202 #endif
203 	for (; *addr != '\0'; addr++)
204 	{
205 		if ((*addr & 0340) == 0200)
206 			break;
207 	}
208 	if (*addr == '\0')
209 	{
210 		if (delimptr != NULL && savedelim != '\0')
211 			*delimptr = savedelim;
212 		return FALSE;
213 	}
214 	setstat(EX_USAGE);
215 	usrerr("553 Address contained invalid control characters");
216   addrfailure:
217 	if (delimptr != NULL && savedelim != '\0')
218 		*delimptr = savedelim;
219 	return TRUE;
220 }
221 /*
222 **  ALLOCADDR -- do local allocations of address on demand.
223 **
224 **	Also lowercases the host name if requested.
225 **
226 **	Parameters:
227 **		a -- the address to reallocate.
228 **		flags -- the copy flag (see RF_ definitions in sendmail.h
229 **			for a description).
230 **		paddr -- the printname of the address.
231 **
232 **	Returns:
233 **		none.
234 **
235 **	Side Effects:
236 **		Copies portions of a into local buffers as requested.
237 */
238 
239 void
allocaddr(a,flags,paddr)240 allocaddr(a, flags, paddr)
241 	register ADDRESS *a;
242 	int flags;
243 	char *paddr;
244 {
245 	if (tTd(24, 4))
246 		printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
247 
248 	a->q_paddr = paddr;
249 
250 	if (a->q_user == NULL)
251 		a->q_user = "";
252 	if (a->q_host == NULL)
253 		a->q_host = "";
254 
255 	if (bitset(RF_COPYPARSE, flags))
256 	{
257 		a->q_host = newstr(a->q_host);
258 		if (a->q_user != a->q_paddr)
259 			a->q_user = newstr(a->q_user);
260 	}
261 
262 	if (a->q_paddr == NULL)
263 		a->q_paddr = a->q_user;
264 }
265 /*
266 **  PRESCAN -- Prescan name and make it canonical
267 **
268 **	Scans a name and turns it into a set of tokens.  This process
269 **	deletes blanks and comments (in parentheses).
270 **
271 **	This routine knows about quoted strings and angle brackets.
272 **
273 **	There are certain subtleties to this routine.  The one that
274 **	comes to mind now is that backslashes on the ends of names
275 **	are silently stripped off; this is intentional.  The problem
276 **	is that some versions of sndmsg (like at LBL) set the kill
277 **	character to something other than @ when reading addresses;
278 **	so people type "csvax.eric\@berkeley" -- which screws up the
279 **	berknet mailer.
280 **
281 **	Parameters:
282 **		addr -- the name to chomp.
283 **		delim -- the delimiter for the address, normally
284 **			'\0' or ','; \0 is accepted in any case.
285 **			If '\t' then we are reading the .cf file.
286 **		pvpbuf -- place to put the saved text -- note that
287 **			the pointers are static.
288 **		pvpbsize -- size of pvpbuf.
289 **		delimptr -- if non-NULL, set to the location of the
290 **			terminating delimiter.
291 **		toktab -- if set, a token table to use for parsing.
292 **			If NULL, use the default table.
293 **
294 **	Returns:
295 **		A pointer to a vector of tokens.
296 **		NULL on error.
297 */
298 
299 /* states and character types */
300 # define OPR		0	/* operator */
301 # define ATM		1	/* atom */
302 # define QST		2	/* in quoted string */
303 # define SPC		3	/* chewing up spaces */
304 # define ONE		4	/* pick up one character */
305 # define ILL		5	/* illegal character */
306 
307 # define NSTATES	6	/* number of states */
308 # define TYPE		017	/* mask to select state type */
309 
310 /* meta bits for table */
311 # define M		020	/* meta character; don't pass through */
312 # define B		040	/* cause a break */
313 # define MB		M|B	/* meta-break */
314 
315 static short StateTab[NSTATES][NSTATES] =
316 {
317    /*	oldst	chtype>	OPR	ATM	QST	SPC	ONE	ILL	*/
318 	/*OPR*/		OPR|B,	ATM|B,	QST|B,	SPC|MB,	ONE|B,	ILL|MB,
319 	/*ATM*/		OPR|B,	ATM,	QST|B,	SPC|MB,	ONE|B,	ILL|MB,
320 	/*QST*/		QST,	QST,	OPR,	QST,	QST,	QST,
321 	/*SPC*/		OPR,	ATM,	QST,	SPC|M,	ONE,	ILL|MB,
322 	/*ONE*/		OPR,	OPR,	OPR,	OPR,	OPR,	ILL|MB,
323 	/*ILL*/		OPR|B,	ATM|B,	QST|B,	SPC|MB,	ONE|B,	ILL|M,
324 };
325 
326 /* token type table -- it gets modified with $o characters */
327 static u_char	TokTypeTab[256] =
328 {
329     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
330 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
331     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
332 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
333     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
334 	SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
335     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
336 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
337     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
338 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
339     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
340 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
341     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
342 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
343     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
344 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
345 
346     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
347 	OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
348     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
349 	OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
350     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
351 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
352     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
353 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
354     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
355 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
356     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
357 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
358     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
359 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
360     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
361 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
362 };
363 
364 /* token type table for MIME parsing */
365 u_char	MimeTokenTab[256] =
366 {
367     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
368 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
369     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
370 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
371     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
372 	SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
373     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
374 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
375     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
376 	OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
377     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
378 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
379     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
380 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
381     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
382 	ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
383 
384     /*	nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
385 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
386     /*	dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
387 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
388     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
389 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
390     /*	0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
391 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
392     /*	@   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
393 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
394     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _    */
395 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
396     /*	`   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
397 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
398     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
399 	ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
400 };
401 
402 
403 # define NOCHAR		-1	/* signal nothing in lookahead token */
404 
405 char **
prescan(addr,delim,pvpbuf,pvpbsize,delimptr,toktab)406 prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
407 	char *addr;
408 	int delim;
409 	char pvpbuf[];
410 	char **delimptr;
411 	u_char *toktab;
412 {
413 	register char *p;
414 	register char *q;
415 	register int c;
416 	char **avp;
417 	bool bslashmode;
418 	int cmntcnt;
419 	int anglecnt;
420 	char *tok;
421 	int state;
422 	int newstate;
423 	char *saveto = CurEnv->e_to;
424 	static char *av[MAXATOM+1];
425 	static char firsttime = TRUE;
426 	extern int errno;
427 
428 	if (firsttime)
429 	{
430 		/* initialize the token type table */
431 		char obuf[50];
432 
433 		firsttime = FALSE;
434 		expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv);
435 		strcat(obuf, DELIMCHARS);
436 		for (p = obuf; *p != '\0'; p++)
437 		{
438 			if (TokTypeTab[*p & 0xff] == ATM)
439 				TokTypeTab[*p & 0xff] = OPR;
440 		}
441 	}
442 	if (toktab == NULL)
443 		toktab = TokTypeTab;
444 
445 	/* make sure error messages don't have garbage on them */
446 	errno = 0;
447 
448 	q = pvpbuf;
449 	bslashmode = FALSE;
450 	cmntcnt = 0;
451 	anglecnt = 0;
452 	avp = av;
453 	state = ATM;
454 	c = NOCHAR;
455 	p = addr;
456 	CurEnv->e_to = p;
457 	if (tTd(22, 11))
458 	{
459 		printf("prescan: ");
460 		xputs(p);
461 		(void) putchar('\n');
462 	}
463 
464 	do
465 	{
466 		/* read a token */
467 		tok = q;
468 		for (;;)
469 		{
470 			/* store away any old lookahead character */
471 			if (c != NOCHAR && !bslashmode)
472 			{
473 				/* see if there is room */
474 				if (q >= &pvpbuf[pvpbsize - 5])
475 				{
476 					usrerr("553 Address too long");
477 					if (strlen(addr) > MAXNAME)
478 						addr[MAXNAME] = '\0';
479 	returnnull:
480 					if (delimptr != NULL)
481 						*delimptr = p;
482 					CurEnv->e_to = saveto;
483 					return (NULL);
484 				}
485 
486 				/* squirrel it away */
487 				*q++ = c;
488 			}
489 
490 			/* read a new input character */
491 			c = *p++;
492 			if (c == '\0')
493 			{
494 				/* diagnose and patch up bad syntax */
495 				if (state == QST)
496 				{
497 					usrerr("653 Unbalanced '\"'");
498 					c = '"';
499 				}
500 				else if (cmntcnt > 0)
501 				{
502 					usrerr("653 Unbalanced '('");
503 					c = ')';
504 				}
505 				else if (anglecnt > 0)
506 				{
507 					c = '>';
508 					usrerr("653 Unbalanced '<'");
509 				}
510 				else
511 					break;
512 
513 				p--;
514 			}
515 			else if (c == delim && anglecnt <= 0 &&
516 					cmntcnt <= 0 && state != QST)
517 				break;
518 
519 			if (tTd(22, 101))
520 				printf("c=%c, s=%d; ", c, state);
521 
522 			/* chew up special characters */
523 			*q = '\0';
524 			if (bslashmode)
525 			{
526 				bslashmode = FALSE;
527 
528 				/* kludge \! for naive users */
529 				if (cmntcnt > 0)
530 				{
531 					c = NOCHAR;
532 					continue;
533 				}
534 				else if (c != '!' || state == QST)
535 				{
536 					*q++ = '\\';
537 					continue;
538 				}
539 			}
540 
541 			if (c == '\\')
542 			{
543 				bslashmode = TRUE;
544 			}
545 			else if (state == QST)
546 			{
547 				/* do nothing, just avoid next clauses */
548 			}
549 			else if (c == '(')
550 			{
551 				cmntcnt++;
552 				c = NOCHAR;
553 			}
554 			else if (c == ')')
555 			{
556 				if (cmntcnt <= 0)
557 				{
558 					usrerr("653 Unbalanced ')'");
559 					c = NOCHAR;
560 				}
561 				else
562 					cmntcnt--;
563 			}
564 			else if (cmntcnt > 0)
565 				c = NOCHAR;
566 			else if (c == '<')
567 				anglecnt++;
568 			else if (c == '>')
569 			{
570 				if (anglecnt <= 0)
571 				{
572 					usrerr("653 Unbalanced '>'");
573 					c = NOCHAR;
574 				}
575 				else
576 					anglecnt--;
577 			}
578 			else if (delim == ' ' && isascii(c) && isspace(c))
579 				c = ' ';
580 
581 			if (c == NOCHAR)
582 				continue;
583 
584 			/* see if this is end of input */
585 			if (c == delim && anglecnt <= 0 && state != QST)
586 				break;
587 
588 			newstate = StateTab[state][toktab[c & 0xff]];
589 			if (tTd(22, 101))
590 				printf("ns=%02o\n", newstate);
591 			state = newstate & TYPE;
592 			if (state == ILL)
593 			{
594 				if (isascii(c) && isprint(c))
595 					usrerr("653 Illegal character %c", c);
596 				else
597 					usrerr("653 Illegal character 0x%02x", c);
598 			}
599 			if (bitset(M, newstate))
600 				c = NOCHAR;
601 			if (bitset(B, newstate))
602 				break;
603 		}
604 
605 		/* new token */
606 		if (tok != q)
607 		{
608 			*q++ = '\0';
609 			if (tTd(22, 36))
610 			{
611 				printf("tok=");
612 				xputs(tok);
613 				(void) putchar('\n');
614 			}
615 			if (avp >= &av[MAXATOM])
616 			{
617 				syserr("553 prescan: too many tokens");
618 				goto returnnull;
619 			}
620 			if (q - tok > MAXNAME)
621 			{
622 				syserr("553 prescan: token too long");
623 				goto returnnull;
624 			}
625 			*avp++ = tok;
626 		}
627 	} while (c != '\0' && (c != delim || anglecnt > 0));
628 	*avp = NULL;
629 	p--;
630 	if (delimptr != NULL)
631 		*delimptr = p;
632 	if (tTd(22, 12))
633 	{
634 		printf("prescan==>");
635 		printav(av);
636 	}
637 	CurEnv->e_to = saveto;
638 	if (av[0] == NULL)
639 	{
640 		if (tTd(22, 1))
641 			printf("prescan: null leading token\n");
642 		return (NULL);
643 	}
644 	return (av);
645 }
646 /*
647 **  REWRITE -- apply rewrite rules to token vector.
648 **
649 **	This routine is an ordered production system.  Each rewrite
650 **	rule has a LHS (called the pattern) and a RHS (called the
651 **	rewrite); 'rwr' points the the current rewrite rule.
652 **
653 **	For each rewrite rule, 'avp' points the address vector we
654 **	are trying to match against, and 'pvp' points to the pattern.
655 **	If pvp points to a special match value (MATCHZANY, MATCHANY,
656 **	MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
657 **	matched is saved away in the match vector (pointed to by 'mvp').
658 **
659 **	When a match between avp & pvp does not match, we try to
660 **	back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
661 **	we must also back out the match in mvp.  If we reach a
662 **	MATCHANY or MATCHZANY we just extend the match and start
663 **	over again.
664 **
665 **	When we finally match, we rewrite the address vector
666 **	and try over again.
667 **
668 **	Parameters:
669 **		pvp -- pointer to token vector.
670 **		ruleset -- the ruleset to use for rewriting.
671 **		reclevel -- recursion level (to catch loops).
672 **		e -- the current envelope.
673 **
674 **	Returns:
675 **		A status code.  If EX_TEMPFAIL, higher level code should
676 **			attempt recovery.
677 **
678 **	Side Effects:
679 **		pvp is modified.
680 */
681 
682 struct match
683 {
684 	char	**first;	/* first token matched */
685 	char	**last;		/* last token matched */
686 	char	**pattern;	/* pointer to pattern */
687 };
688 
689 # define MAXMATCH	9	/* max params per rewrite */
690 
691 # ifndef MAXRULERECURSION
692 #  define MAXRULERECURSION	50	/* max recursion depth */
693 # endif
694 
695 
696 int
rewrite(pvp,ruleset,reclevel,e)697 rewrite(pvp, ruleset, reclevel, e)
698 	char **pvp;
699 	int ruleset;
700 	int reclevel;
701 	register ENVELOPE *e;
702 {
703 	register char *ap;		/* address pointer */
704 	register char *rp;		/* rewrite pointer */
705 	register char **avp;		/* address vector pointer */
706 	register char **rvp;		/* rewrite vector pointer */
707 	register struct match *mlp;	/* cur ptr into mlist */
708 	register struct rewrite *rwr;	/* pointer to current rewrite rule */
709 	int ruleno;			/* current rule number */
710 	int rstat = EX_OK;		/* return status */
711 	int loopcount;
712 	struct match mlist[MAXMATCH];	/* stores match on LHS */
713 	char *npvp[MAXATOM+1];		/* temporary space for rebuild */
714 
715 	if (OpMode == MD_TEST || tTd(21, 1))
716 	{
717 		printf("rewrite: ruleset %2d   input:", ruleset);
718 		printav(pvp);
719 	}
720 	if (ruleset < 0 || ruleset >= MAXRWSETS)
721 	{
722 		syserr("554 rewrite: illegal ruleset number %d", ruleset);
723 		return EX_CONFIG;
724 	}
725 	if (reclevel++ > MAXRULERECURSION)
726 	{
727 		syserr("rewrite: infinite recursion, ruleset %d", ruleset);
728 		return EX_CONFIG;
729 	}
730 	if (pvp == NULL)
731 		return EX_USAGE;
732 
733 	/*
734 	**  Run through the list of rewrite rules, applying
735 	**	any that match.
736 	*/
737 
738 	ruleno = 1;
739 	loopcount = 0;
740 	for (rwr = RewriteRules[ruleset]; rwr != NULL; )
741 	{
742 		if (tTd(21, 12))
743 		{
744 			printf("-----trying rule:");
745 			printav(rwr->r_lhs);
746 		}
747 
748 		/* try to match on this rule */
749 		mlp = mlist;
750 		rvp = rwr->r_lhs;
751 		avp = pvp;
752 		if (++loopcount > 100)
753 		{
754 			syserr("554 Infinite loop in ruleset %d, rule %d",
755 				ruleset, ruleno);
756 			if (tTd(21, 1))
757 			{
758 				printf("workspace: ");
759 				printav(pvp);
760 			}
761 			break;
762 		}
763 
764 		while ((ap = *avp) != NULL || *rvp != NULL)
765 		{
766 			rp = *rvp;
767 			if (tTd(21, 35))
768 			{
769 				printf("ADVANCE rp=");
770 				xputs(rp);
771 				printf(", ap=");
772 				xputs(ap);
773 				printf("\n");
774 			}
775 			if (rp == NULL)
776 			{
777 				/* end-of-pattern before end-of-address */
778 				goto backup;
779 			}
780 			if (ap == NULL && (*rp & 0377) != MATCHZANY &&
781 			    (*rp & 0377) != MATCHZERO)
782 			{
783 				/* end-of-input with patterns left */
784 				goto backup;
785 			}
786 
787 			switch (*rp & 0377)
788 			{
789 				char buf[MAXLINE];
790 
791 			  case MATCHCLASS:
792 				/* match any phrase in a class */
793 				mlp->pattern = rvp;
794 				mlp->first = avp;
795 	extendclass:
796 				ap = *avp;
797 				if (ap == NULL)
798 					goto backup;
799 				mlp->last = avp++;
800 				cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
801 				if (!wordinclass(buf, rp[1]))
802 				{
803 					if (tTd(21, 36))
804 					{
805 						printf("EXTEND  rp=");
806 						xputs(rp);
807 						printf(", ap=");
808 						xputs(ap);
809 						printf("\n");
810 					}
811 					goto extendclass;
812 				}
813 				if (tTd(21, 36))
814 					printf("CLMATCH\n");
815 				mlp++;
816 				break;
817 
818 			  case MATCHNCLASS:
819 				/* match any token not in a class */
820 				if (wordinclass(ap, rp[1]))
821 					goto backup;
822 
823 				/* fall through */
824 
825 			  case MATCHONE:
826 			  case MATCHANY:
827 				/* match exactly one token */
828 				mlp->pattern = rvp;
829 				mlp->first = avp;
830 				mlp->last = avp++;
831 				mlp++;
832 				break;
833 
834 			  case MATCHZANY:
835 				/* match zero or more tokens */
836 				mlp->pattern = rvp;
837 				mlp->first = avp;
838 				mlp->last = avp - 1;
839 				mlp++;
840 				break;
841 
842 			  case MATCHZERO:
843 				/* match zero tokens */
844 				break;
845 
846 			  case MACRODEXPAND:
847 				/*
848 				**  Match against run-time macro.
849 				**  This algorithm is broken for the
850 				**  general case (no recursive macros,
851 				**  improper tokenization) but should
852 				**  work for the usual cases.
853 				*/
854 
855 				ap = macvalue(rp[1], e);
856 				mlp->first = avp;
857 				if (tTd(21, 2))
858 					printf("rewrite: LHS $&%c => \"%s\"\n",
859 						rp[1],
860 						ap == NULL ? "(NULL)" : ap);
861 
862 				if (ap == NULL)
863 					break;
864 				while (*ap != '\0')
865 				{
866 					if (*avp == NULL ||
867 					    strncasecmp(ap, *avp, strlen(*avp)) != 0)
868 					{
869 						/* no match */
870 						avp = mlp->first;
871 						goto backup;
872 					}
873 					ap += strlen(*avp++);
874 				}
875 
876 				/* match */
877 				break;
878 
879 			  default:
880 				/* must have exact match */
881 				if (strcasecmp(rp, ap))
882 					goto backup;
883 				avp++;
884 				break;
885 			}
886 
887 			/* successful match on this token */
888 			rvp++;
889 			continue;
890 
891 	  backup:
892 			/* match failed -- back up */
893 			while (--mlp >= mlist)
894 			{
895 				rvp = mlp->pattern;
896 				rp = *rvp;
897 				avp = mlp->last + 1;
898 				ap = *avp;
899 
900 				if (tTd(21, 36))
901 				{
902 					printf("BACKUP  rp=");
903 					xputs(rp);
904 					printf(", ap=");
905 					xputs(ap);
906 					printf("\n");
907 				}
908 
909 				if (ap == NULL)
910 				{
911 					/* run off the end -- back up again */
912 					continue;
913 				}
914 				if ((*rp & 0377) == MATCHANY ||
915 				    (*rp & 0377) == MATCHZANY)
916 				{
917 					/* extend binding and continue */
918 					mlp->last = avp++;
919 					rvp++;
920 					mlp++;
921 					break;
922 				}
923 				if ((*rp & 0377) == MATCHCLASS)
924 				{
925 					/* extend binding and try again */
926 					mlp->last = avp;
927 					goto extendclass;
928 				}
929 			}
930 
931 			if (mlp < mlist)
932 			{
933 				/* total failure to match */
934 				break;
935 			}
936 		}
937 
938 		/*
939 		**  See if we successfully matched
940 		*/
941 
942 		if (mlp < mlist || *rvp != NULL)
943 		{
944 			if (tTd(21, 10))
945 				printf("----- rule fails\n");
946 			rwr = rwr->r_next;
947 			ruleno++;
948 			loopcount = 0;
949 			continue;
950 		}
951 
952 		rvp = rwr->r_rhs;
953 		if (tTd(21, 12))
954 		{
955 			printf("-----rule matches:");
956 			printav(rvp);
957 		}
958 
959 		rp = *rvp;
960 		if ((*rp & 0377) == CANONUSER)
961 		{
962 			rvp++;
963 			rwr = rwr->r_next;
964 			ruleno++;
965 			loopcount = 0;
966 		}
967 		else if ((*rp & 0377) == CANONHOST)
968 		{
969 			rvp++;
970 			rwr = NULL;
971 		}
972 		else if ((*rp & 0377) == CANONNET)
973 			rwr = NULL;
974 
975 		/* substitute */
976 		for (avp = npvp; *rvp != NULL; rvp++)
977 		{
978 			register struct match *m;
979 			register char **pp;
980 
981 			rp = *rvp;
982 			if ((*rp & 0377) == MATCHREPL)
983 			{
984 				/* substitute from LHS */
985 				m = &mlist[rp[1] - '1'];
986 				if (m < mlist || m >= mlp)
987 				{
988 					syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
989 						ruleset, rp[1]);
990 					return EX_CONFIG;
991 				}
992 				if (tTd(21, 15))
993 				{
994 					printf("$%c:", rp[1]);
995 					pp = m->first;
996 					while (pp <= m->last)
997 					{
998 						printf(" %x=\"", *pp);
999 						(void) fflush(stdout);
1000 						printf("%s\"", *pp++);
1001 					}
1002 					printf("\n");
1003 				}
1004 				pp = m->first;
1005 				while (pp <= m->last)
1006 				{
1007 					if (avp >= &npvp[MAXATOM])
1008 					{
1009 						syserr("554 rewrite: expansion too long");
1010 						return EX_DATAERR;
1011 					}
1012 					*avp++ = *pp++;
1013 				}
1014 			}
1015 			else
1016 			{
1017 				/* vanilla replacement */
1018 				if (avp >= &npvp[MAXATOM])
1019 				{
1020 	toolong:
1021 					syserr("554 rewrite: expansion too long");
1022 					return EX_DATAERR;
1023 				}
1024 				if ((*rp & 0377) != MACRODEXPAND)
1025 					*avp++ = rp;
1026 				else
1027 				{
1028 					*avp = macvalue(rp[1], e);
1029 					if (tTd(21, 2))
1030 						printf("rewrite: RHS $&%c => \"%s\"\n",
1031 							rp[1],
1032 							*avp == NULL ? "(NULL)" : *avp);
1033 					if (*avp != NULL)
1034 						avp++;
1035 				}
1036 			}
1037 		}
1038 		*avp++ = NULL;
1039 
1040 		/*
1041 		**  Check for any hostname/keyword lookups.
1042 		*/
1043 
1044 		for (rvp = npvp; *rvp != NULL; rvp++)
1045 		{
1046 			char **hbrvp;
1047 			char **xpvp;
1048 			int trsize;
1049 			char *replac;
1050 			int endtoken;
1051 			STAB *map;
1052 			char *mapname;
1053 			char **key_rvp;
1054 			char **arg_rvp;
1055 			char **default_rvp;
1056 			char buf[MAXNAME + 1];
1057 			char *pvpb1[MAXATOM + 1];
1058 			char *argvect[10];
1059 			char pvpbuf[PSBUFSIZE];
1060 			char *nullpvp[1];
1061 
1062 			if ((**rvp & 0377) != HOSTBEGIN &&
1063 			    (**rvp & 0377) != LOOKUPBEGIN)
1064 				continue;
1065 
1066 			/*
1067 			**  Got a hostname/keyword lookup.
1068 			**
1069 			**	This could be optimized fairly easily.
1070 			*/
1071 
1072 			hbrvp = rvp;
1073 			if ((**rvp & 0377) == HOSTBEGIN)
1074 			{
1075 				endtoken = HOSTEND;
1076 				mapname = "host";
1077 			}
1078 			else
1079 			{
1080 				endtoken = LOOKUPEND;
1081 				mapname = *++rvp;
1082 			}
1083 			map = stab(mapname, ST_MAP, ST_FIND);
1084 			if (map == NULL)
1085 				syserr("554 rewrite: map %s not found", mapname);
1086 
1087 			/* extract the match part */
1088 			key_rvp = ++rvp;
1089 			default_rvp = NULL;
1090 			arg_rvp = argvect;
1091 			xpvp = NULL;
1092 			replac = pvpbuf;
1093 			while (*rvp != NULL && (**rvp & 0377) != endtoken)
1094 			{
1095 				int nodetype = **rvp & 0377;
1096 
1097 				if (nodetype != CANONHOST && nodetype != CANONUSER)
1098 				{
1099 					rvp++;
1100 					continue;
1101 				}
1102 
1103 				*rvp++ = NULL;
1104 
1105 				if (xpvp != NULL)
1106 				{
1107 					cataddr(xpvp, NULL, replac,
1108 						&pvpbuf[sizeof pvpbuf] - replac,
1109 						'\0');
1110 					*++arg_rvp = replac;
1111 					replac += strlen(replac) + 1;
1112 					xpvp = NULL;
1113 				}
1114 				switch (nodetype)
1115 				{
1116 				  case CANONHOST:
1117 					xpvp = rvp;
1118 					break;
1119 
1120 				  case CANONUSER:
1121 					default_rvp = rvp;
1122 					break;
1123 				}
1124 			}
1125 			if (*rvp != NULL)
1126 				*rvp++ = NULL;
1127 			if (xpvp != NULL)
1128 			{
1129 				cataddr(xpvp, NULL, replac,
1130 					&pvpbuf[sizeof pvpbuf] - replac,
1131 					'\0');
1132 				*++arg_rvp = replac;
1133 			}
1134 			*++arg_rvp = NULL;
1135 
1136 			/* save the remainder of the input string */
1137 			trsize = (int) (avp - rvp + 1) * sizeof *rvp;
1138 			bcopy((char *) rvp, (char *) pvpb1, trsize);
1139 
1140 			/* look it up */
1141 			cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
1142 			argvect[0] = buf;
1143 			if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
1144 			{
1145 				auto int stat = EX_OK;
1146 
1147 				if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags))
1148 					stripquotes(buf);
1149 
1150 				/* XXX should try to auto-open the map here */
1151 
1152 				if (tTd(60, 1))
1153 					printf("map_lookup(%s, %s) => ",
1154 						mapname, buf);
1155 				replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
1156 						buf, argvect, &stat);
1157 				if (tTd(60, 1))
1158 					printf("%s (%d)\n",
1159 						replac ? replac : "NOT FOUND",
1160 						stat);
1161 
1162 				/* should recover if stat == EX_TEMPFAIL */
1163 				if (stat == EX_TEMPFAIL)
1164 				{
1165 					rstat = EX_TEMPFAIL;
1166 					if (tTd(60, 1))
1167 						printf("map_lookup(%s, %s) failed (stat = %d)\n",
1168 							mapname, buf, stat);
1169 					if (e->e_message == NULL)
1170 					{
1171 						char mbuf[300];
1172 
1173 						sprintf(mbuf, "map %s: lookup (%s) failed",
1174 							mapname, buf);
1175 						e->e_message = newstr(mbuf);
1176 					}
1177 				}
1178 			}
1179 			else
1180 				replac = NULL;
1181 
1182 			/* if no replacement, use default */
1183 			if (replac == NULL && default_rvp != NULL)
1184 			{
1185 				/* create the default */
1186 				cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
1187 				replac = buf;
1188 			}
1189 
1190 			if (replac == NULL)
1191 			{
1192 				xpvp = key_rvp;
1193 			}
1194 			else if (*replac == '\0')
1195 			{
1196 				/* null replacement */
1197 				nullpvp[0] = NULL;
1198 				xpvp = nullpvp;
1199 			}
1200 			else
1201 			{
1202 				/* scan the new replacement */
1203 				xpvp = prescan(replac, '\0', pvpbuf,
1204 					       sizeof pvpbuf, NULL, NULL);
1205 				if (xpvp == NULL)
1206 				{
1207 					/* prescan already printed error */
1208 					return EX_DATAERR;
1209 				}
1210 			}
1211 
1212 			/* append it to the token list */
1213 			for (avp = hbrvp; *xpvp != NULL; xpvp++)
1214 			{
1215 				*avp++ = newstr(*xpvp);
1216 				if (avp >= &npvp[MAXATOM])
1217 					goto toolong;
1218 			}
1219 
1220 			/* restore the old trailing information */
1221 			for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
1222 				if (avp >= &npvp[MAXATOM])
1223 					goto toolong;
1224 
1225 			break;
1226 		}
1227 
1228 		/*
1229 		**  Check for subroutine calls.
1230 		*/
1231 
1232 		if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
1233 		{
1234 			int stat;
1235 
1236 			if (npvp[1] == NULL)
1237 			{
1238 				syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
1239 					ruleset, ruleno);
1240 				*pvp = NULL;
1241 			}
1242 			else
1243 			{
1244 				int ruleset;
1245 				STAB *s;
1246 
1247 				bcopy((char *) &npvp[2], (char *) pvp,
1248 					(int) (avp - npvp - 2) * sizeof *avp);
1249 				if (tTd(21, 3))
1250 					printf("-----callsubr %s\n", npvp[1]);
1251 				ruleset = strtorwset(npvp[1], NULL, ST_FIND);
1252 				stat = rewrite(pvp, ruleset, reclevel, e);
1253 				if (rstat == EX_OK || stat == EX_TEMPFAIL)
1254 					rstat = stat;
1255 				if (*pvp != NULL && (**pvp & 0377) == CANONNET)
1256 				rwr = NULL;
1257 			}
1258 		}
1259 		else
1260 		{
1261 			bcopy((char *) npvp, (char *) pvp,
1262 				(int) (avp - npvp) * sizeof *avp);
1263 		}
1264 		if (tTd(21, 4))
1265 		{
1266 			printf("rewritten as:");
1267 			printav(pvp);
1268 		}
1269 	}
1270 
1271 	if (OpMode == MD_TEST || tTd(21, 1))
1272 	{
1273 		printf("rewrite: ruleset %2d returns:", ruleset);
1274 		printav(pvp);
1275 	}
1276 
1277 	return rstat;
1278 }
1279 /*
1280 **  BUILDADDR -- build address from token vector.
1281 **
1282 **	Parameters:
1283 **		tv -- token vector.
1284 **		a -- pointer to address descriptor to fill.
1285 **			If NULL, one will be allocated.
1286 **		flags -- info regarding whether this is a sender or
1287 **			a recipient.
1288 **		e -- the current envelope.
1289 **
1290 **	Returns:
1291 **		NULL if there was an error.
1292 **		'a' otherwise.
1293 **
1294 **	Side Effects:
1295 **		fills in 'a'
1296 */
1297 
1298 struct errcodes
1299 {
1300 	char	*ec_name;		/* name of error code */
1301 	int	ec_code;		/* numeric code */
1302 } ErrorCodes[] =
1303 {
1304 	"usage",	EX_USAGE,
1305 	"nouser",	EX_NOUSER,
1306 	"nohost",	EX_NOHOST,
1307 	"unavailable",	EX_UNAVAILABLE,
1308 	"software",	EX_SOFTWARE,
1309 	"tempfail",	EX_TEMPFAIL,
1310 	"protocol",	EX_PROTOCOL,
1311 #ifdef EX_CONFIG
1312 	"config",	EX_CONFIG,
1313 #endif
1314 	NULL,		EX_UNAVAILABLE,
1315 };
1316 
1317 ADDRESS *
buildaddr(tv,a,flags,e)1318 buildaddr(tv, a, flags, e)
1319 	register char **tv;
1320 	register ADDRESS *a;
1321 	int flags;
1322 	register ENVELOPE *e;
1323 {
1324 	struct mailer **mp;
1325 	register struct mailer *m;
1326 	register char *p;
1327 	char *mname;
1328 	char **hostp;
1329 	char hbuf[MAXNAME + 1];
1330 	static MAILER errormailer;
1331 	static char *errorargv[] = { "ERROR", NULL };
1332 	static char ubuf[MAXNAME + 1];
1333 
1334 	if (tTd(24, 5))
1335 	{
1336 		printf("buildaddr, flags=%x, tv=", flags);
1337 		printav(tv);
1338 	}
1339 
1340 	if (a == NULL)
1341 		a = (ADDRESS *) xalloc(sizeof *a);
1342 	bzero((char *) a, sizeof *a);
1343 
1344 	/* set up default error return flags */
1345 	a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
1346 
1347 	/* figure out what net/mailer to use */
1348 	if (*tv == NULL || (**tv & 0377) != CANONNET)
1349 	{
1350 		syserr("554 buildaddr: no net");
1351 badaddr:
1352 		a->q_flags |= QBADADDR;
1353 		a->q_mailer = &errormailer;
1354 		if (errormailer.m_name == NULL)
1355 		{
1356 			/* initialize the bogus mailer */
1357 			errormailer.m_name = "*error*";
1358 			errormailer.m_mailer = "ERROR";
1359 			errormailer.m_argv = errorargv;
1360 		}
1361 		return a;
1362 	}
1363 	mname = *++tv;
1364 
1365 	/* extract host and user portions */
1366 	if ((**++tv & 0377) == CANONHOST)
1367 		hostp = ++tv;
1368 	else
1369 		hostp = NULL;
1370 	while (*tv != NULL && (**tv & 0377) != CANONUSER)
1371 		tv++;
1372 	if (*tv == NULL)
1373 	{
1374 		syserr("554 buildaddr: no user");
1375 		goto badaddr;
1376 	}
1377 	if (hostp != NULL)
1378 		cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
1379 	cataddr(++tv, NULL, ubuf, sizeof ubuf, '\0');
1380 
1381 	/* save away the host name */
1382 	if (strcasecmp(mname, "error") == 0)
1383 	{
1384 		if (hostp != NULL)
1385 		{
1386 			register struct errcodes *ep;
1387 
1388 			if (strchr(hbuf, '.') != NULL)
1389 			{
1390 				a->q_status = newstr(hbuf);
1391 				setstat(dsntoexitstat(hbuf));
1392 			}
1393 			else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
1394 			{
1395 				setstat(atoi(hbuf));
1396 			}
1397 			else
1398 			{
1399 				for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
1400 					if (strcasecmp(ep->ec_name, hbuf) == 0)
1401 						break;
1402 				setstat(ep->ec_code);
1403 			}
1404 		}
1405 		else
1406 			setstat(EX_UNAVAILABLE);
1407 		stripquotes(ubuf);
1408 		if (isascii(ubuf[0]) && isdigit(ubuf[0]) &&
1409 		    isascii(ubuf[1]) && isdigit(ubuf[1]) &&
1410 		    isascii(ubuf[2]) && isdigit(ubuf[2]) &&
1411 		    ubuf[3] == ' ')
1412 		{
1413 			char fmt[10];
1414 
1415 			strncpy(fmt, ubuf, 3);
1416 			strcpy(&fmt[3], " %s");
1417 			usrerr(fmt, ubuf + 4);
1418 
1419 			/*
1420 			**  If this is a 4xx code and we aren't running
1421 			**  SMTP on our input, bounce this message;
1422 			**  otherwise it disappears without a trace.
1423 			*/
1424 
1425 			if (fmt[0] == '4' && OpMode != MD_SMTP &&
1426 			    OpMode != MD_DAEMON)
1427 			{
1428 				e->e_flags |= EF_FATALERRS;
1429 			}
1430 		}
1431 		else
1432 		{
1433 			usrerr("553 %s", ubuf);
1434 		}
1435 		goto badaddr;
1436 	}
1437 
1438 	for (mp = Mailer; (m = *mp++) != NULL; )
1439 	{
1440 		if (strcasecmp(m->m_name, mname) == 0)
1441 			break;
1442 	}
1443 	if (m == NULL)
1444 	{
1445 		syserr("554 buildaddr: unknown mailer %s", mname);
1446 		goto badaddr;
1447 	}
1448 	a->q_mailer = m;
1449 
1450 	/* figure out what host (if any) */
1451 	if (hostp == NULL)
1452 	{
1453 		if (!bitnset(M_LOCALMAILER, m->m_flags))
1454 		{
1455 			syserr("554 buildaddr: no host");
1456 			goto badaddr;
1457 		}
1458 		a->q_host = NULL;
1459 	}
1460 	else
1461 		a->q_host = newstr(hbuf);
1462 
1463 	/* figure out the user */
1464 	p = ubuf;
1465 	if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
1466 	{
1467 		p++;
1468 		tv++;
1469 		a->q_flags |= QNOTREMOTE;
1470 	}
1471 
1472 	/* do special mapping for local mailer */
1473 	if (*p == '"')
1474 		p++;
1475 	if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
1476 		a->q_mailer = m = ProgMailer;
1477 	else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
1478 		a->q_mailer = m = FileMailer;
1479 	else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
1480 	{
1481 		/* may be :include: */
1482 		stripquotes(ubuf);
1483 		if (strncasecmp(ubuf, ":include:", 9) == 0)
1484 		{
1485 			/* if :include:, don't need further rewriting */
1486 			a->q_mailer = m = InclMailer;
1487 			a->q_user = newstr(&ubuf[9]);
1488 			return a;
1489 		}
1490 	}
1491 
1492 	/* rewrite according recipient mailer rewriting rules */
1493 	define('h', a->q_host, e);
1494 	if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
1495 	{
1496 		/* sender addresses done later */
1497 		(void) rewrite(tv, 2, 0, e);
1498 		if (m->m_re_rwset > 0)
1499 		       (void) rewrite(tv, m->m_re_rwset, 0, e);
1500 	}
1501 	(void) rewrite(tv, 4, 0, e);
1502 
1503 	/* save the result for the command line/RCPT argument */
1504 	cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
1505 	a->q_user = ubuf;
1506 
1507 	/*
1508 	**  Do mapping to lower case as requested by mailer
1509 	*/
1510 
1511 	if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
1512 		makelower(a->q_host);
1513 	if (!bitnset(M_USR_UPPER, m->m_flags))
1514 		makelower(a->q_user);
1515 
1516 	return a;
1517 }
1518 /*
1519 **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
1520 **
1521 **	Parameters:
1522 **		pvp -- parameter vector to rebuild.
1523 **		evp -- last parameter to include.  Can be NULL to
1524 **			use entire pvp.
1525 **		buf -- buffer to build the string into.
1526 **		sz -- size of buf.
1527 **		spacesub -- the space separator character; if null,
1528 **			use SpaceSub.
1529 **
1530 **	Returns:
1531 **		none.
1532 **
1533 **	Side Effects:
1534 **		Destroys buf.
1535 */
1536 
1537 void
cataddr(pvp,evp,buf,sz,spacesub)1538 cataddr(pvp, evp, buf, sz, spacesub)
1539 	char **pvp;
1540 	char **evp;
1541 	char *buf;
1542 	register int sz;
1543 	int spacesub;
1544 {
1545 	bool oatomtok = FALSE;
1546 	bool natomtok = FALSE;
1547 	register int i;
1548 	register char *p;
1549 
1550 	if (spacesub == '\0')
1551 		spacesub = SpaceSub;
1552 
1553 	if (pvp == NULL)
1554 	{
1555 		(void) strcpy(buf, "");
1556 		return;
1557 	}
1558 	p = buf;
1559 	sz -= 2;
1560 	while (*pvp != NULL && (i = strlen(*pvp)) < sz)
1561 	{
1562 		natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
1563 		if (oatomtok && natomtok)
1564 			*p++ = spacesub;
1565 		(void) strcpy(p, *pvp);
1566 		oatomtok = natomtok;
1567 		p += i;
1568 		sz -= i + 1;
1569 		if (pvp++ == evp)
1570 			break;
1571 	}
1572 	*p = '\0';
1573 }
1574 /*
1575 **  SAMEADDR -- Determine if two addresses are the same
1576 **
1577 **	This is not just a straight comparison -- if the mailer doesn't
1578 **	care about the host we just ignore it, etc.
1579 **
1580 **	Parameters:
1581 **		a, b -- pointers to the internal forms to compare.
1582 **
1583 **	Returns:
1584 **		TRUE -- they represent the same mailbox.
1585 **		FALSE -- they don't.
1586 **
1587 **	Side Effects:
1588 **		none.
1589 */
1590 
1591 bool
sameaddr(a,b)1592 sameaddr(a, b)
1593 	register ADDRESS *a;
1594 	register ADDRESS *b;
1595 {
1596 	register ADDRESS *ca, *cb;
1597 
1598 	/* if they don't have the same mailer, forget it */
1599 	if (a->q_mailer != b->q_mailer)
1600 		return (FALSE);
1601 
1602 	/* if the user isn't the same, we can drop out */
1603 	if (strcmp(a->q_user, b->q_user) != 0)
1604 		return (FALSE);
1605 
1606 	/* if we have good uids for both but they differ, these are different */
1607 	if (a->q_mailer == ProgMailer)
1608 	{
1609 		ca = getctladdr(a);
1610 		cb = getctladdr(b);
1611 		if (ca != NULL && cb != NULL &&
1612 		    bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
1613 		    ca->q_uid != cb->q_uid)
1614 			return (FALSE);
1615 	}
1616 
1617 	/* otherwise compare hosts (but be careful for NULL ptrs) */
1618 	if (a->q_host == b->q_host)
1619 	{
1620 		/* probably both null pointers */
1621 		return (TRUE);
1622 	}
1623 	if (a->q_host == NULL || b->q_host == NULL)
1624 	{
1625 		/* only one is a null pointer */
1626 		return (FALSE);
1627 	}
1628 	if (strcmp(a->q_host, b->q_host) != 0)
1629 		return (FALSE);
1630 
1631 	return (TRUE);
1632 }
1633 /*
1634 **  PRINTADDR -- print address (for debugging)
1635 **
1636 **	Parameters:
1637 **		a -- the address to print
1638 **		follow -- follow the q_next chain.
1639 **
1640 **	Returns:
1641 **		none.
1642 **
1643 **	Side Effects:
1644 **		none.
1645 */
1646 
1647 struct qflags
1648 {
1649 	char	*qf_name;
1650 	u_long	qf_bit;
1651 };
1652 
1653 struct qflags	AddressFlags[] =
1654 {
1655 	"QDONTSEND",		QDONTSEND,
1656 	"QBADADDR",		QBADADDR,
1657 	"QGOODUID",		QGOODUID,
1658 	"QPRIMARY",		QPRIMARY,
1659 	"QQUEUEUP",		QQUEUEUP,
1660 	"QSENT",		QSENT,
1661 	"QNOTREMOTE",		QNOTREMOTE,
1662 	"QSELFREF",		QSELFREF,
1663 	"QVERIFIED",		QVERIFIED,
1664 	"QBOGUSSHELL",		QBOGUSSHELL,
1665 	"QUNSAFEADDR",		QUNSAFEADDR,
1666 	"QPINGONSUCCESS",	QPINGONSUCCESS,
1667 	"QPINGONFAILURE",	QPINGONFAILURE,
1668 	"QPINGONDELAY",		QPINGONDELAY,
1669 	"QHASNOTIFY",		QHASNOTIFY,
1670 	"QRELAYED",		QRELAYED,
1671 	"QEXPANDED",		QEXPANDED,
1672 	"QDELIVERED",		QDELIVERED,
1673 	"QDELAYED",		QDELAYED,
1674 	"QTHISPASS",		QTHISPASS,
1675 	NULL
1676 };
1677 
1678 void
printaddr(a,follow)1679 printaddr(a, follow)
1680 	register ADDRESS *a;
1681 	bool follow;
1682 {
1683 	register MAILER *m;
1684 	MAILER pseudomailer;
1685 	register struct qflags *qfp;
1686 	bool firstone;
1687 
1688 	if (a == NULL)
1689 	{
1690 		printf("[NULL]\n");
1691 		return;
1692 	}
1693 
1694 	while (a != NULL)
1695 	{
1696 		printf("%x=", a);
1697 		(void) fflush(stdout);
1698 
1699 		/* find the mailer -- carefully */
1700 		m = a->q_mailer;
1701 		if (m == NULL)
1702 		{
1703 			m = &pseudomailer;
1704 			m->m_mno = -1;
1705 			m->m_name = "NULL";
1706 		}
1707 
1708 		printf("%s:\n\tmailer %d (%s), host `%s'\n",
1709 		       a->q_paddr, m->m_mno, m->m_name,
1710 		       a->q_host == NULL ? "<null>" : a->q_host);
1711 		printf("\tuser `%s', ruser `%s'\n",
1712 		       a->q_user,
1713 		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
1714 		printf("\tnext=%x, alias %x, uid %d, gid %d\n",
1715 		       a->q_next, a->q_alias, a->q_uid, a->q_gid);
1716 		printf("\tflags=%lx<", a->q_flags);
1717 		firstone = TRUE;
1718 		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
1719 		{
1720 			if (!bitset(qfp->qf_bit, a->q_flags))
1721 				continue;
1722 			if (!firstone)
1723 				printf(",");
1724 			firstone = FALSE;
1725 			printf("%s", qfp->qf_name);
1726 		}
1727 		printf(">\n");
1728 		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
1729 		       a->q_owner == NULL ? "(none)" : a->q_owner,
1730 		       a->q_home == NULL ? "(none)" : a->q_home,
1731 		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
1732 		printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n",
1733 		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
1734 		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
1735 		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
1736 
1737 		if (!follow)
1738 			return;
1739 		a = a->q_next;
1740 	}
1741 }
1742 /*
1743 **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
1744 **
1745 **	Parameters:
1746 **		a -- pointer to the address
1747 **
1748 **	Returns:
1749 **		TRUE -- if this address is "empty" (i.e., no one should
1750 **			ever generate replies to it.
1751 **		FALSE -- if it is a "regular" (read: replyable) address.
1752 */
1753 
1754 bool
emptyaddr(a)1755 emptyaddr(a)
1756 	register ADDRESS *a;
1757 {
1758 	return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
1759 }
1760 /*
1761 **  REMOTENAME -- return the name relative to the current mailer
1762 **
1763 **	Parameters:
1764 **		name -- the name to translate.
1765 **		m -- the mailer that we want to do rewriting relative
1766 **			to.
1767 **		flags -- fine tune operations.
1768 **		pstat -- pointer to status word.
1769 **		e -- the current envelope.
1770 **
1771 **	Returns:
1772 **		the text string representing this address relative to
1773 **			the receiving mailer.
1774 **
1775 **	Side Effects:
1776 **		none.
1777 **
1778 **	Warnings:
1779 **		The text string returned is tucked away locally;
1780 **			copy it if you intend to save it.
1781 */
1782 
1783 char *
remotename(name,m,flags,pstat,e)1784 remotename(name, m, flags, pstat, e)
1785 	char *name;
1786 	struct mailer *m;
1787 	int flags;
1788 	int *pstat;
1789 	register ENVELOPE *e;
1790 {
1791 	register char **pvp;
1792 	char *fancy;
1793 	char *oldg = macvalue('g', e);
1794 	int rwset;
1795 	static char buf[MAXNAME + 1];
1796 	char lbuf[MAXNAME + 1];
1797 	char pvpbuf[PSBUFSIZE];
1798 	extern char *crackaddr();
1799 
1800 	if (tTd(12, 1))
1801 		printf("remotename(%s)\n", name);
1802 
1803 	/* don't do anything if we are tagging it as special */
1804 	if (bitset(RF_SENDERADDR, flags))
1805 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
1806 						     : m->m_se_rwset;
1807 	else
1808 		rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
1809 						     : m->m_re_rwset;
1810 	if (rwset < 0)
1811 		return (name);
1812 
1813 	/*
1814 	**  Do a heuristic crack of this name to extract any comment info.
1815 	**	This will leave the name as a comment and a $g macro.
1816 	*/
1817 
1818 	if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
1819 		fancy = "\201g";
1820 	else
1821 		fancy = crackaddr(name);
1822 
1823 	/*
1824 	**  Turn the name into canonical form.
1825 	**	Normally this will be RFC 822 style, i.e., "user@domain".
1826 	**	If this only resolves to "user", and the "C" flag is
1827 	**	specified in the sending mailer, then the sender's
1828 	**	domain will be appended.
1829 	*/
1830 
1831 	pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
1832 	if (pvp == NULL)
1833 		return (name);
1834 	if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1835 		*pstat = EX_TEMPFAIL;
1836 	if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
1837 	{
1838 		/* append from domain to this address */
1839 		register char **pxp = pvp;
1840 
1841 		/* see if there is an "@domain" in the current name */
1842 		while (*pxp != NULL && strcmp(*pxp, "@") != 0)
1843 			pxp++;
1844 		if (*pxp == NULL)
1845 		{
1846 			/* no.... append the "@domain" from the sender */
1847 			register char **qxq = e->e_fromdomain;
1848 
1849 			while ((*pxp++ = *qxq++) != NULL)
1850 				continue;
1851 			if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1852 				*pstat = EX_TEMPFAIL;
1853 		}
1854 	}
1855 
1856 	/*
1857 	**  Do more specific rewriting.
1858 	**	Rewrite using ruleset 1 or 2 depending on whether this is
1859 	**		a sender address or not.
1860 	**	Then run it through any receiving-mailer-specific rulesets.
1861 	*/
1862 
1863 	if (bitset(RF_SENDERADDR, flags))
1864 	{
1865 		if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
1866 			*pstat = EX_TEMPFAIL;
1867 	}
1868 	else
1869 	{
1870 		if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
1871 			*pstat = EX_TEMPFAIL;
1872 	}
1873 	if (rwset > 0)
1874 	{
1875 		if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
1876 			*pstat = EX_TEMPFAIL;
1877 	}
1878 
1879 	/*
1880 	**  Do any final sanitation the address may require.
1881 	**	This will normally be used to turn internal forms
1882 	**	(e.g., user@host.LOCAL) into external form.  This
1883 	**	may be used as a default to the above rules.
1884 	*/
1885 
1886 	if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
1887 		*pstat = EX_TEMPFAIL;
1888 
1889 	/*
1890 	**  Now restore the comment information we had at the beginning.
1891 	*/
1892 
1893 	cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
1894 	define('g', lbuf, e);
1895 
1896 	/* need to make sure route-addrs have <angle brackets> */
1897 	if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
1898 		expand("<\201g>", buf, sizeof buf, e);
1899 	else
1900 		expand(fancy, buf, sizeof buf, e);
1901 
1902 	define('g', oldg, e);
1903 
1904 	if (tTd(12, 1))
1905 		printf("remotename => `%s'\n", buf);
1906 	return (buf);
1907 }
1908 /*
1909 **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
1910 **
1911 **	Parameters:
1912 **		a -- the address to map (but just the user name part).
1913 **		sendq -- the sendq in which to install any replacement
1914 **			addresses.
1915 **		aliaslevel -- the alias nesting depth.
1916 **		e -- the envelope.
1917 **
1918 **	Returns:
1919 **		none.
1920 */
1921 
1922 void
maplocaluser(a,sendq,aliaslevel,e)1923 maplocaluser(a, sendq, aliaslevel, e)
1924 	register ADDRESS *a;
1925 	ADDRESS **sendq;
1926 	int aliaslevel;
1927 	ENVELOPE *e;
1928 {
1929 	register char **pvp;
1930 	register ADDRESS *a1 = NULL;
1931 	auto char *delimptr;
1932 	char pvpbuf[PSBUFSIZE];
1933 
1934 	if (tTd(29, 1))
1935 	{
1936 		printf("maplocaluser: ");
1937 		printaddr(a, FALSE);
1938 	}
1939 	pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
1940 	if (pvp == NULL)
1941 		return;
1942 
1943 	(void) rewrite(pvp, 5, 0, e);
1944 	if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
1945 		return;
1946 
1947 	/* if non-null, mailer destination specified -- has it changed? */
1948 	a1 = buildaddr(pvp, NULL, 0, e);
1949 	if (a1 == NULL || sameaddr(a, a1))
1950 		return;
1951 
1952 	/* mark old address as dead; insert new address */
1953 	a->q_flags |= QDONTSEND;
1954 	if (tTd(29, 5))
1955 	{
1956 		printf("maplocaluser: QDONTSEND ");
1957 		printaddr(a, FALSE);
1958 	}
1959 	a1->q_alias = a;
1960 	allocaddr(a1, RF_COPYALL, NULL);
1961 	(void) recipient(a1, sendq, aliaslevel, e);
1962 }
1963 /*
1964 **  DEQUOTE_INIT -- initialize dequote map
1965 **
1966 **	This is a no-op.
1967 **
1968 **	Parameters:
1969 **		map -- the internal map structure.
1970 **		args -- arguments.
1971 **
1972 **	Returns:
1973 **		TRUE.
1974 */
1975 
1976 bool
dequote_init(map,args)1977 dequote_init(map, args)
1978 	MAP *map;
1979 	char *args;
1980 {
1981 	register char *p = args;
1982 
1983 	map->map_mflags |= MF_KEEPQUOTES;
1984 	for (;;)
1985 	{
1986 		while (isascii(*p) && isspace(*p))
1987 			p++;
1988 		if (*p != '-')
1989 			break;
1990 		switch (*++p)
1991 		{
1992 		  case 'a':
1993 			map->map_app = ++p;
1994 			break;
1995 
1996 		  case 's':
1997 			map->map_coldelim = *++p;
1998 			break;
1999 		}
2000 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2001 			p++;
2002 		if (*p != '\0')
2003 			*p = '\0';
2004 	}
2005 	if (map->map_app != NULL)
2006 		map->map_app = newstr(map->map_app);
2007 
2008 	return TRUE;
2009 }
2010 /*
2011 **  DEQUOTE_MAP -- unquote an address
2012 **
2013 **	Parameters:
2014 **		map -- the internal map structure (ignored).
2015 **		name -- the name to dequote.
2016 **		av -- arguments (ignored).
2017 **		statp -- pointer to status out-parameter.
2018 **
2019 **	Returns:
2020 **		NULL -- if there were no quotes, or if the resulting
2021 **			unquoted buffer would not be acceptable to prescan.
2022 **		else -- The dequoted buffer.
2023 */
2024 
2025 char *
dequote_map(map,name,av,statp)2026 dequote_map(map, name, av, statp)
2027 	MAP *map;
2028 	char *name;
2029 	char **av;
2030 	int *statp;
2031 {
2032 	register char *p;
2033 	register char *q;
2034 	register char c;
2035 	int anglecnt = 0;
2036 	int cmntcnt = 0;
2037 	int quotecnt = 0;
2038 	int spacecnt = 0;
2039 	bool quotemode = FALSE;
2040 	bool bslashmode = FALSE;
2041 	char spacesub = map->map_coldelim;
2042 
2043 	for (p = q = name; (c = *p++) != '\0'; )
2044 	{
2045 		if (bslashmode)
2046 		{
2047 			bslashmode = FALSE;
2048 			*q++ = c;
2049 			continue;
2050 		}
2051 
2052 		if (c == ' ' && spacesub != '\0')
2053 			c = spacesub;
2054 
2055 		switch (c)
2056 		{
2057 		  case '\\':
2058 			bslashmode = TRUE;
2059 			break;
2060 
2061 		  case '(':
2062 			cmntcnt++;
2063 			break;
2064 
2065 		  case ')':
2066 			if (cmntcnt-- <= 0)
2067 				return NULL;
2068 			break;
2069 
2070 		  case ' ':
2071 			spacecnt++;
2072 			break;
2073 		}
2074 
2075 		if (cmntcnt > 0)
2076 		{
2077 			*q++ = c;
2078 			continue;
2079 		}
2080 
2081 		switch (c)
2082 		{
2083 		  case '"':
2084 			quotemode = !quotemode;
2085 			quotecnt++;
2086 			continue;
2087 
2088 		  case '<':
2089 			anglecnt++;
2090 			break;
2091 
2092 		  case '>':
2093 			if (anglecnt-- <= 0)
2094 				return NULL;
2095 			break;
2096 		}
2097 		*q++ = c;
2098 	}
2099 
2100 	if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
2101 	    quotemode || quotecnt <= 0 || spacecnt != 0)
2102 		return NULL;
2103 	*q++ = '\0';
2104 	return name;
2105 }
2106