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*58671Seric static char sccsid[] = "@(#)usersmtp.c 6.15 (Berkeley) 03/14/93 (with SMTP)"; 1433731Sbostic #else 15*58671Seric static char sccsid[] = "@(#)usersmtp.c 6.15 (Berkeley) 03/14/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 */ 38*58671Seric 39*58671Seric #ifdef __STDC__ 40*58671Seric extern smtpmessage(char *f, MAILER *m, MCI *mci, ...); 41*58671Seric #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; 6514886Seric EVENT *gte; 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 10457379Seric SmtpPhase = mci->mci_phase = "user open"; 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); 11558112Seric r = reply(m, mci, e, TimeOuts.to_initial); 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 12453751Seric smtpmessage("HELO %s", m, mci, MyHostName); 12557379Seric SmtpPhase = mci->mci_phase = "HELO wait"; 12653751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 12758112Seric r = reply(m, mci, e, TimeOuts.to_helo); 1288005Seric if (r < 0) 12952104Seric goto tempfail1; 1308005Seric else if (REPLYTYPE(r) == 5) 13114913Seric goto unavailable; 1327963Seric else if (REPLYTYPE(r) != 2) 13352104Seric goto tempfail1; 1344976Seric 1354976Seric /* 1369315Seric ** If this is expected to be another sendmail, send some internal 1379315Seric ** commands. 1389315Seric */ 1399315Seric 14010688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1419315Seric { 1429315Seric /* tell it to be verbose */ 14353751Seric smtpmessage("VERB", m, mci); 14458112Seric r = reply(m, mci, e, TimeOuts.to_miscshort); 1459315Seric if (r < 0) 14652104Seric goto tempfail2; 1479315Seric } 1489315Seric 14953751Seric mci->mci_state = MCIS_OPEN; 15054967Seric return; 15153751Seric 15253751Seric tempfail1: 15353751Seric tempfail2: 15453751Seric mci->mci_exitstat = EX_TEMPFAIL; 15557379Seric if (mci->mci_errno == 0) 15657379Seric mci->mci_errno = errno; 15757379Seric if (mci->mci_state != MCIS_CLOSED) 15857379Seric smtpquit(m, mci, e); 15954967Seric return; 16053751Seric 16153751Seric unavailable: 16253751Seric mci->mci_exitstat = EX_UNAVAILABLE; 16353751Seric mci->mci_errno = errno; 16453751Seric smtpquit(m, mci, e); 16554967Seric return; 16653751Seric } 16753751Seric 16853751Seric smtpmailfrom(m, mci, e) 16953751Seric struct mailer *m; 17054967Seric MCI *mci; 17153751Seric ENVELOPE *e; 17253751Seric { 17353751Seric int r; 17453751Seric char buf[MAXNAME]; 17553751Seric 17657943Seric if (tTd(17, 2)) 17757943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 17857943Seric 1799315Seric /* 1804865Seric ** Send the MAIL command. 1814865Seric ** Designates the sender. 1824865Seric */ 1834796Seric 18453751Seric mci->mci_state = MCIS_ACTIVE; 18553751Seric 18658050Seric expand("\201<", buf, &buf[sizeof buf - 1], e); 18753751Seric if (e->e_from.q_mailer == LocalMailer || 18810688Seric !bitnset(M_FROMPATH, m->m_flags)) 1898436Seric { 19053751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 1918436Seric } 1928436Seric else 1938436Seric { 19453751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 19510308Seric buf[0] == '@' ? ',' : ':', buf); 1968436Seric } 19757379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 19853751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 19958112Seric r = reply(m, mci, e, TimeOuts.to_mail); 2008005Seric if (r < 0 || REPLYTYPE(r) == 4) 20153751Seric { 20253751Seric mci->mci_exitstat = EX_TEMPFAIL; 20353751Seric mci->mci_errno = errno; 20453751Seric smtpquit(m, mci, e); 20553751Seric return EX_TEMPFAIL; 20653751Seric } 2077963Seric else if (r == 250) 20853751Seric { 20953751Seric mci->mci_exitstat = EX_OK; 21053751Seric return EX_OK; 21153751Seric } 2127963Seric else if (r == 552) 21353751Seric { 21453751Seric /* signal service unavailable */ 21553751Seric mci->mci_exitstat = EX_UNAVAILABLE; 21653751Seric smtpquit(m, mci, e); 21753751Seric return EX_UNAVAILABLE; 21853751Seric } 21914913Seric 22058008Seric #ifdef LOG 22158020Seric if (LogLevel > 1) 22258008Seric { 22358008Seric syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 22458008Seric e->e_id, SmtpReplyBuffer); 22558008Seric } 22658008Seric #endif 22758008Seric 22814913Seric /* protocol error -- close up */ 22953751Seric smtpquit(m, mci, e); 23053751Seric mci->mci_exitstat = EX_PROTOCOL; 23153751Seric return EX_PROTOCOL; 2324684Seric } 2334684Seric /* 2344976Seric ** SMTPRCPT -- designate recipient. 2354797Seric ** 2364797Seric ** Parameters: 2374865Seric ** to -- address of recipient. 23810175Seric ** m -- the mailer we are sending to. 23957379Seric ** mci -- the connection info for this transaction. 24057379Seric ** e -- the envelope for this transaction. 2414797Seric ** 2424797Seric ** Returns: 2434865Seric ** exit status corresponding to recipient status. 2444797Seric ** 2454797Seric ** Side Effects: 2464865Seric ** Sends the mail via SMTP. 2474797Seric */ 2484797Seric 24953751Seric smtprcpt(to, m, mci, e) 2504865Seric ADDRESS *to; 25110175Seric register MAILER *m; 25254967Seric MCI *mci; 25353751Seric ENVELOPE *e; 2544797Seric { 2554797Seric register int r; 2564797Seric 25753751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2584865Seric 25957379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 26053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 26158112Seric r = reply(m, mci, e, TimeOuts.to_rcpt); 2628005Seric if (r < 0 || REPLYTYPE(r) == 4) 2634865Seric return (EX_TEMPFAIL); 2647963Seric else if (REPLYTYPE(r) == 2) 2657963Seric return (EX_OK); 2667964Seric else if (r == 550 || r == 551 || r == 553) 2677964Seric return (EX_NOUSER); 2687964Seric else if (r == 552 || r == 554) 2697964Seric return (EX_UNAVAILABLE); 27058008Seric 27158008Seric #ifdef LOG 27258020Seric if (LogLevel > 1) 27358008Seric { 27458008Seric syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 27558008Seric e->e_id, SmtpReplyBuffer); 27658008Seric } 27758008Seric #endif 27858008Seric 2797964Seric return (EX_PROTOCOL); 2804797Seric } 2814797Seric /* 28210175Seric ** SMTPDATA -- send the data and clean up the transaction. 2834684Seric ** 2844684Seric ** Parameters: 2854865Seric ** m -- mailer being sent to. 2866980Seric ** e -- the envelope for this message. 2874684Seric ** 2884684Seric ** Returns: 2894976Seric ** exit status corresponding to DATA command. 2904684Seric ** 2914684Seric ** Side Effects: 2924865Seric ** none. 2934684Seric */ 2944684Seric 29553740Seric smtpdata(m, mci, e) 2964865Seric struct mailer *m; 29754967Seric register MCI *mci; 2986980Seric register ENVELOPE *e; 2994684Seric { 3004684Seric register int r; 3014684Seric 3024797Seric /* 3034797Seric ** Send the data. 30410175Seric ** First send the command and check that it is ok. 30510175Seric ** Then send the data. 30610175Seric ** Follow it up with a dot to terminate. 30710175Seric ** Finally get the results of the transaction. 3084797Seric */ 3094797Seric 31010175Seric /* send the command and check ok to proceed */ 31153751Seric smtpmessage("DATA", m, mci); 31257379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 31353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 31458112Seric r = reply(m, mci, e, TimeOuts.to_datainit); 3158005Seric if (r < 0 || REPLYTYPE(r) == 4) 31657990Seric { 31757990Seric smtpquit(m, mci, e); 3184797Seric return (EX_TEMPFAIL); 31957990Seric } 3207963Seric else if (r == 554) 32157990Seric { 32257990Seric smtprset(m, mci, e); 3237963Seric return (EX_UNAVAILABLE); 32457990Seric } 3257963Seric else if (r != 354) 32657990Seric { 32758008Seric #ifdef LOG 32858020Seric if (LogLevel > 1) 32958008Seric { 33058008Seric syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 33158008Seric e->e_id, SmtpReplyBuffer); 33258008Seric } 33358008Seric #endif 33457990Seric smtprset(m, mci, e); 3357964Seric return (EX_PROTOCOL); 33657990Seric } 33710175Seric 33810175Seric /* now output the actual message */ 33953751Seric (*e->e_puthdr)(mci->mci_out, m, e); 34053740Seric putline("\n", mci->mci_out, m); 34153751Seric (*e->e_putbody)(mci->mci_out, m, e); 34210175Seric 34310175Seric /* terminate the message */ 34453740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 34558120Seric if (Verbose) 34658151Seric nmessage(">>> ."); 34710175Seric 34810175Seric /* check for the results of the transaction */ 34957379Seric SmtpPhase = mci->mci_phase = "result wait"; 35053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 35158112Seric r = reply(m, mci, e, TimeOuts.to_datafinal); 35253751Seric if (r < 0) 35357990Seric { 35457990Seric smtpquit(m, mci, e); 3554797Seric return (EX_TEMPFAIL); 35657990Seric } 35753751Seric mci->mci_state = MCIS_OPEN; 35853751Seric if (REPLYTYPE(r) == 4) 35953751Seric return (EX_TEMPFAIL); 3607963Seric else if (r == 250) 3617963Seric return (EX_OK); 3627963Seric else if (r == 552 || r == 554) 3637963Seric return (EX_UNAVAILABLE); 36458008Seric #ifdef LOG 36558020Seric if (LogLevel > 1) 36658008Seric { 36758008Seric syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 36858008Seric e->e_id, SmtpReplyBuffer); 36958008Seric } 37058008Seric #endif 3717964Seric return (EX_PROTOCOL); 3724684Seric } 3734684Seric /* 3744865Seric ** SMTPQUIT -- close the SMTP connection. 3754865Seric ** 3764865Seric ** Parameters: 37715535Seric ** m -- a pointer to the mailer. 3784865Seric ** 3794865Seric ** Returns: 3804865Seric ** none. 3814865Seric ** 3824865Seric ** Side Effects: 3834865Seric ** sends the final protocol and closes the connection. 3844865Seric */ 3854865Seric 38653751Seric smtpquit(m, mci, e) 38753751Seric register MAILER *m; 38854967Seric register MCI *mci; 38953751Seric ENVELOPE *e; 3904865Seric { 3919391Seric int i; 3924865Seric 39354967Seric /* send the quit message if we haven't gotten I/O error */ 39453751Seric if (mci->mci_state != MCIS_ERROR) 3959391Seric { 39653751Seric smtpmessage("QUIT", m, mci); 39758112Seric (void) reply(m, mci, e, TimeOuts.to_quit); 39853740Seric if (mci->mci_state == MCIS_CLOSED) 39910159Seric return; 4009391Seric } 4019391Seric 40252676Seric /* now actually close the connection and pick up the zombie */ 40352676Seric i = endmailer(mci, m->m_argv[0]); 4049391Seric if (i != EX_OK) 40558151Seric syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 4064865Seric } 4074865Seric /* 40854967Seric ** SMTPRSET -- send a RSET (reset) command 40954967Seric */ 41054967Seric 41154967Seric smtprset(m, mci, e) 41254967Seric register MAILER *m; 41354967Seric register MCI *mci; 41454967Seric ENVELOPE *e; 41554967Seric { 41654967Seric int r; 41754967Seric 41854967Seric smtpmessage("RSET", m, mci); 41958112Seric r = reply(m, mci, e, TimeOuts.to_rset); 42057734Seric if (r < 0) 42157734Seric mci->mci_state = MCIS_ERROR; 42254967Seric else if (REPLYTYPE(r) == 2) 42357734Seric { 42457734Seric mci->mci_state = MCIS_OPEN; 42557734Seric return; 42657734Seric } 42757734Seric smtpquit(m, mci, e); 42854967Seric } 42954967Seric /* 43054967Seric ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 43154967Seric */ 43254967Seric 43354967Seric smtpnoop(mci) 43454967Seric register MCI *mci; 43554967Seric { 43654967Seric int r; 43754967Seric MAILER *m = mci->mci_mailer; 43854967Seric extern ENVELOPE BlankEnvelope; 43954967Seric ENVELOPE *e = &BlankEnvelope; 44054967Seric 44154967Seric smtpmessage("NOOP", m, mci); 44258112Seric r = reply(m, mci, e, TimeOuts.to_miscshort); 44358061Seric if (r < 0 || REPLYTYPE(r) != 2) 44454967Seric smtpquit(m, mci, e); 44554967Seric return r; 44654967Seric } 44754967Seric /* 4484684Seric ** REPLY -- read arpanet reply 4494684Seric ** 4504684Seric ** Parameters: 45110175Seric ** m -- the mailer we are reading the reply from. 45257379Seric ** mci -- the mailer connection info structure. 45357379Seric ** e -- the current envelope. 45457379Seric ** timeout -- the timeout for reads. 4554684Seric ** 4564684Seric ** Returns: 4574684Seric ** reply code it reads. 4584684Seric ** 4594684Seric ** Side Effects: 4604684Seric ** flushes the mail file. 4614684Seric */ 4624684Seric 46357379Seric reply(m, mci, e, timeout) 46453751Seric MAILER *m; 46554967Seric MCI *mci; 46653751Seric ENVELOPE *e; 4674684Seric { 46857379Seric if (mci->mci_out != NULL) 46957379Seric (void) fflush(mci->mci_out); 4704684Seric 4717677Seric if (tTd(18, 1)) 4724796Seric printf("reply\n"); 4734796Seric 4747356Seric /* 4757356Seric ** Read the input line, being careful not to hang. 4767356Seric */ 4777356Seric 4784684Seric for (;;) 4794684Seric { 4804684Seric register int r; 4817356Seric register char *p; 48253751Seric extern time_t curtime(); 4834684Seric 4847685Seric /* actually do the read */ 48553751Seric if (e->e_xfp != NULL) 48653751Seric (void) fflush(e->e_xfp); /* for debugging */ 4877356Seric 48810054Seric /* if we are in the process of closing just give the code */ 48953740Seric if (mci->mci_state == MCIS_CLOSED) 49010054Seric return (SMTPCLOSING); 49110054Seric 49210054Seric /* get the line from the other side */ 49357379Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in, 49457379Seric timeout); 49553751Seric mci->mci_lastuse = curtime(); 49653751Seric 49710054Seric if (p == NULL) 49810131Seric { 49910148Seric extern char MsgBuf[]; /* err.c */ 50010148Seric 50121065Seric /* if the remote end closed early, fake an error */ 50221065Seric if (errno == 0) 50321065Seric # ifdef ECONNRESET 50421065Seric errno = ECONNRESET; 50556795Seric # else /* ECONNRESET */ 50621065Seric errno = EPIPE; 50756795Seric # endif /* ECONNRESET */ 50821065Seric 50957379Seric mci->mci_errno = errno; 51057642Seric mci->mci_exitstat = EX_TEMPFAIL; 51158151Seric message("451 %s: reply: read error from %s", 51257642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 51357203Seric mci->mci_host); 51410420Seric /* if debugging, pause so we can see state */ 51510420Seric if (tTd(18, 100)) 51610420Seric pause(); 51710148Seric # ifdef LOG 51858020Seric if (LogLevel > 1) 51957203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 52056795Seric # endif /* LOG */ 52154967Seric mci->mci_state = MCIS_ERROR; 52253751Seric smtpquit(m, mci, e); 52310054Seric return (-1); 52410131Seric } 52510054Seric fixcrlf(SmtpReplyBuffer, TRUE); 52610054Seric 52756795Seric if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) 52814900Seric { 52914900Seric /* serious error -- log the previous command */ 53014900Seric if (SmtpMsgBuffer[0] != '\0') 53153751Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 53214900Seric SmtpMsgBuffer[0] = '\0'; 53314900Seric 53414900Seric /* now log the message as from the other side */ 53553751Seric fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 53614900Seric } 53714900Seric 53814900Seric /* display the input for verbose mode */ 53958120Seric if (Verbose) 54058151Seric nmessage("%s", SmtpReplyBuffer); 5417356Seric 5427356Seric /* if continuation is required, we can go on */ 54358050Seric if (SmtpReplyBuffer[3] == '-' || 54458050Seric !(isascii(SmtpReplyBuffer[0]) && isdigit(SmtpReplyBuffer[0]))) 5454684Seric continue; 5467356Seric 5477356Seric /* decode the reply code */ 5489391Seric r = atoi(SmtpReplyBuffer); 5497356Seric 5507356Seric /* extra semantics: 0xx codes are "informational" */ 5514684Seric if (r < 100) 5524684Seric continue; 5537356Seric 55458061Seric /* save temporary failure messages for posterity */ 55558061Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 55658061Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 55758061Seric 5589391Seric /* reply code 421 is "Service Shutting Down" */ 55953740Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 5609391Seric { 56110054Seric /* send the quit protocol */ 56253740Seric mci->mci_state = MCIS_SSD; 56353751Seric smtpquit(m, mci, e); 5649391Seric } 5659391Seric 5664684Seric return (r); 5674684Seric } 5684684Seric } 5694796Seric /* 5704865Seric ** SMTPMESSAGE -- send message to server 5714796Seric ** 5724796Seric ** Parameters: 5734796Seric ** f -- format 57410175Seric ** m -- the mailer to control formatting. 5754796Seric ** a, b, c -- parameters 5764796Seric ** 5774796Seric ** Returns: 5784796Seric ** none. 5794796Seric ** 5804796Seric ** Side Effects: 58153740Seric ** writes message to mci->mci_out. 5824796Seric */ 5834796Seric 5844865Seric /*VARARGS1*/ 58557642Seric #ifdef __STDC__ 58657642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 58757642Seric #else 58857642Seric smtpmessage(f, m, mci, va_alist) 5894796Seric char *f; 59010175Seric MAILER *m; 59154967Seric MCI *mci; 59257642Seric va_dcl 59357642Seric #endif 5944796Seric { 59556852Seric VA_LOCAL_DECL 59656852Seric 59757135Seric VA_START(mci); 59856852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 59956852Seric VA_END; 60058120Seric if (tTd(18, 1) || Verbose) 60158151Seric nmessage(">>> %s", SmtpMsgBuffer); 60253740Seric if (mci->mci_out != NULL) 60353740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 60454967Seric m == NULL ? "\r\n" : m->m_eol); 6054796Seric } 6065182Seric 60756795Seric # endif /* SMTP */ 608