122716Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642831Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822716Sdist 933731Sbostic # include "sendmail.h" 1022716Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef SMTP 13*59285Seric static char sccsid[] = "@(#)usersmtp.c 6.27 (Berkeley) 04/26/93 (with SMTP)"; 1433731Sbostic #else 15*59285Seric static char sccsid[] = "@(#)usersmtp.c 6.27 (Berkeley) 04/26/93 (without SMTP)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 194684Seric # include <sysexits.h> 2021065Seric # include <errno.h> 214684Seric 2233731Sbostic # ifdef SMTP 234684Seric 244684Seric /* 259391Seric ** USERSMTP -- run SMTP protocol from the user end. 269391Seric ** 279391Seric ** This protocol is described in RFC821. 289391Seric */ 299391Seric 309391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 319391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 329391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 339391Seric 3414900Seric char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 3510054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 3621065Seric char SmtpError[MAXLINE] = ""; /* save failure error messages */ 3710054Seric int SmtpPid; /* pid of mailer */ 3858671Seric 3958671Seric #ifdef __STDC__ 4058671Seric extern smtpmessage(char *f, MAILER *m, MCI *mci, ...); 4158671Seric #endif 429391Seric /* 434865Seric ** SMTPINIT -- initialize SMTP. 444684Seric ** 454865Seric ** Opens the connection and sends the initial protocol. 464684Seric ** 474684Seric ** Parameters: 484865Seric ** m -- mailer to create connection to. 494865Seric ** pvp -- pointer to parameter vector to pass to 504865Seric ** the mailer. 514684Seric ** 524684Seric ** Returns: 5354967Seric ** none. 544684Seric ** 554684Seric ** Side Effects: 564865Seric ** creates connection and sends initial protocol. 574684Seric */ 584684Seric 5954967Seric smtpinit(m, mci, e) 604865Seric struct mailer *m; 6154967Seric register MCI *mci; 6253751Seric ENVELOPE *e; 634684Seric { 644865Seric register int r; 6558957Seric register char *p; 6652107Seric extern STAB *stab(); 67*59285Seric extern void helo_options(); 684684Seric 6957379Seric if (tTd(17, 1)) 7057379Seric { 7157379Seric printf("smtpinit "); 7257379Seric mci_dump(mci); 7357379Seric } 7457379Seric 754865Seric /* 764865Seric ** Open the connection to the mailer. 774865Seric */ 784684Seric 7921065Seric SmtpError[0] = '\0'; 8057379Seric CurHostName = mci->mci_host; /* XXX UGLY XXX */ 8154967Seric switch (mci->mci_state) 826051Seric { 8354967Seric case MCIS_ACTIVE: 8454967Seric /* need to clear old information */ 8554967Seric smtprset(m, mci, e); 8657734Seric /* fall through */ 8715139Seric 8854967Seric case MCIS_OPEN: 8954967Seric return; 9054967Seric 9154967Seric case MCIS_ERROR: 9254967Seric case MCIS_SSD: 9354967Seric /* shouldn't happen */ 9454967Seric smtpquit(m, mci, e); 9557734Seric /* fall through */ 9654967Seric 9754967Seric case MCIS_CLOSED: 9858151Seric syserr("451 smtpinit: state CLOSED"); 9954967Seric return; 10054967Seric 10154967Seric case MCIS_OPENING: 10254967Seric break; 1036051Seric } 1044796Seric 10554967Seric mci->mci_state = MCIS_OPENING; 10654967Seric 1074865Seric /* 1084865Seric ** Get the greeting message. 10914913Seric ** This should appear spontaneously. Give it five minutes to 11014886Seric ** happen. 1114865Seric */ 1124797Seric 11357379Seric SmtpPhase = mci->mci_phase = "greeting wait"; 11453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 115*59285Seric r = reply(m, mci, e, TimeOuts.to_initial, NULL); 1168005Seric if (r < 0 || REPLYTYPE(r) != 2) 11752104Seric goto tempfail1; 1184684Seric 1194865Seric /* 1204976Seric ** Send the HELO command. 1217963Seric ** My mother taught me to always introduce myself. 1224976Seric */ 1234976Seric 124*59285Seric if (bitnset(M_ESMTP, m->m_flags)) 125*59285Seric mci->mci_flags |= MCIF_ESMTP; 126*59285Seric 127*59285Seric tryhelo: 128*59285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 129*59285Seric { 130*59285Seric smtpmessage("EHLO %s", m, mci, MyHostName); 131*59285Seric SmtpPhase = mci->mci_phase = "EHLO wait"; 132*59285Seric } 133*59285Seric else 134*59285Seric { 135*59285Seric smtpmessage("HELO %s", m, mci, MyHostName); 136*59285Seric SmtpPhase = mci->mci_phase = "HELO wait"; 137*59285Seric } 13853751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 139*59285Seric r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 1408005Seric if (r < 0) 14152104Seric goto tempfail1; 1428005Seric else if (REPLYTYPE(r) == 5) 143*59285Seric { 144*59285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 145*59285Seric { 146*59285Seric /* try old SMTP instead */ 147*59285Seric mci->mci_flags &= ~MCIF_ESMTP; 148*59285Seric goto tryhelo; 149*59285Seric } 15014913Seric goto unavailable; 151*59285Seric } 1527963Seric else if (REPLYTYPE(r) != 2) 15352104Seric goto tempfail1; 1544976Seric 1554976Seric /* 15658957Seric ** Check to see if we actually ended up talking to ourself. 15758957Seric ** This means we didn't know about an alias or MX, or we managed 15858957Seric ** to connect to an echo server. 15958957Seric */ 16058957Seric 16159026Seric p = strchr(&SmtpReplyBuffer[4], ' '); 16258957Seric if (p != NULL) 16358957Seric *p == '\0'; 16459026Seric if (strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 16558957Seric { 16658957Seric syserr("553 %s config error: mail loops back to myself", 16758957Seric MyHostName); 16858957Seric mci->mci_exitstat = EX_CONFIG; 16958957Seric mci->mci_errno = 0; 17058957Seric smtpquit(m, mci, e); 17158957Seric return; 17258957Seric } 17358957Seric 17458957Seric /* 1759315Seric ** If this is expected to be another sendmail, send some internal 1769315Seric ** commands. 1779315Seric */ 1789315Seric 17910688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1809315Seric { 1819315Seric /* tell it to be verbose */ 18253751Seric smtpmessage("VERB", m, mci); 183*59285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 1849315Seric if (r < 0) 18552104Seric goto tempfail2; 1869315Seric } 1879315Seric 18853751Seric mci->mci_state = MCIS_OPEN; 18954967Seric return; 19053751Seric 19153751Seric tempfail1: 19253751Seric tempfail2: 19353751Seric mci->mci_exitstat = EX_TEMPFAIL; 19457379Seric if (mci->mci_errno == 0) 19557379Seric mci->mci_errno = errno; 19657379Seric if (mci->mci_state != MCIS_CLOSED) 19757379Seric smtpquit(m, mci, e); 19854967Seric return; 19953751Seric 20053751Seric unavailable: 20153751Seric mci->mci_exitstat = EX_UNAVAILABLE; 20253751Seric mci->mci_errno = errno; 20353751Seric smtpquit(m, mci, e); 20454967Seric return; 20553751Seric } 206*59285Seric /* 207*59285Seric ** HELO_OPTIONS -- process the options on a HELO line. 208*59285Seric ** 209*59285Seric ** Parameters: 210*59285Seric ** line -- the response line. 211*59285Seric ** m -- the mailer. 212*59285Seric ** mci -- the mailer connection info. 213*59285Seric ** e -- the envelope. 214*59285Seric ** 215*59285Seric ** Returns: 216*59285Seric ** none. 217*59285Seric */ 21853751Seric 219*59285Seric void 220*59285Seric helo_options(line, m, mci, e) 221*59285Seric char *line; 222*59285Seric MAILER *m; 223*59285Seric register MCI *mci; 224*59285Seric ENVELOPE *e; 225*59285Seric { 226*59285Seric register char *p; 227*59285Seric 228*59285Seric if (strlen(line) < 5) 229*59285Seric return; 230*59285Seric line += 4; 231*59285Seric p = strchr(line, ' '); 232*59285Seric if (p != NULL) 233*59285Seric *p++ = '\0'; 234*59285Seric if (strcasecmp(line, "size") == 0) 235*59285Seric { 236*59285Seric mci->mci_flags |= MCIF_SIZE; 237*59285Seric if (p != NULL) 238*59285Seric mci->mci_maxsize = atol(p); 239*59285Seric } 240*59285Seric else if (strcasecmp(line, "8bitmime") == 0) 241*59285Seric mci->mci_flags |= MCIF_8BITMIME; 242*59285Seric else if (strcasecmp(line, "expn") == 0) 243*59285Seric mci->mci_flags |= MCIF_EXPN; 244*59285Seric } 245*59285Seric /* 246*59285Seric ** SMTPMAILFROM -- send MAIL command 247*59285Seric ** 248*59285Seric ** Parameters: 249*59285Seric ** m -- the mailer. 250*59285Seric ** mci -- the mailer connection structure. 251*59285Seric ** e -- the envelope (including the sender to specify). 252*59285Seric */ 253*59285Seric 25453751Seric smtpmailfrom(m, mci, e) 25553751Seric struct mailer *m; 25654967Seric MCI *mci; 25753751Seric ENVELOPE *e; 25853751Seric { 25953751Seric int r; 26053751Seric char buf[MAXNAME]; 261*59285Seric char optbuf[MAXLINE]; 26253751Seric 26357943Seric if (tTd(17, 2)) 26457943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 26557943Seric 266*59285Seric /* set up appropriate options to include */ 267*59285Seric if (bitset(MCIF_SIZE, mci->mci_flags)) 268*59285Seric sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 269*59285Seric else 270*59285Seric strcpy(optbuf, ""); 271*59285Seric 2729315Seric /* 2734865Seric ** Send the MAIL command. 2744865Seric ** Designates the sender. 2754865Seric */ 2764796Seric 27753751Seric mci->mci_state = MCIS_ACTIVE; 27853751Seric 27958680Seric if (bitset(EF_RESPONSE, e->e_flags)) 28058680Seric (void) strcpy(buf, ""); 28158680Seric else 28258680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 28353751Seric if (e->e_from.q_mailer == LocalMailer || 28410688Seric !bitnset(M_FROMPATH, m->m_flags)) 2858436Seric { 286*59285Seric smtpmessage("MAIL From:<%s>%s", m, mci, buf, optbuf); 2878436Seric } 2888436Seric else 2898436Seric { 290*59285Seric smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 291*59285Seric buf[0] == '@' ? ',' : ':', buf, optbuf); 2928436Seric } 29357379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 29453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 295*59285Seric r = reply(m, mci, e, TimeOuts.to_mail, NULL); 2968005Seric if (r < 0 || REPLYTYPE(r) == 4) 29753751Seric { 29853751Seric mci->mci_exitstat = EX_TEMPFAIL; 29953751Seric mci->mci_errno = errno; 30053751Seric smtpquit(m, mci, e); 30153751Seric return EX_TEMPFAIL; 30253751Seric } 3037963Seric else if (r == 250) 30453751Seric { 30553751Seric mci->mci_exitstat = EX_OK; 30653751Seric return EX_OK; 30753751Seric } 3087963Seric else if (r == 552) 30953751Seric { 31053751Seric /* signal service unavailable */ 31153751Seric mci->mci_exitstat = EX_UNAVAILABLE; 31253751Seric smtpquit(m, mci, e); 31353751Seric return EX_UNAVAILABLE; 31453751Seric } 31514913Seric 31658008Seric #ifdef LOG 31758020Seric if (LogLevel > 1) 31858008Seric { 31958008Seric syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 32058008Seric e->e_id, SmtpReplyBuffer); 32158008Seric } 32258008Seric #endif 32358008Seric 32414913Seric /* protocol error -- close up */ 32553751Seric smtpquit(m, mci, e); 32653751Seric mci->mci_exitstat = EX_PROTOCOL; 32753751Seric return EX_PROTOCOL; 3284684Seric } 3294684Seric /* 3304976Seric ** SMTPRCPT -- designate recipient. 3314797Seric ** 3324797Seric ** Parameters: 3334865Seric ** to -- address of recipient. 33410175Seric ** m -- the mailer we are sending to. 33557379Seric ** mci -- the connection info for this transaction. 33657379Seric ** e -- the envelope for this transaction. 3374797Seric ** 3384797Seric ** Returns: 3394865Seric ** exit status corresponding to recipient status. 3404797Seric ** 3414797Seric ** Side Effects: 3424865Seric ** Sends the mail via SMTP. 3434797Seric */ 3444797Seric 34553751Seric smtprcpt(to, m, mci, e) 3464865Seric ADDRESS *to; 34710175Seric register MAILER *m; 34854967Seric MCI *mci; 34953751Seric ENVELOPE *e; 3504797Seric { 3514797Seric register int r; 3524797Seric 35353751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 3544865Seric 35557379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 35653751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 357*59285Seric r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 3588005Seric if (r < 0 || REPLYTYPE(r) == 4) 3594865Seric return (EX_TEMPFAIL); 3607963Seric else if (REPLYTYPE(r) == 2) 3617963Seric return (EX_OK); 3627964Seric else if (r == 550 || r == 551 || r == 553) 3637964Seric return (EX_NOUSER); 3647964Seric else if (r == 552 || r == 554) 3657964Seric return (EX_UNAVAILABLE); 36658008Seric 36758008Seric #ifdef LOG 36858020Seric if (LogLevel > 1) 36958008Seric { 37058008Seric syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 37158008Seric e->e_id, SmtpReplyBuffer); 37258008Seric } 37358008Seric #endif 37458008Seric 3757964Seric return (EX_PROTOCOL); 3764797Seric } 3774797Seric /* 37810175Seric ** SMTPDATA -- send the data and clean up the transaction. 3794684Seric ** 3804684Seric ** Parameters: 3814865Seric ** m -- mailer being sent to. 3826980Seric ** e -- the envelope for this message. 3834684Seric ** 3844684Seric ** Returns: 3854976Seric ** exit status corresponding to DATA command. 3864684Seric ** 3874684Seric ** Side Effects: 3884865Seric ** none. 3894684Seric */ 3904684Seric 39153740Seric smtpdata(m, mci, e) 3924865Seric struct mailer *m; 39354967Seric register MCI *mci; 3946980Seric register ENVELOPE *e; 3954684Seric { 3964684Seric register int r; 3974684Seric 3984797Seric /* 3994797Seric ** Send the data. 40010175Seric ** First send the command and check that it is ok. 40110175Seric ** Then send the data. 40210175Seric ** Follow it up with a dot to terminate. 40310175Seric ** Finally get the results of the transaction. 4044797Seric */ 4054797Seric 40610175Seric /* send the command and check ok to proceed */ 40753751Seric smtpmessage("DATA", m, mci); 40857379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 40953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 410*59285Seric r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 4118005Seric if (r < 0 || REPLYTYPE(r) == 4) 41257990Seric { 41357990Seric smtpquit(m, mci, e); 4144797Seric return (EX_TEMPFAIL); 41557990Seric } 4167963Seric else if (r == 554) 41757990Seric { 41857990Seric smtprset(m, mci, e); 4197963Seric return (EX_UNAVAILABLE); 42057990Seric } 4217963Seric else if (r != 354) 42257990Seric { 42358008Seric #ifdef LOG 42458020Seric if (LogLevel > 1) 42558008Seric { 42658008Seric syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 42758008Seric e->e_id, SmtpReplyBuffer); 42858008Seric } 42958008Seric #endif 43057990Seric smtprset(m, mci, e); 4317964Seric return (EX_PROTOCOL); 43257990Seric } 43310175Seric 43410175Seric /* now output the actual message */ 43553751Seric (*e->e_puthdr)(mci->mci_out, m, e); 43653740Seric putline("\n", mci->mci_out, m); 43753751Seric (*e->e_putbody)(mci->mci_out, m, e); 43810175Seric 43910175Seric /* terminate the message */ 44053740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 44158120Seric if (Verbose) 44258151Seric nmessage(">>> ."); 44310175Seric 44410175Seric /* check for the results of the transaction */ 44557379Seric SmtpPhase = mci->mci_phase = "result wait"; 44653751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 447*59285Seric r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 44853751Seric if (r < 0) 44957990Seric { 45057990Seric smtpquit(m, mci, e); 4514797Seric return (EX_TEMPFAIL); 45257990Seric } 45353751Seric mci->mci_state = MCIS_OPEN; 45458917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 45553751Seric if (REPLYTYPE(r) == 4) 45653751Seric return (EX_TEMPFAIL); 4577963Seric else if (r == 250) 4587963Seric return (EX_OK); 4597963Seric else if (r == 552 || r == 554) 4607963Seric return (EX_UNAVAILABLE); 46158008Seric #ifdef LOG 46258020Seric if (LogLevel > 1) 46358008Seric { 46458008Seric syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 46558008Seric e->e_id, SmtpReplyBuffer); 46658008Seric } 46758008Seric #endif 4687964Seric return (EX_PROTOCOL); 4694684Seric } 4704684Seric /* 4714865Seric ** SMTPQUIT -- close the SMTP connection. 4724865Seric ** 4734865Seric ** Parameters: 47415535Seric ** m -- a pointer to the mailer. 4754865Seric ** 4764865Seric ** Returns: 4774865Seric ** none. 4784865Seric ** 4794865Seric ** Side Effects: 4804865Seric ** sends the final protocol and closes the connection. 4814865Seric */ 4824865Seric 48353751Seric smtpquit(m, mci, e) 48453751Seric register MAILER *m; 48554967Seric register MCI *mci; 48653751Seric ENVELOPE *e; 4874865Seric { 4889391Seric int i; 4894865Seric 49054967Seric /* send the quit message if we haven't gotten I/O error */ 49153751Seric if (mci->mci_state != MCIS_ERROR) 4929391Seric { 49353751Seric smtpmessage("QUIT", m, mci); 494*59285Seric (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 49553740Seric if (mci->mci_state == MCIS_CLOSED) 49610159Seric return; 4979391Seric } 4989391Seric 49952676Seric /* now actually close the connection and pick up the zombie */ 50058846Seric i = endmailer(mci, e, m->m_argv); 5019391Seric if (i != EX_OK) 50258151Seric syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 5034865Seric } 5044865Seric /* 50554967Seric ** SMTPRSET -- send a RSET (reset) command 50654967Seric */ 50754967Seric 50854967Seric smtprset(m, mci, e) 50954967Seric register MAILER *m; 51054967Seric register MCI *mci; 51154967Seric ENVELOPE *e; 51254967Seric { 51354967Seric int r; 51454967Seric 51554967Seric smtpmessage("RSET", m, mci); 516*59285Seric r = reply(m, mci, e, TimeOuts.to_rset, NULL); 51757734Seric if (r < 0) 51857734Seric mci->mci_state = MCIS_ERROR; 51954967Seric else if (REPLYTYPE(r) == 2) 52057734Seric { 52157734Seric mci->mci_state = MCIS_OPEN; 52257734Seric return; 52357734Seric } 52457734Seric smtpquit(m, mci, e); 52554967Seric } 52654967Seric /* 52758867Seric ** SMTPPROBE -- check the connection state 52854967Seric */ 52954967Seric 53058867Seric smtpprobe(mci) 53154967Seric register MCI *mci; 53254967Seric { 53354967Seric int r; 53454967Seric MAILER *m = mci->mci_mailer; 53554967Seric extern ENVELOPE BlankEnvelope; 53654967Seric ENVELOPE *e = &BlankEnvelope; 53754967Seric 53858867Seric smtpmessage("RSET", m, mci); 539*59285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 54058061Seric if (r < 0 || REPLYTYPE(r) != 2) 54154967Seric smtpquit(m, mci, e); 54254967Seric return r; 54354967Seric } 54454967Seric /* 5454684Seric ** REPLY -- read arpanet reply 5464684Seric ** 5474684Seric ** Parameters: 54810175Seric ** m -- the mailer we are reading the reply from. 54957379Seric ** mci -- the mailer connection info structure. 55057379Seric ** e -- the current envelope. 55157379Seric ** timeout -- the timeout for reads. 552*59285Seric ** pfunc -- processing function for second and subsequent 553*59285Seric ** lines of response -- if null, no special 554*59285Seric ** processing is done. 5554684Seric ** 5564684Seric ** Returns: 5574684Seric ** reply code it reads. 5584684Seric ** 5594684Seric ** Side Effects: 5604684Seric ** flushes the mail file. 5614684Seric */ 5624684Seric 563*59285Seric reply(m, mci, e, timeout, pfunc) 56453751Seric MAILER *m; 56554967Seric MCI *mci; 56653751Seric ENVELOPE *e; 567*59285Seric time_t timeout; 568*59285Seric void (*pfunc)(); 5694684Seric { 57059014Seric register char *bufp; 57159014Seric register int r; 572*59285Seric bool firstline = TRUE; 57358957Seric char junkbuf[MAXLINE]; 57458957Seric 57557379Seric if (mci->mci_out != NULL) 57657379Seric (void) fflush(mci->mci_out); 5774684Seric 5787677Seric if (tTd(18, 1)) 5794796Seric printf("reply\n"); 5804796Seric 5817356Seric /* 5827356Seric ** Read the input line, being careful not to hang. 5837356Seric */ 5847356Seric 58559014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 5864684Seric { 5877356Seric register char *p; 58853751Seric extern time_t curtime(); 5894684Seric 5907685Seric /* actually do the read */ 59153751Seric if (e->e_xfp != NULL) 59253751Seric (void) fflush(e->e_xfp); /* for debugging */ 5937356Seric 59410054Seric /* if we are in the process of closing just give the code */ 59553740Seric if (mci->mci_state == MCIS_CLOSED) 59610054Seric return (SMTPCLOSING); 59710054Seric 59858680Seric if (mci->mci_out != NULL) 59958680Seric fflush(mci->mci_out); 60058680Seric 60110054Seric /* get the line from the other side */ 60258957Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout); 60353751Seric mci->mci_lastuse = curtime(); 60453751Seric 60510054Seric if (p == NULL) 60610131Seric { 60710148Seric extern char MsgBuf[]; /* err.c */ 60810148Seric 60921065Seric /* if the remote end closed early, fake an error */ 61021065Seric if (errno == 0) 61121065Seric # ifdef ECONNRESET 61221065Seric errno = ECONNRESET; 61356795Seric # else /* ECONNRESET */ 61421065Seric errno = EPIPE; 61556795Seric # endif /* ECONNRESET */ 61621065Seric 61757379Seric mci->mci_errno = errno; 61857642Seric mci->mci_exitstat = EX_TEMPFAIL; 61958151Seric message("451 %s: reply: read error from %s", 62057642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 62157203Seric mci->mci_host); 62210420Seric /* if debugging, pause so we can see state */ 62310420Seric if (tTd(18, 100)) 62410420Seric pause(); 62510148Seric # ifdef LOG 62658020Seric if (LogLevel > 1) 62757203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 62856795Seric # endif /* LOG */ 62954967Seric mci->mci_state = MCIS_ERROR; 63053751Seric smtpquit(m, mci, e); 63110054Seric return (-1); 63210131Seric } 63358957Seric fixcrlf(bufp, TRUE); 63410054Seric 63559014Seric if (e->e_xfp != NULL && strchr("45", bufp[0]) != NULL) 63614900Seric { 63714900Seric /* serious error -- log the previous command */ 63859014Seric if (SmtpMsgBuffer[0] != '\0') 63959014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 64059014Seric SmtpMsgBuffer[0] = '\0'; 64114900Seric 64214900Seric /* now log the message as from the other side */ 64358957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 64414900Seric } 64514900Seric 64614900Seric /* display the input for verbose mode */ 64758120Seric if (Verbose) 64858957Seric nmessage("%s", bufp); 6497356Seric 650*59285Seric /* process the line */ 651*59285Seric if (pfunc != NULL && !firstline) 652*59285Seric (*pfunc)(bufp, m, mci, e); 653*59285Seric 654*59285Seric firstline = FALSE; 655*59285Seric 6567356Seric /* if continuation is required, we can go on */ 65759014Seric if (bufp[3] == '-') 6584684Seric continue; 6597356Seric 66059014Seric /* ignore improperly formated input */ 66159014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 66259014Seric continue; 66359014Seric 6647356Seric /* decode the reply code */ 66559014Seric r = atoi(bufp); 6667356Seric 6677356Seric /* extra semantics: 0xx codes are "informational" */ 66859014Seric if (r >= 100) 66959014Seric break; 67059014Seric } 6717356Seric 67259014Seric /* 67359014Seric ** Now look at SmtpReplyBuffer -- only care about the first 67459014Seric ** line of the response from here on out. 67559014Seric */ 67658061Seric 67759014Seric /* save temporary failure messages for posterity */ 67859014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 67959014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 6809391Seric 68159014Seric /* reply code 421 is "Service Shutting Down" */ 68259014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 68359014Seric { 68459014Seric /* send the quit protocol */ 68559014Seric mci->mci_state = MCIS_SSD; 68659014Seric smtpquit(m, mci, e); 6874684Seric } 68859014Seric 68959014Seric return (r); 6904684Seric } 6914796Seric /* 6924865Seric ** SMTPMESSAGE -- send message to server 6934796Seric ** 6944796Seric ** Parameters: 6954796Seric ** f -- format 69610175Seric ** m -- the mailer to control formatting. 6974796Seric ** a, b, c -- parameters 6984796Seric ** 6994796Seric ** Returns: 7004796Seric ** none. 7014796Seric ** 7024796Seric ** Side Effects: 70353740Seric ** writes message to mci->mci_out. 7044796Seric */ 7054796Seric 7064865Seric /*VARARGS1*/ 70757642Seric #ifdef __STDC__ 70857642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 70957642Seric #else 71057642Seric smtpmessage(f, m, mci, va_alist) 7114796Seric char *f; 71210175Seric MAILER *m; 71354967Seric MCI *mci; 71457642Seric va_dcl 71557642Seric #endif 7164796Seric { 71756852Seric VA_LOCAL_DECL 71856852Seric 71957135Seric VA_START(mci); 72056852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 72156852Seric VA_END; 72258680Seric 72358120Seric if (tTd(18, 1) || Verbose) 72458151Seric nmessage(">>> %s", SmtpMsgBuffer); 72553740Seric if (mci->mci_out != NULL) 72658680Seric { 72753740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 72854967Seric m == NULL ? "\r\n" : m->m_eol); 72958680Seric } 73059149Seric else if (tTd(18, 1)) 73158725Seric { 73259149Seric printf("smtpmessage: NULL mci_out\n"); 73358725Seric } 7344796Seric } 7355182Seric 73656795Seric # endif /* SMTP */ 737