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