1 %{
2 #include "common.h"
3 #include <ctype.h>
4 #include "smtpd.h"
5
6 #define YYSTYPE yystype
7 typedef struct quux yystype;
8 struct quux {
9 String *s;
10 int c;
11 };
12 Biobuf *yyfp;
13 YYSTYPE *bang;
14 extern Biobuf bin;
15 extern int debug;
16
17 YYSTYPE cat(YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*);
18 int yyparse(void);
19 int yylex(void);
20 YYSTYPE anonymous(void);
21 %}
22
23 %term SPACE
24 %term CNTRL
25 %term CRLF
26 %start conversation
27 %%
28
29 conversation : cmd
30 | conversation cmd
31 ;
32 cmd : error
33 | 'h' 'e' 'l' 'o' spaces sdomain CRLF
34 { hello($6.s, 0); }
35 | 'e' 'h' 'l' 'o' spaces sdomain CRLF
36 { hello($6.s, 1); }
37 | 'm' 'a' 'i' 'l' spaces 'f' 'r' 'o' 'm' ':' spath CRLF
38 { sender($11.s); }
39 | 'm' 'a' 'i' 'l' spaces 'f' 'r' 'o' 'm' ':' spath spaces 'a' 'u' 't' 'h' '=' sauth CRLF
40 { sender($11.s); }
41 | 'r' 'c' 'p' 't' spaces 't' 'o' ':' spath CRLF
42 { receiver($9.s); }
43 | 'd' 'a' 't' 'a' CRLF
44 { data(); }
45 | 'r' 's' 'e' 't' CRLF
46 { reset(); }
47 | 's' 'e' 'n' 'd' spaces 'f' 'r' 'o' 'm' ':' spath CRLF
48 { sender($11.s); }
49 | 's' 'o' 'm' 'l' spaces 'f' 'r' 'o' 'm' ':' spath CRLF
50 { sender($11.s); }
51 | 's' 'a' 'm' 'l' spaces 'f' 'r' 'o' 'm' ':' spath CRLF
52 { sender($11.s); }
53 | 'v' 'r' 'f' 'y' spaces string CRLF
54 { verify($6.s); }
55 | 'e' 'x' 'p' 'n' spaces string CRLF
56 { verify($6.s); }
57 | 'h' 'e' 'l' 'p' CRLF
58 { help(0); }
59 | 'h' 'e' 'l' 'p' spaces string CRLF
60 { help($6.s); }
61 | 'n' 'o' 'o' 'p' CRLF
62 { noop(); }
63 | 'q' 'u' 'i' 't' CRLF
64 { quit(); }
65 | 't' 'u' 'r' 'n' CRLF
66 { turn(); }
67 | 's' 't' 'a' 'r' 't' 't' 'l' 's' CRLF
68 { starttls(); }
69 | 'a' 'u' 't' 'h' spaces name spaces string CRLF
70 { auth($6.s, $8.s); }
71 | 'a' 'u' 't' 'h' spaces name CRLF
72 { auth($6.s, nil); }
73 | CRLF
74 { reply("501 illegal command or bad syntax\r\n"); }
75 ;
76 path : '<' '>' ={ $$ = anonymous(); }
77 | '<' mailbox '>' ={ $$ = $2; }
78 | '<' a_d_l ':' mailbox '>' ={ $$ = cat(&$2, bang, &$4, 0, 0 ,0, 0); }
79 ;
80 spath : path ={ $$ = $1; }
81 | spaces path ={ $$ = $2; }
82 ;
83 auth : path ={ $$ = $1; }
84 | mailbox ={ $$ = $1; }
85 ;
86 sauth : auth ={ $$ = $1; }
87 | spaces auth ={ $$ = $2; }
88 ;
89 ;
90 a_d_l : at_domain ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
91 | at_domain ',' a_d_l ={ $$ = cat(&$1, bang, &$3, 0, 0, 0, 0); }
92 ;
93 at_domain : '@' domain ={ $$ = cat(&$2, 0, 0, 0, 0 ,0, 0); }
94 ;
95 sdomain : domain ={ $$ = $1; }
96 | domain spaces ={ $$ = $1; }
97 ;
98 domain : element ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
99 | element '.' ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
100 | element '.' domain ={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); }
101 ;
102 element : name ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
103 | '#' number ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
104 | '[' ']' ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
105 | '[' dotnum ']' ={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); }
106 ;
107 mailbox : local_part ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
108 | local_part '@' domain ={ $$ = cat(&$3, bang, &$1, 0, 0 ,0, 0); }
109 ;
110 local_part : dot_string ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
111 | quoted_string ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
112 ;
113 name : let_dig ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
114 | let_dig ld_str ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
115 | let_dig ldh_str ld_str ={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); }
116 ;
117 ld_str : let_dig
118 | let_dig ld_str ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
119 ;
120 ldh_str : hunder
121 | ld_str hunder ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
122 | ldh_str ld_str hunder ={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); }
123 ;
124 let_dig : a
125 | d
126 ;
127 dot_string : string ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
128 | string '.' dot_string ={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); }
129 ;
130
131 string : char ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
132 | string char ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
133 ;
134
135 quoted_string : '"' qtext '"' ={ $$ = cat(&$1, &$2, &$3, 0, 0 ,0, 0); }
136 ;
137 qtext : '\\' x ={ $$ = cat(&$2, 0, 0, 0, 0 ,0, 0); }
138 | qtext '\\' x ={ $$ = cat(&$1, &$3, 0, 0, 0 ,0, 0); }
139 | q
140 | qtext q ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
141 ;
142 char : c
143 | '\\' x ={ $$ = $2; }
144 ;
145 dotnum : snum '.' snum '.' snum '.' snum ={ $$ = cat(&$1, &$2, &$3, &$4, &$5, &$6, &$7); }
146 ;
147 number : d ={ $$ = cat(&$1, 0, 0, 0, 0 ,0, 0); }
148 | number d ={ $$ = cat(&$1, &$2, 0, 0, 0 ,0, 0); }
149 ;
150 snum : number ={ if(atoi(s_to_c($1.s)) > 255) print("bad snum\n"); }
151 ;
152 spaces : SPACE ={ $$ = $1; }
153 | SPACE spaces ={ $$ = $1; }
154 ;
155 hunder : '-' | '_'
156 ;
157 special1 : CNTRL
158 | '(' | ')' | ',' | '.'
159 | ':' | ';' | '<' | '>' | '@'
160 ;
161 special : special1 | '\\' | '"'
162 ;
163 notspecial : '!' | '#' | '$' | '%' | '&' | '\''
164 | '*' | '+' | '-' | '/'
165 | '=' | '?'
166 | '[' | ']' | '^' | '_' | '`' | '{' | '|' | '}' | '~'
167 ;
168
169 a : 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i'
170 | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r'
171 | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
172 ;
173 d : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
174 ;
175 c : a | d | notspecial
176 ;
177 q : a | d | special1 | notspecial | SPACE
178 ;
179 x : a | d | special | notspecial | SPACE
180 ;
181 %%
182
183 void
184 parseinit(void)
185 {
186 bang = (YYSTYPE*)malloc(sizeof(YYSTYPE));
187 bang->c = '!';
188 bang->s = 0;
189 yyfp = &bin;
190 }
191
192 int
yylex(void)193 yylex(void)
194 {
195 int c;
196
197 for(;;){
198 c = Bgetc(yyfp);
199 if(c == -1)
200 return 0;
201 if(debug)
202 fprint(2, "%c", c);
203 yylval.c = c = c & 0x7F;
204 if(c == '\n'){
205 return CRLF;
206 }
207 if(c == '\r'){
208 c = Bgetc(yyfp);
209 if(c != '\n'){
210 Bungetc(yyfp);
211 c = '\r';
212 } else {
213 if(debug)
214 fprint(2, "%c", c);
215 return CRLF;
216 }
217 }
218 if(isalpha(c))
219 return tolower(c);
220 if(isspace(c))
221 return SPACE;
222 if(iscntrl(c))
223 return CNTRL;
224 return c;
225 }
226 }
227
228 YYSTYPE
cat(YYSTYPE * y1,YYSTYPE * y2,YYSTYPE * y3,YYSTYPE * y4,YYSTYPE * y5,YYSTYPE * y6,YYSTYPE * y7)229 cat(YYSTYPE *y1, YYSTYPE *y2, YYSTYPE *y3, YYSTYPE *y4, YYSTYPE *y5, YYSTYPE *y6, YYSTYPE *y7)
230 {
231 YYSTYPE rv;
232
233 memset(&rv, 0, sizeof rv);
234 if(y1->s)
235 rv.s = y1->s;
236 else {
237 rv.s = s_new();
238 s_putc(rv.s, y1->c);
239 s_terminate(rv.s);
240 }
241 if(y2){
242 if(y2->s){
243 s_append(rv.s, s_to_c(y2->s));
244 s_free(y2->s);
245 } else {
246 s_putc(rv.s, y2->c);
247 s_terminate(rv.s);
248 }
249 } else
250 return rv;
251 if(y3){
252 if(y3->s){
253 s_append(rv.s, s_to_c(y3->s));
254 s_free(y3->s);
255 } else {
256 s_putc(rv.s, y3->c);
257 s_terminate(rv.s);
258 }
259 } else
260 return rv;
261 if(y4){
262 if(y4->s){
263 s_append(rv.s, s_to_c(y4->s));
264 s_free(y4->s);
265 } else {
266 s_putc(rv.s, y4->c);
267 s_terminate(rv.s);
268 }
269 } else
270 return rv;
271 if(y5){
272 if(y5->s){
273 s_append(rv.s, s_to_c(y5->s));
274 s_free(y5->s);
275 } else {
276 s_putc(rv.s, y5->c);
277 s_terminate(rv.s);
278 }
279 } else
280 return rv;
281 if(y6){
282 if(y6->s){
283 s_append(rv.s, s_to_c(y6->s));
284 s_free(y6->s);
285 } else {
286 s_putc(rv.s, y6->c);
287 s_terminate(rv.s);
288 }
289 } else
290 return rv;
291 if(y7){
292 if(y7->s){
293 s_append(rv.s, s_to_c(y7->s));
294 s_free(y7->s);
295 } else {
296 s_putc(rv.s, y7->c);
297 s_terminate(rv.s);
298 }
299 } else
300 return rv;
301 return rv;
302 }
303
304 void
yyerror(char * x)305 yyerror(char *x)
306 {
307 USED(x);
308 }
309
310 /*
311 * an anonymous user
312 */
313 YYSTYPE
anonymous(void)314 anonymous(void)
315 {
316 YYSTYPE rv;
317
318 memset(&rv, 0, sizeof rv);
319 rv.s = s_copy("/dev/null");
320 return rv;
321 }
322