Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

%{
#include "common.h"
#include <ctype.h>
#include "smtpd.h"

#define YYMAXDEPTH      500             /* was default 150 */

#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(); }
                | '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("500 5.5.1 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) fprint(2, "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;
        return rv;
}

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

/*
 *  an anonymous user
 */
YYSTYPE
anonymous(void)
{
        YYSTYPE rv;

        rv.s = s_copy("/dev/null");
        return rv;
}