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