| |
| #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 */ |
| } |