#line	2	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
#include "common.h"
#include "smtp.h"
#include <ctype.h>

char	*yylp;		/* next character to be lex'd */
int	yydone;		/* tell yylex to give up */
char	*yybuffer;	/* first parsed character */
char	*yyend;		/* end of buffer to be parsed */
Node	*root;
Field	*firstfield;
Field	*lastfield;
Node	*usender;
Node	*usys;
Node	*udate;
char	*startfield, *endfield;
int	originator;
int	destination;
int	date;
int	received;
int	messageid;
extern	int	yyerrflag;
#ifndef	YYMAXDEPTH
#define	YYMAXDEPTH	150
#endif
#ifndef	YYSTYPE
#define	YYSTYPE	int
#endif
YYSTYPE	yylval;
YYSTYPE	yyval;
#define	WORD	57346
#define	DATE	57347
#define	RESENT_DATE	57348
#define	RETURN_PATH	57349
#define	FROM	57350
#define	SENDER	57351
#define	REPLY_TO	57352
#define	RESENT_FROM	57353
#define	RESENT_SENDER	57354
#define	RESENT_REPLY_TO	57355
#define	SUBJECT	57356
#define	TO	57357
#define	CC	57358
#define	BCC	57359
#define	RESENT_TO	57360
#define	RESENT_CC	57361
#define	RESENT_BCC	57362
#define	REMOTE	57363
#define	PRECEDENCE	57364
#define	MIMEVERSION	57365
#define	CONTENTTYPE	57366
#define	MESSAGEID	57367
#define	RECEIVED	57368
#define	MAILER	57369
#define	BADTOKEN	57370
#define YYEOFCODE 1
#define YYERRCODE 2

#line	246	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"


/*
 *  Initialize the parsing.  Done once for each header field.
 */
void
yyinit(char *p, int len)
{
	yybuffer = p;
	yylp = p;
	yyend = p + len;
	firstfield = lastfield = 0;
	received = 0;
}

/*
 *  keywords identifying header fields we care about
 */
typedef struct Keyword	Keyword;
struct Keyword {
	char	*rep;
	int	val;
};

/* field names that we need to recognize */
Keyword key[] = {
	{ "date", DATE },
	{ "resent-date", RESENT_DATE },
	{ "return_path", RETURN_PATH },
	{ "from", FROM },
	{ "sender", SENDER },
	{ "reply-to", REPLY_TO },
	{ "resent-from", RESENT_FROM },
	{ "resent-sender", RESENT_SENDER },
	{ "resent-reply-to", RESENT_REPLY_TO },
	{ "to", TO },
	{ "cc", CC },
	{ "bcc", BCC },
	{ "resent-to", RESENT_TO },
	{ "resent-cc", RESENT_CC },
	{ "resent-bcc", RESENT_BCC },
	{ "remote", REMOTE },
	{ "subject", SUBJECT },
	{ "precedence", PRECEDENCE },
	{ "mime-version", MIMEVERSION },
	{ "content-type", CONTENTTYPE },
	{ "message-id", MESSAGEID },
	{ "received", RECEIVED },
	{ "mailer", MAILER },
	{ "who-the-hell-cares", WORD }
};

/*
 *  Lexical analysis for an rfc822 header field.  Continuation lines
 *  are handled in yywhite() when skipping over white space.
 *
 */
int
yylex(void)
{
	String *t;
	int quoting;
	int escaping;
	char *start;
	Keyword *kp;
	int c, d;

/*	print("lexing\n"); /**/
	if(yylp >= yyend)
		return 0;
	if(yydone)
		return 0;

	quoting = escaping = 0;
	start = yylp;
	yylval = malloc(sizeof(Node));
	yylval->white = yylval->s = 0;
	yylval->next = 0;
	yylval->addr = 0;
	yylval->start = yylp;
	for(t = 0; yylp < yyend; yylp++){
		c = *yylp & 0xff;

		/* dump nulls, they can't be in header */
		if(c == 0)
			continue;

		if(escaping) {
			escaping = 0;
		} else if(quoting) {
			switch(c){
			case '\\':
				escaping = 1;
				break;
			case '\n':
				d = (*(yylp+1))&0xff;
				if(d != ' ' && d != '\t'){
					quoting = 0;
					yylp--;
					continue;
				}
				break;
			case '"':
				quoting = 0;
				break;
			}
		} else {
			switch(c){
			case '\\':
				escaping = 1;
				break;
			case '(':
			case ' ':
			case '\t':
			case '\r':
				goto out;
			case '\n':
				if(yylp == start){
					yylp++;
/*					print("lex(c %c)\n", c); /**/
					yylval->end = yylp;
					return yylval->c = c;
				}
				goto out;
			case '@':
			case '>':
			case '<':
			case ':':
			case ',':
			case ';':
				if(yylp == start){
					yylp++;
					yylval->white = yywhite();
/*					print("lex(c %c)\n", c); /**/
					yylval->end = yylp;
					return yylval->c = c;
				}
				goto out;
			case '"':
				quoting = 1;
				break;
			default:
				break;
			}
		}
		if(t == 0)
			t = s_new();
		s_putc(t, c);
	}
out:
	yylval->white = yywhite();
	if(t) {
		s_terminate(t);
	} else				/* message begins with white-space! */
		return yylval->c = '\n';
	yylval->s = t;
	for(kp = key; kp->val != WORD; kp++)
		if(cistrcmp(s_to_c(t), kp->rep)==0)
			break;
/*	print("lex(%d) %s\n", kp->val-WORD, s_to_c(t)); /**/
	yylval->end = yylp;
	return yylval->c = kp->val;
}

void
yyerror(char *x)
{
	USED(x);

	/*fprint(2, "parse err: %s\n", x);/**/
}

/*
 *  parse white space and comments
 */
String *
yywhite(void)
{
	String *w;
	int clevel;
	int c;
	int escaping;

	escaping = clevel = 0;
	for(w = 0; yylp < yyend; yylp++){
		c = *yylp & 0xff;

		/* dump nulls, they can't be in header */
		if(c == 0)
			continue;

		if(escaping){
			escaping = 0;
		} else if(clevel) {
			switch(c){
			case '\n':
				/*
				 *  look for multiline fields
				 */
				if(*(yylp+1)==' ' || *(yylp+1)=='\t')
					break;
				else
					goto out;
			case '\\':
				escaping = 1;
				break;
			case '(':
				clevel++;
				break;
			case ')':
				clevel--;
				break;
			}
		} else {
			switch(c){
			case '\\':
				escaping = 1;
				break;
			case '(':
				clevel++;
				break;
			case ' ':
			case '\t':
			case '\r':
				break;
			case '\n':
				/*
				 *  look for multiline fields
				 */
				if(*(yylp+1)==' ' || *(yylp+1)=='\t')
					break;
				else
					goto out;
			default:
				goto out;
			}
		}
		if(w == 0)
			w = s_new();
		s_putc(w, c);
	}
out:
	if(w)
		s_terminate(w);
	return w;
}

/*
 *  link two parsed entries together
 */
Node*
link2(Node *p1, Node *p2)
{
	Node *p;

	for(p = p1; p->next; p = p->next)
		;
	p->next = p2;
	return p1;
}

/*
 *  link three parsed entries together
 */
Node*
link3(Node *p1, Node *p2, Node *p3)
{
	Node *p;

	for(p = p2; p->next; p = p->next)
		;
	p->next = p3;

	for(p = p1; p->next; p = p->next)
		;
	p->next = p2;

	return p1;
}

/*
 *  make a:b, move all white space after both
 */
Node*
colon(Node *p1, Node *p2)
{
	if(p1->white){
		if(p2->white)
			s_append(p1->white, s_to_c(p2->white));
	} else {
		p1->white = p2->white;
		p2->white = 0;
	}

	s_append(p1->s, ":");
	if(p2->s)
		s_append(p1->s, s_to_c(p2->s));

	if(p1->end < p2->end)
		p1->end = p2->end;
	freenode(p2);
	return p1;
}

/*
 *  concatenate two fields, move all white space after both
 */
Node*
concat(Node *p1, Node *p2)
{
	char buf[2];

	if(p1->white){
		if(p2->white)
			s_append(p1->white, s_to_c(p2->white));
	} else {
		p1->white = p2->white;
		p2->white = 0;
	}

	if(p1->s == nil){
		buf[0] = p1->c;
		buf[1] = 0;
		p1->s = s_new();
		s_append(p1->s, buf);
	}

	if(p2->s)
		s_append(p1->s, s_to_c(p2->s));
	else {
		buf[0] = p2->c;
		buf[1] = 0;
		s_append(p1->s, buf);
	}

	if(p1->end < p2->end)
		p1->end = p2->end;
	freenode(p2);
	return p1;
}

/*
 *  look for disallowed chars in the field name
 */
int
badfieldname(Node *p)
{
	for(; p; p = p->next){
		/* field name can't contain white space */
		if(p->white && p->next)
			return 1;
	}
	return 0;
}

/*
 *  mark as an address
 */
Node *
address(Node *p)
{
	p->addr = 1;
	return p;
}

/*
 *  case independent string compare
 */
int
cistrcmp(char *s1, char *s2)
{
	int c1, c2;

	for(; *s1; s1++, s2++){
		c1 = isupper(*s1) ? tolower(*s1) : *s1;
		c2 = isupper(*s2) ? tolower(*s2) : *s2;
		if (c1 != c2)
			return -1;
	}
	return *s2;
}

/*
 *  free a node
 */
void
freenode(Node *p)
{
	Node *tp;

	while(p){
		tp = p->next;
		if(p->s)
			s_free(p->s);
		if(p->white)
			s_free(p->white);
		free(p);
		p = tp;
	}
}


/*
 *  an anonymous user
 */
Node*
nobody(Node *p)
{
	if(p->s)
		s_free(p->s);
	p->s = s_copy("pOsTmAsTeR");
	p->addr = 1;
	return p;
}

/*
 *  add anything that was dropped because of a parse error
 */
void
missing(Node *p)
{
	Node *np;
	char *start, *end;
	Field *f;
	String *s;

	start = yybuffer;
	if(lastfield != nil){
		for(np = lastfield->node; np; np = np->next)
			start = np->end+1;
	}

	end = p->start-1;

	if(end <= start)
		return;

	if(strncmp(start, "From ", 5) == 0)
		return;

	np = malloc(sizeof(Node));
	np->start = start;
	np->end = end;
	np->white = nil;
	s = s_copy("BadHeader: ");
	np->s = s_nappend(s, start, end-start);
	np->next = nil;

	f = malloc(sizeof(Field));
	f->next = 0;
	f->node = np;
	f->source = 0;
	if(firstfield)
		lastfield->next = f;
	else
		firstfield = f;
	lastfield = f;
}

/*
 *  create a new field
 */
void
newfield(Node *p, int source)
{
	Field *f;

	missing(p);

	f = malloc(sizeof(Field));
	f->next = 0;
	f->node = p;
	f->source = source;
	if(firstfield)
		lastfield->next = f;
	else
		firstfield = f;
	lastfield = f;
	endfield = startfield;
	startfield = yylp;
}

/*
 *  fee a list of fields
 */
void
freefield(Field *f)
{
	Field *tf;

	while(f){
		tf = f->next;
		freenode(f->node);
		free(f);
		f = tf;
	}
}

/*
 *  add some white space to a node
 */
Node*
whiten(Node *p)
{
	Node *tp;

	for(tp = p; tp->next; tp = tp->next)
		;
	if(tp->white == 0)
		tp->white = s_copy(" ");
	return p;
}

void
yycleanup(void)
{
	Field *f, *fnext;
	Node *np, *next;

	for(f = firstfield; f; f = fnext){
		for(np = f->node; np; np = next){
			if(np->s)
				s_free(np->s);
			if(np->white)
				s_free(np->white);
			next = np->next;
			free(np);
		}
		fnext = f->next;
		free(f);
	}
	firstfield = lastfield = 0;
}
static	const	short	yyexca[] =
{-1, 1,
	1, -1,
	-2, 0,
-1, 47,
	1, 4,
	-2, 0,
-1, 112,
	29, 72,
	31, 72,
	32, 72,
	35, 72,
	-2, 74
};
#define	YYNPROD	122
#define	YYPRIVATE 57344
#define	YYLAST	608
static	const	short	yyact[] =
{
 112, 133, 136,  53, 121, 111, 134,  55, 109, 118,
 119, 116, 162, 171,  35,  48, 166,  54,   5, 166,
 179, 114, 115, 155,  49, 101, 100,  99,  95,  94,
  93,  92,  98,  91, 132,  90, 123,  89, 122,  88,
  87,  86,  85,  84,  83,  82,  97,  81,  80, 106,
  47,  46, 110, 117, 153, 168, 108,   2,  56,  57,
  58,  59,  60,  61,  62,  63,  64,  65,  73,  66,
  67,  68,  69,  70,  71,  72,  74,  75,  76,  77,
  78,  79, 124, 124,  49,  55, 177, 131, 110,  52,
 110, 110, 138, 137, 140, 141, 124, 124,  51, 120,
 124, 124, 124,  50, 102, 104, 135, 154,  31,  32,
 107, 157, 105,  14,  55,  55, 156,  13, 161, 117,
 117, 139, 158, 124, 142, 143, 144, 145, 146, 147,
 163, 164, 160,  12, 148, 149,  11, 157, 150, 151,
 152,  10, 156,   9,   8,   7,   3,   1,   0, 124,
 124, 124, 124, 124,   0, 169,   0,   0, 110, 165,
   0,   0, 170, 117,   0,   0,   0,   0, 173, 176,
 178,   0,   0,   0, 172,   0,   0,   0, 180,   0,
   0, 182, 183,   0,   0, 165, 165, 165, 165, 165,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0, 174,  56,  57,  58,  59,  60,  61,  62,
  63,  64,  65,  73,  66,  67,  68,  69,  70,  71,
  72,  74,  75,  76,  77,  78,  79,   0,   0, 128,
 130, 129, 125, 126, 127,  15,   0,  36,  16,  17,
  19, 103,  20,  18,  23,  22,  21,  30,  24,  26,
  28,  25,  27,  29,   0,  34,  37,  38,  39,  33,
  40,   0,   4,   0,  45,  44,  41,  42,  43,  56,
  57,  58,  59,  60,  61,  62,  63,  64,  65,  73,
  66,  67,  68,  69,  70,  71,  72,  74,  75,  76,
  77,  78,  79,   0,   0,  96,  45,  44,  41,  42,
  43,  15,   0,  36,  16,  17,  19,   6,  20,  18,
  23,  22,  21,  30,  24,  26,  28,  25,  27,  29,
   0,  34,  37,  38,  39,  33,  40,   0,   4,   0,
  45,  44,  41,  42,  43,  15,   0,  36,  16,  17,
  19, 103,  20,  18,  23,  22,  21,  30,  24,  26,
  28,  25,  27,  29,   0,  34,  37,  38,  39,  33,
  40,   0,   0,   0,  45,  44,  41,  42,  43,  56,
  57,  58,  59,  60,  61,  62,  63,  64,  65,  73,
  66,  67,  68,  69,  70,  71,  72,  74,  75,  76,
  77,  78,  79,   0,   0,   0,   0, 175, 113,   0,
  52,  56,  57,  58,  59,  60,  61,  62,  63,  64,
  65,  73,  66,  67,  68,  69,  70,  71,  72,  74,
  75,  76,  77,  78,  79,   0,   0,   0,   0,   0,
 113,   0,  52,  56,  57,  58,  59,  60,  61,  62,
  63,  64,  65,  73,  66,  67,  68,  69,  70,  71,
  72,  74,  75,  76,  77,  78,  79,   0,   0,   0,
   0,   0,   0, 159,  52,  56,  57,  58,  59,  60,
  61,  62,  63,  64,  65,  73,  66,  67,  68,  69,
  70,  71,  72,  74,  75,  76,  77,  78,  79,   0,
   0,   0,   0,   0,   0,   0,  52,  56,  57,  58,
  59,  60,  61,  62,  63,  64,  65,  73,  66,  67,
  68,  69,  70,  71,  72,  74,  75,  76,  77,  78,
  79,   0,   0, 167,   0,   0, 113,  56,  57,  58,
  59,  60,  61,  62,  63,  64,  65,  73,  66,  67,
  68,  69,  70,  71,  72,  74,  75,  76,  77,  78,
  79,   0,   0,   0,   0,   0, 113,  56,  57,  58,
  59,  60,  61,  62,  63,  64,  65,  73,  66,  67,
  68,  69,  70,  71,  72,  74,  75,  76,  77,  78,
  79,   0,   0, 181,  56,  57,  58,  59,  60,  61,
  62,  63,  64,  65,  73,  66,  67,  68,  69,  70,
  71,  72,  74,  75,  76,  77,  78,  79
};
static	const	short	yypact[] =
{
 299,-1000,-1000,  22,-1000,  21,  54,-1000,-1000,-1000,
-1000,-1000,-1000,-1000,-1000,  19,  17,  15,  14,  13,
  12,  11,  10,   9,   7,   5,   3,   1,   0,  -1,
  -2, 265,  -3,  -4,  -5,-1000,-1000,-1000,-1000,-1000,
-1000,-1000,-1000,-1000,-1000,-1000, 233, 233, 580, 397,
  -9,-1000, 580, -26, -25,-1000,-1000,-1000,-1000,-1000,
-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
 333, 199, 199, 397, 461, 397, 397, 397, 397, 397,
 397, 397, 397, 397, 397, 199, 199,-1000,-1000, 199,
 199, 199,-1000,  -6,-1000,  33, 580,  -8,-1000,-1000,
 523,-1000,-1000, 429, 580, -23,-1000,-1000, 580, 580,
-1000,-1000, 199,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
-1000,-1000, -15,-1000,-1000,-1000, 493,-1000,-1000, -15,
-1000,-1000, -15, -15, -15, -15, -15, -15, 199, 199,
 199, 199, 199,  47, 580, 397,-1000,-1000, -21,-1000,
 -25, -26, 580,-1000,-1000,-1000, 397, 365, 580, 580,
-1000,-1000,-1000,-1000, -12,-1000,-1000, 553,-1000,-1000,
 580, 580,-1000,-1000
};
static	const	short	yypgo[] =
{
   0, 147,  57, 146,  18, 145, 144, 143, 141, 136,
 133, 117, 113,   8, 112,   0,  34, 110,   6,   4,
  38, 109, 108,   1, 106,   2,   5, 103,  17,  98,
  11,   3,  36,  86,  14
};
static	const	short	yyr1[] =
{
   0,   1,   1,   2,   2,   2,   4,   4,   4,   4,
   4,   4,   4,   4,   4,   3,   6,   6,   6,   6,
   6,   6,   6,   5,   5,   7,   7,   7,   7,   7,
   7,   7,   7,   7,   7,   7,   7,   8,   8,  11,
  11,  12,  12,  10,  10,  21,  21,  21,  21,   9,
   9,  16,  16,  23,  23,  24,  24,  17,  17,  18,
  18,  18,  26,  26,  13,  13,  27,  27,  29,  29,
  28,  28,  31,  30,  25,  25,  20,  20,  32,  32,
  32,  32,  32,  32,  32,  19,  14,  33,  33,  15,
  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,
  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,
  15,  15,  15,  22,  22,  22,  22,  34,  34,  34,
  34,  34
};
static	const	short	yyr2[] =
{
   0,   1,   3,   1,   2,   3,   1,   1,   1,   1,
   1,   1,   1,   1,   3,   6,   3,   3,   3,   3,
   3,   3,   3,   3,   3,   2,   3,   2,   3,   2,
   3,   2,   3,   2,   3,   2,   3,   3,   2,   3,
   2,   3,   2,   3,   2,   1,   1,   1,   1,   3,
   2,   1,   3,   1,   1,   4,   3,   1,   3,   1,
   2,   1,   3,   2,   3,   1,   2,   4,   1,   1,
   3,   3,   1,   1,   1,   2,   1,   2,   1,   1,
   1,   1,   1,   1,   1,   1,   6,   1,   3,   1,
   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
   1,   1,   1,   1,   1,   2,   2,   1,   1,   1,
   1,   1
};
static	const	short	yychk[] =
{
-1000,  -1,  -2,  -3,  29,  -4,   8,  -5,  -6,  -7,
  -8,  -9, -10, -11, -12,   2,   5,   6,  10,   7,
   9,  13,  12,  11,  15,  18,  16,  19,  17,  20,
  14, -22, -21,  26,  22, -34,   4,  23,  24,  25,
  27,  33,  34,  35,  32,  31,  29,  29, -13,  30,
 -27, -29,  35, -31, -28, -15,   4,   5,   6,   7,
   8,   9,  10,  11,  12,  13,  15,  16,  17,  18,
  19,  20,  21,  14,  22,  23,  24,  25,  26,  27,
  29,  30,  30,  30,  30,  30,  30,  30,  30,  30,
  30,  30,  30,  30,  30,  30,  30, -34, -15,  30,
  30,  30,  -2,   8,  -2, -14, -15, -17, -18, -13,
 -25, -26, -15,  33,  30,  31, -30, -15,  35,  35,
  -4, -19, -20, -32, -15,  33,  34,  35,  30,  32,
  31, -19, -16, -23, -18, -24, -25, -13, -18, -16,
 -18, -18, -16, -16, -16, -16, -16, -16, -20, -20,
 -20, -20, -20,  21, -15,  31, -26, -15, -13,  34,
 -28, -31,  35, -30, -30, -32,  31,  30,   8, -15,
 -18,  34, -30, -23, -16,  32, -15, -33, -15,  32,
 -15,  30, -15, -15
};
static	const	short	yydef[] =
{
   0,  -2,   1,   0,   3,   0,   0,   6,   7,   8,
   9,  10,  11,  12,  13,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0, 113, 114,  45,  46,  47,
  48, 117, 118, 119, 120, 121,   0,  -2,   0,   0,
   0,  65,   0,  68,  69,  72,  89,  90,  91,  92,
  93,  94,  95,  96,  97,  98,  99, 100, 101, 102,
 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
   0,   0,   0,   0,   0,   0,   0,   0,   0,  25,
  27,  29,  31,  33,  35,  38,  50, 115, 116,  44,
  40,  42,   2,   0,   5,   0,   0,  18,  57,  59,
   0,  61,  -2,   0,   0,   0,  66,  73,   0,   0,
  14,  23,  85,  76,  78,  79,  80,  81,  82,  83,
  84,  24,  16,  51,  53,  54,   0,  17,  19,  20,
  21,  22,  26,  28,  30,  32,  34,  36,  37,  49,
  43,  39,  41,   0,   0,   0,  60,  75,   0,  63,
  64,   0,   0,  70,  71,  77,   0,   0,   0,   0,
  58,  62,  67,  52,   0,  56,  15,   0,  87,  55,
   0,   0,  86,  88
};
static	const	short	yytok1[] =
{
   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  29,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,  31,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,  30,  32,
  33,   0,  34,   0,  35
};
static	const	short	yytok2[] =
{
   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,
  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,
  22,  23,  24,  25,  26,  27,  28
};
static	const	long	yytok3[] =
{
   0
};
#define YYFLAG 		-1000
#define YYERROR		goto yyerrlab
#define YYACCEPT	return(0)
#define YYABORT		return(1)
#define	yyclearin	yychar = -1
#define	yyerrok		yyerrflag = 0

#ifdef	yydebug
#include	"y.debug"
#else
#define	yydebug		0
static	const	char*	yytoknames[1];		/* for debugging */
static	const	char*	yystates[1];		/* for debugging */
#endif

/*	parser for yacc output	*/
#ifdef YYARG
#define	yynerrs		yyarg->yynerrs
#define	yyerrflag	yyarg->yyerrflag
#define yyval		yyarg->yyval
#define yylval		yyarg->yylval
#else
int	yynerrs = 0;		/* number of errors */
int	yyerrflag = 0;		/* error recovery flag */
#endif

extern	int	fprint(int, char*, ...);
extern	int	sprint(char*, char*, ...);

static const char*
yytokname(int yyc)
{
	static char x[10];

	if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
	if(yytoknames[yyc-1])
		return yytoknames[yyc-1];
	sprint(x, "<%d>", yyc);
	return x;
}

static const char*
yystatname(int yys)
{
	static char x[10];

	if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
	if(yystates[yys])
		return yystates[yys];
	sprint(x, "<%d>\n", yys);
	return x;
}

static long
#ifdef YYARG
yylex1(struct Yyarg *yyarg)
#else
yylex1(void)
#endif
{
	long yychar;
	const long *t3p;
	int c;

#ifdef YYARG	
	yychar = yylex(yyarg);
#else
	yychar = yylex();
#endif
	if(yychar <= 0) {
		c = yytok1[0];
		goto out;
	}
	if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
		c = yytok1[yychar];
		goto out;
	}
	if(yychar >= YYPRIVATE)
		if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
			c = yytok2[yychar-YYPRIVATE];
			goto out;
		}
	for(t3p=yytok3;; t3p+=2) {
		c = t3p[0];
		if(c == yychar) {
			c = t3p[1];
			goto out;
		}
		if(c == 0)
			break;
	}
	c = 0;

out:
	if(c == 0)
		c = yytok2[1];	/* unknown char */
	if(yydebug >= 3)
		fprint(2, "lex %.4lux %s\n", yychar, yytokname(c));
	return c;
}

int
#ifdef YYARG
yyparse(struct Yyarg *yyarg)
#else
yyparse(void)
#endif
{
	struct
	{
		YYSTYPE	yyv;
		int	yys;
	} yys[YYMAXDEPTH], *yyp, *yypt;
	const short *yyxi;
	int yyj, yym, yystate, yyn, yyg;
	long yychar;
#ifndef YYARG
	YYSTYPE save1, save2;
	int save3, save4;

	save1 = yylval;
	save2 = yyval;
	save3 = yynerrs;
	save4 = yyerrflag;
#endif

	yystate = 0;
	yychar = -1;
	yynerrs = 0;
	yyerrflag = 0;
	yyp = &yys[-1];
	goto yystack;

ret0:
	yyn = 0;
	goto ret;

ret1:
	yyn = 1;
	goto ret;

ret:
#ifndef YYARG
	yylval = save1;
	yyval = save2;
	yynerrs = save3;
	yyerrflag = save4;
#endif
	return yyn;

yystack:
	/* put a state and value onto the stack */
	if(yydebug >= 4)
		fprint(2, "char %s in %s", yytokname(yychar), yystatname(yystate));

	yyp++;
	if(yyp >= &yys[YYMAXDEPTH]) {
		yyerror("yacc stack overflow");
		goto ret1;
	}
	yyp->yys = yystate;
	yyp->yyv = yyval;

yynewstate:
	yyn = yypact[yystate];
	if(yyn <= YYFLAG)
		goto yydefault; /* simple state */
	if(yychar < 0)
#ifdef YYARG
		yychar = yylex1(yyarg);
#else
		yychar = yylex1();
#endif
	yyn += yychar;
	if(yyn < 0 || yyn >= YYLAST)
		goto yydefault;
	yyn = yyact[yyn];
	if(yychk[yyn] == yychar) { /* valid shift */
		yychar = -1;
		yyval = yylval;
		yystate = yyn;
		if(yyerrflag > 0)
			yyerrflag--;
		goto yystack;
	}

yydefault:
	/* default state action */
	yyn = yydef[yystate];
	if(yyn == -2) {
		if(yychar < 0)
#ifdef YYARG
		yychar = yylex1(yyarg);
#else
		yychar = yylex1();
#endif

		/* look through exception table */
		for(yyxi=yyexca;; yyxi+=2)
			if(yyxi[0] == -1 && yyxi[1] == yystate)
				break;
		for(yyxi += 2;; yyxi += 2) {
			yyn = yyxi[0];
			if(yyn < 0 || yyn == yychar)
				break;
		}
		yyn = yyxi[1];
		if(yyn < 0)
			goto ret0;
	}
	if(yyn == 0) {
		/* error ... attempt to resume parsing */
		switch(yyerrflag) {
		case 0:   /* brand new error */
			yyerror("syntax error");
			if(yydebug >= 1) {
				fprint(2, "%s", yystatname(yystate));
				fprint(2, "saw %s\n", yytokname(yychar));
			}
			goto yyerrlab;
		yyerrlab:
			yynerrs++;

		case 1:
		case 2: /* incompletely recovered error ... try again */
			yyerrflag = 3;

			/* find a state where "error" is a legal shift action */
			while(yyp >= yys) {
				yyn = yypact[yyp->yys] + YYERRCODE;
				if(yyn >= 0 && yyn < YYLAST) {
					yystate = yyact[yyn];  /* simulate a shift of "error" */
					if(yychk[yystate] == YYERRCODE)
						goto yystack;
				}

				/* the current yyp has no shift onn "error", pop stack */
				if(yydebug >= 2)
					fprint(2, "error recovery pops state %d, uncovers %d\n",
						yyp->yys, (yyp-1)->yys );
				yyp--;
			}
			/* there is no state on the stack with an error shift ... abort */
			goto ret1;

		case 3:  /* no shift yet; clobber input char */
			if(yydebug >= 2)
				fprint(2, "error recovery discards %s\n", yytokname(yychar));
			if(yychar == YYEOFCODE)
				goto ret1;
			yychar = -1;
			goto yynewstate;   /* try again in the same state */
		}
	}

	/* reduction by production yyn */
	if(yydebug >= 2)
		fprint(2, "reduce %d in:\n\t%s", yyn, yystatname(yystate));

	yypt = yyp;
	yyp -= yyr2[yyn];
	yyval = (yyp+1)->yyv;
	yym = yyn;

	/* consult goto table to find next state */
	yyn = yyr1[yyn];
	yyg = yypgo[yyn];
	yyj = yyg + yyp->yys + 1;

	if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
		yystate = yyact[yyg];
	switch(yym) {
		
case 3:
#line	56	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yydone = 1; } break;
case 6:
#line	61	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ date = 1; } break;
case 7:
#line	63	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ originator = 1; } break;
case 8:
#line	65	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ destination = 1; } break;
case 15:
#line	74	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ freenode(yypt[-5].yyv); freenode(yypt[-2].yyv); freenode(yypt[-1].yyv);
			  usender = yypt[-4].yyv; udate = yypt[-3].yyv; usys = yypt[-0].yyv;
			} break;
case 16:
#line	79	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 1); } break;
case 17:
#line	81	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 1); } break;
case 18:
#line	83	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 1); } break;
case 19:
#line	85	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 1); } break;
case 20:
#line	87	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 1); } break;
case 21:
#line	89	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 1); } break;
case 22:
#line	91	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 1); } break;
case 23:
#line	94	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 24:
#line	96	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 25:
#line	99	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 26:
#line	101	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 27:
#line	103	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 28:
#line	105	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 29:
#line	107	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 30:
#line	109	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 31:
#line	111	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 32:
#line	113	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 33:
#line	115	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 34:
#line	117	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 35:
#line	119	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 36:
#line	121	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 37:
#line	124	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 38:
#line	126	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 39:
#line	129	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); received++; } break;
case 40:
#line	131	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); received++; } break;
case 41:
#line	134	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 42:
#line	136	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 43:
#line	139	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 44:
#line	141	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0); } break;
case 47:
#line	143	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ messageid = 1; } break;
case 49:
#line	146	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ /* hack to allow same lex for field names and the rest */
			 if(badfieldname(yypt[-2].yyv)){
				freenode(yypt[-2].yyv);
				freenode(yypt[-1].yyv);
				freenode(yypt[-0].yyv);
				return 1;
			 }
			 newfield(link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv), 0);
			} break;
case 50:
#line	156	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ /* hack to allow same lex for field names and the rest */
			 if(badfieldname(yypt[-1].yyv)){
				freenode(yypt[-1].yyv);
				freenode(yypt[-0].yyv);
				return 1;
			 }
			 newfield(link2(yypt[-1].yyv, yypt[-0].yyv), 0);
			} break;
case 52:
#line	167	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
case 55:
#line	173	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link2(yypt[-3].yyv, link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv)); } break;
case 56:
#line	175	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
case 58:
#line	179	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
case 60:
#line	183	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link2(yypt[-1].yyv, yypt[-0].yyv); } break;
case 62:
#line	187	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
case 63:
#line	189	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = nobody(yypt[-0].yyv); freenode(yypt[-1].yyv); } break;
case 64:
#line	192	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = address(concat(yypt[-2].yyv, concat(yypt[-1].yyv, yypt[-0].yyv))); } break;
case 66:
#line	196	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = concat(yypt[-1].yyv, yypt[-0].yyv); } break;
case 67:
#line	198	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = concat(yypt[-3].yyv, concat(yypt[-2].yyv, concat(yypt[-1].yyv, yypt[-0].yyv))); } break;
case 68:
#line	201	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = address(yypt[-0].yyv); } break;
case 70:
#line	205	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = address(concat(yypt[-2].yyv, concat(yypt[-1].yyv, yypt[-0].yyv)));} break;
case 71:
#line	207	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = address(concat(yypt[-2].yyv, concat(yypt[-1].yyv, yypt[-0].yyv)));} break;
case 75:
#line	215	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link2(yypt[-1].yyv, yypt[-0].yyv); } break;
case 77:
#line	219	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link2(yypt[-1].yyv, yypt[-0].yyv); } break;
case 86:
#line	226	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link3(yypt[-5].yyv, yypt[-3].yyv, link3(yypt[-4].yyv, yypt[-0].yyv, link2(yypt[-2].yyv, yypt[-1].yyv))); } break;
case 88:
#line	230	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link3(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
case 115:
#line	240	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link2(yypt[-1].yyv, yypt[-0].yyv); } break;
case 116:
#line	242	"/usr/local/plan9/src/cmd/upas/smtp/rfc822.y"
{ yyval = link2(yypt[-1].yyv, yypt[-0].yyv); } break;
	}
	goto yystack;  /* stack new state and value */
}