diff options
Diffstat (limited to 'src/cmd/upas/smtp/smtpd.y')
-rw-r--r-- | src/cmd/upas/smtp/smtpd.y | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/src/cmd/upas/smtp/smtpd.y b/src/cmd/upas/smtp/smtpd.y new file mode 100644 index 00000000..57b89a02 --- /dev/null +++ b/src/cmd/upas/smtp/smtpd.y @@ -0,0 +1,317 @@ +%{ +#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; +} + +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; + + 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; +} + +void +yyerror(char *x) +{ + USED(x); +} + +/* + * an anonymous user + */ +YYSTYPE +anonymous(void) +{ + YYSTYPE rv; + + rv.s = s_copy("/dev/null"); + return rv; +} |