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