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