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