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*60210Seric static char sccsid[] = "@(#)usersmtp.c 6.31 (Berkeley) 05/21/93 (with SMTP)"; 1433731Sbostic #else 15*60210Seric static char sccsid[] = "@(#)usersmtp.c 6.31 (Berkeley) 05/21/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*60210Seric extern void esmtp_check(); 6859285Seric extern void helo_options(); 694684Seric 7057379Seric if (tTd(17, 1)) 7157379Seric { 7257379Seric printf("smtpinit "); 7357379Seric mci_dump(mci); 7457379Seric } 7557379Seric 764865Seric /* 774865Seric ** Open the connection to the mailer. 784865Seric */ 794684Seric 8021065Seric SmtpError[0] = '\0'; 8157379Seric CurHostName = mci->mci_host; /* XXX UGLY XXX */ 8254967Seric switch (mci->mci_state) 836051Seric { 8454967Seric case MCIS_ACTIVE: 8554967Seric /* need to clear old information */ 8654967Seric smtprset(m, mci, e); 8757734Seric /* fall through */ 8815139Seric 8954967Seric case MCIS_OPEN: 9054967Seric return; 9154967Seric 9254967Seric case MCIS_ERROR: 9354967Seric case MCIS_SSD: 9454967Seric /* shouldn't happen */ 9554967Seric smtpquit(m, mci, e); 9657734Seric /* fall through */ 9754967Seric 9854967Seric case MCIS_CLOSED: 9958151Seric syserr("451 smtpinit: state CLOSED"); 10054967Seric return; 10154967Seric 10254967Seric case MCIS_OPENING: 10354967Seric break; 1046051Seric } 1054796Seric 10654967Seric mci->mci_state = MCIS_OPENING; 10754967Seric 1084865Seric /* 1094865Seric ** Get the greeting message. 11014913Seric ** This should appear spontaneously. Give it five minutes to 11114886Seric ** happen. 1124865Seric */ 1134797Seric 11457379Seric SmtpPhase = mci->mci_phase = "greeting wait"; 11553751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 116*60210Seric r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); 1178005Seric if (r < 0 || REPLYTYPE(r) != 2) 11852104Seric goto tempfail1; 1194684Seric 1204865Seric /* 1214976Seric ** Send the HELO command. 1227963Seric ** My mother taught me to always introduce myself. 1234976Seric */ 1244976Seric 12559285Seric if (bitnset(M_ESMTP, m->m_flags)) 12659285Seric mci->mci_flags |= MCIF_ESMTP; 12759285Seric 12859285Seric tryhelo: 12959285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 13059285Seric { 13159285Seric smtpmessage("EHLO %s", m, mci, MyHostName); 13259285Seric SmtpPhase = mci->mci_phase = "EHLO wait"; 13359285Seric } 13459285Seric else 13559285Seric { 13659285Seric smtpmessage("HELO %s", m, mci, MyHostName); 13759285Seric SmtpPhase = mci->mci_phase = "HELO wait"; 13859285Seric } 13953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 14059285Seric r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 1418005Seric if (r < 0) 14252104Seric goto tempfail1; 1438005Seric else if (REPLYTYPE(r) == 5) 14459285Seric { 14559285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 14659285Seric { 14759285Seric /* try old SMTP instead */ 14859285Seric mci->mci_flags &= ~MCIF_ESMTP; 14959285Seric goto tryhelo; 15059285Seric } 15114913Seric goto unavailable; 15259285Seric } 1537963Seric else if (REPLYTYPE(r) != 2) 15452104Seric goto tempfail1; 1554976Seric 1564976Seric /* 15758957Seric ** Check to see if we actually ended up talking to ourself. 15858957Seric ** This means we didn't know about an alias or MX, or we managed 15958957Seric ** to connect to an echo server. 16058957Seric */ 16158957Seric 16259026Seric p = strchr(&SmtpReplyBuffer[4], ' '); 16358957Seric if (p != NULL) 16458957Seric *p == '\0'; 16559026Seric if (strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 16658957Seric { 16758957Seric syserr("553 %s config error: mail loops back to myself", 16858957Seric MyHostName); 16958957Seric mci->mci_exitstat = EX_CONFIG; 17058957Seric mci->mci_errno = 0; 17158957Seric smtpquit(m, mci, e); 17258957Seric return; 17358957Seric } 17458957Seric 17558957Seric /* 1769315Seric ** If this is expected to be another sendmail, send some internal 1779315Seric ** commands. 1789315Seric */ 1799315Seric 18010688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1819315Seric { 1829315Seric /* tell it to be verbose */ 18353751Seric smtpmessage("VERB", m, mci); 18459285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 1859315Seric if (r < 0) 18652104Seric goto tempfail2; 1879315Seric } 1889315Seric 18953751Seric mci->mci_state = MCIS_OPEN; 19054967Seric return; 19153751Seric 19253751Seric tempfail1: 19353751Seric tempfail2: 19453751Seric mci->mci_exitstat = EX_TEMPFAIL; 19557379Seric if (mci->mci_errno == 0) 19657379Seric mci->mci_errno = errno; 19757379Seric if (mci->mci_state != MCIS_CLOSED) 19857379Seric smtpquit(m, mci, e); 19954967Seric return; 20053751Seric 20153751Seric unavailable: 20253751Seric mci->mci_exitstat = EX_UNAVAILABLE; 20353751Seric mci->mci_errno = errno; 20453751Seric smtpquit(m, mci, e); 20554967Seric return; 20653751Seric } 20759285Seric /* 208*60210Seric ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 209*60210Seric ** 210*60210Seric ** 211*60210Seric ** Parameters: 212*60210Seric ** line -- the response line. 213*60210Seric ** m -- the mailer. 214*60210Seric ** mci -- the mailer connection info. 215*60210Seric ** e -- the envelope. 216*60210Seric ** 217*60210Seric ** Returns: 218*60210Seric ** none. 219*60210Seric */ 220*60210Seric 221*60210Seric void 222*60210Seric esmtp_check(line, m, mci, e) 223*60210Seric char *line; 224*60210Seric MAILER *m; 225*60210Seric register MCI *mci; 226*60210Seric ENVELOPE *e; 227*60210Seric { 228*60210Seric if (strlen(line) < 5) 229*60210Seric return; 230*60210Seric line += 4; 231*60210Seric if (strncmp(line, "ESMTP ", 6) == 0) 232*60210Seric mci->mci_flags |= MCIF_ESMTP; 233*60210Seric } 234*60210Seric /* 23559285Seric ** HELO_OPTIONS -- process the options on a HELO line. 23659285Seric ** 23759285Seric ** Parameters: 23859285Seric ** line -- the response line. 23959285Seric ** m -- the mailer. 24059285Seric ** mci -- the mailer connection info. 24159285Seric ** e -- the envelope. 24259285Seric ** 24359285Seric ** Returns: 24459285Seric ** none. 24559285Seric */ 24653751Seric 24759285Seric void 24859285Seric helo_options(line, m, mci, e) 24959285Seric char *line; 25059285Seric MAILER *m; 25159285Seric register MCI *mci; 25259285Seric ENVELOPE *e; 25359285Seric { 25459285Seric register char *p; 25559285Seric 25659285Seric if (strlen(line) < 5) 25759285Seric return; 25859285Seric line += 4; 25959285Seric p = strchr(line, ' '); 26059285Seric if (p != NULL) 26159285Seric *p++ = '\0'; 26259285Seric if (strcasecmp(line, "size") == 0) 26359285Seric { 26459285Seric mci->mci_flags |= MCIF_SIZE; 26559285Seric if (p != NULL) 26659285Seric mci->mci_maxsize = atol(p); 26759285Seric } 26859285Seric else if (strcasecmp(line, "8bitmime") == 0) 26959285Seric mci->mci_flags |= MCIF_8BITMIME; 27059285Seric else if (strcasecmp(line, "expn") == 0) 27159285Seric mci->mci_flags |= MCIF_EXPN; 27259285Seric } 27359285Seric /* 27459285Seric ** SMTPMAILFROM -- send MAIL command 27559285Seric ** 27659285Seric ** Parameters: 27759285Seric ** m -- the mailer. 27859285Seric ** mci -- the mailer connection structure. 27959285Seric ** e -- the envelope (including the sender to specify). 28059285Seric */ 28159285Seric 28253751Seric smtpmailfrom(m, mci, e) 28353751Seric struct mailer *m; 28454967Seric MCI *mci; 28553751Seric ENVELOPE *e; 28653751Seric { 28753751Seric int r; 28853751Seric char buf[MAXNAME]; 28959285Seric char optbuf[MAXLINE]; 29053751Seric 29157943Seric if (tTd(17, 2)) 29257943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 29357943Seric 29459285Seric /* set up appropriate options to include */ 29559285Seric if (bitset(MCIF_SIZE, mci->mci_flags)) 29659285Seric sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 29759285Seric else 29859285Seric strcpy(optbuf, ""); 29959285Seric 3009315Seric /* 3014865Seric ** Send the MAIL command. 3024865Seric ** Designates the sender. 3034865Seric */ 3044796Seric 30553751Seric mci->mci_state = MCIS_ACTIVE; 30653751Seric 30759540Seric if (bitset(EF_RESPONSE, e->e_flags) && 30859540Seric !bitnset(M_NO_NULL_FROM, m->m_flags)) 30958680Seric (void) strcpy(buf, ""); 31058680Seric else 31158680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 31253751Seric if (e->e_from.q_mailer == LocalMailer || 31310688Seric !bitnset(M_FROMPATH, m->m_flags)) 3148436Seric { 31559285Seric smtpmessage("MAIL From:<%s>%s", m, mci, buf, optbuf); 3168436Seric } 3178436Seric else 3188436Seric { 31959285Seric smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 32059285Seric buf[0] == '@' ? ',' : ':', buf, optbuf); 3218436Seric } 32257379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 32353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 32459285Seric r = reply(m, mci, e, TimeOuts.to_mail, NULL); 3258005Seric if (r < 0 || REPLYTYPE(r) == 4) 32653751Seric { 32753751Seric mci->mci_exitstat = EX_TEMPFAIL; 32853751Seric mci->mci_errno = errno; 32953751Seric smtpquit(m, mci, e); 33053751Seric return EX_TEMPFAIL; 33153751Seric } 3327963Seric else if (r == 250) 33353751Seric { 33453751Seric mci->mci_exitstat = EX_OK; 33553751Seric return EX_OK; 33653751Seric } 3377963Seric else if (r == 552) 33853751Seric { 33953751Seric /* signal service unavailable */ 34053751Seric mci->mci_exitstat = EX_UNAVAILABLE; 34153751Seric smtpquit(m, mci, e); 34253751Seric return EX_UNAVAILABLE; 34353751Seric } 34414913Seric 34558008Seric #ifdef LOG 34658020Seric if (LogLevel > 1) 34758008Seric { 34858008Seric syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 34958008Seric e->e_id, SmtpReplyBuffer); 35058008Seric } 35158008Seric #endif 35258008Seric 35314913Seric /* protocol error -- close up */ 35453751Seric smtpquit(m, mci, e); 35553751Seric mci->mci_exitstat = EX_PROTOCOL; 35653751Seric return EX_PROTOCOL; 3574684Seric } 3584684Seric /* 3594976Seric ** SMTPRCPT -- designate recipient. 3604797Seric ** 3614797Seric ** Parameters: 3624865Seric ** to -- address of recipient. 36310175Seric ** m -- the mailer we are sending to. 36457379Seric ** mci -- the connection info for this transaction. 36557379Seric ** e -- the envelope for this transaction. 3664797Seric ** 3674797Seric ** Returns: 3684865Seric ** exit status corresponding to recipient status. 3694797Seric ** 3704797Seric ** Side Effects: 3714865Seric ** Sends the mail via SMTP. 3724797Seric */ 3734797Seric 37453751Seric smtprcpt(to, m, mci, e) 3754865Seric ADDRESS *to; 37610175Seric register MAILER *m; 37754967Seric MCI *mci; 37853751Seric ENVELOPE *e; 3794797Seric { 3804797Seric register int r; 3814797Seric 38253751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 3834865Seric 38457379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 38553751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 38659285Seric r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 3878005Seric if (r < 0 || REPLYTYPE(r) == 4) 3884865Seric return (EX_TEMPFAIL); 3897963Seric else if (REPLYTYPE(r) == 2) 3907963Seric return (EX_OK); 3917964Seric else if (r == 550 || r == 551 || r == 553) 3927964Seric return (EX_NOUSER); 3937964Seric else if (r == 552 || r == 554) 3947964Seric return (EX_UNAVAILABLE); 39558008Seric 39658008Seric #ifdef LOG 39758020Seric if (LogLevel > 1) 39858008Seric { 39958008Seric syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 40058008Seric e->e_id, SmtpReplyBuffer); 40158008Seric } 40258008Seric #endif 40358008Seric 4047964Seric return (EX_PROTOCOL); 4054797Seric } 4064797Seric /* 40710175Seric ** SMTPDATA -- send the data and clean up the transaction. 4084684Seric ** 4094684Seric ** Parameters: 4104865Seric ** m -- mailer being sent to. 4116980Seric ** e -- the envelope for this message. 4124684Seric ** 4134684Seric ** Returns: 4144976Seric ** exit status corresponding to DATA command. 4154684Seric ** 4164684Seric ** Side Effects: 4174865Seric ** none. 4184684Seric */ 4194684Seric 42053740Seric smtpdata(m, mci, e) 4214865Seric struct mailer *m; 42254967Seric register MCI *mci; 4236980Seric register ENVELOPE *e; 4244684Seric { 4254684Seric register int r; 4264684Seric 4274797Seric /* 4284797Seric ** Send the data. 42910175Seric ** First send the command and check that it is ok. 43010175Seric ** Then send the data. 43110175Seric ** Follow it up with a dot to terminate. 43210175Seric ** Finally get the results of the transaction. 4334797Seric */ 4344797Seric 43510175Seric /* send the command and check ok to proceed */ 43653751Seric smtpmessage("DATA", m, mci); 43757379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 43853751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 43959285Seric r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 4408005Seric if (r < 0 || REPLYTYPE(r) == 4) 44157990Seric { 44257990Seric smtpquit(m, mci, e); 4434797Seric return (EX_TEMPFAIL); 44457990Seric } 4457963Seric else if (r == 554) 44657990Seric { 44757990Seric smtprset(m, mci, e); 4487963Seric return (EX_UNAVAILABLE); 44957990Seric } 4507963Seric else if (r != 354) 45157990Seric { 45258008Seric #ifdef LOG 45358020Seric if (LogLevel > 1) 45458008Seric { 45558008Seric syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 45658008Seric e->e_id, SmtpReplyBuffer); 45758008Seric } 45858008Seric #endif 45957990Seric smtprset(m, mci, e); 4607964Seric return (EX_PROTOCOL); 46157990Seric } 46210175Seric 46310175Seric /* now output the actual message */ 46453751Seric (*e->e_puthdr)(mci->mci_out, m, e); 46553740Seric putline("\n", mci->mci_out, m); 46659730Seric (*e->e_putbody)(mci->mci_out, m, e, NULL); 46710175Seric 46810175Seric /* terminate the message */ 46953740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 47058120Seric if (Verbose) 47158151Seric nmessage(">>> ."); 47210175Seric 47310175Seric /* check for the results of the transaction */ 47457379Seric SmtpPhase = mci->mci_phase = "result wait"; 47553751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 47659285Seric r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 47753751Seric if (r < 0) 47857990Seric { 47957990Seric smtpquit(m, mci, e); 4804797Seric return (EX_TEMPFAIL); 48157990Seric } 48253751Seric mci->mci_state = MCIS_OPEN; 48358917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 48453751Seric if (REPLYTYPE(r) == 4) 48553751Seric return (EX_TEMPFAIL); 4867963Seric else if (r == 250) 4877963Seric return (EX_OK); 4887963Seric else if (r == 552 || r == 554) 4897963Seric return (EX_UNAVAILABLE); 49058008Seric #ifdef LOG 49158020Seric if (LogLevel > 1) 49258008Seric { 49358008Seric syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 49458008Seric e->e_id, SmtpReplyBuffer); 49558008Seric } 49658008Seric #endif 4977964Seric return (EX_PROTOCOL); 4984684Seric } 4994684Seric /* 5004865Seric ** SMTPQUIT -- close the SMTP connection. 5014865Seric ** 5024865Seric ** Parameters: 50315535Seric ** m -- a pointer to the mailer. 5044865Seric ** 5054865Seric ** Returns: 5064865Seric ** none. 5074865Seric ** 5084865Seric ** Side Effects: 5094865Seric ** sends the final protocol and closes the connection. 5104865Seric */ 5114865Seric 51253751Seric smtpquit(m, mci, e) 51353751Seric register MAILER *m; 51454967Seric register MCI *mci; 51553751Seric ENVELOPE *e; 5164865Seric { 5179391Seric int i; 5184865Seric 51954967Seric /* send the quit message if we haven't gotten I/O error */ 52053751Seric if (mci->mci_state != MCIS_ERROR) 5219391Seric { 52253751Seric smtpmessage("QUIT", m, mci); 52359285Seric (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 52453740Seric if (mci->mci_state == MCIS_CLOSED) 52510159Seric return; 5269391Seric } 5279391Seric 52852676Seric /* now actually close the connection and pick up the zombie */ 52958846Seric i = endmailer(mci, e, m->m_argv); 5309391Seric if (i != EX_OK) 53158151Seric syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 5324865Seric } 5334865Seric /* 53454967Seric ** SMTPRSET -- send a RSET (reset) command 53554967Seric */ 53654967Seric 53754967Seric smtprset(m, mci, e) 53854967Seric register MAILER *m; 53954967Seric register MCI *mci; 54054967Seric ENVELOPE *e; 54154967Seric { 54254967Seric int r; 54354967Seric 54454967Seric smtpmessage("RSET", m, mci); 54559285Seric r = reply(m, mci, e, TimeOuts.to_rset, NULL); 54657734Seric if (r < 0) 54757734Seric mci->mci_state = MCIS_ERROR; 54854967Seric else if (REPLYTYPE(r) == 2) 54957734Seric { 55057734Seric mci->mci_state = MCIS_OPEN; 55157734Seric return; 55257734Seric } 55357734Seric smtpquit(m, mci, e); 55454967Seric } 55554967Seric /* 55658867Seric ** SMTPPROBE -- check the connection state 55754967Seric */ 55854967Seric 55958867Seric smtpprobe(mci) 56054967Seric register MCI *mci; 56154967Seric { 56254967Seric int r; 56354967Seric MAILER *m = mci->mci_mailer; 56454967Seric extern ENVELOPE BlankEnvelope; 56554967Seric ENVELOPE *e = &BlankEnvelope; 56654967Seric 56758867Seric smtpmessage("RSET", m, mci); 56859285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 56958061Seric if (r < 0 || REPLYTYPE(r) != 2) 57054967Seric smtpquit(m, mci, e); 57154967Seric return r; 57254967Seric } 57354967Seric /* 5744684Seric ** REPLY -- read arpanet reply 5754684Seric ** 5764684Seric ** Parameters: 57710175Seric ** m -- the mailer we are reading the reply from. 57857379Seric ** mci -- the mailer connection info structure. 57957379Seric ** e -- the current envelope. 58057379Seric ** timeout -- the timeout for reads. 58159285Seric ** pfunc -- processing function for second and subsequent 58259285Seric ** lines of response -- if null, no special 58359285Seric ** processing is done. 5844684Seric ** 5854684Seric ** Returns: 5864684Seric ** reply code it reads. 5874684Seric ** 5884684Seric ** Side Effects: 5894684Seric ** flushes the mail file. 5904684Seric */ 5914684Seric 59259285Seric reply(m, mci, e, timeout, pfunc) 59353751Seric MAILER *m; 59454967Seric MCI *mci; 59553751Seric ENVELOPE *e; 59659285Seric time_t timeout; 59759285Seric void (*pfunc)(); 5984684Seric { 59959014Seric register char *bufp; 60059014Seric register int r; 60159285Seric bool firstline = TRUE; 60258957Seric char junkbuf[MAXLINE]; 60358957Seric 60457379Seric if (mci->mci_out != NULL) 60557379Seric (void) fflush(mci->mci_out); 6064684Seric 6077677Seric if (tTd(18, 1)) 6084796Seric printf("reply\n"); 6094796Seric 6107356Seric /* 6117356Seric ** Read the input line, being careful not to hang. 6127356Seric */ 6137356Seric 61459014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 6154684Seric { 6167356Seric register char *p; 61753751Seric extern time_t curtime(); 6184684Seric 6197685Seric /* actually do the read */ 62053751Seric if (e->e_xfp != NULL) 62153751Seric (void) fflush(e->e_xfp); /* for debugging */ 6227356Seric 62310054Seric /* if we are in the process of closing just give the code */ 62453740Seric if (mci->mci_state == MCIS_CLOSED) 62510054Seric return (SMTPCLOSING); 62610054Seric 62758680Seric if (mci->mci_out != NULL) 62858680Seric fflush(mci->mci_out); 62958680Seric 63010054Seric /* get the line from the other side */ 63158957Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout); 63253751Seric mci->mci_lastuse = curtime(); 63353751Seric 63410054Seric if (p == NULL) 63510131Seric { 63610148Seric extern char MsgBuf[]; /* err.c */ 63710148Seric 63821065Seric /* if the remote end closed early, fake an error */ 63921065Seric if (errno == 0) 64021065Seric # ifdef ECONNRESET 64121065Seric errno = ECONNRESET; 64256795Seric # else /* ECONNRESET */ 64321065Seric errno = EPIPE; 64456795Seric # endif /* ECONNRESET */ 64521065Seric 64657379Seric mci->mci_errno = errno; 64757642Seric mci->mci_exitstat = EX_TEMPFAIL; 64858151Seric message("451 %s: reply: read error from %s", 64957642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 65057203Seric mci->mci_host); 65110420Seric /* if debugging, pause so we can see state */ 65210420Seric if (tTd(18, 100)) 65310420Seric pause(); 65410148Seric # ifdef LOG 65558020Seric if (LogLevel > 1) 65657203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 65756795Seric # endif /* LOG */ 65854967Seric mci->mci_state = MCIS_ERROR; 65953751Seric smtpquit(m, mci, e); 66010054Seric return (-1); 66110131Seric } 66258957Seric fixcrlf(bufp, TRUE); 66310054Seric 66459014Seric if (e->e_xfp != NULL && strchr("45", bufp[0]) != NULL) 66514900Seric { 66614900Seric /* serious error -- log the previous command */ 66759014Seric if (SmtpMsgBuffer[0] != '\0') 66859014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 66959014Seric SmtpMsgBuffer[0] = '\0'; 67014900Seric 67114900Seric /* now log the message as from the other side */ 67258957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 67314900Seric } 67414900Seric 67514900Seric /* display the input for verbose mode */ 67658120Seric if (Verbose) 67759956Seric nmessage("050 %s", bufp); 6787356Seric 67959285Seric /* process the line */ 68059285Seric if (pfunc != NULL && !firstline) 68159285Seric (*pfunc)(bufp, m, mci, e); 68259285Seric 68359285Seric firstline = FALSE; 68459285Seric 6857356Seric /* if continuation is required, we can go on */ 68659014Seric if (bufp[3] == '-') 6874684Seric continue; 6887356Seric 68959014Seric /* ignore improperly formated input */ 69059014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 69159014Seric continue; 69259014Seric 6937356Seric /* decode the reply code */ 69459014Seric r = atoi(bufp); 6957356Seric 6967356Seric /* extra semantics: 0xx codes are "informational" */ 69759014Seric if (r >= 100) 69859014Seric break; 69959014Seric } 7007356Seric 70159014Seric /* 70259014Seric ** Now look at SmtpReplyBuffer -- only care about the first 70359014Seric ** line of the response from here on out. 70459014Seric */ 70558061Seric 70659014Seric /* save temporary failure messages for posterity */ 70759014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 70859014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 7099391Seric 71059014Seric /* reply code 421 is "Service Shutting Down" */ 71159014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 71259014Seric { 71359014Seric /* send the quit protocol */ 71459014Seric mci->mci_state = MCIS_SSD; 71559014Seric smtpquit(m, mci, e); 7164684Seric } 71759014Seric 71859014Seric return (r); 7194684Seric } 7204796Seric /* 7214865Seric ** SMTPMESSAGE -- send message to server 7224796Seric ** 7234796Seric ** Parameters: 7244796Seric ** f -- format 72510175Seric ** m -- the mailer to control formatting. 7264796Seric ** a, b, c -- parameters 7274796Seric ** 7284796Seric ** Returns: 7294796Seric ** none. 7304796Seric ** 7314796Seric ** Side Effects: 73253740Seric ** writes message to mci->mci_out. 7334796Seric */ 7344796Seric 7354865Seric /*VARARGS1*/ 73657642Seric #ifdef __STDC__ 73757642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 73857642Seric #else 73957642Seric smtpmessage(f, m, mci, va_alist) 7404796Seric char *f; 74110175Seric MAILER *m; 74254967Seric MCI *mci; 74357642Seric va_dcl 74457642Seric #endif 7454796Seric { 74656852Seric VA_LOCAL_DECL 74756852Seric 74857135Seric VA_START(mci); 74956852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 75056852Seric VA_END; 75158680Seric 75258120Seric if (tTd(18, 1) || Verbose) 75358151Seric nmessage(">>> %s", SmtpMsgBuffer); 75453740Seric if (mci->mci_out != NULL) 75558680Seric { 75653740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 75754967Seric m == NULL ? "\r\n" : m->m_eol); 75858680Seric } 75959149Seric else if (tTd(18, 1)) 76058725Seric { 76159149Seric printf("smtpmessage: NULL mci_out\n"); 76258725Seric } 7634796Seric } 7645182Seric 76556795Seric # endif /* SMTP */ 766