xref: /plan9/sys/src/cmd/upas/smtp/smtpd.y (revision 426fe5994a5cc658001a4bec2c6d67ca434c4ae9)
1 %{
2 #include "common.h"
3 #include <ctype.h>
4 #include "smtpd.h"
5 
6 #define YYMAXDEPTH	500		/* was default 150 */
7 
8 #define YYSTYPE yystype
9 typedef struct quux yystype;
10 struct quux {
11 	String	*s;
12 	int	c;
13 };
14 Biobuf *yyfp;
15 YYSTYPE *bang;
16 extern Biobuf bin;
17 extern int debug;
18 
19 YYSTYPE cat(YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*, YYSTYPE*);
20 int yyparse(void);
21 int yylex(void);
22 YYSTYPE anonymous(void);
23 %}
24 
25 %term SPACE
26 %term CNTRL
27 %term CRLF
28 %start conversation
29 %%
30 
31 conversation	: cmd
32 		| conversation cmd
33 		;
34 cmd		: error
35 		| 'h' 'e' 'l' 'o' spaces sdomain CRLF
36 			{ hello($6.s, 0); }
37 		| 'e' 'h' 'l' 'o' spaces sdomain CRLF
38 			{ hello($6.s, 1); }
39 		| 'm' 'a' 'i' 'l' spaces 'f' 'r' 'o' 'm' ':' spath CRLF
40 			{ sender($11.s); }
41 		| 'm' 'a' 'i' 'l' spaces 'f' 'r' 'o' 'm' ':' spath spaces 'a' 'u' 't' 'h' '=' sauth CRLF
42 			{ sender($11.s); }
43 		| 'r' 'c' 'p' 't' spaces 't' 'o' ':' spath CRLF
44 			{ receiver($9.s); }
45 		| 'd' 'a' 't' 'a' CRLF
46 			{ data(); }
47 		| 'r' 's' 'e' 't' CRLF
48 			{ reset(); }
49 		| 's' 'e' 'n' 'd' spaces 'f' 'r' 'o' 'm' ':' spath CRLF
50 			{ sender($11.s); }
51 		| 's' 'o' 'm' 'l' spaces 'f' 'r' 'o' 'm'  ':' spath CRLF
52 			{ sender($11.s); }
53 		| 's' 'a' 'm' 'l' spaces 'f' 'r' 'o' 'm' ':' spath CRLF
54 			{ sender($11.s); }
55 		| 'v' 'r' 'f' 'y' spaces string CRLF
56 			{ verify($6.s); }
57 		| 'e' 'x' 'p' 'n' spaces string CRLF
58 			{ verify($6.s); }
59 		| 'h' 'e' 'l' 'p' CRLF
60 			{ help(0); }
61 		| 'h' 'e' 'l' 'p' spaces string CRLF
62 			{ help($6.s); }
63 		| 'n' 'o' 'o' 'p' CRLF
64 			{ noop(); }
65 		| 'q' 'u' 'i' 't' CRLF
66 			{ quit(); }
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("500 5.5.1 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) fprint(2, "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 
yylex(void)192 yylex(void)
193 {
194 	int c;
195 
196 	for(;;){
197 		c = Bgetc(yyfp);
198 		if(c == -1)
199 			return 0;
200 		if(debug)
201 			fprint(2, "%c", c);
202 		yylval.c = c = c & 0x7F;
203 		if(c == '\n'){
204 			return CRLF;
205 		}
206 		if(c == '\r'){
207 			c = Bgetc(yyfp);
208 			if(c != '\n'){
209 				Bungetc(yyfp);
210 				c = '\r';
211 			} else {
212 				if(debug)
213 					fprint(2, "%c", c);
214 				return CRLF;
215 			}
216 		}
217 		if(isalpha(c))
218 			return tolower(c);
219 		if(isspace(c))
220 			return SPACE;
221 		if(iscntrl(c))
222 			return CNTRL;
223 		return c;
224 	}
225 }
226 
227 YYSTYPE
cat(YYSTYPE * y1,YYSTYPE * y2,YYSTYPE * y3,YYSTYPE * y4,YYSTYPE * y5,YYSTYPE * y6,YYSTYPE * y7)228 cat(YYSTYPE *y1, YYSTYPE *y2, YYSTYPE *y3, YYSTYPE *y4, YYSTYPE *y5, YYSTYPE *y6, YYSTYPE *y7)
229 {
230 	YYSTYPE rv;
231 
232 	if(y1->s)
233 		rv.s = y1->s;
234 	else {
235 		rv.s = s_new();
236 		s_putc(rv.s, y1->c);
237 		s_terminate(rv.s);
238 	}
239 	if(y2){
240 		if(y2->s){
241 			s_append(rv.s, s_to_c(y2->s));
242 			s_free(y2->s);
243 		} else {
244 			s_putc(rv.s, y2->c);
245 			s_terminate(rv.s);
246 		}
247 	} else
248 		return rv;
249 	if(y3){
250 		if(y3->s){
251 			s_append(rv.s, s_to_c(y3->s));
252 			s_free(y3->s);
253 		} else {
254 			s_putc(rv.s, y3->c);
255 			s_terminate(rv.s);
256 		}
257 	} else
258 		return rv;
259 	if(y4){
260 		if(y4->s){
261 			s_append(rv.s, s_to_c(y4->s));
262 			s_free(y4->s);
263 		} else {
264 			s_putc(rv.s, y4->c);
265 			s_terminate(rv.s);
266 		}
267 	} else
268 		return rv;
269 	if(y5){
270 		if(y5->s){
271 			s_append(rv.s, s_to_c(y5->s));
272 			s_free(y5->s);
273 		} else {
274 			s_putc(rv.s, y5->c);
275 			s_terminate(rv.s);
276 		}
277 	} else
278 		return rv;
279 	if(y6){
280 		if(y6->s){
281 			s_append(rv.s, s_to_c(y6->s));
282 			s_free(y6->s);
283 		} else {
284 			s_putc(rv.s, y6->c);
285 			s_terminate(rv.s);
286 		}
287 	} else
288 		return rv;
289 	if(y7){
290 		if(y7->s){
291 			s_append(rv.s, s_to_c(y7->s));
292 			s_free(y7->s);
293 		} else {
294 			s_putc(rv.s, y7->c);
295 			s_terminate(rv.s);
296 		}
297 	} else
298 		return rv;
299 	return rv;
300 }
301 
302 void
yyerror(char * x)303 yyerror(char *x)
304 {
305 	USED(x);
306 }
307 
308 /*
309  *  an anonymous user
310  */
311 YYSTYPE
anonymous(void)312 anonymous(void)
313 {
314 	YYSTYPE rv;
315 
316 	rv.s = s_copy("/dev/null");
317 	return rv;
318 }
319