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*59956Seric static char sccsid[] = "@(#)usersmtp.c 6.30 (Berkeley) 05/12/93 (with SMTP)"; 1433731Sbostic #else 15*59956Seric static char sccsid[] = "@(#)usersmtp.c 6.30 (Berkeley) 05/12/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(); 6759285Seric 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); 11559285Seric 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 12459285Seric if (bitnset(M_ESMTP, m->m_flags)) 12559285Seric mci->mci_flags |= MCIF_ESMTP; 12659285Seric 12759285Seric tryhelo: 12859285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 12959285Seric { 13059285Seric smtpmessage("EHLO %s", m, mci, MyHostName); 13159285Seric SmtpPhase = mci->mci_phase = "EHLO wait"; 13259285Seric } 13359285Seric else 13459285Seric { 13559285Seric smtpmessage("HELO %s", m, mci, MyHostName); 13659285Seric SmtpPhase = mci->mci_phase = "HELO wait"; 13759285Seric } 13853751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 13959285Seric r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 1408005Seric if (r < 0) 14152104Seric goto tempfail1; 1428005Seric else if (REPLYTYPE(r) == 5) 14359285Seric { 14459285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 14559285Seric { 14659285Seric /* try old SMTP instead */ 14759285Seric mci->mci_flags &= ~MCIF_ESMTP; 14859285Seric goto tryhelo; 14959285Seric } 15014913Seric goto unavailable; 15159285Seric } 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); 18359285Seric 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 } 20659285Seric /* 20759285Seric ** HELO_OPTIONS -- process the options on a HELO line. 20859285Seric ** 20959285Seric ** Parameters: 21059285Seric ** line -- the response line. 21159285Seric ** m -- the mailer. 21259285Seric ** mci -- the mailer connection info. 21359285Seric ** e -- the envelope. 21459285Seric ** 21559285Seric ** Returns: 21659285Seric ** none. 21759285Seric */ 21853751Seric 21959285Seric void 22059285Seric helo_options(line, m, mci, e) 22159285Seric char *line; 22259285Seric MAILER *m; 22359285Seric register MCI *mci; 22459285Seric ENVELOPE *e; 22559285Seric { 22659285Seric register char *p; 22759285Seric 22859285Seric if (strlen(line) < 5) 22959285Seric return; 23059285Seric line += 4; 23159285Seric p = strchr(line, ' '); 23259285Seric if (p != NULL) 23359285Seric *p++ = '\0'; 23459285Seric if (strcasecmp(line, "size") == 0) 23559285Seric { 23659285Seric mci->mci_flags |= MCIF_SIZE; 23759285Seric if (p != NULL) 23859285Seric mci->mci_maxsize = atol(p); 23959285Seric } 24059285Seric else if (strcasecmp(line, "8bitmime") == 0) 24159285Seric mci->mci_flags |= MCIF_8BITMIME; 24259285Seric else if (strcasecmp(line, "expn") == 0) 24359285Seric mci->mci_flags |= MCIF_EXPN; 24459285Seric } 24559285Seric /* 24659285Seric ** SMTPMAILFROM -- send MAIL command 24759285Seric ** 24859285Seric ** Parameters: 24959285Seric ** m -- the mailer. 25059285Seric ** mci -- the mailer connection structure. 25159285Seric ** e -- the envelope (including the sender to specify). 25259285Seric */ 25359285Seric 25453751Seric smtpmailfrom(m, mci, e) 25553751Seric struct mailer *m; 25654967Seric MCI *mci; 25753751Seric ENVELOPE *e; 25853751Seric { 25953751Seric int r; 26053751Seric char buf[MAXNAME]; 26159285Seric char optbuf[MAXLINE]; 26253751Seric 26357943Seric if (tTd(17, 2)) 26457943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 26557943Seric 26659285Seric /* set up appropriate options to include */ 26759285Seric if (bitset(MCIF_SIZE, mci->mci_flags)) 26859285Seric sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 26959285Seric else 27059285Seric strcpy(optbuf, ""); 27159285Seric 2729315Seric /* 2734865Seric ** Send the MAIL command. 2744865Seric ** Designates the sender. 2754865Seric */ 2764796Seric 27753751Seric mci->mci_state = MCIS_ACTIVE; 27853751Seric 27959540Seric if (bitset(EF_RESPONSE, e->e_flags) && 28059540Seric !bitnset(M_NO_NULL_FROM, m->m_flags)) 28158680Seric (void) strcpy(buf, ""); 28258680Seric else 28358680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 28453751Seric if (e->e_from.q_mailer == LocalMailer || 28510688Seric !bitnset(M_FROMPATH, m->m_flags)) 2868436Seric { 28759285Seric smtpmessage("MAIL From:<%s>%s", m, mci, buf, optbuf); 2888436Seric } 2898436Seric else 2908436Seric { 29159285Seric smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 29259285Seric buf[0] == '@' ? ',' : ':', buf, optbuf); 2938436Seric } 29457379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 29553751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 29659285Seric r = reply(m, mci, e, TimeOuts.to_mail, NULL); 2978005Seric if (r < 0 || REPLYTYPE(r) == 4) 29853751Seric { 29953751Seric mci->mci_exitstat = EX_TEMPFAIL; 30053751Seric mci->mci_errno = errno; 30153751Seric smtpquit(m, mci, e); 30253751Seric return EX_TEMPFAIL; 30353751Seric } 3047963Seric else if (r == 250) 30553751Seric { 30653751Seric mci->mci_exitstat = EX_OK; 30753751Seric return EX_OK; 30853751Seric } 3097963Seric else if (r == 552) 31053751Seric { 31153751Seric /* signal service unavailable */ 31253751Seric mci->mci_exitstat = EX_UNAVAILABLE; 31353751Seric smtpquit(m, mci, e); 31453751Seric return EX_UNAVAILABLE; 31553751Seric } 31614913Seric 31758008Seric #ifdef LOG 31858020Seric if (LogLevel > 1) 31958008Seric { 32058008Seric syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 32158008Seric e->e_id, SmtpReplyBuffer); 32258008Seric } 32358008Seric #endif 32458008Seric 32514913Seric /* protocol error -- close up */ 32653751Seric smtpquit(m, mci, e); 32753751Seric mci->mci_exitstat = EX_PROTOCOL; 32853751Seric return EX_PROTOCOL; 3294684Seric } 3304684Seric /* 3314976Seric ** SMTPRCPT -- designate recipient. 3324797Seric ** 3334797Seric ** Parameters: 3344865Seric ** to -- address of recipient. 33510175Seric ** m -- the mailer we are sending to. 33657379Seric ** mci -- the connection info for this transaction. 33757379Seric ** e -- the envelope for this transaction. 3384797Seric ** 3394797Seric ** Returns: 3404865Seric ** exit status corresponding to recipient status. 3414797Seric ** 3424797Seric ** Side Effects: 3434865Seric ** Sends the mail via SMTP. 3444797Seric */ 3454797Seric 34653751Seric smtprcpt(to, m, mci, e) 3474865Seric ADDRESS *to; 34810175Seric register MAILER *m; 34954967Seric MCI *mci; 35053751Seric ENVELOPE *e; 3514797Seric { 3524797Seric register int r; 3534797Seric 35453751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 3554865Seric 35657379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 35753751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 35859285Seric r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 3598005Seric if (r < 0 || REPLYTYPE(r) == 4) 3604865Seric return (EX_TEMPFAIL); 3617963Seric else if (REPLYTYPE(r) == 2) 3627963Seric return (EX_OK); 3637964Seric else if (r == 550 || r == 551 || r == 553) 3647964Seric return (EX_NOUSER); 3657964Seric else if (r == 552 || r == 554) 3667964Seric return (EX_UNAVAILABLE); 36758008Seric 36858008Seric #ifdef LOG 36958020Seric if (LogLevel > 1) 37058008Seric { 37158008Seric syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 37258008Seric e->e_id, SmtpReplyBuffer); 37358008Seric } 37458008Seric #endif 37558008Seric 3767964Seric return (EX_PROTOCOL); 3774797Seric } 3784797Seric /* 37910175Seric ** SMTPDATA -- send the data and clean up the transaction. 3804684Seric ** 3814684Seric ** Parameters: 3824865Seric ** m -- mailer being sent to. 3836980Seric ** e -- the envelope for this message. 3844684Seric ** 3854684Seric ** Returns: 3864976Seric ** exit status corresponding to DATA command. 3874684Seric ** 3884684Seric ** Side Effects: 3894865Seric ** none. 3904684Seric */ 3914684Seric 39253740Seric smtpdata(m, mci, e) 3934865Seric struct mailer *m; 39454967Seric register MCI *mci; 3956980Seric register ENVELOPE *e; 3964684Seric { 3974684Seric register int r; 3984684Seric 3994797Seric /* 4004797Seric ** Send the data. 40110175Seric ** First send the command and check that it is ok. 40210175Seric ** Then send the data. 40310175Seric ** Follow it up with a dot to terminate. 40410175Seric ** Finally get the results of the transaction. 4054797Seric */ 4064797Seric 40710175Seric /* send the command and check ok to proceed */ 40853751Seric smtpmessage("DATA", m, mci); 40957379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 41053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 41159285Seric r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 4128005Seric if (r < 0 || REPLYTYPE(r) == 4) 41357990Seric { 41457990Seric smtpquit(m, mci, e); 4154797Seric return (EX_TEMPFAIL); 41657990Seric } 4177963Seric else if (r == 554) 41857990Seric { 41957990Seric smtprset(m, mci, e); 4207963Seric return (EX_UNAVAILABLE); 42157990Seric } 4227963Seric else if (r != 354) 42357990Seric { 42458008Seric #ifdef LOG 42558020Seric if (LogLevel > 1) 42658008Seric { 42758008Seric syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 42858008Seric e->e_id, SmtpReplyBuffer); 42958008Seric } 43058008Seric #endif 43157990Seric smtprset(m, mci, e); 4327964Seric return (EX_PROTOCOL); 43357990Seric } 43410175Seric 43510175Seric /* now output the actual message */ 43653751Seric (*e->e_puthdr)(mci->mci_out, m, e); 43753740Seric putline("\n", mci->mci_out, m); 43859730Seric (*e->e_putbody)(mci->mci_out, m, e, NULL); 43910175Seric 44010175Seric /* terminate the message */ 44153740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 44258120Seric if (Verbose) 44358151Seric nmessage(">>> ."); 44410175Seric 44510175Seric /* check for the results of the transaction */ 44657379Seric SmtpPhase = mci->mci_phase = "result wait"; 44753751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 44859285Seric r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 44953751Seric if (r < 0) 45057990Seric { 45157990Seric smtpquit(m, mci, e); 4524797Seric return (EX_TEMPFAIL); 45357990Seric } 45453751Seric mci->mci_state = MCIS_OPEN; 45558917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 45653751Seric if (REPLYTYPE(r) == 4) 45753751Seric return (EX_TEMPFAIL); 4587963Seric else if (r == 250) 4597963Seric return (EX_OK); 4607963Seric else if (r == 552 || r == 554) 4617963Seric return (EX_UNAVAILABLE); 46258008Seric #ifdef LOG 46358020Seric if (LogLevel > 1) 46458008Seric { 46558008Seric syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 46658008Seric e->e_id, SmtpReplyBuffer); 46758008Seric } 46858008Seric #endif 4697964Seric return (EX_PROTOCOL); 4704684Seric } 4714684Seric /* 4724865Seric ** SMTPQUIT -- close the SMTP connection. 4734865Seric ** 4744865Seric ** Parameters: 47515535Seric ** m -- a pointer to the mailer. 4764865Seric ** 4774865Seric ** Returns: 4784865Seric ** none. 4794865Seric ** 4804865Seric ** Side Effects: 4814865Seric ** sends the final protocol and closes the connection. 4824865Seric */ 4834865Seric 48453751Seric smtpquit(m, mci, e) 48553751Seric register MAILER *m; 48654967Seric register MCI *mci; 48753751Seric ENVELOPE *e; 4884865Seric { 4899391Seric int i; 4904865Seric 49154967Seric /* send the quit message if we haven't gotten I/O error */ 49253751Seric if (mci->mci_state != MCIS_ERROR) 4939391Seric { 49453751Seric smtpmessage("QUIT", m, mci); 49559285Seric (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 49653740Seric if (mci->mci_state == MCIS_CLOSED) 49710159Seric return; 4989391Seric } 4999391Seric 50052676Seric /* now actually close the connection and pick up the zombie */ 50158846Seric i = endmailer(mci, e, m->m_argv); 5029391Seric if (i != EX_OK) 50358151Seric syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 5044865Seric } 5054865Seric /* 50654967Seric ** SMTPRSET -- send a RSET (reset) command 50754967Seric */ 50854967Seric 50954967Seric smtprset(m, mci, e) 51054967Seric register MAILER *m; 51154967Seric register MCI *mci; 51254967Seric ENVELOPE *e; 51354967Seric { 51454967Seric int r; 51554967Seric 51654967Seric smtpmessage("RSET", m, mci); 51759285Seric r = reply(m, mci, e, TimeOuts.to_rset, NULL); 51857734Seric if (r < 0) 51957734Seric mci->mci_state = MCIS_ERROR; 52054967Seric else if (REPLYTYPE(r) == 2) 52157734Seric { 52257734Seric mci->mci_state = MCIS_OPEN; 52357734Seric return; 52457734Seric } 52557734Seric smtpquit(m, mci, e); 52654967Seric } 52754967Seric /* 52858867Seric ** SMTPPROBE -- check the connection state 52954967Seric */ 53054967Seric 53158867Seric smtpprobe(mci) 53254967Seric register MCI *mci; 53354967Seric { 53454967Seric int r; 53554967Seric MAILER *m = mci->mci_mailer; 53654967Seric extern ENVELOPE BlankEnvelope; 53754967Seric ENVELOPE *e = &BlankEnvelope; 53854967Seric 53958867Seric smtpmessage("RSET", m, mci); 54059285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 54158061Seric if (r < 0 || REPLYTYPE(r) != 2) 54254967Seric smtpquit(m, mci, e); 54354967Seric return r; 54454967Seric } 54554967Seric /* 5464684Seric ** REPLY -- read arpanet reply 5474684Seric ** 5484684Seric ** Parameters: 54910175Seric ** m -- the mailer we are reading the reply from. 55057379Seric ** mci -- the mailer connection info structure. 55157379Seric ** e -- the current envelope. 55257379Seric ** timeout -- the timeout for reads. 55359285Seric ** pfunc -- processing function for second and subsequent 55459285Seric ** lines of response -- if null, no special 55559285Seric ** processing is done. 5564684Seric ** 5574684Seric ** Returns: 5584684Seric ** reply code it reads. 5594684Seric ** 5604684Seric ** Side Effects: 5614684Seric ** flushes the mail file. 5624684Seric */ 5634684Seric 56459285Seric reply(m, mci, e, timeout, pfunc) 56553751Seric MAILER *m; 56654967Seric MCI *mci; 56753751Seric ENVELOPE *e; 56859285Seric time_t timeout; 56959285Seric void (*pfunc)(); 5704684Seric { 57159014Seric register char *bufp; 57259014Seric register int r; 57359285Seric bool firstline = TRUE; 57458957Seric char junkbuf[MAXLINE]; 57558957Seric 57657379Seric if (mci->mci_out != NULL) 57757379Seric (void) fflush(mci->mci_out); 5784684Seric 5797677Seric if (tTd(18, 1)) 5804796Seric printf("reply\n"); 5814796Seric 5827356Seric /* 5837356Seric ** Read the input line, being careful not to hang. 5847356Seric */ 5857356Seric 58659014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 5874684Seric { 5887356Seric register char *p; 58953751Seric extern time_t curtime(); 5904684Seric 5917685Seric /* actually do the read */ 59253751Seric if (e->e_xfp != NULL) 59353751Seric (void) fflush(e->e_xfp); /* for debugging */ 5947356Seric 59510054Seric /* if we are in the process of closing just give the code */ 59653740Seric if (mci->mci_state == MCIS_CLOSED) 59710054Seric return (SMTPCLOSING); 59810054Seric 59958680Seric if (mci->mci_out != NULL) 60058680Seric fflush(mci->mci_out); 60158680Seric 60210054Seric /* get the line from the other side */ 60358957Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout); 60453751Seric mci->mci_lastuse = curtime(); 60553751Seric 60610054Seric if (p == NULL) 60710131Seric { 60810148Seric extern char MsgBuf[]; /* err.c */ 60910148Seric 61021065Seric /* if the remote end closed early, fake an error */ 61121065Seric if (errno == 0) 61221065Seric # ifdef ECONNRESET 61321065Seric errno = ECONNRESET; 61456795Seric # else /* ECONNRESET */ 61521065Seric errno = EPIPE; 61656795Seric # endif /* ECONNRESET */ 61721065Seric 61857379Seric mci->mci_errno = errno; 61957642Seric mci->mci_exitstat = EX_TEMPFAIL; 62058151Seric message("451 %s: reply: read error from %s", 62157642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 62257203Seric mci->mci_host); 62310420Seric /* if debugging, pause so we can see state */ 62410420Seric if (tTd(18, 100)) 62510420Seric pause(); 62610148Seric # ifdef LOG 62758020Seric if (LogLevel > 1) 62857203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 62956795Seric # endif /* LOG */ 63054967Seric mci->mci_state = MCIS_ERROR; 63153751Seric smtpquit(m, mci, e); 63210054Seric return (-1); 63310131Seric } 63458957Seric fixcrlf(bufp, TRUE); 63510054Seric 63659014Seric if (e->e_xfp != NULL && strchr("45", bufp[0]) != NULL) 63714900Seric { 63814900Seric /* serious error -- log the previous command */ 63959014Seric if (SmtpMsgBuffer[0] != '\0') 64059014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 64159014Seric SmtpMsgBuffer[0] = '\0'; 64214900Seric 64314900Seric /* now log the message as from the other side */ 64458957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 64514900Seric } 64614900Seric 64714900Seric /* display the input for verbose mode */ 64858120Seric if (Verbose) 649*59956Seric nmessage("050 %s", bufp); 6507356Seric 65159285Seric /* process the line */ 65259285Seric if (pfunc != NULL && !firstline) 65359285Seric (*pfunc)(bufp, m, mci, e); 65459285Seric 65559285Seric firstline = FALSE; 65659285Seric 6577356Seric /* if continuation is required, we can go on */ 65859014Seric if (bufp[3] == '-') 6594684Seric continue; 6607356Seric 66159014Seric /* ignore improperly formated input */ 66259014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 66359014Seric continue; 66459014Seric 6657356Seric /* decode the reply code */ 66659014Seric r = atoi(bufp); 6677356Seric 6687356Seric /* extra semantics: 0xx codes are "informational" */ 66959014Seric if (r >= 100) 67059014Seric break; 67159014Seric } 6727356Seric 67359014Seric /* 67459014Seric ** Now look at SmtpReplyBuffer -- only care about the first 67559014Seric ** line of the response from here on out. 67659014Seric */ 67758061Seric 67859014Seric /* save temporary failure messages for posterity */ 67959014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 68059014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 6819391Seric 68259014Seric /* reply code 421 is "Service Shutting Down" */ 68359014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 68459014Seric { 68559014Seric /* send the quit protocol */ 68659014Seric mci->mci_state = MCIS_SSD; 68759014Seric smtpquit(m, mci, e); 6884684Seric } 68959014Seric 69059014Seric return (r); 6914684Seric } 6924796Seric /* 6934865Seric ** SMTPMESSAGE -- send message to server 6944796Seric ** 6954796Seric ** Parameters: 6964796Seric ** f -- format 69710175Seric ** m -- the mailer to control formatting. 6984796Seric ** a, b, c -- parameters 6994796Seric ** 7004796Seric ** Returns: 7014796Seric ** none. 7024796Seric ** 7034796Seric ** Side Effects: 70453740Seric ** writes message to mci->mci_out. 7054796Seric */ 7064796Seric 7074865Seric /*VARARGS1*/ 70857642Seric #ifdef __STDC__ 70957642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 71057642Seric #else 71157642Seric smtpmessage(f, m, mci, va_alist) 7124796Seric char *f; 71310175Seric MAILER *m; 71454967Seric MCI *mci; 71557642Seric va_dcl 71657642Seric #endif 7174796Seric { 71856852Seric VA_LOCAL_DECL 71956852Seric 72057135Seric VA_START(mci); 72156852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 72256852Seric VA_END; 72358680Seric 72458120Seric if (tTd(18, 1) || Verbose) 72558151Seric nmessage(">>> %s", SmtpMsgBuffer); 72653740Seric if (mci->mci_out != NULL) 72758680Seric { 72853740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 72954967Seric m == NULL ? "\r\n" : m->m_eol); 73058680Seric } 73159149Seric else if (tTd(18, 1)) 73258725Seric { 73359149Seric printf("smtpmessage: NULL mci_out\n"); 73458725Seric } 7354796Seric } 7365182Seric 73756795Seric # endif /* SMTP */ 738