|  | %{ | 
|  | #include "common.h" | 
|  | #include <ctype.h> | 
|  | #include "smtpd.h" | 
|  |  | 
|  | #define YYSTYPE yystype | 
|  | typedef struct quux yystype; | 
|  | struct quux { | 
|  | String	*s; | 
|  | int	c; | 
|  | }; | 
|  | Biobuf *yyfp; | 
|  | YYSTYPE *bang; | 
|  | extern Biobuf bin; | 
|  | extern int debug; | 
|  |  | 
|  | YYSTYPE cat(YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*); | 
|  | int yyparse(void); | 
|  | int yylex(void); | 
|  | YYSTYPE anonymous(void); | 
|  | %} | 
|  |  | 
|  | %term SPACE | 
|  | %term CNTRL | 
|  | %term CRLF | 
|  | %start conversation | 
|  | %% | 
|  |  | 
|  | conversation	: cmd | 
|  | | conversation cmd | 
|  | ; | 
|  | cmd		: error | 
|  | | 'h' 'e' 'l' 'o' spaces sdomain CRLF | 
|  | { hello($6.s, 0); } | 
|  | | 'e' 'h' 'l' 'o' spaces sdomain CRLF | 
|  | { hello($6.s, 1); } | 
|  | | 'm' 'a' 'i' 'l' spaces 'f' 'r' 'o' 'm' ':' spath CRLF | 
|  | { sender($11.s); } | 
|  | | 'm' 'a' 'i' 'l' spaces 'f' 'r' 'o' 'm' ':' spath spaces 'a' 'u' 't' 'h' '=' sauth CRLF | 
|  | { sender($11.s); } | 
|  | | 'r' 'c' 'p' 't' spaces 't' 'o' ':' spath CRLF | 
|  | { receiver($9.s); } | 
|  | | 'd' 'a' 't' 'a' CRLF | 
|  | { data(); } | 
|  | | 'r' 's' 'e' 't' CRLF | 
|  | { reset(); } | 
|  | | 's' 'e' 'n' 'd' spaces 'f' 'r' 'o' 'm' ':' spath CRLF | 
|  | { sender($11.s); } | 
|  | | 's' 'o' 'm' 'l' spaces 'f' 'r' 'o' 'm'  ':' spath CRLF | 
|  | { sender($11.s); } | 
|  | | 's' 'a' 'm' 'l' spaces 'f' 'r' 'o' 'm' ':' spath CRLF | 
|  | { sender($11.s); } | 
|  | | 'v' 'r' 'f' 'y' spaces string CRLF | 
|  | { verify($6.s); } | 
|  | | 'e' 'x' 'p' 'n' spaces string CRLF | 
|  | { verify($6.s); } | 
|  | | 'h' 'e' 'l' 'p' CRLF | 
|  | { help(0); } | 
|  | | 'h' 'e' 'l' 'p' spaces string CRLF | 
|  | { help($6.s); } | 
|  | | 'n' 'o' 'o' 'p' CRLF | 
|  | { noop(); } | 
|  | | 'q' 'u' 'i' 't' CRLF | 
|  | { quit(); } | 
|  | | 't' 'u' 'r' 'n' CRLF | 
|  | { turn(); } | 
|  | | 's' 't' 'a' 'r' 't' 't' 'l' 's' CRLF | 
|  | { starttls(); } | 
|  | | 'a' 'u' 't' 'h' spaces name spaces string CRLF | 
|  | { auth($6.s, $8.s); } | 
|  | | 'a' 'u' 't' 'h' spaces name CRLF | 
|  | { auth($6.s, nil); } | 
|  | | CRLF | 
|  | { reply("501 illegal command or bad syntax\r\n"); } | 
|  | ; | 
|  | path		: '<' '>'			={ $$ = anonymous(); } | 
|  | | '<' mailbox '>'		={ $$ = $2; } | 
|  | | '<' a_d_l ':' mailbox '>'	={ $$ = cat(&$2, bang, &$4, 0, 0 ,0, 0); } | 
|  | ; | 
|  | spath		: path			={ $$ = $1; } | 
|  | | spaces path		={ $$ = $2; } | 
|  | ; | 
|  | auth		: path			={ $$ = $1; } | 
|  | | mailbox		={ $$ = $1; } | 
|  | ; | 
|  | sauth		: auth			={ $$ = $1; } | 
|  | | spaces auth		={ $$ = $2; } | 
|  | ; | 
|  | ; | 
|  | a_d_l		: at_domain		={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | at_domain ',' a_d_l	={ $$ = cat(&$1, bang, &$3, 0, 0, 0, 0); } | 
|  | ; | 
|  | at_domain	: '@' domain		={ $$ = cat(&$2, 0, 0, 0, 0 ,0, 0); } | 
|  | ; | 
|  | sdomain		: domain		={ $$ = $1; } | 
|  | | domain spaces		={ $$ = $1; } | 
|  | ; | 
|  | domain		: element		={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | element '.'		={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | element '.' domain	={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); } | 
|  | ; | 
|  | element		: name			={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | '#' number		={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | | '[' ']'		={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | | '[' dotnum ']'	={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); } | 
|  | ; | 
|  | mailbox		: local_part		={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | local_part '@' domain	={ $$ = cat(&$3, bang, &$1, 0, 0 ,0, 0); } | 
|  | ; | 
|  | local_part	: dot_string		={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | quoted_string		={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | ; | 
|  | name		: let_dig			={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | let_dig ld_str		={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | | let_dig ldh_str ld_str	={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); } | 
|  | ; | 
|  | ld_str		: let_dig | 
|  | | let_dig ld_str		={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | ; | 
|  | ldh_str		: hunder | 
|  | | ld_str hunder		={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | | ldh_str ld_str hunder	={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); } | 
|  | ; | 
|  | let_dig		: a | 
|  | | d | 
|  | ; | 
|  | dot_string	: string			={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | string '.' dot_string		={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); } | 
|  | ; | 
|  |  | 
|  | string		: char	={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | string char	={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | ; | 
|  |  | 
|  | quoted_string	: '"' qtext '"'	={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); } | 
|  | ; | 
|  | qtext		: '\\' x		={ $$ = cat(&$2, 0, 0, 0, 0 ,0, 0); } | 
|  | | qtext '\\' x		={ $$ = cat(&$1, &$3, 0, 0, 0 ,0, 0); } | 
|  | | q | 
|  | | qtext q		={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | ; | 
|  | char		: c | 
|  | | '\\' x		={ $$ = $2; } | 
|  | ; | 
|  | dotnum		: snum '.' snum '.' snum '.' snum ={ $$ = cat(&$1, &$2, &$3, &$4, &$5, &$6, &$7); } | 
|  | ; | 
|  | number		: d		={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); } | 
|  | | number d	={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); } | 
|  | ; | 
|  | snum		: number		={ if(atoi(s_to_c($1.s)) > 255) print("bad snum\n"); } | 
|  | ; | 
|  | spaces		: SPACE		={ $$ = $1; } | 
|  | | SPACE	spaces	={ $$ = $1; } | 
|  | ; | 
|  | hunder		: '-' | '_' | 
|  | ; | 
|  | special1	: CNTRL | 
|  | | '(' | ')' | ',' | '.' | 
|  | | ':' | ';' | '<' | '>' | '@' | 
|  | ; | 
|  | special		: special1 | '\\' | '"' | 
|  | ; | 
|  | notspecial	: '!' | '#' | '$' | '%' | '&' | '\'' | 
|  | | '*' | '+' | '-' | '/' | 
|  | | '=' | '?' | 
|  | | '[' | ']' | '^' | '_' | '`' | '{' | '|' | '}' | '~' | 
|  | ; | 
|  |  | 
|  | a		: 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 
|  | | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 
|  | | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | 
|  | ; | 
|  | d		: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 
|  | ; | 
|  | c		: a | d | notspecial | 
|  | ; | 
|  | q		: a | d | special1 | notspecial | SPACE | 
|  | ; | 
|  | x		: a | d | special | notspecial | SPACE | 
|  | ; | 
|  | %% | 
|  |  | 
|  | void | 
|  | parseinit(void) | 
|  | { | 
|  | bang = (YYSTYPE*)malloc(sizeof(YYSTYPE)); | 
|  | bang->c = '!'; | 
|  | bang->s = 0; | 
|  | yyfp = &bin; | 
|  | } | 
|  |  | 
|  | int | 
|  | yylex(void) | 
|  | { | 
|  | int c; | 
|  |  | 
|  | for(;;){ | 
|  | c = Bgetc(yyfp); | 
|  | if(c == -1) | 
|  | return 0; | 
|  | if(debug) | 
|  | fprint(2, "%c", c); | 
|  | yylval.c = c = c & 0x7F; | 
|  | if(c == '\n'){ | 
|  | return CRLF; | 
|  | } | 
|  | if(c == '\r'){ | 
|  | c = Bgetc(yyfp); | 
|  | if(c != '\n'){ | 
|  | Bungetc(yyfp); | 
|  | c = '\r'; | 
|  | } else { | 
|  | if(debug) | 
|  | fprint(2, "%c", c); | 
|  | return CRLF; | 
|  | } | 
|  | } | 
|  | if(isalpha(c)) | 
|  | return tolower(c); | 
|  | if(isspace(c)) | 
|  | return SPACE; | 
|  | if(iscntrl(c)) | 
|  | return CNTRL; | 
|  | return c; | 
|  | } | 
|  | } | 
|  |  | 
|  | YYSTYPE | 
|  | cat(YYSTYPE *y1, YYSTYPE *y2, YYSTYPE *y3, YYSTYPE *y4, YYSTYPE *y5, YYSTYPE *y6, YYSTYPE *y7) | 
|  | { | 
|  | YYSTYPE rv; | 
|  |  | 
|  | memset(&rv, 0, sizeof rv); | 
|  | if(y1->s) | 
|  | rv.s = y1->s; | 
|  | else { | 
|  | rv.s = s_new(); | 
|  | s_putc(rv.s, y1->c); | 
|  | s_terminate(rv.s); | 
|  | } | 
|  | if(y2){ | 
|  | if(y2->s){ | 
|  | s_append(rv.s, s_to_c(y2->s)); | 
|  | s_free(y2->s); | 
|  | } else { | 
|  | s_putc(rv.s, y2->c); | 
|  | s_terminate(rv.s); | 
|  | } | 
|  | } else | 
|  | return rv; | 
|  | if(y3){ | 
|  | if(y3->s){ | 
|  | s_append(rv.s, s_to_c(y3->s)); | 
|  | s_free(y3->s); | 
|  | } else { | 
|  | s_putc(rv.s, y3->c); | 
|  | s_terminate(rv.s); | 
|  | } | 
|  | } else | 
|  | return rv; | 
|  | if(y4){ | 
|  | if(y4->s){ | 
|  | s_append(rv.s, s_to_c(y4->s)); | 
|  | s_free(y4->s); | 
|  | } else { | 
|  | s_putc(rv.s, y4->c); | 
|  | s_terminate(rv.s); | 
|  | } | 
|  | } else | 
|  | return rv; | 
|  | if(y5){ | 
|  | if(y5->s){ | 
|  | s_append(rv.s, s_to_c(y5->s)); | 
|  | s_free(y5->s); | 
|  | } else { | 
|  | s_putc(rv.s, y5->c); | 
|  | s_terminate(rv.s); | 
|  | } | 
|  | } else | 
|  | return rv; | 
|  | if(y6){ | 
|  | if(y6->s){ | 
|  | s_append(rv.s, s_to_c(y6->s)); | 
|  | s_free(y6->s); | 
|  | } else { | 
|  | s_putc(rv.s, y6->c); | 
|  | s_terminate(rv.s); | 
|  | } | 
|  | } else | 
|  | return rv; | 
|  | if(y7){ | 
|  | if(y7->s){ | 
|  | s_append(rv.s, s_to_c(y7->s)); | 
|  | s_free(y7->s); | 
|  | } else { | 
|  | s_putc(rv.s, y7->c); | 
|  | s_terminate(rv.s); | 
|  | } | 
|  | } else | 
|  | return rv; | 
|  | return rv; | 
|  | } | 
|  |  | 
|  | void | 
|  | yyerror(char *x) | 
|  | { | 
|  | USED(x); | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  an anonymous user | 
|  | */ | 
|  | YYSTYPE | 
|  | anonymous(void) | 
|  | { | 
|  | YYSTYPE rv; | 
|  |  | 
|  | memset(&rv, 0, sizeof rv); | 
|  | rv.s = s_copy("/dev/null"); | 
|  | return rv; | 
|  | } |