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