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