1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 # include "sendmail.h" 10 11 #ifndef lint 12 #ifdef SMTP 13 static char sccsid[] = "@(#)usersmtp.c 8.25 (Berkeley) 11/05/94 (with SMTP)"; 14 #else 15 static char sccsid[] = "@(#)usersmtp.c 8.25 (Berkeley) 11/05/94 (without SMTP)"; 16 #endif 17 #endif /* not lint */ 18 19 # include <sysexits.h> 20 # include <errno.h> 21 22 # ifdef SMTP 23 24 /* 25 ** USERSMTP -- run SMTP protocol from the user end. 26 ** 27 ** This protocol is described in RFC821. 28 */ 29 30 #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 31 #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 32 #define SMTPCLOSING 421 /* "Service Shutting Down" */ 33 34 char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 35 char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 36 char SmtpError[MAXLINE] = ""; /* save failure error messages */ 37 int SmtpPid; /* pid of mailer */ 38 bool SmtpNeedIntro; /* need "while talking" in transcript */ 39 40 #ifdef __STDC__ 41 extern smtpmessage(char *f, MAILER *m, MCI *mci, ...); 42 #endif 43 /* 44 ** SMTPINIT -- initialize SMTP. 45 ** 46 ** Opens the connection and sends the initial protocol. 47 ** 48 ** Parameters: 49 ** m -- mailer to create connection to. 50 ** pvp -- pointer to parameter vector to pass to 51 ** the mailer. 52 ** 53 ** Returns: 54 ** none. 55 ** 56 ** Side Effects: 57 ** creates connection and sends initial protocol. 58 */ 59 60 smtpinit(m, mci, e) 61 struct mailer *m; 62 register MCI *mci; 63 ENVELOPE *e; 64 { 65 register int r; 66 register char *p; 67 extern void esmtp_check(); 68 extern void helo_options(); 69 70 if (tTd(18, 1)) 71 { 72 printf("smtpinit "); 73 mci_dump(mci, FALSE); 74 } 75 76 /* 77 ** Open the connection to the mailer. 78 */ 79 80 SmtpError[0] = '\0'; 81 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 82 SmtpNeedIntro = TRUE; 83 switch (mci->mci_state) 84 { 85 case MCIS_ACTIVE: 86 /* need to clear old information */ 87 smtprset(m, mci, e); 88 /* fall through */ 89 90 case MCIS_OPEN: 91 return; 92 93 case MCIS_ERROR: 94 case MCIS_SSD: 95 /* shouldn't happen */ 96 smtpquit(m, mci, e); 97 /* fall through */ 98 99 case MCIS_CLOSED: 100 syserr("451 smtpinit: state CLOSED"); 101 return; 102 103 case MCIS_OPENING: 104 break; 105 } 106 107 mci->mci_state = MCIS_OPENING; 108 109 /* 110 ** Get the greeting message. 111 ** This should appear spontaneously. Give it five minutes to 112 ** happen. 113 */ 114 115 SmtpPhase = mci->mci_phase = "client greeting"; 116 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 117 r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); 118 if (r < 0 || REPLYTYPE(r) == 4) 119 goto tempfail1; 120 if (REPLYTYPE(r) != 2) 121 goto unavailable; 122 123 /* 124 ** Send the HELO command. 125 ** My mother taught me to always introduce myself. 126 */ 127 128 if (bitnset(M_ESMTP, m->m_flags)) 129 mci->mci_flags |= MCIF_ESMTP; 130 131 tryhelo: 132 if (bitset(MCIF_ESMTP, mci->mci_flags)) 133 { 134 smtpmessage("EHLO %s", m, mci, MyHostName); 135 SmtpPhase = mci->mci_phase = "client EHLO"; 136 } 137 else 138 { 139 smtpmessage("HELO %s", m, mci, MyHostName); 140 SmtpPhase = mci->mci_phase = "client HELO"; 141 } 142 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 143 r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 144 if (r < 0) 145 goto tempfail1; 146 else if (REPLYTYPE(r) == 5) 147 { 148 if (bitset(MCIF_ESMTP, mci->mci_flags)) 149 { 150 /* try old SMTP instead */ 151 mci->mci_flags &= ~MCIF_ESMTP; 152 goto tryhelo; 153 } 154 goto unavailable; 155 } 156 else if (REPLYTYPE(r) != 2) 157 goto tempfail1; 158 159 /* 160 ** Check to see if we actually ended up talking to ourself. 161 ** This means we didn't know about an alias or MX, or we managed 162 ** to connect to an echo server. 163 */ 164 165 p = strchr(&SmtpReplyBuffer[4], ' '); 166 if (p != NULL) 167 *p = '\0'; 168 if (!bitnset(M_NOLOOPCHECK, m->m_flags) && 169 strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 170 { 171 syserr("553 %s config error: mail loops back to myself", 172 MyHostName); 173 mci->mci_exitstat = EX_CONFIG; 174 mci->mci_errno = 0; 175 smtpquit(m, mci, e); 176 return; 177 } 178 179 /* 180 ** If this is expected to be another sendmail, send some internal 181 ** commands. 182 */ 183 184 if (bitnset(M_INTERNAL, m->m_flags)) 185 { 186 /* tell it to be verbose */ 187 smtpmessage("VERB", m, mci); 188 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 189 if (r < 0) 190 goto tempfail2; 191 } 192 193 if (mci->mci_state != MCIS_CLOSED) 194 { 195 mci->mci_state = MCIS_OPEN; 196 return; 197 } 198 199 /* got a 421 error code during startup */ 200 201 tempfail1: 202 tempfail2: 203 mci->mci_exitstat = EX_TEMPFAIL; 204 if (mci->mci_errno == 0) 205 mci->mci_errno = errno; 206 if (mci->mci_state != MCIS_CLOSED) 207 smtpquit(m, mci, e); 208 return; 209 210 unavailable: 211 mci->mci_exitstat = EX_UNAVAILABLE; 212 mci->mci_errno = errno; 213 smtpquit(m, mci, e); 214 return; 215 } 216 /* 217 ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 218 ** 219 ** 220 ** Parameters: 221 ** line -- the response line. 222 ** m -- the mailer. 223 ** mci -- the mailer connection info. 224 ** e -- the envelope. 225 ** 226 ** Returns: 227 ** none. 228 */ 229 230 void 231 esmtp_check(line, m, mci, e) 232 char *line; 233 MAILER *m; 234 register MCI *mci; 235 ENVELOPE *e; 236 { 237 if (strlen(line) < 5) 238 return; 239 line += 4; 240 if (strncmp(line, "ESMTP ", 6) == 0) 241 mci->mci_flags |= MCIF_ESMTP; 242 } 243 /* 244 ** HELO_OPTIONS -- process the options on a HELO line. 245 ** 246 ** Parameters: 247 ** line -- the response line. 248 ** m -- the mailer. 249 ** mci -- the mailer connection info. 250 ** e -- the envelope. 251 ** 252 ** Returns: 253 ** none. 254 */ 255 256 void 257 helo_options(line, m, mci, e) 258 char *line; 259 MAILER *m; 260 register MCI *mci; 261 ENVELOPE *e; 262 { 263 register char *p; 264 265 if (strlen(line) < 5) 266 return; 267 line += 4; 268 p = strchr(line, ' '); 269 if (p != NULL) 270 *p++ = '\0'; 271 if (strcasecmp(line, "size") == 0) 272 { 273 mci->mci_flags |= MCIF_SIZE; 274 if (p != NULL) 275 mci->mci_maxsize = atol(p); 276 } 277 else if (strcasecmp(line, "8bitmime") == 0) 278 { 279 mci->mci_flags |= MCIF_8BITMIME; 280 mci->mci_flags &= ~MCIF_7BIT; 281 } 282 else if (strcasecmp(line, "expn") == 0) 283 mci->mci_flags |= MCIF_EXPN; 284 else if (strcasecmp(line, "x-dsn-0") == 0) 285 mci->mci_flags |= MCIF_DSN; 286 } 287 /* 288 ** SMTPMAILFROM -- send MAIL command 289 ** 290 ** Parameters: 291 ** m -- the mailer. 292 ** mci -- the mailer connection structure. 293 ** e -- the envelope (including the sender to specify). 294 */ 295 296 smtpmailfrom(m, mci, e) 297 struct mailer *m; 298 MCI *mci; 299 ENVELOPE *e; 300 { 301 int r; 302 char *bufp; 303 char *bodytype; 304 char buf[MAXNAME]; 305 char optbuf[MAXLINE]; 306 307 if (tTd(18, 2)) 308 printf("smtpmailfrom: CurHost=%s\n", CurHostName); 309 310 /* set up appropriate options to include */ 311 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 312 sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 313 else 314 strcpy(optbuf, ""); 315 316 bodytype = e->e_bodytype; 317 if (bitset(MCIF_8BITMIME, mci->mci_flags)) 318 { 319 if (bodytype == NULL && 320 bitset(MM_MIME8BIT, MimeMode) && 321 bitset(EF_HAS8BIT, e->e_flags) && 322 !bitnset(M_8BITS, m->m_flags)) 323 bodytype = "8BITMIME"; 324 if (bodytype != NULL) 325 { 326 strcat(optbuf, " BODY="); 327 strcat(optbuf, bodytype); 328 } 329 } 330 else if (bitnset(M_8BITS, m->m_flags)) 331 { 332 /* just pass it through */ 333 } 334 else if (bitset(MM_CVTMIME, MimeMode) && 335 (e->e_bodytype == NULL ? !bitset(MM_PASS8BIT, MimeMode) 336 : strcasecmp(e->e_bodytype, "7bit") != 0)) 337 { 338 /* must convert from 8bit MIME format to 7bit encoded */ 339 mci->mci_flags |= MCIF_CVT8TO7; 340 } 341 else if (!bitset(MM_PASS8BIT, MimeMode)) 342 { 343 /* cannot just send a 8-bit version */ 344 usrerr("%s does not support 8BITMIME", mci->mci_host); 345 return EX_DATAERR; 346 } 347 348 if (e->e_envid != NULL && bitset(MCIF_DSN, mci->mci_flags)) 349 { 350 strcat(optbuf, " ENVID="); 351 strcat(optbuf, e->e_envid); 352 } 353 354 /* 355 ** Send the MAIL command. 356 ** Designates the sender. 357 */ 358 359 mci->mci_state = MCIS_ACTIVE; 360 361 if (bitset(EF_RESPONSE, e->e_flags) && 362 !bitnset(M_NO_NULL_FROM, m->m_flags)) 363 (void) strcpy(buf, ""); 364 else 365 expand("\201g", buf, &buf[sizeof buf - 1], e); 366 if (buf[0] == '<') 367 { 368 /* strip off <angle brackets> (put back on below) */ 369 bufp = &buf[strlen(buf) - 1]; 370 if (*bufp == '>') 371 *bufp = '\0'; 372 bufp = &buf[1]; 373 } 374 else 375 bufp = buf; 376 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 377 !bitnset(M_FROMPATH, m->m_flags)) 378 { 379 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 380 } 381 else 382 { 383 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 384 *bufp == '@' ? ',' : ':', bufp, optbuf); 385 } 386 SmtpPhase = mci->mci_phase = "client MAIL"; 387 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 388 r = reply(m, mci, e, TimeOuts.to_mail, NULL); 389 if (r < 0 || REPLYTYPE(r) == 4) 390 { 391 mci->mci_exitstat = EX_TEMPFAIL; 392 mci->mci_errno = errno; 393 smtpquit(m, mci, e); 394 return EX_TEMPFAIL; 395 } 396 else if (r == 250) 397 { 398 mci->mci_exitstat = EX_OK; 399 return EX_OK; 400 } 401 else if (r == 552) 402 { 403 /* signal service unavailable */ 404 mci->mci_exitstat = EX_UNAVAILABLE; 405 smtpquit(m, mci, e); 406 return EX_UNAVAILABLE; 407 } 408 409 #ifdef LOG 410 if (LogLevel > 1) 411 { 412 syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s", 413 e->e_id, mci->mci_host, SmtpReplyBuffer); 414 } 415 #endif 416 417 /* protocol error -- close up */ 418 smtpquit(m, mci, e); 419 mci->mci_exitstat = EX_PROTOCOL; 420 return EX_PROTOCOL; 421 } 422 /* 423 ** SMTPRCPT -- designate recipient. 424 ** 425 ** Parameters: 426 ** to -- address of recipient. 427 ** m -- the mailer we are sending to. 428 ** mci -- the connection info for this transaction. 429 ** e -- the envelope for this transaction. 430 ** 431 ** Returns: 432 ** exit status corresponding to recipient status. 433 ** 434 ** Side Effects: 435 ** Sends the mail via SMTP. 436 */ 437 438 smtprcpt(to, m, mci, e) 439 ADDRESS *to; 440 register MAILER *m; 441 MCI *mci; 442 ENVELOPE *e; 443 { 444 register int r; 445 char optbuf[MAXLINE]; 446 447 strcpy(optbuf, ""); 448 if (bitset(MCIF_DSN, mci->mci_flags)) 449 { 450 strcat(optbuf, " NOTIFY="); 451 if (bitset(QPINGONFAILURE, to->q_flags)) 452 { 453 if (bitset(QPINGONSUCCESS, to->q_flags)) 454 strcat(optbuf, "ALWAYS"); 455 else 456 strcat(optbuf, "FAILURE"); 457 } 458 else 459 { 460 if (bitset(QPINGONSUCCESS, to->q_flags)) 461 strcat(optbuf, "SUCCESS"); 462 else 463 strcat(optbuf, "NEVER"); 464 } 465 if (bitset(QHASRETPARAM, to->q_flags)) 466 { 467 strcat(optbuf, " RET="); 468 if (bitset(QNOBODYRETURN, to->q_flags)) 469 strcat(optbuf, "NO"); 470 else 471 strcat(optbuf, "YES"); 472 } 473 } 474 else if (bitset(QPINGONSUCCESS, to->q_flags)) 475 { 476 to->q_flags |= QRELAYED; 477 fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 478 to->q_paddr); 479 } 480 481 smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 482 483 SmtpPhase = mci->mci_phase = "client RCPT"; 484 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 485 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 486 setstatus(to, SmtpReplyBuffer); 487 if (r < 0 || REPLYTYPE(r) == 4) 488 return (EX_TEMPFAIL); 489 else if (REPLYTYPE(r) == 2) 490 return (EX_OK); 491 else if (r == 550 || r == 551 || r == 553) 492 return (EX_NOUSER); 493 else if (r == 552 || r == 554) 494 return (EX_UNAVAILABLE); 495 496 #ifdef LOG 497 if (LogLevel > 1) 498 { 499 syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s", 500 e->e_id, mci->mci_host, SmtpReplyBuffer); 501 } 502 #endif 503 504 return (EX_PROTOCOL); 505 } 506 /* 507 ** SMTPDATA -- send the data and clean up the transaction. 508 ** 509 ** Parameters: 510 ** m -- mailer being sent to. 511 ** e -- the envelope for this message. 512 ** 513 ** Returns: 514 ** exit status corresponding to DATA command. 515 ** 516 ** Side Effects: 517 ** none. 518 */ 519 520 static jmp_buf CtxDataTimeout; 521 static int datatimeout(); 522 523 smtpdata(m, mci, e) 524 struct mailer *m; 525 register MCI *mci; 526 register ENVELOPE *e; 527 { 528 register int r; 529 register EVENT *ev; 530 time_t timeout; 531 532 /* 533 ** Send the data. 534 ** First send the command and check that it is ok. 535 ** Then send the data. 536 ** Follow it up with a dot to terminate. 537 ** Finally get the results of the transaction. 538 */ 539 540 /* send the command and check ok to proceed */ 541 smtpmessage("DATA", m, mci); 542 SmtpPhase = mci->mci_phase = "client DATA 354"; 543 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 544 r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 545 if (r < 0 || REPLYTYPE(r) == 4) 546 { 547 smtpquit(m, mci, e); 548 return (EX_TEMPFAIL); 549 } 550 else if (r == 554) 551 { 552 smtprset(m, mci, e); 553 return (EX_UNAVAILABLE); 554 } 555 else if (r != 354) 556 { 557 #ifdef LOG 558 if (LogLevel > 1) 559 { 560 syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s", 561 e->e_id, mci->mci_host, SmtpReplyBuffer); 562 } 563 #endif 564 smtprset(m, mci, e); 565 return (EX_PROTOCOL); 566 } 567 568 /* 569 ** Set timeout around data writes. Make it at least large 570 ** enough for DNS timeouts on all recipients plus some fudge 571 ** factor. The main thing is that it should not be infinite. 572 */ 573 574 if (setjmp(CtxDataTimeout) != 0) 575 { 576 mci->mci_errno = errno; 577 mci->mci_exitstat = EX_TEMPFAIL; 578 mci->mci_state = MCIS_ERROR; 579 syserr("451 timeout writing message to %s", mci->mci_host); 580 smtpquit(m, mci, e); 581 return EX_TEMPFAIL; 582 } 583 584 timeout = e->e_msgsize / 16; 585 if (timeout < (time_t) 60) 586 timeout = (time_t) 60; 587 timeout += e->e_nrcpts * 90; 588 ev = setevent(timeout, datatimeout, 0); 589 590 /* 591 ** Output the actual message. 592 */ 593 594 (*e->e_puthdr)(mci, e->e_header, e); 595 (*e->e_putbody)(mci, e, NULL); 596 597 /* 598 ** Cleanup after sending message. 599 */ 600 601 clrevent(ev); 602 603 if (ferror(mci->mci_out)) 604 { 605 /* error during processing -- don't send the dot */ 606 mci->mci_errno = EIO; 607 mci->mci_exitstat = EX_IOERR; 608 mci->mci_state = MCIS_ERROR; 609 smtpquit(m, mci, e); 610 return EX_IOERR; 611 } 612 613 /* terminate the message */ 614 fprintf(mci->mci_out, ".%s", m->m_eol); 615 if (TrafficLogFile != NULL) 616 fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); 617 if (Verbose) 618 nmessage(">>> ."); 619 620 /* check for the results of the transaction */ 621 SmtpPhase = mci->mci_phase = "client DATA 250"; 622 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 623 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 624 if (r < 0) 625 { 626 smtpquit(m, mci, e); 627 return (EX_TEMPFAIL); 628 } 629 mci->mci_state = MCIS_OPEN; 630 e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 631 if (REPLYTYPE(r) == 4) 632 return (EX_TEMPFAIL); 633 else if (r == 250) 634 return (EX_OK); 635 else if (r == 552 || r == 554) 636 return (EX_UNAVAILABLE); 637 #ifdef LOG 638 if (LogLevel > 1) 639 { 640 syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s", 641 e->e_id, mci->mci_host, SmtpReplyBuffer); 642 } 643 #endif 644 return (EX_PROTOCOL); 645 } 646 647 648 static int 649 datatimeout() 650 { 651 longjmp(CtxDataTimeout, 1); 652 } 653 /* 654 ** SMTPQUIT -- close the SMTP connection. 655 ** 656 ** Parameters: 657 ** m -- a pointer to the mailer. 658 ** 659 ** Returns: 660 ** none. 661 ** 662 ** Side Effects: 663 ** sends the final protocol and closes the connection. 664 */ 665 666 smtpquit(m, mci, e) 667 register MAILER *m; 668 register MCI *mci; 669 ENVELOPE *e; 670 { 671 bool oldSuprErrs = SuprErrs; 672 673 /* 674 ** Suppress errors here -- we may be processing a different 675 ** job when we do the quit connection, and we don't want the 676 ** new job to be penalized for something that isn't it's 677 ** problem. 678 */ 679 680 SuprErrs = TRUE; 681 682 /* send the quit message if we haven't gotten I/O error */ 683 if (mci->mci_state != MCIS_ERROR) 684 { 685 SmtpPhase = "client QUIT"; 686 smtpmessage("QUIT", m, mci); 687 (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 688 SuprErrs = oldSuprErrs; 689 if (mci->mci_state == MCIS_CLOSED) 690 { 691 SuprErrs = oldSuprErrs; 692 return; 693 } 694 } 695 696 /* now actually close the connection and pick up the zombie */ 697 (void) endmailer(mci, e, NULL); 698 699 SuprErrs = oldSuprErrs; 700 } 701 /* 702 ** SMTPRSET -- send a RSET (reset) command 703 */ 704 705 smtprset(m, mci, e) 706 register MAILER *m; 707 register MCI *mci; 708 ENVELOPE *e; 709 { 710 int r; 711 712 SmtpPhase = "client RSET"; 713 smtpmessage("RSET", m, mci); 714 r = reply(m, mci, e, TimeOuts.to_rset, NULL); 715 if (r < 0) 716 mci->mci_state = MCIS_ERROR; 717 else if (REPLYTYPE(r) == 2) 718 { 719 mci->mci_state = MCIS_OPEN; 720 return; 721 } 722 smtpquit(m, mci, e); 723 } 724 /* 725 ** SMTPPROBE -- check the connection state 726 */ 727 728 smtpprobe(mci) 729 register MCI *mci; 730 { 731 int r; 732 MAILER *m = mci->mci_mailer; 733 extern ENVELOPE BlankEnvelope; 734 ENVELOPE *e = &BlankEnvelope; 735 736 SmtpPhase = "client probe"; 737 smtpmessage("RSET", m, mci); 738 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 739 if (r < 0 || REPLYTYPE(r) != 2) 740 smtpquit(m, mci, e); 741 return r; 742 } 743 /* 744 ** REPLY -- read arpanet reply 745 ** 746 ** Parameters: 747 ** m -- the mailer we are reading the reply from. 748 ** mci -- the mailer connection info structure. 749 ** e -- the current envelope. 750 ** timeout -- the timeout for reads. 751 ** pfunc -- processing function for second and subsequent 752 ** lines of response -- if null, no special 753 ** processing is done. 754 ** 755 ** Returns: 756 ** reply code it reads. 757 ** 758 ** Side Effects: 759 ** flushes the mail file. 760 */ 761 762 reply(m, mci, e, timeout, pfunc) 763 MAILER *m; 764 MCI *mci; 765 ENVELOPE *e; 766 time_t timeout; 767 void (*pfunc)(); 768 { 769 register char *bufp; 770 register int r; 771 bool firstline = TRUE; 772 char junkbuf[MAXLINE]; 773 774 if (mci->mci_out != NULL) 775 (void) fflush(mci->mci_out); 776 777 if (tTd(18, 1)) 778 printf("reply\n"); 779 780 /* 781 ** Read the input line, being careful not to hang. 782 */ 783 784 for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 785 { 786 register char *p; 787 extern time_t curtime(); 788 789 /* actually do the read */ 790 if (e->e_xfp != NULL) 791 (void) fflush(e->e_xfp); /* for debugging */ 792 793 /* if we are in the process of closing just give the code */ 794 if (mci->mci_state == MCIS_CLOSED) 795 return (SMTPCLOSING); 796 797 if (mci->mci_out != NULL) 798 fflush(mci->mci_out); 799 800 /* get the line from the other side */ 801 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 802 mci->mci_lastuse = curtime(); 803 804 if (p == NULL) 805 { 806 bool oldholderrs; 807 extern char MsgBuf[]; /* err.c */ 808 809 /* if the remote end closed early, fake an error */ 810 if (errno == 0) 811 # ifdef ECONNRESET 812 errno = ECONNRESET; 813 # else /* ECONNRESET */ 814 errno = EPIPE; 815 # endif /* ECONNRESET */ 816 817 mci->mci_errno = errno; 818 mci->mci_exitstat = EX_TEMPFAIL; 819 oldholderrs = HoldErrs; 820 HoldErrs = TRUE; 821 usrerr("451 reply: read error from %s", mci->mci_host); 822 823 /* if debugging, pause so we can see state */ 824 if (tTd(18, 100)) 825 pause(); 826 mci->mci_state = MCIS_ERROR; 827 smtpquit(m, mci, e); 828 #ifdef XDEBUG 829 { 830 char wbuf[MAXLINE]; 831 char *p = wbuf; 832 if (e->e_to != NULL) 833 { 834 sprintf(p, "%s... ", e->e_to); 835 p += strlen(p); 836 } 837 sprintf(p, "reply(%s) during %s", 838 mci->mci_host, SmtpPhase); 839 checkfd012(wbuf); 840 } 841 #endif 842 HoldErrs = oldholderrs; 843 return (-1); 844 } 845 fixcrlf(bufp, TRUE); 846 847 /* EHLO failure is not a real error */ 848 if (e->e_xfp != NULL && (bufp[0] == '4' || 849 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 850 { 851 /* serious error -- log the previous command */ 852 if (SmtpNeedIntro) 853 { 854 /* inform user who we are chatting with */ 855 fprintf(CurEnv->e_xfp, 856 "... while talking to %s:\n", 857 CurHostName); 858 SmtpNeedIntro = FALSE; 859 } 860 if (SmtpMsgBuffer[0] != '\0') 861 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 862 SmtpMsgBuffer[0] = '\0'; 863 864 /* now log the message as from the other side */ 865 fprintf(e->e_xfp, "<<< %s\n", bufp); 866 } 867 868 /* display the input for verbose mode */ 869 if (Verbose) 870 nmessage("050 %s", bufp); 871 872 /* process the line */ 873 if (pfunc != NULL && !firstline) 874 (*pfunc)(bufp, m, mci, e); 875 876 firstline = FALSE; 877 878 /* if continuation is required, we can go on */ 879 if (bufp[3] == '-') 880 continue; 881 882 /* ignore improperly formated input */ 883 if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 884 continue; 885 886 /* decode the reply code */ 887 r = atoi(bufp); 888 889 /* extra semantics: 0xx codes are "informational" */ 890 if (r >= 100) 891 break; 892 } 893 894 /* 895 ** Now look at SmtpReplyBuffer -- only care about the first 896 ** line of the response from here on out. 897 */ 898 899 /* save temporary failure messages for posterity */ 900 if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 901 (void) strcpy(SmtpError, SmtpReplyBuffer); 902 903 /* reply code 421 is "Service Shutting Down" */ 904 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 905 { 906 /* send the quit protocol */ 907 mci->mci_state = MCIS_SSD; 908 smtpquit(m, mci, e); 909 } 910 911 return (r); 912 } 913 /* 914 ** SMTPMESSAGE -- send message to server 915 ** 916 ** Parameters: 917 ** f -- format 918 ** m -- the mailer to control formatting. 919 ** a, b, c -- parameters 920 ** 921 ** Returns: 922 ** none. 923 ** 924 ** Side Effects: 925 ** writes message to mci->mci_out. 926 */ 927 928 /*VARARGS1*/ 929 #ifdef __STDC__ 930 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 931 #else 932 smtpmessage(f, m, mci, va_alist) 933 char *f; 934 MAILER *m; 935 MCI *mci; 936 va_dcl 937 #endif 938 { 939 VA_LOCAL_DECL 940 941 VA_START(mci); 942 (void) vsprintf(SmtpMsgBuffer, f, ap); 943 VA_END; 944 945 if (tTd(18, 1) || Verbose) 946 nmessage(">>> %s", SmtpMsgBuffer); 947 if (TrafficLogFile != NULL) 948 fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); 949 if (mci->mci_out != NULL) 950 { 951 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 952 m == NULL ? "\r\n" : m->m_eol); 953 } 954 else if (tTd(18, 1)) 955 { 956 printf("smtpmessage: NULL mci_out\n"); 957 } 958 } 959 960 # endif /* SMTP */ 961