1 /* smtp.c  -  Simple Mail Transfer Protocol, RFC822
2  * Copyright (c) 2006,2012 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3  * This is confidential unpublished proprietary source code of the author.
4  * NO WARRANTY, not even implied warranties. Contains trade secrets.
5  * Distribution prohibited unless authorized in writing. See file COPYING.
6  * Special grant: smtp.c may be used with zxid open source project under
7  * same licensing terms as zxid itself.
8  * $Id$
9  *
10  * 15.4.2006, started work over Easter holiday --Sampo
11  * 25.4.2006, Viva a revolu��o! Developed SMTP reception to HMTP proxy side --Sampo
12  * 1.5.2006,  Vappu. Progress over first of May weekend --Sampo
13  * 16.8.2012, modified license grant to allow use with ZXID.org --Sampo
14  */
15 
16 #include "platform.h"
17 #include "errmac.h"
18 #include "akbox.h"
19 #include "hiios.h"
20 #include "hiproto.h"
21 
22 #include <ctype.h>
23 #include <memory.h>
24 #include <netinet/in.h> /* htons(3) and friends */
25 #include <stdlib.h>
26 
27 #ifdef ENA_S5066
28 #include "sis5066.h"
29 #endif
30 
31 /* ================== SENDING SMTP PRIMITIVES ================== */
32 
33 extern char remote_station_addr[];
34 
35 /* Called by:  smtp_data, smtp_resp_wait_220_greet, smtp_resp_wait_250_from_ehlo x2, smtp_resp_wait_250_msg_sent x2, smtp_resp_wait_354_from_data x2 */
36 static void hmtp_send(struct hi_thr* hit, struct hi_io* io, int len, char* d, int len2, char* d2)
37 {
38 #ifdef ENA_S5066
39   struct hi_pdu* resp = sis_encode_start(hit, S_UNIDATA_REQUEST,
40 					 SPRIM_TLEN(unidata_req) + len + len2);
41   resp->m[6]  = SAP_ID_HMTP;
42   memcpy(resp->m + 7, /*io->ad.dts->remote_station_addr*/ remote_station_addr, 4);
43   resp->m[11] = 0x20;    /* nonarq delivery mode */
44   resp->m[12] = 0x00;    /* no re tx + infinite TTL */
45   resp->m[13] = 0;
46   resp->m[14] = 0;
47   resp->m[15] = ((len + len2) >> 8) & 0x00ff;
48   resp->m[16] =  (len + len2) & 0x00ff;
49   D("len=%d len2=%d", len, len2);
50   if (len2)
51     hi_send3(hit, io, 0, 0, resp, 17, resp->m, len, d, len2, d2);
52   else
53     hi_send2(hit, io, 0, 0, resp, 17, resp->m, len, d);
54 #endif
55 }
56 
57 /* Called from SIS rx layer with u_pdu payload. This could be either HMTP client
58  * commands that need to be sent to an SMTP server, or this could be a reply
59  * from the remote HMTP server. To make life more difficult, the u_pdu may
60  * have been arbitrarily segmented. On response path we need to filter out
61  * the HMTP responses that were already given to SMTP server in order to play SMTP.
62  * On request path, we need to collect and batch the responses so they can be
63  * sent in one go to HMTP pipe. */
64 
65 /* Called by: */
66 void smtp_send(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* req, int len, char* d)
67 {
68   struct hi_pdu* smtp_resp;
69   /* Determine role from whether we are listening SMTP or
70    * we have SMTP as remote (backend) connection. */
71 
72   if (!io->pair) {
73     struct hi_host_spec* hs;
74     struct hi_io* smtp_c;
75     /* If we are SMTP server, the pairing will already exist. Thus lack of pairing means
76      * we are SMTP client and must open a new connection to remote. */
77     hs = hi_prototab[HIPROTO_SMTP].specs;
78     if (!hs) {
79       ERR("You MUST configure a SMTP remote for HMTP-to-SMTP gateway to work. %d", io->fd);
80       exit(1);
81     }
82     smtp_c = hi_open_tcp(hit, hs, HIPROTO_SMTP);
83     if (!smtp_c) {
84       ERR("Failed to establish SMTP client connection %x", io->fd);
85       return;
86     }
87     smtp_c->n = hs->conns;
88     hs->conns = smtp_c;
89     io->pair = smtp_c;
90     smtp_c->pair = io;
91   }
92 
93   //HEXDUMP("smtp_send: ", d, d+len, 800);
94 
95   switch (io->pair->qel.kind) { /* Pairing already established, the pair determiones the role. */
96   case HI_TCP_S:   /* We are acting as an SMTP server, SIS primitive contains HMTP status  */
97     D("HI_TCP_S req(%p) len=%x", req, len);
98     /* *** may need to strip away some redundant cruft */
99     smtp_resp = hi_pdu_alloc(hit, "hmtp_send");
100     hi_send1(hit, io->pair, 0, 0, smtp_resp, len, d);
101     io->pair->ad.smtp.state = SMTP_END;
102     break;
103   case HI_TCP_C:   /* We are acting as an SMTP client, SIS primitive contains HMTP commands */
104     D("HI_TCP_C req(%p) len=%x", req, len);
105     req->scan = d;
106     io->pair->ad.smtp.uni_ind_hmtp = req;
107     io->pair->ad.smtp.state = SMTP_INIT;  /* Wait for 220 greet. */
108     return;
109   default: NEVERNEVER("impossible pair kind(%d)", io->pair->qel.kind);
110   }
111 
112   /* *** Assemble complete SMTP PDU? This may take several U_PDUs to accomplish. */
113 }
114 
115 /* ================== DECODING SMTP PRIMITIVES ================== */
116 
117 #define CRLF_CHECK(p,lim,req) \
118   if (p >= lim) { req->need = 1 + lim - req->m;  return 0; } \
119   if (*p == '\r') { \
120     ++p; \
121     if (p == lim) { req->need = 1 + lim - req->m;  return 0; } \
122     if (*p != '\n') goto bad; \
123     ++p; \
124   } else if (*p == '\n') \
125     ++p; \
126   else goto bad
127 
128 
129 /* Called by:  smtp_decode_req */
130 static int smtp_ehlo(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* req)
131 {
132   char* p = req->m;
133   char* lim = req->ap;
134 
135   if (lim - p < 7) {   /* too little, need more for "EHLO s\n" */
136     req->need = 7 - (lim - p);
137     return 0;
138   }
139 
140   p[0] = toupper(p[0]);
141   p[1] = toupper(p[1]);
142   p[2] = toupper(p[2]);
143   p[3] = toupper(p[3]);
144   if (memcmp(p, "EHLO ", 5) && memcmp(req->m, "HELO ", 5)) goto bad;
145   p += 5;
146 
147   for (; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ;
148   CRLF_CHECK(p, lim, req);
149 
150   hi_sendf(hit, io, 0, 0, "250-%s\r\n250-PIPELINING\r\n250 8-BIT MIME\r\n", SMTP_EHLO_CLI);
151   io->pair = hi_prototab[HIPROTO_SIS].specs->conns;
152   hi_prototab[HIPROTO_SIS].specs->conns->pair = io;  /* But there could be multiple? */
153 #if 0   /* We do this nowdays during setup */
154   sis_send_bind(hit, io->pair, SAP_ID_HMTP, 0, 0x0200);  /* 0x0200 == nonarq, no repeats */
155 #endif
156   io->ad.smtp.state = SMTP_MAIN;
157   req->need = (p - req->m) + 5;
158   req->ad.smtp.skip_ehlo = req->scan = p;
159   D("EHLO ok req(%p)", req);
160   return 0;
161  bad:
162   ERR("Bad SMTP PDU. fd(%x)", io->fd);
163   return HI_CONN_CLOSE;
164 }
165 
166 /* Called by:  smtp_decode_req x2 */
167 static int smtp_mail_from(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* req)
168 {
169   char* p = req->scan;
170   char* lim = req->ap;
171 
172   if (lim - p < 5) {
173     req->need = 5 - (lim - p);
174     return 0;
175   }
176 
177   p[0] = toupper(p[0]);
178   p[1] = toupper(p[1]);
179   p[2] = toupper(p[2]);
180   p[3] = toupper(p[3]);
181 
182   if (!memcmp(p, "QUIT", 4)) {
183     p += 4;
184     CRLF_CHECK(p, lim, req);
185     hi_sendf(hit, io, 0, 0, "221 bye\r\n");
186     return HI_CONN_CLOSE;
187   }
188 
189   if (lim - p < 11) {
190     req->need = 11 - (lim - p);
191     return 0;
192   }
193 
194   p[5] = toupper(p[5]);
195   p[6] = toupper(p[6]);
196   p[7] = toupper(p[7]);
197   p[8] = toupper(p[8]);
198 
199   if (memcmp(p, "MAIL FROM:", 10)) goto bad;
200   p += 10;
201 
202   for (; p < lim && !ONE_OF_3(*p, '>', '\r', '\n'); ++p) ;
203   if (p == lim) { req->need = 1;  return 0; }
204   if (*p != '>') goto bad;
205   ++p;
206   CRLF_CHECK(p, lim, req);
207   hi_sendf(hit, io, 0, 0, "250 sok\r\n");
208   io->ad.smtp.state = SMTP_TO;
209   req->need = (p - req->m) + 5;   /* "DATA\n" */
210   req->scan = p;
211   D("MAIL FROM ok req(%p)", req);
212   return 0;
213  bad:
214   ERR("Bad SMTP PDU(%p). fd(%x)", req, io->fd);
215   //HEXDUMP("p: ", p, lim, 50);
216   //HEXDUMP("m: ", req->m, lim, 50);
217   return HI_CONN_CLOSE;
218 }
219 
220 /* Called by:  smtp_decode_req */
221 static int smtp_rcpt_to(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* req)
222 {
223   char* p = req->scan;
224   char* lim = req->ap;
225 
226   if (lim - p < 5) {   /* "DATA\n" */
227     req->need = 5 - (lim - p);
228     return 0;
229   }
230 
231   p[0] = toupper(p[0]);
232   p[1] = toupper(p[1]);
233   p[2] = toupper(p[2]);
234   p[3] = toupper(p[3]);
235 
236   if (!memcmp(p, "QUIT", 4)) {
237     p += 4;
238     CRLF_CHECK(p, lim, req);
239     hi_sendf(hit, io, 0, 0, "221 bye\r\n");
240     return HI_CONN_CLOSE;
241   }
242 
243   if (!memcmp(p, "DATA", 4)) {
244     p += 4;
245     CRLF_CHECK(p, lim, req);
246     hi_sendf(hit, io, 0, 0, "354 end with .\r\n");
247     io->ad.smtp.state = SMTP_MORE1;
248     req->need = (p - req->m) + 2; /* .\n */
249     req->scan = p-1;  /* leave \n to be scanned to avoid beginning of mail special case */
250     D("DATA seen req(%p) need=%d", req, req->need);
251     return 0;
252   }
253 
254   if (lim - p < 12) {   /* "RCPT TO:<x>\n" */
255     req->need = 12 - (lim - p);
256     return 0;
257   }
258 
259   p[5] = toupper(p[5]);
260   p[6] = toupper(p[6]);
261 
262   if (memcmp(p, "RCPT TO:", 8)) goto bad;
263   p += 8;
264 
265   for (; p < lim && !ONE_OF_3(*p, '>', '\r', '\n'); ++p) ;
266   if (p == lim) { req->need = 1;  return 0; }
267   if (*p != '>') goto bad;
268   ++p;
269   CRLF_CHECK(p, lim, req);
270   hi_sendf(hit, io, 0, 0, "250 rok\r\n");
271   req->need = (p - req->m) + 5;
272   req->scan = p;
273   D("RCPT TO ok req(%p)", req);
274   return 0;
275 
276  bad:
277   ERR("Bad SMTP PDU. fd(%x)", io->fd);
278   return HI_CONN_CLOSE;
279 }
280 
281 /* Called by:  smtp_decode_req */
282 static int smtp_data(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* req)
283 {
284   char* p = req->scan;
285   char* lim = req->ap;
286 
287   switch (io->ad.smtp.state) {
288   case SMTP_MORE0: break;
289   case SMTP_MORE1: goto look_for_dot;
290   case SMTP_MORE2:
291   default: NEVERNEVER("impossible SMTP state %d", io->ad.smtp.state);
292   }
293 
294   while (lim - p >= 3) {    /* \n.\n */
295     for (; *p != '\n' && lim - p >= 3; ++p) ; /* \n.\n */
296     if (lim - p < 3)
297       break;
298     ++p;
299   look_for_dot:
300     if (p[0] == '.' && ONE_OF_2(p[1], '\r', '\n')) {
301       ++p;
302       if (*p == '\r') {
303 	++p;
304 	if (p == lim) break;
305 	if (*p != '\n') continue;   /* this happens a lot */
306       }
307       ++p;   /* *p was '\n' */
308 
309       /* End of message, hurrah! */
310 
311       D("End-of-message seen req(%p)", req);
312       hmtp_send(hit, io->pair, p - req->m, req->m, 6, "QUIT\r\n");
313 #if 1
314       io->ad.smtp.state = SMTP_WAIT;
315       req->need = 0;  /* Hold it until we get response from SIS layer. */
316 #else
317       hi_sendf(hit, io, 0, 0, "250 sent\r\n");   /* *** hold this off? */
318       req->need = (p - req->m) + 5;
319       /* *** not clear how second message could be sent. Perhaps we need second scan pointer? */
320 #endif
321       req->scan = p;
322       return 0;
323     }
324   }
325   /* *** need to handle mail larger than U_PDU case */
326   req->need = 3 - (lim - p);
327   req->scan = p-1;
328   D("more data needed req(%p) need=%d", req, req->need);
329   return 0;
330 
331  bad:
332   ERR("Bad SMTP PDU. fd(%x)", io->fd);
333   return HI_CONN_CLOSE;
334 }
335 
336 /* Called by: */
337 int smtp_decode_req(struct hi_thr* hit, struct hi_io* io)
338 {
339   struct hi_pdu* req = io->cur_pdu;
340   D("smtp_state(%d) scan(%.*s)", io->ad.smtp.state, (int)MIN(7, req->ap - req->scan), req->scan);
341   switch (io->ad.smtp.state) {
342   case SMTP_START:  return smtp_ehlo(hit, io, req);
343   case SMTP_MAIN:   return smtp_mail_from(hit, io, req);
344   case SMTP_TO:     return smtp_rcpt_to(hit, io, req);
345   case SMTP_MORE0:
346   case SMTP_MORE1:
347   case SMTP_MORE2:  return smtp_data(hit, io, req);
348   case SMTP_WAIT:
349   case SMTP_STATUS: D("Unexpected state %x", io->ad.smtp.state);
350   case SMTP_END:    return smtp_mail_from(hit, io, req);
351   default: NEVERNEVER("impossible SMTP state %d", io->ad.smtp.state);
352   }
353   return 0;
354 }
355 
356 /* ========= Process responses from SMTP server ========= */
357 
358 /* The responses are generally in response to parallel process where HMTP is received from
359  * SIS layer and written as SMTP commands to the server. Onve we have enough responses,
360  * we need to send HMTP response using SIS layer. Generally this is detected
361  * by recognizing "354 enter mail" response followed by "250 sent". Earlier 250 responses
362  * must not trigger HMTP pdu. Any other response than 250, 354, or 221 quit triggers
363  * HMTP error response. */
364 
365 /* Called by:  smtp_decode_resp */
366 static int smtp_resp_wait_220_greet(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp)
367 {
368   char* p = resp->scan;
369   char* lim = resp->ap;
370   int n = lim - p;
371 
372   if (n < 6) {  /* 220 m\n or 220-m\n */
373     resp->need = (6 - n) + (p - resp->m);  /* what we have plus what we need */
374     return 0;
375   }
376 
377   if (!THREE_IN_ROW(p, '2', '2', '0'))  /* 220 greet */
378     goto bad;
379 
380   switch (n = p[3]) {
381   case ' ':
382   case '-':
383     for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ;
384     CRLF_CHECK(p, lim, resp);
385     resp->scan = p;
386     break;
387   default: goto bad;
388   }
389   if (n == ' ') {
390     D("220 greet seen resp(%p)", resp);
391     hi_sendf(hit, io, 0, 0, "EHLO %s\r\n", SMTP_GREET_DOMAIN);
392     io->ad.smtp.state = SMTP_RDY;
393   }
394   resp->need = 6 + p - resp->m;  /* Prime the pump for next response */
395   return 0;
396 
397  bad:
398   D("SMTP server sent bad response(%.*s)", n, p);
399   if (io->pair)
400     hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0);
401   return HI_CONN_CLOSE;
402 }
403 
404 /* Called by:  smtp_decode_resp */
405 static int smtp_resp_wait_250_from_ehlo(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp)
406 {
407   char* p = resp->scan;
408   char* lim = resp->ap;
409   int n = lim - p;
410 
411   if (n < 6) {  /* 250 m\n or 250-m\n */
412     resp->need = (6 - n) + (p - resp->m);  /* what we have plus what we need */
413     return 0;
414   }
415 
416   if (!THREE_IN_ROW(p, '2', '5', '0'))
417     goto bad;
418 
419   switch (n = p[3]) {
420   case ' ':
421   case '-':
422     for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ;
423     CRLF_CHECK(p, lim, resp);
424     resp->scan = p;
425     break;
426   default: goto bad;
427   }
428   if (n == ' ') {
429     if (io->ad.smtp.uni_ind_hmtp) {
430       /* Send payload immediately */
431       /* io->ad.smtp.uni_ind_hmtp is the sis unidata_ind primitive contaning HMTP request */
432       char* payload;
433       char* q = io->ad.smtp.uni_ind_hmtp->scan;
434       char* qlim = io->ad.smtp.uni_ind_hmtp->ap;
435       struct hi_pdu* pdu = hi_pdu_alloc(hit, "smtp_wait_250");
436 
437       if (qlim-q < 25)   /* *** should determine this number better */
438 	goto badhmtp;
439 
440       /* Skip EHLO if any */
441 
442       q[0] = toupper(q[0]);
443       q[1] = toupper(q[1]);
444       q[2] = toupper(q[2]);
445       q[3] = toupper(q[3]);
446 
447       if (memcmp(q, "EHLO ", 5))
448 	goto badhmtp;
449 
450       for (q+=5; q < qlim && !ONE_OF_2(*q, '\r', '\n'); ++q) ;
451       if (q == qlim)
452 	goto badhmtp;
453       if (*q == '\r') {
454 	++q;
455 	if (q == qlim || *q != '\n')
456 	  goto badhmtp;
457       }
458       ++q;
459       if (q == qlim)
460 	goto badhmtp;
461 
462       payload = q;
463 
464       /* Scan till end of DATA command. We can not send the actual data before 354 response
465        * to DATA command, for which we wait in SEND state. */
466 
467       for (; q+6 < qlim; ++q) {
468 	if (q[0] == '\n'
469 	    && ONE_OF_2(q[1], 'D', 'd')
470 	    && ONE_OF_2(q[2], 'A', 'a')
471 	    && ONE_OF_2(q[3], 'T', 't')
472 	    && ONE_OF_2(q[4], 'A', 'a')
473 	    && ONE_OF_2(q[5], '\r', '\n')
474 	    ) {
475 	  if (q[5] == '\r' && ((q+7 >= qlim) || q[6] != '\n'))
476 	    continue;
477 	  q += (q[5] == '\r') ? 7 : 6;
478 	  break;
479 	}
480       }
481 
482       D("250 for EHLO seen resp(%p)", resp);
483       io->ad.smtp.uni_ind_hmtp->scan = q;
484       hi_send1(hit, io, 0, 0, pdu, q-payload, payload);
485       io->ad.smtp.state = SMTP_SEND;
486       /* *** if hmtp / smtp message was not complete, arrange further SIS layer
487        *     I/O to be forwarded into the smtp connection. Similarily, if the
488        *     hmtp message has not arrived yet at all, it should be forwarded
489        *     as soon as it does arrive. */
490     } else {
491       NEVER("smtp client io is missing is unidata_ind_hmtp? %p", io->pair);
492       return HI_CONN_CLOSE;
493     }
494   }
495   resp->need = 6 + p - resp->m;  /* Prime the pump for next response */
496   return 0;
497 
498  bad:
499   D("SMTP server sent bad response(%.*s)", n, p);
500   if (io->pair)
501     hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0);
502   return HI_CONN_CLOSE;
503  badhmtp:
504   D("Bad HMTP PDU from SIS layer %d", 0);
505   if (io->pair)
506     hmtp_send(hit, io->pair, 9, "500 Bad\r\n", 0, 0);
507   return HI_CONN_CLOSE;
508 }
509 
510 /* Called by:  smtp_decode_resp */
511 static int smtp_resp_wait_354_from_data(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp)
512 {
513   char* p = resp->scan;
514   char* lim = resp->ap;
515   int next_state, n = lim - p;
516 
517   if (n < 6) {  /* 250 m\n or 250-m\n */
518     resp->need = (6 - n) + (p - resp->m);  /* what we have plus what we need */
519     return 0;
520   }
521 
522   if        (THREE_IN_ROW(p, '3', '5', '4')) {  /* 354 enter mail */
523     next_state = SMTP_SENT;
524   } else if (THREE_IN_ROW(p, '2', '5', '0')) {
525     next_state = io->ad.smtp.state;
526   } else
527     goto bad;
528 
529   switch (n = p[3]) {
530   case ' ':
531   case '-':
532     for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ;
533     CRLF_CHECK(p, lim, resp);
534     resp->scan = p;
535     break;
536   default: goto bad;
537   }
538   if (n == ' ' && next_state == SMTP_SENT) {
539     if (io->ad.smtp.uni_ind_hmtp) {
540       /* Send payload immediately */
541       /* io->ad.smtp.uni_ind_hmtp is the sis unidata_ind primitive contaning HMTP request */
542       char* payload;
543       char* q = io->ad.smtp.uni_ind_hmtp->scan;
544       char* qlim = io->ad.smtp.uni_ind_hmtp->ap;
545       struct hi_pdu* pdu = hi_pdu_alloc(hit, "smtp_wait_354");
546 
547       payload = q;
548       --q;  /* Take the new line from preceding DATA to avoid special case later */
549 
550       /* Make sure QUIT is NOT sent (we will send one ourselves, eventually). Scan for message
551        * terminating "\r\n.\r\n". Its also possible we will not see message terminator. That
552        * means the message is so big it takes several SIS primitives to transmit. */
553 
554       for (; q+2 < qlim; ++q) {
555 	if (q[0] == '\n' && q[1] == '.' && ONE_OF_2(q[2], '\r', '\n')) {
556 	  if (q[2] == '\r' && ((q+3 >= qlim) || q[3] != '\n'))
557 	    continue;
558 	  q += (q[2] == '\r') ? 4 : 3;
559 	  break;
560 	}
561       }
562 
563       D("354 for DATA seen resp(%p), sending %d bytes", resp, (int)(q-payload));
564       hi_send1(hit, io, 0, 0, pdu, q-payload, payload);
565       io->ad.smtp.state = SMTP_SENT;
566       /* *** if hmtp / smtp message was not complete, arrange further SIS layer
567        *     I/O to be forwarded into the smtp connection. Similarily, if the
568        *     hmtp message has not arrived yet at all, it should be forwarded
569        *     as soon as it does arrive. */
570     } else {
571       NEVER("smtp client io is missing is unidata_ind_hmtp? %p", io->pair);
572       return HI_CONN_CLOSE;
573     }
574   }
575   resp->need = 6 + p - resp->m;  /* Prime the pump for next response */
576   return 0;
577 
578  bad:
579   D("SMTP server sent bad response(%.*s)", n, p);
580   if (io->pair)
581     hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0);
582   return HI_CONN_CLOSE;
583  badhmtp:
584   D("Bad HMTP PDU from SIS layer %d", 0);
585   if (io->pair)
586     hmtp_send(hit, io->pair, 9, "500 Bad\r\n", 0, 0);
587   return HI_CONN_CLOSE;
588 }
589 
590 /* Called by:  smtp_decode_resp */
591 static int smtp_resp_wait_250_msg_sent(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp)
592 {
593   char* p = resp->scan;
594   char* lim = resp->ap;
595   int n = lim - p;
596 
597   if (n < 6) {  /* 250 m\n or 250-m\n */
598     resp->need = (6 - n) + (p - resp->m);  /* what we have plus what we need */
599     return 0;
600   }
601 
602   if (!THREE_IN_ROW(p, '2', '5', '0'))     /* 250 message sent */
603     goto bad;
604 
605   switch (n = p[3]) {
606   case ' ':
607   case '-':
608     for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ;
609     CRLF_CHECK(p, lim, resp);
610     resp->scan = p;
611     break;
612   default: goto bad;
613   }
614   if (n == ' ') {
615     /* *** should we attempt to skip the 220 greeting? */
616     D("250 after data 354 seen resp(%p)", resp);
617     hmtp_send(hit, io->pair, p-resp->m, resp->m, 13, "221 goodbye\r\n");
618     hi_sendf(hit, io, 0, 0, "QUIT\r\n");   /* One message per connection! */
619     io->ad.smtp.state = SMTP_QUIT;
620   }
621   resp->need = 6 + p - resp->m;  /* Prime the pump for next response */
622   return 0;
623 
624  bad:
625   D("SMTP server sent bad response(%.*s)", n, p);
626   if (io->pair)
627     hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0);
628   return HI_CONN_CLOSE;
629 }
630 
631 /* Called by:  smtp_decode_resp */
632 static int smtp_resp_wait_221_goodbye(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp)
633 {
634   char* p = resp->scan;
635   char* lim = resp->ap;
636   int n = lim - p;
637 
638   if (n < 6) {  /* 250 m\n or 250-m\n */
639     resp->need = (6 - n) + (p - resp->m);  /* what we have plus what we need */
640     return 0;
641   }
642 
643   if (!THREE_IN_ROW(p, '2', '2', '1'))     /* 221 goodbye */
644     goto bad;
645 
646   switch (n = p[3]) {
647   case ' ':
648   case '-':
649     for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ;
650     CRLF_CHECK(p, lim, resp);
651     resp->scan = p;
652     break;
653   default: goto bad;
654   }
655   if (n == ' ') {
656     D("221 bye seen resp(%p)", resp);
657     io->ad.smtp.state = SMTP_INIT;
658     return HI_CONN_CLOSE;
659   }
660   resp->need = 6 + p - resp->m;  /* Prime the pump for next response */
661   return 0;
662 
663  bad:
664   D("SMTP server sent bad response(%.*s)", n, p);
665   return HI_CONN_CLOSE;
666 }
667 
668 /* Called by: */
669 int smtp_decode_resp(struct hi_thr* hit, struct hi_io* io)
670 {
671   struct hi_pdu* resp = io->cur_pdu;
672   D("smtp_state(%d) scan(%.*s)", io->ad.smtp.state, (int)MIN(7, resp->ap-resp->scan), resp->scan);
673   switch (io->ad.smtp.state) {
674   case SMTP_INIT: return smtp_resp_wait_220_greet(hit, io, resp);
675   case SMTP_EHLO: D("Unexpected state %x", io->ad.smtp.state);
676   case SMTP_RDY:  return smtp_resp_wait_250_from_ehlo(hit, io, resp);
677   case SMTP_MAIL:
678   case SMTP_RCPT:
679   case SMTP_DATA: D("Unexpected state %x", io->ad.smtp.state);
680   case SMTP_SEND: return smtp_resp_wait_354_from_data(hit, io, resp);
681   case SMTP_SENT: return smtp_resp_wait_250_msg_sent(hit, io, resp);
682   case SMTP_QUIT: return smtp_resp_wait_221_goodbye(hit, io, resp);
683   default: NEVERNEVER("impossible SMTP state %d", io->ad.smtp.state);
684   }
685   return 0;
686 }
687 
688 /* EOF  --  smtp.c */
689 
690