13e12c5d1SDavid du Colombier %{
23e12c5d1SDavid du Colombier #include "common.h"
33e12c5d1SDavid du Colombier #include "smtp.h"
43e12c5d1SDavid du Colombier #include <ctype.h>
53e12c5d1SDavid du Colombier
6*426fe599SDavid du Colombier #define YYMAXDEPTH 500 /* was default 150 */
7*426fe599SDavid du Colombier
83e12c5d1SDavid du Colombier char *yylp; /* next character to be lex'd */
9332d2f58SDavid du Colombier int yydone; /* tell yylex to give up */
10219b2ee8SDavid du Colombier char *yybuffer; /* first parsed character */
119a747e4fSDavid du Colombier char *yyend; /* end of buffer to be parsed */
123e12c5d1SDavid du Colombier Node *root;
133e12c5d1SDavid du Colombier Field *firstfield;
143e12c5d1SDavid du Colombier Field *lastfield;
153e12c5d1SDavid du Colombier Node *usender;
163e12c5d1SDavid du Colombier Node *usys;
173e12c5d1SDavid du Colombier Node *udate;
18332d2f58SDavid du Colombier char *startfield, *endfield;
193e12c5d1SDavid du Colombier int originator;
20219b2ee8SDavid du Colombier int destination;
213e12c5d1SDavid du Colombier int date;
227dd7cddfSDavid du Colombier int received;
239a747e4fSDavid du Colombier int messageid;
243e12c5d1SDavid du Colombier %}
253e12c5d1SDavid du Colombier
263e12c5d1SDavid du Colombier %term WORD
273e12c5d1SDavid du Colombier %term DATE
283e12c5d1SDavid du Colombier %term RESENT_DATE
293e12c5d1SDavid du Colombier %term RETURN_PATH
303e12c5d1SDavid du Colombier %term FROM
313e12c5d1SDavid du Colombier %term SENDER
323e12c5d1SDavid du Colombier %term REPLY_TO
333e12c5d1SDavid du Colombier %term RESENT_FROM
343e12c5d1SDavid du Colombier %term RESENT_SENDER
353e12c5d1SDavid du Colombier %term RESENT_REPLY_TO
36219b2ee8SDavid du Colombier %term SUBJECT
373e12c5d1SDavid du Colombier %term TO
383e12c5d1SDavid du Colombier %term CC
393e12c5d1SDavid du Colombier %term BCC
403e12c5d1SDavid du Colombier %term RESENT_TO
413e12c5d1SDavid du Colombier %term RESENT_CC
423e12c5d1SDavid du Colombier %term RESENT_BCC
433e12c5d1SDavid du Colombier %term REMOTE
447dd7cddfSDavid du Colombier %term PRECEDENCE
45219b2ee8SDavid du Colombier %term MIMEVERSION
46219b2ee8SDavid du Colombier %term CONTENTTYPE
47219b2ee8SDavid du Colombier %term MESSAGEID
48219b2ee8SDavid du Colombier %term RECEIVED
49219b2ee8SDavid du Colombier %term MAILER
507dd7cddfSDavid du Colombier %term BADTOKEN
513e12c5d1SDavid du Colombier %start msg
523e12c5d1SDavid du Colombier %%
533e12c5d1SDavid du Colombier
543e12c5d1SDavid du Colombier msg : fields
553e12c5d1SDavid du Colombier | unixfrom '\n' fields
563e12c5d1SDavid du Colombier ;
57332d2f58SDavid du Colombier fields : '\n'
58332d2f58SDavid du Colombier { yydone = 1; }
59332d2f58SDavid du Colombier | field '\n'
603e12c5d1SDavid du Colombier | field '\n' fields
613e12c5d1SDavid du Colombier ;
623e12c5d1SDavid du Colombier field : dates
633e12c5d1SDavid du Colombier { date = 1; }
643e12c5d1SDavid du Colombier | originator
653e12c5d1SDavid du Colombier { originator = 1; }
663e12c5d1SDavid du Colombier | destination
67219b2ee8SDavid du Colombier { destination = 1; }
68219b2ee8SDavid du Colombier | subject
693e12c5d1SDavid du Colombier | optional
70219b2ee8SDavid du Colombier | ignored
717dd7cddfSDavid du Colombier | received
727dd7cddfSDavid du Colombier | precedence
73332d2f58SDavid du Colombier | error '\n' field
743e12c5d1SDavid du Colombier ;
753e12c5d1SDavid du Colombier unixfrom : FROM route_addr unix_date_time REMOTE FROM word
763e12c5d1SDavid du Colombier { freenode($1); freenode($4); freenode($5);
773e12c5d1SDavid du Colombier usender = $2; udate = $3; usys = $6;
783e12c5d1SDavid du Colombier }
793e12c5d1SDavid du Colombier ;
803e12c5d1SDavid du Colombier originator : REPLY_TO ':' address_list
813e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 1); }
823e12c5d1SDavid du Colombier | RETURN_PATH ':' route_addr
833e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 1); }
843e12c5d1SDavid du Colombier | FROM ':' mailbox_list
853e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 1); }
863e12c5d1SDavid du Colombier | SENDER ':' mailbox
873e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 1); }
883e12c5d1SDavid du Colombier | RESENT_REPLY_TO ':' address_list
893e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 1); }
907dd7cddfSDavid du Colombier | RESENT_SENDER ':' mailbox
917dd7cddfSDavid du Colombier { newfield(link3($1, $2, $3), 1); }
927dd7cddfSDavid du Colombier | RESENT_FROM ':' mailbox
937dd7cddfSDavid du Colombier { newfield(link3($1, $2, $3), 1); }
943e12c5d1SDavid du Colombier ;
953e12c5d1SDavid du Colombier dates : DATE ':' date_time
963e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
973e12c5d1SDavid du Colombier | RESENT_DATE ':' date_time
983e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
993e12c5d1SDavid du Colombier ;
1007dd7cddfSDavid du Colombier destination : TO ':'
1017dd7cddfSDavid du Colombier { newfield(link2($1, $2), 0); }
1027dd7cddfSDavid du Colombier | TO ':' address_list
1033e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1047dd7cddfSDavid du Colombier | RESENT_TO ':'
1057dd7cddfSDavid du Colombier { newfield(link2($1, $2), 0); }
1063e12c5d1SDavid du Colombier | RESENT_TO ':' address_list
1073e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1087dd7cddfSDavid du Colombier | CC ':'
1097dd7cddfSDavid du Colombier { newfield(link2($1, $2), 0); }
1103e12c5d1SDavid du Colombier | CC ':' address_list
1113e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1127dd7cddfSDavid du Colombier | RESENT_CC ':'
1137dd7cddfSDavid du Colombier { newfield(link2($1, $2), 0); }
1143e12c5d1SDavid du Colombier | RESENT_CC ':' address_list
1153e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1163e12c5d1SDavid du Colombier | BCC ':'
1173e12c5d1SDavid du Colombier { newfield(link2($1, $2), 0); }
1183e12c5d1SDavid du Colombier | BCC ':' address_list
1193e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1203e12c5d1SDavid du Colombier | RESENT_BCC ':'
1213e12c5d1SDavid du Colombier { newfield(link2($1, $2), 0); }
1223e12c5d1SDavid du Colombier | RESENT_BCC ':' address_list
1233e12c5d1SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1243e12c5d1SDavid du Colombier ;
125219b2ee8SDavid du Colombier subject : SUBJECT ':' things
126219b2ee8SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1277dd7cddfSDavid du Colombier | SUBJECT ':'
1287dd7cddfSDavid du Colombier { newfield(link2($1, $2), 0); }
1297dd7cddfSDavid du Colombier ;
1307dd7cddfSDavid du Colombier received : RECEIVED ':' things
1317dd7cddfSDavid du Colombier { newfield(link3($1, $2, $3), 0); received++; }
1327dd7cddfSDavid du Colombier | RECEIVED ':'
1337dd7cddfSDavid du Colombier { newfield(link2($1, $2), 0); received++; }
1347dd7cddfSDavid du Colombier ;
1357dd7cddfSDavid du Colombier precedence : PRECEDENCE ':' things
1367dd7cddfSDavid du Colombier { newfield(link3($1, $2, $3), 0); }
1377dd7cddfSDavid du Colombier | PRECEDENCE ':'
1387dd7cddfSDavid du Colombier { newfield(link2($1, $2), 0); }
139219b2ee8SDavid du Colombier ;
140219b2ee8SDavid du Colombier ignored : ignoredhdr ':' things
141219b2ee8SDavid du Colombier { newfield(link3($1, $2, $3), 0); }
142219b2ee8SDavid du Colombier | ignoredhdr ':'
143219b2ee8SDavid du Colombier { newfield(link2($1, $2), 0); }
144219b2ee8SDavid du Colombier ;
1459a747e4fSDavid du Colombier ignoredhdr : MIMEVERSION | CONTENTTYPE | MESSAGEID { messageid = 1; } | MAILER
146219b2ee8SDavid du Colombier ;
1477dd7cddfSDavid du Colombier optional : fieldwords ':' things
1487dd7cddfSDavid du Colombier { /* hack to allow same lex for field names and the rest */
1497dd7cddfSDavid du Colombier if(badfieldname($1)){
1507dd7cddfSDavid du Colombier freenode($1);
1517dd7cddfSDavid du Colombier freenode($2);
1527dd7cddfSDavid du Colombier freenode($3);
1537dd7cddfSDavid du Colombier return 1;
1547dd7cddfSDavid du Colombier }
1557dd7cddfSDavid du Colombier newfield(link3($1, $2, $3), 0);
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier | fieldwords ':'
1587dd7cddfSDavid du Colombier { /* hack to allow same lex for field names and the rest */
1597dd7cddfSDavid du Colombier if(badfieldname($1)){
1607dd7cddfSDavid du Colombier freenode($1);
1617dd7cddfSDavid du Colombier freenode($2);
1627dd7cddfSDavid du Colombier return 1;
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier newfield(link2($1, $2), 0);
1657dd7cddfSDavid du Colombier }
1663e12c5d1SDavid du Colombier ;
1673e12c5d1SDavid du Colombier address_list : address
1683e12c5d1SDavid du Colombier | address_list ',' address
1693e12c5d1SDavid du Colombier { $$ = link3($1, $2, $3); }
1703e12c5d1SDavid du Colombier ;
1713e12c5d1SDavid du Colombier address : mailbox
1723e12c5d1SDavid du Colombier | group
1733e12c5d1SDavid du Colombier ;
1747dd7cddfSDavid du Colombier group : phrase ':' address_list ';'
1757dd7cddfSDavid du Colombier { $$ = link2($1, link3($2, $3, $4)); }
1767dd7cddfSDavid du Colombier | phrase ':' ';'
1777dd7cddfSDavid du Colombier { $$ = link3($1, $2, $3); }
1783e12c5d1SDavid du Colombier ;
1793e12c5d1SDavid du Colombier mailbox_list : mailbox
1803e12c5d1SDavid du Colombier | mailbox_list ',' mailbox
1813e12c5d1SDavid du Colombier { $$ = link3($1, $2, $3); }
1823e12c5d1SDavid du Colombier ;
1833e12c5d1SDavid du Colombier mailbox : route_addr
1843e12c5d1SDavid du Colombier | phrase brak_addr
1853e12c5d1SDavid du Colombier { $$ = link2($1, $2); }
1867dd7cddfSDavid du Colombier | brak_addr
1873e12c5d1SDavid du Colombier ;
1883e12c5d1SDavid du Colombier brak_addr : '<' route_addr '>'
1893e12c5d1SDavid du Colombier { $$ = link3($1, $2, $3); }
1903e12c5d1SDavid du Colombier | '<' '>'
1919a747e4fSDavid du Colombier { $$ = nobody($2); freenode($1); }
1923e12c5d1SDavid du Colombier ;
193219b2ee8SDavid du Colombier route_addr : route ':' at_addr
1947dd7cddfSDavid du Colombier { $$ = address(concat($1, concat($2, $3))); }
1953e12c5d1SDavid du Colombier | addr_spec
1963e12c5d1SDavid du Colombier ;
1973e12c5d1SDavid du Colombier route : '@' domain
1987dd7cddfSDavid du Colombier { $$ = concat($1, $2); }
1993e12c5d1SDavid du Colombier | route ',' '@' domain
2007dd7cddfSDavid du Colombier { $$ = concat($1, concat($2, concat($3, $4))); }
2013e12c5d1SDavid du Colombier ;
2023e12c5d1SDavid du Colombier addr_spec : local_part
2033e12c5d1SDavid du Colombier { $$ = address($1); }
204219b2ee8SDavid du Colombier | at_addr
205219b2ee8SDavid du Colombier ;
206219b2ee8SDavid du Colombier at_addr : local_part '@' domain
2077dd7cddfSDavid du Colombier { $$ = address(concat($1, concat($2, $3)));}
2087dd7cddfSDavid du Colombier | at_addr '@' domain
2097dd7cddfSDavid du Colombier { $$ = address(concat($1, concat($2, $3)));}
2103e12c5d1SDavid du Colombier ;
2113e12c5d1SDavid du Colombier local_part : word
2123e12c5d1SDavid du Colombier ;
2133e12c5d1SDavid du Colombier domain : word
2143e12c5d1SDavid du Colombier ;
2153e12c5d1SDavid du Colombier phrase : word
2163e12c5d1SDavid du Colombier | phrase word
2173e12c5d1SDavid du Colombier { $$ = link2($1, $2); }
2183e12c5d1SDavid du Colombier ;
2193e12c5d1SDavid du Colombier things : thing
2203e12c5d1SDavid du Colombier | things thing
2213e12c5d1SDavid du Colombier { $$ = link2($1, $2); }
2223e12c5d1SDavid du Colombier ;
2233e12c5d1SDavid du Colombier thing : word | '<' | '>' | '@' | ':' | ';' | ','
2243e12c5d1SDavid du Colombier ;
2253e12c5d1SDavid du Colombier date_time : things
2263e12c5d1SDavid du Colombier ;
2273e12c5d1SDavid du Colombier unix_date_time : word word word unix_time word word
2283e12c5d1SDavid du Colombier { $$ = link3($1, $3, link3($2, $6, link2($4, $5))); }
2293e12c5d1SDavid du Colombier ;
2303e12c5d1SDavid du Colombier unix_time : word
2313e12c5d1SDavid du Colombier | unix_time ':' word
2323e12c5d1SDavid du Colombier { $$ = link3($1, $2, $3); }
2333e12c5d1SDavid du Colombier ;
2343e12c5d1SDavid du Colombier word : WORD | DATE | RESENT_DATE | RETURN_PATH | FROM | SENDER
2353e12c5d1SDavid du Colombier | REPLY_TO | RESENT_FROM | RESENT_SENDER | RESENT_REPLY_TO
236219b2ee8SDavid du Colombier | TO | CC | BCC | RESENT_TO | RESENT_CC | RESENT_BCC | REMOTE | SUBJECT
2377dd7cddfSDavid du Colombier | PRECEDENCE | MIMEVERSION | CONTENTTYPE | MESSAGEID | RECEIVED | MAILER
2383e12c5d1SDavid du Colombier ;
2397dd7cddfSDavid du Colombier fieldwords : fieldword
2407dd7cddfSDavid du Colombier | WORD
2417dd7cddfSDavid du Colombier | fieldwords fieldword
2427dd7cddfSDavid du Colombier { $$ = link2($1, $2); }
2437dd7cddfSDavid du Colombier | fieldwords word
2447dd7cddfSDavid du Colombier { $$ = link2($1, $2); }
2457dd7cddfSDavid du Colombier ;
2467dd7cddfSDavid du Colombier fieldword : '<' | '>' | '@' | ';' | ','
2473e12c5d1SDavid du Colombier ;
2483e12c5d1SDavid du Colombier %%
2493e12c5d1SDavid du Colombier
2503e12c5d1SDavid du Colombier /*
2513e12c5d1SDavid du Colombier * Initialize the parsing. Done once for each header field.
2523e12c5d1SDavid du Colombier */
2533e12c5d1SDavid du Colombier void
2549a747e4fSDavid du Colombier yyinit(char *p, int len)
2553e12c5d1SDavid du Colombier {
256219b2ee8SDavid du Colombier yybuffer = p;
257bd389b36SDavid du Colombier yylp = p;
2589a747e4fSDavid du Colombier yyend = p + len;
2593e12c5d1SDavid du Colombier firstfield = lastfield = 0;
2607dd7cddfSDavid du Colombier received = 0;
2613e12c5d1SDavid du Colombier }
2623e12c5d1SDavid du Colombier
2633e12c5d1SDavid du Colombier /*
2643e12c5d1SDavid du Colombier * keywords identifying header fields we care about
2653e12c5d1SDavid du Colombier */
2663e12c5d1SDavid du Colombier typedef struct Keyword Keyword;
2673e12c5d1SDavid du Colombier struct Keyword {
2683e12c5d1SDavid du Colombier char *rep;
2693e12c5d1SDavid du Colombier int val;
2703e12c5d1SDavid du Colombier };
2713e12c5d1SDavid du Colombier
2727dd7cddfSDavid du Colombier /* field names that we need to recognize */
2733e12c5d1SDavid du Colombier Keyword key[] = {
2743e12c5d1SDavid du Colombier { "date", DATE },
2753e12c5d1SDavid du Colombier { "resent-date", RESENT_DATE },
2763e12c5d1SDavid du Colombier { "return_path", RETURN_PATH },
2773e12c5d1SDavid du Colombier { "from", FROM },
2783e12c5d1SDavid du Colombier { "sender", SENDER },
2793e12c5d1SDavid du Colombier { "reply-to", REPLY_TO },
2803e12c5d1SDavid du Colombier { "resent-from", RESENT_FROM },
2813e12c5d1SDavid du Colombier { "resent-sender", RESENT_SENDER },
2823e12c5d1SDavid du Colombier { "resent-reply-to", RESENT_REPLY_TO },
2833e12c5d1SDavid du Colombier { "to", TO },
2843e12c5d1SDavid du Colombier { "cc", CC },
2853e12c5d1SDavid du Colombier { "bcc", BCC },
2863e12c5d1SDavid du Colombier { "resent-to", RESENT_TO },
2873e12c5d1SDavid du Colombier { "resent-cc", RESENT_CC },
2883e12c5d1SDavid du Colombier { "resent-bcc", RESENT_BCC },
2893e12c5d1SDavid du Colombier { "remote", REMOTE },
290219b2ee8SDavid du Colombier { "subject", SUBJECT },
2917dd7cddfSDavid du Colombier { "precedence", PRECEDENCE },
292219b2ee8SDavid du Colombier { "mime-version", MIMEVERSION },
293219b2ee8SDavid du Colombier { "content-type", CONTENTTYPE },
294219b2ee8SDavid du Colombier { "message-id", MESSAGEID },
295219b2ee8SDavid du Colombier { "received", RECEIVED },
296219b2ee8SDavid du Colombier { "mailer", MAILER },
2973e12c5d1SDavid du Colombier { "who-the-hell-cares", WORD }
2983e12c5d1SDavid du Colombier };
2993e12c5d1SDavid du Colombier
3003e12c5d1SDavid du Colombier /*
3013e12c5d1SDavid du Colombier * Lexical analysis for an rfc822 header field. Continuation lines
3023e12c5d1SDavid du Colombier * are handled in yywhite() when skipping over white space.
3033e12c5d1SDavid du Colombier *
3043e12c5d1SDavid du Colombier */
yylex(void)3053e12c5d1SDavid du Colombier yylex(void)
3063e12c5d1SDavid du Colombier {
3073e12c5d1SDavid du Colombier String *t;
3083e12c5d1SDavid du Colombier int quoting;
3097dd7cddfSDavid du Colombier int escaping;
3103e12c5d1SDavid du Colombier char *start;
3113e12c5d1SDavid du Colombier Keyword *kp;
312219b2ee8SDavid du Colombier int c, d;
3133e12c5d1SDavid du Colombier
3143e12c5d1SDavid du Colombier /* print("lexing\n"); /**/
3159a747e4fSDavid du Colombier if(yylp >= yyend)
3163e12c5d1SDavid du Colombier return 0;
317332d2f58SDavid du Colombier if(yydone)
318332d2f58SDavid du Colombier return 0;
3193e12c5d1SDavid du Colombier
3207dd7cddfSDavid du Colombier quoting = escaping = 0;
3213e12c5d1SDavid du Colombier start = yylp;
3223e12c5d1SDavid du Colombier yylval = malloc(sizeof(Node));
3233e12c5d1SDavid du Colombier yylval->white = yylval->s = 0;
3243e12c5d1SDavid du Colombier yylval->next = 0;
3253e12c5d1SDavid du Colombier yylval->addr = 0;
326332d2f58SDavid du Colombier yylval->start = yylp;
3279a747e4fSDavid du Colombier for(t = 0; yylp < yyend; yylp++){
3287dd7cddfSDavid du Colombier c = *yylp & 0xff;
3299a747e4fSDavid du Colombier
3309a747e4fSDavid du Colombier /* dump nulls, they can't be in header */
3319a747e4fSDavid du Colombier if(c == 0)
3329a747e4fSDavid du Colombier continue;
3339a747e4fSDavid du Colombier
3347dd7cddfSDavid du Colombier if(escaping) {
3357dd7cddfSDavid du Colombier escaping = 0;
3367dd7cddfSDavid du Colombier } else if(quoting) {
3373e12c5d1SDavid du Colombier switch(c){
3383e12c5d1SDavid du Colombier case '\\':
3397dd7cddfSDavid du Colombier escaping = 1;
3403e12c5d1SDavid du Colombier break;
341219b2ee8SDavid du Colombier case '\n':
3427dd7cddfSDavid du Colombier d = (*(yylp+1))&0xff;
343219b2ee8SDavid du Colombier if(d != ' ' && d != '\t'){
344219b2ee8SDavid du Colombier quoting = 0;
345219b2ee8SDavid du Colombier yylp--;
3467dd7cddfSDavid du Colombier continue;
347219b2ee8SDavid du Colombier }
348219b2ee8SDavid du Colombier break;
3493e12c5d1SDavid du Colombier case '"':
3503e12c5d1SDavid du Colombier quoting = 0;
3513e12c5d1SDavid du Colombier break;
3523e12c5d1SDavid du Colombier }
3533e12c5d1SDavid du Colombier } else {
3543e12c5d1SDavid du Colombier switch(c){
3553e12c5d1SDavid du Colombier case '\\':
3567dd7cddfSDavid du Colombier escaping = 1;
3573e12c5d1SDavid du Colombier break;
3583e12c5d1SDavid du Colombier case '(':
3593e12c5d1SDavid du Colombier case ' ':
3603e12c5d1SDavid du Colombier case '\t':
3613e12c5d1SDavid du Colombier case '\r':
3623e12c5d1SDavid du Colombier goto out;
3633e12c5d1SDavid du Colombier case '\n':
364219b2ee8SDavid du Colombier if(yylp == start){
365219b2ee8SDavid du Colombier yylp++;
366219b2ee8SDavid du Colombier /* print("lex(c %c)\n", c); /**/
367219b2ee8SDavid du Colombier yylval->end = yylp;
368219b2ee8SDavid du Colombier return yylval->c = c;
369219b2ee8SDavid du Colombier }
370219b2ee8SDavid du Colombier goto out;
3713e12c5d1SDavid du Colombier case '@':
3723e12c5d1SDavid du Colombier case '>':
3733e12c5d1SDavid du Colombier case '<':
3743e12c5d1SDavid du Colombier case ':':
3753e12c5d1SDavid du Colombier case ',':
3763e12c5d1SDavid du Colombier case ';':
3773e12c5d1SDavid du Colombier if(yylp == start){
3783e12c5d1SDavid du Colombier yylp++;
3793e12c5d1SDavid du Colombier yylval->white = yywhite();
3803e12c5d1SDavid du Colombier /* print("lex(c %c)\n", c); /**/
3813e12c5d1SDavid du Colombier yylval->end = yylp;
3823e12c5d1SDavid du Colombier return yylval->c = c;
3833e12c5d1SDavid du Colombier }
3843e12c5d1SDavid du Colombier goto out;
3853e12c5d1SDavid du Colombier case '"':
3863e12c5d1SDavid du Colombier quoting = 1;
3873e12c5d1SDavid du Colombier break;
3883e12c5d1SDavid du Colombier default:
3893e12c5d1SDavid du Colombier break;
3903e12c5d1SDavid du Colombier }
3913e12c5d1SDavid du Colombier }
3923e12c5d1SDavid du Colombier if(t == 0)
3933e12c5d1SDavid du Colombier t = s_new();
3943e12c5d1SDavid du Colombier s_putc(t, c);
3953e12c5d1SDavid du Colombier }
3963e12c5d1SDavid du Colombier out:
3973e12c5d1SDavid du Colombier yylval->white = yywhite();
398bd389b36SDavid du Colombier if(t) {
399bd389b36SDavid du Colombier s_terminate(t);
400bd389b36SDavid du Colombier } else /* message begins with white-space! */
401bd389b36SDavid du Colombier return yylval->c = '\n';
4023e12c5d1SDavid du Colombier yylval->s = t;
4033e12c5d1SDavid du Colombier for(kp = key; kp->val != WORD; kp++)
4043e12c5d1SDavid du Colombier if(cistrcmp(s_to_c(t), kp->rep)==0)
4053e12c5d1SDavid du Colombier break;
4063e12c5d1SDavid du Colombier /* print("lex(%d) %s\n", kp->val-WORD, s_to_c(t)); /**/
4073e12c5d1SDavid du Colombier yylval->end = yylp;
4083e12c5d1SDavid du Colombier return yylval->c = kp->val;
4093e12c5d1SDavid du Colombier }
4103e12c5d1SDavid du Colombier
4113e12c5d1SDavid du Colombier void
yyerror(char * x)4123e12c5d1SDavid du Colombier yyerror(char *x)
4133e12c5d1SDavid du Colombier {
414bd389b36SDavid du Colombier USED(x);
415bd389b36SDavid du Colombier
4163e12c5d1SDavid du Colombier /*fprint(2, "parse err: %s\n", x);/**/
4173e12c5d1SDavid du Colombier }
4183e12c5d1SDavid du Colombier
4193e12c5d1SDavid du Colombier /*
4203e12c5d1SDavid du Colombier * parse white space and comments
4213e12c5d1SDavid du Colombier */
4223e12c5d1SDavid du Colombier String *
yywhite(void)4233e12c5d1SDavid du Colombier yywhite(void)
4243e12c5d1SDavid du Colombier {
4253e12c5d1SDavid du Colombier String *w;
4263e12c5d1SDavid du Colombier int clevel;
4273e12c5d1SDavid du Colombier int c;
4287dd7cddfSDavid du Colombier int escaping;
4293e12c5d1SDavid du Colombier
4307dd7cddfSDavid du Colombier escaping = clevel = 0;
4319a747e4fSDavid du Colombier for(w = 0; yylp < yyend; yylp++){
4327dd7cddfSDavid du Colombier c = *yylp & 0xff;
4339a747e4fSDavid du Colombier
4349a747e4fSDavid du Colombier /* dump nulls, they can't be in header */
4359a747e4fSDavid du Colombier if(c == 0)
4369a747e4fSDavid du Colombier continue;
4379a747e4fSDavid du Colombier
4387dd7cddfSDavid du Colombier if(escaping){
4397dd7cddfSDavid du Colombier escaping = 0;
4407dd7cddfSDavid du Colombier } else if(clevel) {
4413e12c5d1SDavid du Colombier switch(c){
4423e12c5d1SDavid du Colombier case '\n':
4433e12c5d1SDavid du Colombier /*
4443e12c5d1SDavid du Colombier * look for multiline fields
4453e12c5d1SDavid du Colombier */
4463e12c5d1SDavid du Colombier if(*(yylp+1)==' ' || *(yylp+1)=='\t')
4473e12c5d1SDavid du Colombier break;
4483e12c5d1SDavid du Colombier else
4493e12c5d1SDavid du Colombier goto out;
4503e12c5d1SDavid du Colombier case '\\':
4517dd7cddfSDavid du Colombier escaping = 1;
4523e12c5d1SDavid du Colombier break;
4533e12c5d1SDavid du Colombier case '(':
4543e12c5d1SDavid du Colombier clevel++;
4553e12c5d1SDavid du Colombier break;
4563e12c5d1SDavid du Colombier case ')':
4573e12c5d1SDavid du Colombier clevel--;
4583e12c5d1SDavid du Colombier break;
4593e12c5d1SDavid du Colombier }
4603e12c5d1SDavid du Colombier } else {
4613e12c5d1SDavid du Colombier switch(c){
4623e12c5d1SDavid du Colombier case '\\':
4637dd7cddfSDavid du Colombier escaping = 1;
4643e12c5d1SDavid du Colombier break;
4653e12c5d1SDavid du Colombier case '(':
4663e12c5d1SDavid du Colombier clevel++;
4673e12c5d1SDavid du Colombier break;
4683e12c5d1SDavid du Colombier case ' ':
4693e12c5d1SDavid du Colombier case '\t':
4703e12c5d1SDavid du Colombier case '\r':
4713e12c5d1SDavid du Colombier break;
4723e12c5d1SDavid du Colombier case '\n':
4733e12c5d1SDavid du Colombier /*
4743e12c5d1SDavid du Colombier * look for multiline fields
4753e12c5d1SDavid du Colombier */
4763e12c5d1SDavid du Colombier if(*(yylp+1)==' ' || *(yylp+1)=='\t')
4773e12c5d1SDavid du Colombier break;
4783e12c5d1SDavid du Colombier else
4793e12c5d1SDavid du Colombier goto out;
4803e12c5d1SDavid du Colombier default:
4813e12c5d1SDavid du Colombier goto out;
4823e12c5d1SDavid du Colombier }
4833e12c5d1SDavid du Colombier }
4843e12c5d1SDavid du Colombier if(w == 0)
4853e12c5d1SDavid du Colombier w = s_new();
4863e12c5d1SDavid du Colombier s_putc(w, c);
4873e12c5d1SDavid du Colombier }
4883e12c5d1SDavid du Colombier out:
4893e12c5d1SDavid du Colombier if(w)
4903e12c5d1SDavid du Colombier s_terminate(w);
4913e12c5d1SDavid du Colombier return w;
4923e12c5d1SDavid du Colombier }
4933e12c5d1SDavid du Colombier
4943e12c5d1SDavid du Colombier /*
4953e12c5d1SDavid du Colombier * link two parsed entries together
4963e12c5d1SDavid du Colombier */
4973e12c5d1SDavid du Colombier Node*
link2(Node * p1,Node * p2)4983e12c5d1SDavid du Colombier link2(Node *p1, Node *p2)
4993e12c5d1SDavid du Colombier {
5003e12c5d1SDavid du Colombier Node *p;
5013e12c5d1SDavid du Colombier
5023e12c5d1SDavid du Colombier for(p = p1; p->next; p = p->next)
5033e12c5d1SDavid du Colombier ;
5043e12c5d1SDavid du Colombier p->next = p2;
5053e12c5d1SDavid du Colombier return p1;
5063e12c5d1SDavid du Colombier }
5073e12c5d1SDavid du Colombier
5083e12c5d1SDavid du Colombier /*
5093e12c5d1SDavid du Colombier * link three parsed entries together
5103e12c5d1SDavid du Colombier */
5113e12c5d1SDavid du Colombier Node*
link3(Node * p1,Node * p2,Node * p3)5123e12c5d1SDavid du Colombier link3(Node *p1, Node *p2, Node *p3)
5133e12c5d1SDavid du Colombier {
5143e12c5d1SDavid du Colombier Node *p;
5153e12c5d1SDavid du Colombier
5163e12c5d1SDavid du Colombier for(p = p2; p->next; p = p->next)
5173e12c5d1SDavid du Colombier ;
5183e12c5d1SDavid du Colombier p->next = p3;
5193e12c5d1SDavid du Colombier
5203e12c5d1SDavid du Colombier for(p = p1; p->next; p = p->next)
5213e12c5d1SDavid du Colombier ;
5223e12c5d1SDavid du Colombier p->next = p2;
5233e12c5d1SDavid du Colombier
5243e12c5d1SDavid du Colombier return p1;
5253e12c5d1SDavid du Colombier }
5263e12c5d1SDavid du Colombier
5273e12c5d1SDavid du Colombier /*
528219b2ee8SDavid du Colombier * make a:b, move all white space after both
529219b2ee8SDavid du Colombier */
530219b2ee8SDavid du Colombier Node*
colon(Node * p1,Node * p2)531219b2ee8SDavid du Colombier colon(Node *p1, Node *p2)
532219b2ee8SDavid du Colombier {
533219b2ee8SDavid du Colombier if(p1->white){
534219b2ee8SDavid du Colombier if(p2->white)
535219b2ee8SDavid du Colombier s_append(p1->white, s_to_c(p2->white));
5367dd7cddfSDavid du Colombier } else {
537219b2ee8SDavid du Colombier p1->white = p2->white;
5387dd7cddfSDavid du Colombier p2->white = 0;
5397dd7cddfSDavid du Colombier }
540219b2ee8SDavid du Colombier
541219b2ee8SDavid du Colombier s_append(p1->s, ":");
542219b2ee8SDavid du Colombier if(p2->s)
543219b2ee8SDavid du Colombier s_append(p1->s, s_to_c(p2->s));
544219b2ee8SDavid du Colombier
5457dd7cddfSDavid du Colombier if(p1->end < p2->end)
5467dd7cddfSDavid du Colombier p1->end = p2->end;
547219b2ee8SDavid du Colombier freenode(p2);
548219b2ee8SDavid du Colombier return p1;
549219b2ee8SDavid du Colombier }
550219b2ee8SDavid du Colombier
551219b2ee8SDavid du Colombier /*
5527dd7cddfSDavid du Colombier * concatenate two fields, move all white space after both
5533e12c5d1SDavid du Colombier */
5543e12c5d1SDavid du Colombier Node*
concat(Node * p1,Node * p2)5557dd7cddfSDavid du Colombier concat(Node *p1, Node *p2)
5563e12c5d1SDavid du Colombier {
5577dd7cddfSDavid du Colombier char buf[2];
5587dd7cddfSDavid du Colombier
5593e12c5d1SDavid du Colombier if(p1->white){
5603e12c5d1SDavid du Colombier if(p2->white)
5613e12c5d1SDavid du Colombier s_append(p1->white, s_to_c(p2->white));
5627dd7cddfSDavid du Colombier } else {
5633e12c5d1SDavid du Colombier p1->white = p2->white;
5647dd7cddfSDavid du Colombier p2->white = 0;
5657dd7cddfSDavid du Colombier }
5663e12c5d1SDavid du Colombier
5677dd7cddfSDavid du Colombier if(p1->s == nil){
5687dd7cddfSDavid du Colombier buf[0] = p1->c;
5697dd7cddfSDavid du Colombier buf[1] = 0;
5707dd7cddfSDavid du Colombier p1->s = s_new();
5717dd7cddfSDavid du Colombier s_append(p1->s, buf);
5727dd7cddfSDavid du Colombier }
5737dd7cddfSDavid du Colombier
5743e12c5d1SDavid du Colombier if(p2->s)
5753e12c5d1SDavid du Colombier s_append(p1->s, s_to_c(p2->s));
5767dd7cddfSDavid du Colombier else {
5777dd7cddfSDavid du Colombier buf[0] = p2->c;
5787dd7cddfSDavid du Colombier buf[1] = 0;
5797dd7cddfSDavid du Colombier s_append(p1->s, buf);
5807dd7cddfSDavid du Colombier }
5813e12c5d1SDavid du Colombier
5827dd7cddfSDavid du Colombier if(p1->end < p2->end)
5837dd7cddfSDavid du Colombier p1->end = p2->end;
5843e12c5d1SDavid du Colombier freenode(p2);
5853e12c5d1SDavid du Colombier return p1;
5863e12c5d1SDavid du Colombier }
5873e12c5d1SDavid du Colombier
5883e12c5d1SDavid du Colombier /*
5897dd7cddfSDavid du Colombier * look for disallowed chars in the field name
5907dd7cddfSDavid du Colombier */
5917dd7cddfSDavid du Colombier int
badfieldname(Node * p)5927dd7cddfSDavid du Colombier badfieldname(Node *p)
5937dd7cddfSDavid du Colombier {
5947dd7cddfSDavid du Colombier for(; p; p = p->next){
5957dd7cddfSDavid du Colombier /* field name can't contain white space */
5967dd7cddfSDavid du Colombier if(p->white && p->next)
5977dd7cddfSDavid du Colombier return 1;
5987dd7cddfSDavid du Colombier }
5997dd7cddfSDavid du Colombier return 0;
6007dd7cddfSDavid du Colombier }
6017dd7cddfSDavid du Colombier
6027dd7cddfSDavid du Colombier /*
6033e12c5d1SDavid du Colombier * mark as an address
6043e12c5d1SDavid du Colombier */
6053e12c5d1SDavid du Colombier Node *
address(Node * p)6063e12c5d1SDavid du Colombier address(Node *p)
6073e12c5d1SDavid du Colombier {
6083e12c5d1SDavid du Colombier p->addr = 1;
6093e12c5d1SDavid du Colombier return p;
6103e12c5d1SDavid du Colombier }
6113e12c5d1SDavid du Colombier
6123e12c5d1SDavid du Colombier /*
6133e12c5d1SDavid du Colombier * case independent string compare
6143e12c5d1SDavid du Colombier */
6153e12c5d1SDavid du Colombier int
cistrcmp(char * s1,char * s2)6163e12c5d1SDavid du Colombier cistrcmp(char *s1, char *s2)
6173e12c5d1SDavid du Colombier {
6183e12c5d1SDavid du Colombier int c1, c2;
6193e12c5d1SDavid du Colombier
6203e12c5d1SDavid du Colombier for(; *s1; s1++, s2++){
6213e12c5d1SDavid du Colombier c1 = isupper(*s1) ? tolower(*s1) : *s1;
6223e12c5d1SDavid du Colombier c2 = isupper(*s2) ? tolower(*s2) : *s2;
6233e12c5d1SDavid du Colombier if (c1 != c2)
6243e12c5d1SDavid du Colombier return -1;
6253e12c5d1SDavid du Colombier }
6263e12c5d1SDavid du Colombier return *s2;
6273e12c5d1SDavid du Colombier }
6283e12c5d1SDavid du Colombier
6293e12c5d1SDavid du Colombier /*
6303e12c5d1SDavid du Colombier * free a node
6313e12c5d1SDavid du Colombier */
6323e12c5d1SDavid du Colombier void
freenode(Node * p)6333e12c5d1SDavid du Colombier freenode(Node *p)
6343e12c5d1SDavid du Colombier {
6353e12c5d1SDavid du Colombier Node *tp;
6363e12c5d1SDavid du Colombier
6373e12c5d1SDavid du Colombier while(p){
6383e12c5d1SDavid du Colombier tp = p->next;
6393e12c5d1SDavid du Colombier if(p->s)
6403e12c5d1SDavid du Colombier s_free(p->s);
6413e12c5d1SDavid du Colombier if(p->white)
6423e12c5d1SDavid du Colombier s_free(p->white);
6433e12c5d1SDavid du Colombier free(p);
6443e12c5d1SDavid du Colombier p = tp;
6453e12c5d1SDavid du Colombier }
6463e12c5d1SDavid du Colombier }
6473e12c5d1SDavid du Colombier
6483e12c5d1SDavid du Colombier
6493e12c5d1SDavid du Colombier /*
6503e12c5d1SDavid du Colombier * an anonymous user
6513e12c5d1SDavid du Colombier */
6523e12c5d1SDavid du Colombier Node*
nobody(Node * p)6539a747e4fSDavid du Colombier nobody(Node *p)
6543e12c5d1SDavid du Colombier {
6553e12c5d1SDavid du Colombier if(p->s)
6563e12c5d1SDavid du Colombier s_free(p->s);
6573e12c5d1SDavid du Colombier p->s = s_copy("pOsTmAsTeR");
6583e12c5d1SDavid du Colombier p->addr = 1;
6593e12c5d1SDavid du Colombier return p;
6603e12c5d1SDavid du Colombier }
6613e12c5d1SDavid du Colombier
6623e12c5d1SDavid du Colombier /*
663332d2f58SDavid du Colombier * add anything that was dropped because of a parse error
664332d2f58SDavid du Colombier */
665332d2f58SDavid du Colombier void
missing(Node * p)666332d2f58SDavid du Colombier missing(Node *p)
667332d2f58SDavid du Colombier {
668332d2f58SDavid du Colombier Node *np;
669332d2f58SDavid du Colombier char *start, *end;
670332d2f58SDavid du Colombier Field *f;
671332d2f58SDavid du Colombier String *s;
672332d2f58SDavid du Colombier
673332d2f58SDavid du Colombier start = yybuffer;
674332d2f58SDavid du Colombier if(lastfield != nil){
675332d2f58SDavid du Colombier for(np = lastfield->node; np; np = np->next)
676332d2f58SDavid du Colombier start = np->end+1;
677332d2f58SDavid du Colombier }
678332d2f58SDavid du Colombier
679332d2f58SDavid du Colombier end = p->start-1;
680332d2f58SDavid du Colombier
681332d2f58SDavid du Colombier if(end <= start)
682332d2f58SDavid du Colombier return;
683332d2f58SDavid du Colombier
684332d2f58SDavid du Colombier if(strncmp(start, "From ", 5) == 0)
685332d2f58SDavid du Colombier return;
686332d2f58SDavid du Colombier
687332d2f58SDavid du Colombier np = malloc(sizeof(Node));
688332d2f58SDavid du Colombier np->start = start;
689332d2f58SDavid du Colombier np->end = end;
690332d2f58SDavid du Colombier np->white = nil;
691332d2f58SDavid du Colombier s = s_copy("BadHeader: ");
692332d2f58SDavid du Colombier np->s = s_nappend(s, start, end-start);
693332d2f58SDavid du Colombier np->next = nil;
694332d2f58SDavid du Colombier
695332d2f58SDavid du Colombier f = malloc(sizeof(Field));
696332d2f58SDavid du Colombier f->next = 0;
697332d2f58SDavid du Colombier f->node = np;
698332d2f58SDavid du Colombier f->source = 0;
699332d2f58SDavid du Colombier if(firstfield)
700332d2f58SDavid du Colombier lastfield->next = f;
701332d2f58SDavid du Colombier else
702332d2f58SDavid du Colombier firstfield = f;
703332d2f58SDavid du Colombier lastfield = f;
704332d2f58SDavid du Colombier }
705332d2f58SDavid du Colombier
706332d2f58SDavid du Colombier /*
7073e12c5d1SDavid du Colombier * create a new field
7083e12c5d1SDavid du Colombier */
7093e12c5d1SDavid du Colombier void
newfield(Node * p,int source)7103e12c5d1SDavid du Colombier newfield(Node *p, int source)
7113e12c5d1SDavid du Colombier {
7123e12c5d1SDavid du Colombier Field *f;
7133e12c5d1SDavid du Colombier
714332d2f58SDavid du Colombier missing(p);
715332d2f58SDavid du Colombier
7163e12c5d1SDavid du Colombier f = malloc(sizeof(Field));
7173e12c5d1SDavid du Colombier f->next = 0;
7183e12c5d1SDavid du Colombier f->node = p;
7193e12c5d1SDavid du Colombier f->source = source;
7203e12c5d1SDavid du Colombier if(firstfield)
7213e12c5d1SDavid du Colombier lastfield->next = f;
7223e12c5d1SDavid du Colombier else
7233e12c5d1SDavid du Colombier firstfield = f;
7243e12c5d1SDavid du Colombier lastfield = f;
725332d2f58SDavid du Colombier endfield = startfield;
726332d2f58SDavid du Colombier startfield = yylp;
7273e12c5d1SDavid du Colombier }
7283e12c5d1SDavid du Colombier
7293e12c5d1SDavid du Colombier /*
7303e12c5d1SDavid du Colombier * fee a list of fields
7313e12c5d1SDavid du Colombier */
7323e12c5d1SDavid du Colombier void
freefield(Field * f)7333e12c5d1SDavid du Colombier freefield(Field *f)
7343e12c5d1SDavid du Colombier {
7353e12c5d1SDavid du Colombier Field *tf;
7363e12c5d1SDavid du Colombier
7373e12c5d1SDavid du Colombier while(f){
7383e12c5d1SDavid du Colombier tf = f->next;
7393e12c5d1SDavid du Colombier freenode(f->node);
7403e12c5d1SDavid du Colombier free(f);
7413e12c5d1SDavid du Colombier f = tf;
7423e12c5d1SDavid du Colombier }
7433e12c5d1SDavid du Colombier }
7443e12c5d1SDavid du Colombier
7453e12c5d1SDavid du Colombier /*
7463e12c5d1SDavid du Colombier * add some white space to a node
7473e12c5d1SDavid du Colombier */
7483e12c5d1SDavid du Colombier Node*
whiten(Node * p)7493e12c5d1SDavid du Colombier whiten(Node *p)
7503e12c5d1SDavid du Colombier {
7513e12c5d1SDavid du Colombier Node *tp;
7523e12c5d1SDavid du Colombier
7533e12c5d1SDavid du Colombier for(tp = p; tp->next; tp = tp->next)
7543e12c5d1SDavid du Colombier ;
7553e12c5d1SDavid du Colombier if(tp->white == 0)
7563e12c5d1SDavid du Colombier tp->white = s_copy(" ");
7573e12c5d1SDavid du Colombier return p;
7583e12c5d1SDavid du Colombier }
759219b2ee8SDavid du Colombier
760219b2ee8SDavid du Colombier void
yycleanup(void)761219b2ee8SDavid du Colombier yycleanup(void)
762219b2ee8SDavid du Colombier {
763219b2ee8SDavid du Colombier Field *f, *fnext;
764219b2ee8SDavid du Colombier Node *np, *next;
765219b2ee8SDavid du Colombier
766219b2ee8SDavid du Colombier for(f = firstfield; f; f = fnext){
767219b2ee8SDavid du Colombier for(np = f->node; np; np = next){
768219b2ee8SDavid du Colombier if(np->s)
769219b2ee8SDavid du Colombier s_free(np->s);
770219b2ee8SDavid du Colombier if(np->white)
771219b2ee8SDavid du Colombier s_free(np->white);
772219b2ee8SDavid du Colombier next = np->next;
773219b2ee8SDavid du Colombier free(np);
774219b2ee8SDavid du Colombier }
775219b2ee8SDavid du Colombier fnext = f->next;
776219b2ee8SDavid du Colombier free(f);
777219b2ee8SDavid du Colombier }
778219b2ee8SDavid du Colombier firstfield = lastfield = 0;
779219b2ee8SDavid du Colombier }
780