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*59149Seric static char sccsid[] = "@(#)usersmtp.c 6.26 (Berkeley) 04/18/93 (with SMTP)"; 1433731Sbostic #else 15*59149Seric static char sccsid[] = "@(#)usersmtp.c 6.26 (Berkeley) 04/18/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(); 674684Seric 6857379Seric if (tTd(17, 1)) 6957379Seric { 7057379Seric printf("smtpinit "); 7157379Seric mci_dump(mci); 7257379Seric } 7357379Seric 744865Seric /* 754865Seric ** Open the connection to the mailer. 764865Seric */ 774684Seric 7821065Seric SmtpError[0] = '\0'; 7957379Seric CurHostName = mci->mci_host; /* XXX UGLY XXX */ 8054967Seric switch (mci->mci_state) 816051Seric { 8254967Seric case MCIS_ACTIVE: 8354967Seric /* need to clear old information */ 8454967Seric smtprset(m, mci, e); 8557734Seric /* fall through */ 8615139Seric 8754967Seric case MCIS_OPEN: 8854967Seric return; 8954967Seric 9054967Seric case MCIS_ERROR: 9154967Seric case MCIS_SSD: 9254967Seric /* shouldn't happen */ 9354967Seric smtpquit(m, mci, e); 9457734Seric /* fall through */ 9554967Seric 9654967Seric case MCIS_CLOSED: 9758151Seric syserr("451 smtpinit: state CLOSED"); 9854967Seric return; 9954967Seric 10054967Seric case MCIS_OPENING: 10154967Seric break; 1026051Seric } 1034796Seric 10454967Seric mci->mci_state = MCIS_OPENING; 10554967Seric 1064865Seric /* 1074865Seric ** Get the greeting message. 10814913Seric ** This should appear spontaneously. Give it five minutes to 10914886Seric ** happen. 1104865Seric */ 1114797Seric 11257379Seric SmtpPhase = mci->mci_phase = "greeting wait"; 11353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 11458112Seric r = reply(m, mci, e, TimeOuts.to_initial); 1158005Seric if (r < 0 || REPLYTYPE(r) != 2) 11652104Seric goto tempfail1; 1174684Seric 1184865Seric /* 1194976Seric ** Send the HELO command. 1207963Seric ** My mother taught me to always introduce myself. 1214976Seric */ 1224976Seric 12353751Seric smtpmessage("HELO %s", m, mci, MyHostName); 12457379Seric SmtpPhase = mci->mci_phase = "HELO wait"; 12553751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 12658112Seric r = reply(m, mci, e, TimeOuts.to_helo); 1278005Seric if (r < 0) 12852104Seric goto tempfail1; 1298005Seric else if (REPLYTYPE(r) == 5) 13014913Seric goto unavailable; 1317963Seric else if (REPLYTYPE(r) != 2) 13252104Seric goto tempfail1; 1334976Seric 1344976Seric /* 13558957Seric ** Check to see if we actually ended up talking to ourself. 13658957Seric ** This means we didn't know about an alias or MX, or we managed 13758957Seric ** to connect to an echo server. 13858957Seric */ 13958957Seric 14059026Seric p = strchr(&SmtpReplyBuffer[4], ' '); 14158957Seric if (p != NULL) 14258957Seric *p == '\0'; 14359026Seric if (strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 14458957Seric { 14558957Seric syserr("553 %s config error: mail loops back to myself", 14658957Seric MyHostName); 14758957Seric mci->mci_exitstat = EX_CONFIG; 14858957Seric mci->mci_errno = 0; 14958957Seric smtpquit(m, mci, e); 15058957Seric return; 15158957Seric } 15258957Seric 15358957Seric /* 1549315Seric ** If this is expected to be another sendmail, send some internal 1559315Seric ** commands. 1569315Seric */ 1579315Seric 15810688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1599315Seric { 1609315Seric /* tell it to be verbose */ 16153751Seric smtpmessage("VERB", m, mci); 16258112Seric r = reply(m, mci, e, TimeOuts.to_miscshort); 1639315Seric if (r < 0) 16452104Seric goto tempfail2; 1659315Seric } 1669315Seric 16753751Seric mci->mci_state = MCIS_OPEN; 16854967Seric return; 16953751Seric 17053751Seric tempfail1: 17153751Seric tempfail2: 17253751Seric mci->mci_exitstat = EX_TEMPFAIL; 17357379Seric if (mci->mci_errno == 0) 17457379Seric mci->mci_errno = errno; 17557379Seric if (mci->mci_state != MCIS_CLOSED) 17657379Seric smtpquit(m, mci, e); 17754967Seric return; 17853751Seric 17953751Seric unavailable: 18053751Seric mci->mci_exitstat = EX_UNAVAILABLE; 18153751Seric mci->mci_errno = errno; 18253751Seric smtpquit(m, mci, e); 18354967Seric return; 18453751Seric } 18553751Seric 18653751Seric smtpmailfrom(m, mci, e) 18753751Seric struct mailer *m; 18854967Seric MCI *mci; 18953751Seric ENVELOPE *e; 19053751Seric { 19153751Seric int r; 19253751Seric char buf[MAXNAME]; 19353751Seric 19457943Seric if (tTd(17, 2)) 19557943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 19657943Seric 1979315Seric /* 1984865Seric ** Send the MAIL command. 1994865Seric ** Designates the sender. 2004865Seric */ 2014796Seric 20253751Seric mci->mci_state = MCIS_ACTIVE; 20353751Seric 20458680Seric if (bitset(EF_RESPONSE, e->e_flags)) 20558680Seric (void) strcpy(buf, ""); 20658680Seric else 20758680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 20853751Seric if (e->e_from.q_mailer == LocalMailer || 20910688Seric !bitnset(M_FROMPATH, m->m_flags)) 2108436Seric { 21153751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 2128436Seric } 2138436Seric else 2148436Seric { 21553751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 21610308Seric buf[0] == '@' ? ',' : ':', buf); 2178436Seric } 21857379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 21953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 22058112Seric r = reply(m, mci, e, TimeOuts.to_mail); 2218005Seric if (r < 0 || REPLYTYPE(r) == 4) 22253751Seric { 22353751Seric mci->mci_exitstat = EX_TEMPFAIL; 22453751Seric mci->mci_errno = errno; 22553751Seric smtpquit(m, mci, e); 22653751Seric return EX_TEMPFAIL; 22753751Seric } 2287963Seric else if (r == 250) 22953751Seric { 23053751Seric mci->mci_exitstat = EX_OK; 23153751Seric return EX_OK; 23253751Seric } 2337963Seric else if (r == 552) 23453751Seric { 23553751Seric /* signal service unavailable */ 23653751Seric mci->mci_exitstat = EX_UNAVAILABLE; 23753751Seric smtpquit(m, mci, e); 23853751Seric return EX_UNAVAILABLE; 23953751Seric } 24014913Seric 24158008Seric #ifdef LOG 24258020Seric if (LogLevel > 1) 24358008Seric { 24458008Seric syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 24558008Seric e->e_id, SmtpReplyBuffer); 24658008Seric } 24758008Seric #endif 24858008Seric 24914913Seric /* protocol error -- close up */ 25053751Seric smtpquit(m, mci, e); 25153751Seric mci->mci_exitstat = EX_PROTOCOL; 25253751Seric return EX_PROTOCOL; 2534684Seric } 2544684Seric /* 2554976Seric ** SMTPRCPT -- designate recipient. 2564797Seric ** 2574797Seric ** Parameters: 2584865Seric ** to -- address of recipient. 25910175Seric ** m -- the mailer we are sending to. 26057379Seric ** mci -- the connection info for this transaction. 26157379Seric ** e -- the envelope for this transaction. 2624797Seric ** 2634797Seric ** Returns: 2644865Seric ** exit status corresponding to recipient status. 2654797Seric ** 2664797Seric ** Side Effects: 2674865Seric ** Sends the mail via SMTP. 2684797Seric */ 2694797Seric 27053751Seric smtprcpt(to, m, mci, e) 2714865Seric ADDRESS *to; 27210175Seric register MAILER *m; 27354967Seric MCI *mci; 27453751Seric ENVELOPE *e; 2754797Seric { 2764797Seric register int r; 2774797Seric 27853751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2794865Seric 28057379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 28153751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 28258112Seric r = reply(m, mci, e, TimeOuts.to_rcpt); 2838005Seric if (r < 0 || REPLYTYPE(r) == 4) 2844865Seric return (EX_TEMPFAIL); 2857963Seric else if (REPLYTYPE(r) == 2) 2867963Seric return (EX_OK); 2877964Seric else if (r == 550 || r == 551 || r == 553) 2887964Seric return (EX_NOUSER); 2897964Seric else if (r == 552 || r == 554) 2907964Seric return (EX_UNAVAILABLE); 29158008Seric 29258008Seric #ifdef LOG 29358020Seric if (LogLevel > 1) 29458008Seric { 29558008Seric syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 29658008Seric e->e_id, SmtpReplyBuffer); 29758008Seric } 29858008Seric #endif 29958008Seric 3007964Seric return (EX_PROTOCOL); 3014797Seric } 3024797Seric /* 30310175Seric ** SMTPDATA -- send the data and clean up the transaction. 3044684Seric ** 3054684Seric ** Parameters: 3064865Seric ** m -- mailer being sent to. 3076980Seric ** e -- the envelope for this message. 3084684Seric ** 3094684Seric ** Returns: 3104976Seric ** exit status corresponding to DATA command. 3114684Seric ** 3124684Seric ** Side Effects: 3134865Seric ** none. 3144684Seric */ 3154684Seric 31653740Seric smtpdata(m, mci, e) 3174865Seric struct mailer *m; 31854967Seric register MCI *mci; 3196980Seric register ENVELOPE *e; 3204684Seric { 3214684Seric register int r; 3224684Seric 3234797Seric /* 3244797Seric ** Send the data. 32510175Seric ** First send the command and check that it is ok. 32610175Seric ** Then send the data. 32710175Seric ** Follow it up with a dot to terminate. 32810175Seric ** Finally get the results of the transaction. 3294797Seric */ 3304797Seric 33110175Seric /* send the command and check ok to proceed */ 33253751Seric smtpmessage("DATA", m, mci); 33357379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 33453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 33558112Seric r = reply(m, mci, e, TimeOuts.to_datainit); 3368005Seric if (r < 0 || REPLYTYPE(r) == 4) 33757990Seric { 33857990Seric smtpquit(m, mci, e); 3394797Seric return (EX_TEMPFAIL); 34057990Seric } 3417963Seric else if (r == 554) 34257990Seric { 34357990Seric smtprset(m, mci, e); 3447963Seric return (EX_UNAVAILABLE); 34557990Seric } 3467963Seric else if (r != 354) 34757990Seric { 34858008Seric #ifdef LOG 34958020Seric if (LogLevel > 1) 35058008Seric { 35158008Seric syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 35258008Seric e->e_id, SmtpReplyBuffer); 35358008Seric } 35458008Seric #endif 35557990Seric smtprset(m, mci, e); 3567964Seric return (EX_PROTOCOL); 35757990Seric } 35810175Seric 35910175Seric /* now output the actual message */ 36053751Seric (*e->e_puthdr)(mci->mci_out, m, e); 36153740Seric putline("\n", mci->mci_out, m); 36253751Seric (*e->e_putbody)(mci->mci_out, m, e); 36310175Seric 36410175Seric /* terminate the message */ 36553740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 36658120Seric if (Verbose) 36758151Seric nmessage(">>> ."); 36810175Seric 36910175Seric /* check for the results of the transaction */ 37057379Seric SmtpPhase = mci->mci_phase = "result wait"; 37153751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 37258112Seric r = reply(m, mci, e, TimeOuts.to_datafinal); 37353751Seric if (r < 0) 37457990Seric { 37557990Seric smtpquit(m, mci, e); 3764797Seric return (EX_TEMPFAIL); 37757990Seric } 37853751Seric mci->mci_state = MCIS_OPEN; 37958917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 38053751Seric if (REPLYTYPE(r) == 4) 38153751Seric return (EX_TEMPFAIL); 3827963Seric else if (r == 250) 3837963Seric return (EX_OK); 3847963Seric else if (r == 552 || r == 554) 3857963Seric return (EX_UNAVAILABLE); 38658008Seric #ifdef LOG 38758020Seric if (LogLevel > 1) 38858008Seric { 38958008Seric syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 39058008Seric e->e_id, SmtpReplyBuffer); 39158008Seric } 39258008Seric #endif 3937964Seric return (EX_PROTOCOL); 3944684Seric } 3954684Seric /* 3964865Seric ** SMTPQUIT -- close the SMTP connection. 3974865Seric ** 3984865Seric ** Parameters: 39915535Seric ** m -- a pointer to the mailer. 4004865Seric ** 4014865Seric ** Returns: 4024865Seric ** none. 4034865Seric ** 4044865Seric ** Side Effects: 4054865Seric ** sends the final protocol and closes the connection. 4064865Seric */ 4074865Seric 40853751Seric smtpquit(m, mci, e) 40953751Seric register MAILER *m; 41054967Seric register MCI *mci; 41153751Seric ENVELOPE *e; 4124865Seric { 4139391Seric int i; 4144865Seric 41554967Seric /* send the quit message if we haven't gotten I/O error */ 41653751Seric if (mci->mci_state != MCIS_ERROR) 4179391Seric { 41853751Seric smtpmessage("QUIT", m, mci); 41958112Seric (void) reply(m, mci, e, TimeOuts.to_quit); 42053740Seric if (mci->mci_state == MCIS_CLOSED) 42110159Seric return; 4229391Seric } 4239391Seric 42452676Seric /* now actually close the connection and pick up the zombie */ 42558846Seric i = endmailer(mci, e, m->m_argv); 4269391Seric if (i != EX_OK) 42758151Seric syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 4284865Seric } 4294865Seric /* 43054967Seric ** SMTPRSET -- send a RSET (reset) command 43154967Seric */ 43254967Seric 43354967Seric smtprset(m, mci, e) 43454967Seric register MAILER *m; 43554967Seric register MCI *mci; 43654967Seric ENVELOPE *e; 43754967Seric { 43854967Seric int r; 43954967Seric 44054967Seric smtpmessage("RSET", m, mci); 44158112Seric r = reply(m, mci, e, TimeOuts.to_rset); 44257734Seric if (r < 0) 44357734Seric mci->mci_state = MCIS_ERROR; 44454967Seric else if (REPLYTYPE(r) == 2) 44557734Seric { 44657734Seric mci->mci_state = MCIS_OPEN; 44757734Seric return; 44857734Seric } 44957734Seric smtpquit(m, mci, e); 45054967Seric } 45154967Seric /* 45258867Seric ** SMTPPROBE -- check the connection state 45354967Seric */ 45454967Seric 45558867Seric smtpprobe(mci) 45654967Seric register MCI *mci; 45754967Seric { 45854967Seric int r; 45954967Seric MAILER *m = mci->mci_mailer; 46054967Seric extern ENVELOPE BlankEnvelope; 46154967Seric ENVELOPE *e = &BlankEnvelope; 46254967Seric 46358867Seric smtpmessage("RSET", m, mci); 46458112Seric r = reply(m, mci, e, TimeOuts.to_miscshort); 46558061Seric if (r < 0 || REPLYTYPE(r) != 2) 46654967Seric smtpquit(m, mci, e); 46754967Seric return r; 46854967Seric } 46954967Seric /* 4704684Seric ** REPLY -- read arpanet reply 4714684Seric ** 4724684Seric ** Parameters: 47310175Seric ** m -- the mailer we are reading the reply from. 47457379Seric ** mci -- the mailer connection info structure. 47557379Seric ** e -- the current envelope. 47657379Seric ** timeout -- the timeout for reads. 4774684Seric ** 4784684Seric ** Returns: 4794684Seric ** reply code it reads. 4804684Seric ** 4814684Seric ** Side Effects: 4824684Seric ** flushes the mail file. 4834684Seric */ 4844684Seric 48557379Seric reply(m, mci, e, timeout) 48653751Seric MAILER *m; 48754967Seric MCI *mci; 48853751Seric ENVELOPE *e; 4894684Seric { 49059014Seric register char *bufp; 49159014Seric register int r; 49258957Seric char junkbuf[MAXLINE]; 49358957Seric 49457379Seric if (mci->mci_out != NULL) 49557379Seric (void) fflush(mci->mci_out); 4964684Seric 4977677Seric if (tTd(18, 1)) 4984796Seric printf("reply\n"); 4994796Seric 5007356Seric /* 5017356Seric ** Read the input line, being careful not to hang. 5027356Seric */ 5037356Seric 50459014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 5054684Seric { 5067356Seric register char *p; 50753751Seric extern time_t curtime(); 5084684Seric 5097685Seric /* actually do the read */ 51053751Seric if (e->e_xfp != NULL) 51153751Seric (void) fflush(e->e_xfp); /* for debugging */ 5127356Seric 51310054Seric /* if we are in the process of closing just give the code */ 51453740Seric if (mci->mci_state == MCIS_CLOSED) 51510054Seric return (SMTPCLOSING); 51610054Seric 51758680Seric if (mci->mci_out != NULL) 51858680Seric fflush(mci->mci_out); 51958680Seric 52010054Seric /* get the line from the other side */ 52158957Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout); 52253751Seric mci->mci_lastuse = curtime(); 52353751Seric 52410054Seric if (p == NULL) 52510131Seric { 52610148Seric extern char MsgBuf[]; /* err.c */ 52710148Seric 52821065Seric /* if the remote end closed early, fake an error */ 52921065Seric if (errno == 0) 53021065Seric # ifdef ECONNRESET 53121065Seric errno = ECONNRESET; 53256795Seric # else /* ECONNRESET */ 53321065Seric errno = EPIPE; 53456795Seric # endif /* ECONNRESET */ 53521065Seric 53657379Seric mci->mci_errno = errno; 53757642Seric mci->mci_exitstat = EX_TEMPFAIL; 53858151Seric message("451 %s: reply: read error from %s", 53957642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 54057203Seric mci->mci_host); 54110420Seric /* if debugging, pause so we can see state */ 54210420Seric if (tTd(18, 100)) 54310420Seric pause(); 54410148Seric # ifdef LOG 54558020Seric if (LogLevel > 1) 54657203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 54756795Seric # endif /* LOG */ 54854967Seric mci->mci_state = MCIS_ERROR; 54953751Seric smtpquit(m, mci, e); 55010054Seric return (-1); 55110131Seric } 55258957Seric fixcrlf(bufp, TRUE); 55310054Seric 55459014Seric if (e->e_xfp != NULL && strchr("45", bufp[0]) != NULL) 55514900Seric { 55614900Seric /* serious error -- log the previous command */ 55759014Seric if (SmtpMsgBuffer[0] != '\0') 55859014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 55959014Seric SmtpMsgBuffer[0] = '\0'; 56014900Seric 56114900Seric /* now log the message as from the other side */ 56258957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 56314900Seric } 56414900Seric 56514900Seric /* display the input for verbose mode */ 56658120Seric if (Verbose) 56758957Seric nmessage("%s", bufp); 5687356Seric 5697356Seric /* if continuation is required, we can go on */ 57059014Seric if (bufp[3] == '-') 5714684Seric continue; 5727356Seric 57359014Seric /* ignore improperly formated input */ 57459014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 57559014Seric continue; 57659014Seric 5777356Seric /* decode the reply code */ 57859014Seric r = atoi(bufp); 5797356Seric 5807356Seric /* extra semantics: 0xx codes are "informational" */ 58159014Seric if (r >= 100) 58259014Seric break; 58359014Seric } 5847356Seric 58559014Seric /* 58659014Seric ** Now look at SmtpReplyBuffer -- only care about the first 58759014Seric ** line of the response from here on out. 58859014Seric */ 58958061Seric 59059014Seric /* save temporary failure messages for posterity */ 59159014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 59259014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 5939391Seric 59459014Seric /* reply code 421 is "Service Shutting Down" */ 59559014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 59659014Seric { 59759014Seric /* send the quit protocol */ 59859014Seric mci->mci_state = MCIS_SSD; 59959014Seric smtpquit(m, mci, e); 6004684Seric } 60159014Seric 60259014Seric return (r); 6034684Seric } 6044796Seric /* 6054865Seric ** SMTPMESSAGE -- send message to server 6064796Seric ** 6074796Seric ** Parameters: 6084796Seric ** f -- format 60910175Seric ** m -- the mailer to control formatting. 6104796Seric ** a, b, c -- parameters 6114796Seric ** 6124796Seric ** Returns: 6134796Seric ** none. 6144796Seric ** 6154796Seric ** Side Effects: 61653740Seric ** writes message to mci->mci_out. 6174796Seric */ 6184796Seric 6194865Seric /*VARARGS1*/ 62057642Seric #ifdef __STDC__ 62157642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 62257642Seric #else 62357642Seric smtpmessage(f, m, mci, va_alist) 6244796Seric char *f; 62510175Seric MAILER *m; 62654967Seric MCI *mci; 62757642Seric va_dcl 62857642Seric #endif 6294796Seric { 63056852Seric VA_LOCAL_DECL 63156852Seric 63257135Seric VA_START(mci); 63356852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 63456852Seric VA_END; 63558680Seric 63658120Seric if (tTd(18, 1) || Verbose) 63758151Seric nmessage(">>> %s", SmtpMsgBuffer); 63853740Seric if (mci->mci_out != NULL) 63958680Seric { 64053740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 64154967Seric m == NULL ? "\r\n" : m->m_eol); 64258680Seric } 643*59149Seric else if (tTd(18, 1)) 64458725Seric { 645*59149Seric printf("smtpmessage: NULL mci_out\n"); 64658725Seric } 6474796Seric } 6485182Seric 64956795Seric # endif /* SMTP */ 650