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.22 (Berkeley) 10/26/94 (with SMTP)"; 14 #else 15 static char sccsid[] = "@(#)usersmtp.c 8.22 (Berkeley) 10/26/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 } 285 /* 286 ** SMTPMAILFROM -- send MAIL command 287 ** 288 ** Parameters: 289 ** m -- the mailer. 290 ** mci -- the mailer connection structure. 291 ** e -- the envelope (including the sender to specify). 292 */ 293 294 smtpmailfrom(m, mci, e) 295 struct mailer *m; 296 MCI *mci; 297 ENVELOPE *e; 298 { 299 int r; 300 char *bufp; 301 char buf[MAXNAME]; 302 char optbuf[MAXLINE]; 303 304 if (tTd(18, 2)) 305 printf("smtpmailfrom: CurHost=%s\n", CurHostName); 306 307 /* set up appropriate options to include */ 308 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 309 sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 310 else 311 strcpy(optbuf, ""); 312 313 if (e->e_bodytype != NULL) 314 { 315 if (bitset(MCIF_8BITMIME, mci->mci_flags)) 316 { 317 strcat(optbuf, " BODY="); 318 strcat(optbuf, e->e_bodytype); 319 } 320 else if (!bitset(MM_CVTMIME, MimeMode) && 321 strcasecmp(e->e_bodytype, "7bit") != 0) 322 { 323 /* cannot just send a 7-bit version */ 324 usrerr("%s does not support 8BITMIME", mci->mci_host); 325 return EX_DATAERR; 326 } 327 } 328 329 /* 330 ** Send the MAIL command. 331 ** Designates the sender. 332 */ 333 334 mci->mci_state = MCIS_ACTIVE; 335 336 if (bitset(EF_RESPONSE, e->e_flags) && 337 !bitnset(M_NO_NULL_FROM, m->m_flags)) 338 (void) strcpy(buf, ""); 339 else 340 expand("\201g", buf, &buf[sizeof buf - 1], e); 341 if (buf[0] == '<') 342 { 343 /* strip off <angle brackets> (put back on below) */ 344 bufp = &buf[strlen(buf) - 1]; 345 if (*bufp == '>') 346 *bufp = '\0'; 347 bufp = &buf[1]; 348 } 349 else 350 bufp = buf; 351 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 352 !bitnset(M_FROMPATH, m->m_flags)) 353 { 354 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 355 } 356 else 357 { 358 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 359 *bufp == '@' ? ',' : ':', bufp, optbuf); 360 } 361 SmtpPhase = mci->mci_phase = "client MAIL"; 362 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 363 r = reply(m, mci, e, TimeOuts.to_mail, NULL); 364 if (r < 0 || REPLYTYPE(r) == 4) 365 { 366 mci->mci_exitstat = EX_TEMPFAIL; 367 mci->mci_errno = errno; 368 smtpquit(m, mci, e); 369 return EX_TEMPFAIL; 370 } 371 else if (r == 250) 372 { 373 mci->mci_exitstat = EX_OK; 374 return EX_OK; 375 } 376 else if (r == 552) 377 { 378 /* signal service unavailable */ 379 mci->mci_exitstat = EX_UNAVAILABLE; 380 smtpquit(m, mci, e); 381 return EX_UNAVAILABLE; 382 } 383 384 #ifdef LOG 385 if (LogLevel > 1) 386 { 387 syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s", 388 e->e_id, mci->mci_host, SmtpReplyBuffer); 389 } 390 #endif 391 392 /* protocol error -- close up */ 393 smtpquit(m, mci, e); 394 mci->mci_exitstat = EX_PROTOCOL; 395 return EX_PROTOCOL; 396 } 397 /* 398 ** SMTPRCPT -- designate recipient. 399 ** 400 ** Parameters: 401 ** to -- address of recipient. 402 ** m -- the mailer we are sending to. 403 ** mci -- the connection info for this transaction. 404 ** e -- the envelope for this transaction. 405 ** 406 ** Returns: 407 ** exit status corresponding to recipient status. 408 ** 409 ** Side Effects: 410 ** Sends the mail via SMTP. 411 */ 412 413 smtprcpt(to, m, mci, e) 414 ADDRESS *to; 415 register MAILER *m; 416 MCI *mci; 417 ENVELOPE *e; 418 { 419 register int r; 420 421 smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 422 423 SmtpPhase = mci->mci_phase = "client RCPT"; 424 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 425 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 426 if (r < 0 || REPLYTYPE(r) == 4) 427 return (EX_TEMPFAIL); 428 else if (REPLYTYPE(r) == 2) 429 return (EX_OK); 430 else if (r == 550 || r == 551 || r == 553) 431 return (EX_NOUSER); 432 else if (r == 552 || r == 554) 433 return (EX_UNAVAILABLE); 434 435 #ifdef LOG 436 if (LogLevel > 1) 437 { 438 syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s", 439 e->e_id, mci->mci_host, SmtpReplyBuffer); 440 } 441 #endif 442 443 return (EX_PROTOCOL); 444 } 445 /* 446 ** SMTPDATA -- send the data and clean up the transaction. 447 ** 448 ** Parameters: 449 ** m -- mailer being sent to. 450 ** e -- the envelope for this message. 451 ** 452 ** Returns: 453 ** exit status corresponding to DATA command. 454 ** 455 ** Side Effects: 456 ** none. 457 */ 458 459 static jmp_buf CtxDataTimeout; 460 static int datatimeout(); 461 462 smtpdata(m, mci, e) 463 struct mailer *m; 464 register MCI *mci; 465 register ENVELOPE *e; 466 { 467 register int r; 468 register EVENT *ev; 469 time_t timeout; 470 471 /* 472 ** Send the data. 473 ** First send the command and check that it is ok. 474 ** Then send the data. 475 ** Follow it up with a dot to terminate. 476 ** Finally get the results of the transaction. 477 */ 478 479 /* send the command and check ok to proceed */ 480 smtpmessage("DATA", m, mci); 481 SmtpPhase = mci->mci_phase = "client DATA 354"; 482 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 483 r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 484 if (r < 0 || REPLYTYPE(r) == 4) 485 { 486 smtpquit(m, mci, e); 487 return (EX_TEMPFAIL); 488 } 489 else if (r == 554) 490 { 491 smtprset(m, mci, e); 492 return (EX_UNAVAILABLE); 493 } 494 else if (r != 354) 495 { 496 #ifdef LOG 497 if (LogLevel > 1) 498 { 499 syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s", 500 e->e_id, mci->mci_host, SmtpReplyBuffer); 501 } 502 #endif 503 smtprset(m, mci, e); 504 return (EX_PROTOCOL); 505 } 506 507 /* 508 ** Set timeout around data writes. Make it at least large 509 ** enough for DNS timeouts on all recipients plus some fudge 510 ** factor. The main thing is that it should not be infinite. 511 */ 512 513 if (setjmp(CtxDataTimeout) != 0) 514 { 515 mci->mci_errno = errno; 516 mci->mci_exitstat = EX_TEMPFAIL; 517 mci->mci_state = MCIS_ERROR; 518 syserr("451 timeout writing message to %s", mci->mci_host); 519 smtpquit(m, mci, e); 520 return EX_TEMPFAIL; 521 } 522 523 timeout = e->e_msgsize / 16; 524 if (timeout < (time_t) 60) 525 timeout = (time_t) 60; 526 timeout += e->e_nrcpts * 90; 527 ev = setevent(timeout, datatimeout, 0); 528 529 /* 530 ** Output the actual message. 531 */ 532 533 if (!bitset(MCIF_8BITMIME, mci->mci_flags) && 534 e->e_bodytype != NULL && 535 strcasecmp(e->e_bodytype, "7bit") != 0) 536 { 537 /* must convert from 8bit MIME format to 7bit encoded */ 538 mci->mci_flags |= MCIF_CVT8TO7; 539 } 540 541 (*e->e_puthdr)(mci, e->e_header, e); 542 (*e->e_putbody)(mci, e, NULL); 543 544 /* 545 ** Cleanup after sending message. 546 */ 547 548 clrevent(ev); 549 550 if (ferror(mci->mci_out)) 551 { 552 /* error during processing -- don't send the dot */ 553 mci->mci_errno = EIO; 554 mci->mci_exitstat = EX_IOERR; 555 mci->mci_state = MCIS_ERROR; 556 smtpquit(m, mci, e); 557 return EX_IOERR; 558 } 559 560 /* terminate the message */ 561 fprintf(mci->mci_out, ".%s", m->m_eol); 562 if (TrafficLogFile != NULL) 563 fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); 564 if (Verbose) 565 nmessage(">>> ."); 566 567 /* check for the results of the transaction */ 568 SmtpPhase = mci->mci_phase = "client DATA 250"; 569 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 570 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 571 if (r < 0) 572 { 573 smtpquit(m, mci, e); 574 return (EX_TEMPFAIL); 575 } 576 mci->mci_state = MCIS_OPEN; 577 e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 578 if (REPLYTYPE(r) == 4) 579 return (EX_TEMPFAIL); 580 else if (r == 250) 581 return (EX_OK); 582 else if (r == 552 || r == 554) 583 return (EX_UNAVAILABLE); 584 #ifdef LOG 585 if (LogLevel > 1) 586 { 587 syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s", 588 e->e_id, mci->mci_host, SmtpReplyBuffer); 589 } 590 #endif 591 return (EX_PROTOCOL); 592 } 593 594 595 static int 596 datatimeout() 597 { 598 longjmp(CtxDataTimeout, 1); 599 } 600 /* 601 ** SMTPQUIT -- close the SMTP connection. 602 ** 603 ** Parameters: 604 ** m -- a pointer to the mailer. 605 ** 606 ** Returns: 607 ** none. 608 ** 609 ** Side Effects: 610 ** sends the final protocol and closes the connection. 611 */ 612 613 smtpquit(m, mci, e) 614 register MAILER *m; 615 register MCI *mci; 616 ENVELOPE *e; 617 { 618 bool oldSuprErrs = SuprErrs; 619 620 /* 621 ** Suppress errors here -- we may be processing a different 622 ** job when we do the quit connection, and we don't want the 623 ** new job to be penalized for something that isn't it's 624 ** problem. 625 */ 626 627 SuprErrs = TRUE; 628 629 /* send the quit message if we haven't gotten I/O error */ 630 if (mci->mci_state != MCIS_ERROR) 631 { 632 SmtpPhase = "client QUIT"; 633 smtpmessage("QUIT", m, mci); 634 (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 635 SuprErrs = oldSuprErrs; 636 if (mci->mci_state == MCIS_CLOSED) 637 { 638 SuprErrs = oldSuprErrs; 639 return; 640 } 641 } 642 643 /* now actually close the connection and pick up the zombie */ 644 (void) endmailer(mci, e, NULL); 645 646 SuprErrs = oldSuprErrs; 647 } 648 /* 649 ** SMTPRSET -- send a RSET (reset) command 650 */ 651 652 smtprset(m, mci, e) 653 register MAILER *m; 654 register MCI *mci; 655 ENVELOPE *e; 656 { 657 int r; 658 659 SmtpPhase = "client RSET"; 660 smtpmessage("RSET", m, mci); 661 r = reply(m, mci, e, TimeOuts.to_rset, NULL); 662 if (r < 0) 663 mci->mci_state = MCIS_ERROR; 664 else if (REPLYTYPE(r) == 2) 665 { 666 mci->mci_state = MCIS_OPEN; 667 return; 668 } 669 smtpquit(m, mci, e); 670 } 671 /* 672 ** SMTPPROBE -- check the connection state 673 */ 674 675 smtpprobe(mci) 676 register MCI *mci; 677 { 678 int r; 679 MAILER *m = mci->mci_mailer; 680 extern ENVELOPE BlankEnvelope; 681 ENVELOPE *e = &BlankEnvelope; 682 683 SmtpPhase = "client probe"; 684 smtpmessage("RSET", m, mci); 685 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 686 if (r < 0 || REPLYTYPE(r) != 2) 687 smtpquit(m, mci, e); 688 return r; 689 } 690 /* 691 ** REPLY -- read arpanet reply 692 ** 693 ** Parameters: 694 ** m -- the mailer we are reading the reply from. 695 ** mci -- the mailer connection info structure. 696 ** e -- the current envelope. 697 ** timeout -- the timeout for reads. 698 ** pfunc -- processing function for second and subsequent 699 ** lines of response -- if null, no special 700 ** processing is done. 701 ** 702 ** Returns: 703 ** reply code it reads. 704 ** 705 ** Side Effects: 706 ** flushes the mail file. 707 */ 708 709 reply(m, mci, e, timeout, pfunc) 710 MAILER *m; 711 MCI *mci; 712 ENVELOPE *e; 713 time_t timeout; 714 void (*pfunc)(); 715 { 716 register char *bufp; 717 register int r; 718 bool firstline = TRUE; 719 char junkbuf[MAXLINE]; 720 721 if (mci->mci_out != NULL) 722 (void) fflush(mci->mci_out); 723 724 if (tTd(18, 1)) 725 printf("reply\n"); 726 727 /* 728 ** Read the input line, being careful not to hang. 729 */ 730 731 for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 732 { 733 register char *p; 734 extern time_t curtime(); 735 736 /* actually do the read */ 737 if (e->e_xfp != NULL) 738 (void) fflush(e->e_xfp); /* for debugging */ 739 740 /* if we are in the process of closing just give the code */ 741 if (mci->mci_state == MCIS_CLOSED) 742 return (SMTPCLOSING); 743 744 if (mci->mci_out != NULL) 745 fflush(mci->mci_out); 746 747 /* get the line from the other side */ 748 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 749 mci->mci_lastuse = curtime(); 750 751 if (p == NULL) 752 { 753 bool oldholderrs; 754 extern char MsgBuf[]; /* err.c */ 755 756 /* if the remote end closed early, fake an error */ 757 if (errno == 0) 758 # ifdef ECONNRESET 759 errno = ECONNRESET; 760 # else /* ECONNRESET */ 761 errno = EPIPE; 762 # endif /* ECONNRESET */ 763 764 mci->mci_errno = errno; 765 mci->mci_exitstat = EX_TEMPFAIL; 766 oldholderrs = HoldErrs; 767 HoldErrs = TRUE; 768 usrerr("451 reply: read error from %s", mci->mci_host); 769 770 /* if debugging, pause so we can see state */ 771 if (tTd(18, 100)) 772 pause(); 773 mci->mci_state = MCIS_ERROR; 774 smtpquit(m, mci, e); 775 #ifdef XDEBUG 776 { 777 char wbuf[MAXLINE]; 778 char *p = wbuf; 779 if (e->e_to != NULL) 780 { 781 sprintf(p, "%s... ", e->e_to); 782 p += strlen(p); 783 } 784 sprintf(p, "reply(%s) during %s", 785 mci->mci_host, SmtpPhase); 786 checkfd012(wbuf); 787 } 788 #endif 789 HoldErrs = oldholderrs; 790 return (-1); 791 } 792 fixcrlf(bufp, TRUE); 793 794 /* EHLO failure is not a real error */ 795 if (e->e_xfp != NULL && (bufp[0] == '4' || 796 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 797 { 798 /* serious error -- log the previous command */ 799 if (SmtpNeedIntro) 800 { 801 /* inform user who we are chatting with */ 802 fprintf(CurEnv->e_xfp, 803 "... while talking to %s:\n", 804 CurHostName); 805 SmtpNeedIntro = FALSE; 806 } 807 if (SmtpMsgBuffer[0] != '\0') 808 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 809 SmtpMsgBuffer[0] = '\0'; 810 811 /* now log the message as from the other side */ 812 fprintf(e->e_xfp, "<<< %s\n", bufp); 813 } 814 815 /* display the input for verbose mode */ 816 if (Verbose) 817 nmessage("050 %s", bufp); 818 819 /* process the line */ 820 if (pfunc != NULL && !firstline) 821 (*pfunc)(bufp, m, mci, e); 822 823 firstline = FALSE; 824 825 /* if continuation is required, we can go on */ 826 if (bufp[3] == '-') 827 continue; 828 829 /* ignore improperly formated input */ 830 if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 831 continue; 832 833 /* decode the reply code */ 834 r = atoi(bufp); 835 836 /* extra semantics: 0xx codes are "informational" */ 837 if (r >= 100) 838 break; 839 } 840 841 /* 842 ** Now look at SmtpReplyBuffer -- only care about the first 843 ** line of the response from here on out. 844 */ 845 846 /* save temporary failure messages for posterity */ 847 if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 848 (void) strcpy(SmtpError, SmtpReplyBuffer); 849 850 /* reply code 421 is "Service Shutting Down" */ 851 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 852 { 853 /* send the quit protocol */ 854 mci->mci_state = MCIS_SSD; 855 smtpquit(m, mci, e); 856 } 857 858 return (r); 859 } 860 /* 861 ** SMTPMESSAGE -- send message to server 862 ** 863 ** Parameters: 864 ** f -- format 865 ** m -- the mailer to control formatting. 866 ** a, b, c -- parameters 867 ** 868 ** Returns: 869 ** none. 870 ** 871 ** Side Effects: 872 ** writes message to mci->mci_out. 873 */ 874 875 /*VARARGS1*/ 876 #ifdef __STDC__ 877 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 878 #else 879 smtpmessage(f, m, mci, va_alist) 880 char *f; 881 MAILER *m; 882 MCI *mci; 883 va_dcl 884 #endif 885 { 886 VA_LOCAL_DECL 887 888 VA_START(mci); 889 (void) vsprintf(SmtpMsgBuffer, f, ap); 890 VA_END; 891 892 if (tTd(18, 1) || Verbose) 893 nmessage(">>> %s", SmtpMsgBuffer); 894 if (TrafficLogFile != NULL) 895 fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); 896 if (mci->mci_out != NULL) 897 { 898 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 899 m == NULL ? "\r\n" : m->m_eol); 900 } 901 else if (tTd(18, 1)) 902 { 903 printf("smtpmessage: NULL mci_out\n"); 904 } 905 } 906 907 # endif /* SMTP */ 908