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