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