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*58856Seric static char sccsid[] = "@(#)usersmtp.c 6.19 (Berkeley) 03/29/93 (with SMTP)"; 1433731Sbostic #else 15*58856Seric static char sccsid[] = "@(#)usersmtp.c 6.19 (Berkeley) 03/29/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; 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 18658680Seric if (bitset(EF_RESPONSE, e->e_flags)) 18758680Seric (void) strcpy(buf, ""); 18858680Seric else 18958680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 19053751Seric if (e->e_from.q_mailer == LocalMailer || 19110688Seric !bitnset(M_FROMPATH, m->m_flags)) 1928436Seric { 19353751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 1948436Seric } 1958436Seric else 1968436Seric { 19753751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 19810308Seric buf[0] == '@' ? ',' : ':', buf); 1998436Seric } 20057379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 20153751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 20258112Seric r = reply(m, mci, e, TimeOuts.to_mail); 2038005Seric if (r < 0 || REPLYTYPE(r) == 4) 20453751Seric { 20553751Seric mci->mci_exitstat = EX_TEMPFAIL; 20653751Seric mci->mci_errno = errno; 20753751Seric smtpquit(m, mci, e); 20853751Seric return EX_TEMPFAIL; 20953751Seric } 2107963Seric else if (r == 250) 21153751Seric { 21253751Seric mci->mci_exitstat = EX_OK; 21353751Seric return EX_OK; 21453751Seric } 2157963Seric else if (r == 552) 21653751Seric { 21753751Seric /* signal service unavailable */ 21853751Seric mci->mci_exitstat = EX_UNAVAILABLE; 21953751Seric smtpquit(m, mci, e); 22053751Seric return EX_UNAVAILABLE; 22153751Seric } 22214913Seric 22358008Seric #ifdef LOG 22458020Seric if (LogLevel > 1) 22558008Seric { 22658008Seric syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 22758008Seric e->e_id, SmtpReplyBuffer); 22858008Seric } 22958008Seric #endif 23058008Seric 23114913Seric /* protocol error -- close up */ 23253751Seric smtpquit(m, mci, e); 23353751Seric mci->mci_exitstat = EX_PROTOCOL; 23453751Seric return EX_PROTOCOL; 2354684Seric } 2364684Seric /* 2374976Seric ** SMTPRCPT -- designate recipient. 2384797Seric ** 2394797Seric ** Parameters: 2404865Seric ** to -- address of recipient. 24110175Seric ** m -- the mailer we are sending to. 24257379Seric ** mci -- the connection info for this transaction. 24357379Seric ** e -- the envelope for this transaction. 2444797Seric ** 2454797Seric ** Returns: 2464865Seric ** exit status corresponding to recipient status. 2474797Seric ** 2484797Seric ** Side Effects: 2494865Seric ** Sends the mail via SMTP. 2504797Seric */ 2514797Seric 25253751Seric smtprcpt(to, m, mci, e) 2534865Seric ADDRESS *to; 25410175Seric register MAILER *m; 25554967Seric MCI *mci; 25653751Seric ENVELOPE *e; 2574797Seric { 2584797Seric register int r; 2594797Seric 26053751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2614865Seric 26257379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 26353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 26458112Seric r = reply(m, mci, e, TimeOuts.to_rcpt); 2658005Seric if (r < 0 || REPLYTYPE(r) == 4) 2664865Seric return (EX_TEMPFAIL); 2677963Seric else if (REPLYTYPE(r) == 2) 2687963Seric return (EX_OK); 2697964Seric else if (r == 550 || r == 551 || r == 553) 2707964Seric return (EX_NOUSER); 2717964Seric else if (r == 552 || r == 554) 2727964Seric return (EX_UNAVAILABLE); 27358008Seric 27458008Seric #ifdef LOG 27558020Seric if (LogLevel > 1) 27658008Seric { 27758008Seric syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 27858008Seric e->e_id, SmtpReplyBuffer); 27958008Seric } 28058008Seric #endif 28158008Seric 2827964Seric return (EX_PROTOCOL); 2834797Seric } 2844797Seric /* 28510175Seric ** SMTPDATA -- send the data and clean up the transaction. 2864684Seric ** 2874684Seric ** Parameters: 2884865Seric ** m -- mailer being sent to. 2896980Seric ** e -- the envelope for this message. 2904684Seric ** 2914684Seric ** Returns: 2924976Seric ** exit status corresponding to DATA command. 2934684Seric ** 2944684Seric ** Side Effects: 2954865Seric ** none. 2964684Seric */ 2974684Seric 29853740Seric smtpdata(m, mci, e) 2994865Seric struct mailer *m; 30054967Seric register MCI *mci; 3016980Seric register ENVELOPE *e; 3024684Seric { 3034684Seric register int r; 3044684Seric 3054797Seric /* 3064797Seric ** Send the data. 30710175Seric ** First send the command and check that it is ok. 30810175Seric ** Then send the data. 30910175Seric ** Follow it up with a dot to terminate. 31010175Seric ** Finally get the results of the transaction. 3114797Seric */ 3124797Seric 31310175Seric /* send the command and check ok to proceed */ 31453751Seric smtpmessage("DATA", m, mci); 31557379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 31653751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 31758112Seric r = reply(m, mci, e, TimeOuts.to_datainit); 3188005Seric if (r < 0 || REPLYTYPE(r) == 4) 31957990Seric { 32057990Seric smtpquit(m, mci, e); 3214797Seric return (EX_TEMPFAIL); 32257990Seric } 3237963Seric else if (r == 554) 32457990Seric { 32557990Seric smtprset(m, mci, e); 3267963Seric return (EX_UNAVAILABLE); 32757990Seric } 3287963Seric else if (r != 354) 32957990Seric { 33058008Seric #ifdef LOG 33158020Seric if (LogLevel > 1) 33258008Seric { 33358008Seric syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 33458008Seric e->e_id, SmtpReplyBuffer); 33558008Seric } 33658008Seric #endif 33757990Seric smtprset(m, mci, e); 3387964Seric return (EX_PROTOCOL); 33957990Seric } 34010175Seric 34110175Seric /* now output the actual message */ 34253751Seric (*e->e_puthdr)(mci->mci_out, m, e); 34353740Seric putline("\n", mci->mci_out, m); 34453751Seric (*e->e_putbody)(mci->mci_out, m, e); 34510175Seric 34610175Seric /* terminate the message */ 34753740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 34858120Seric if (Verbose) 34958151Seric nmessage(">>> ."); 35010175Seric 35110175Seric /* check for the results of the transaction */ 35257379Seric SmtpPhase = mci->mci_phase = "result wait"; 35353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 35458112Seric r = reply(m, mci, e, TimeOuts.to_datafinal); 35553751Seric if (r < 0) 35657990Seric { 35757990Seric smtpquit(m, mci, e); 3584797Seric return (EX_TEMPFAIL); 35957990Seric } 36053751Seric mci->mci_state = MCIS_OPEN; 361*58856Seric e->e_message = newstr(&SmtpReplyBuffer[4]); 36253751Seric if (REPLYTYPE(r) == 4) 36353751Seric return (EX_TEMPFAIL); 3647963Seric else if (r == 250) 3657963Seric return (EX_OK); 3667963Seric else if (r == 552 || r == 554) 3677963Seric return (EX_UNAVAILABLE); 36858008Seric #ifdef LOG 36958020Seric if (LogLevel > 1) 37058008Seric { 37158008Seric syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 37258008Seric e->e_id, SmtpReplyBuffer); 37358008Seric } 37458008Seric #endif 3757964Seric return (EX_PROTOCOL); 3764684Seric } 3774684Seric /* 3784865Seric ** SMTPQUIT -- close the SMTP connection. 3794865Seric ** 3804865Seric ** Parameters: 38115535Seric ** m -- a pointer to the mailer. 3824865Seric ** 3834865Seric ** Returns: 3844865Seric ** none. 3854865Seric ** 3864865Seric ** Side Effects: 3874865Seric ** sends the final protocol and closes the connection. 3884865Seric */ 3894865Seric 39053751Seric smtpquit(m, mci, e) 39153751Seric register MAILER *m; 39254967Seric register MCI *mci; 39353751Seric ENVELOPE *e; 3944865Seric { 3959391Seric int i; 3964865Seric 39754967Seric /* send the quit message if we haven't gotten I/O error */ 39853751Seric if (mci->mci_state != MCIS_ERROR) 3999391Seric { 40053751Seric smtpmessage("QUIT", m, mci); 40158112Seric (void) reply(m, mci, e, TimeOuts.to_quit); 40253740Seric if (mci->mci_state == MCIS_CLOSED) 40310159Seric return; 4049391Seric } 4059391Seric 40652676Seric /* now actually close the connection and pick up the zombie */ 40758846Seric i = endmailer(mci, e, m->m_argv); 4089391Seric if (i != EX_OK) 40958151Seric syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 4104865Seric } 4114865Seric /* 41254967Seric ** SMTPRSET -- send a RSET (reset) command 41354967Seric */ 41454967Seric 41554967Seric smtprset(m, mci, e) 41654967Seric register MAILER *m; 41754967Seric register MCI *mci; 41854967Seric ENVELOPE *e; 41954967Seric { 42054967Seric int r; 42154967Seric 42254967Seric smtpmessage("RSET", m, mci); 42358112Seric r = reply(m, mci, e, TimeOuts.to_rset); 42457734Seric if (r < 0) 42557734Seric mci->mci_state = MCIS_ERROR; 42654967Seric else if (REPLYTYPE(r) == 2) 42757734Seric { 42857734Seric mci->mci_state = MCIS_OPEN; 42957734Seric return; 43057734Seric } 43157734Seric smtpquit(m, mci, e); 43254967Seric } 43354967Seric /* 43454967Seric ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 43554967Seric */ 43654967Seric 43754967Seric smtpnoop(mci) 43854967Seric register MCI *mci; 43954967Seric { 44054967Seric int r; 44154967Seric MAILER *m = mci->mci_mailer; 44254967Seric extern ENVELOPE BlankEnvelope; 44354967Seric ENVELOPE *e = &BlankEnvelope; 44454967Seric 44554967Seric smtpmessage("NOOP", m, mci); 44658112Seric r = reply(m, mci, e, TimeOuts.to_miscshort); 44758061Seric if (r < 0 || REPLYTYPE(r) != 2) 44854967Seric smtpquit(m, mci, e); 44954967Seric return r; 45054967Seric } 45154967Seric /* 4524684Seric ** REPLY -- read arpanet reply 4534684Seric ** 4544684Seric ** Parameters: 45510175Seric ** m -- the mailer we are reading the reply from. 45657379Seric ** mci -- the mailer connection info structure. 45757379Seric ** e -- the current envelope. 45857379Seric ** timeout -- the timeout for reads. 4594684Seric ** 4604684Seric ** Returns: 4614684Seric ** reply code it reads. 4624684Seric ** 4634684Seric ** Side Effects: 4644684Seric ** flushes the mail file. 4654684Seric */ 4664684Seric 46757379Seric reply(m, mci, e, timeout) 46853751Seric MAILER *m; 46954967Seric MCI *mci; 47053751Seric ENVELOPE *e; 4714684Seric { 47257379Seric if (mci->mci_out != NULL) 47357379Seric (void) fflush(mci->mci_out); 4744684Seric 4757677Seric if (tTd(18, 1)) 4764796Seric printf("reply\n"); 4774796Seric 4787356Seric /* 4797356Seric ** Read the input line, being careful not to hang. 4807356Seric */ 4817356Seric 4824684Seric for (;;) 4834684Seric { 4844684Seric register int r; 4857356Seric register char *p; 48653751Seric extern time_t curtime(); 4874684Seric 4887685Seric /* actually do the read */ 48953751Seric if (e->e_xfp != NULL) 49053751Seric (void) fflush(e->e_xfp); /* for debugging */ 4917356Seric 49210054Seric /* if we are in the process of closing just give the code */ 49353740Seric if (mci->mci_state == MCIS_CLOSED) 49410054Seric return (SMTPCLOSING); 49510054Seric 49658680Seric if (mci->mci_out != NULL) 49758680Seric fflush(mci->mci_out); 49858680Seric 49910054Seric /* get the line from the other side */ 50057379Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in, 50157379Seric timeout); 50253751Seric mci->mci_lastuse = curtime(); 50353751Seric 50410054Seric if (p == NULL) 50510131Seric { 50610148Seric extern char MsgBuf[]; /* err.c */ 50710148Seric 50821065Seric /* if the remote end closed early, fake an error */ 50921065Seric if (errno == 0) 51021065Seric # ifdef ECONNRESET 51121065Seric errno = ECONNRESET; 51256795Seric # else /* ECONNRESET */ 51321065Seric errno = EPIPE; 51456795Seric # endif /* ECONNRESET */ 51521065Seric 51657379Seric mci->mci_errno = errno; 51757642Seric mci->mci_exitstat = EX_TEMPFAIL; 51858151Seric message("451 %s: reply: read error from %s", 51957642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 52057203Seric mci->mci_host); 52110420Seric /* if debugging, pause so we can see state */ 52210420Seric if (tTd(18, 100)) 52310420Seric pause(); 52410148Seric # ifdef LOG 52558020Seric if (LogLevel > 1) 52657203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 52756795Seric # endif /* LOG */ 52854967Seric mci->mci_state = MCIS_ERROR; 52953751Seric smtpquit(m, mci, e); 53010054Seric return (-1); 53110131Seric } 53210054Seric fixcrlf(SmtpReplyBuffer, TRUE); 53310054Seric 53456795Seric if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) 53514900Seric { 53614900Seric /* serious error -- log the previous command */ 53714900Seric if (SmtpMsgBuffer[0] != '\0') 53853751Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 53914900Seric SmtpMsgBuffer[0] = '\0'; 54014900Seric 54114900Seric /* now log the message as from the other side */ 54253751Seric fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 54314900Seric } 54414900Seric 54514900Seric /* display the input for verbose mode */ 54658120Seric if (Verbose) 54758151Seric nmessage("%s", SmtpReplyBuffer); 5487356Seric 5497356Seric /* if continuation is required, we can go on */ 55058050Seric if (SmtpReplyBuffer[3] == '-' || 55158050Seric !(isascii(SmtpReplyBuffer[0]) && isdigit(SmtpReplyBuffer[0]))) 5524684Seric continue; 5537356Seric 5547356Seric /* decode the reply code */ 5559391Seric r = atoi(SmtpReplyBuffer); 5567356Seric 5577356Seric /* extra semantics: 0xx codes are "informational" */ 5584684Seric if (r < 100) 5594684Seric continue; 5607356Seric 56158061Seric /* save temporary failure messages for posterity */ 56258061Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 56358061Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 56458061Seric 5659391Seric /* reply code 421 is "Service Shutting Down" */ 56653740Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 5679391Seric { 56810054Seric /* send the quit protocol */ 56953740Seric mci->mci_state = MCIS_SSD; 57053751Seric smtpquit(m, mci, e); 5719391Seric } 5729391Seric 5734684Seric return (r); 5744684Seric } 5754684Seric } 5764796Seric /* 5774865Seric ** SMTPMESSAGE -- send message to server 5784796Seric ** 5794796Seric ** Parameters: 5804796Seric ** f -- format 58110175Seric ** m -- the mailer to control formatting. 5824796Seric ** a, b, c -- parameters 5834796Seric ** 5844796Seric ** Returns: 5854796Seric ** none. 5864796Seric ** 5874796Seric ** Side Effects: 58853740Seric ** writes message to mci->mci_out. 5894796Seric */ 5904796Seric 5914865Seric /*VARARGS1*/ 59257642Seric #ifdef __STDC__ 59357642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 59457642Seric #else 59557642Seric smtpmessage(f, m, mci, va_alist) 5964796Seric char *f; 59710175Seric MAILER *m; 59854967Seric MCI *mci; 59957642Seric va_dcl 60057642Seric #endif 6014796Seric { 60256852Seric VA_LOCAL_DECL 60356852Seric 60457135Seric VA_START(mci); 60556852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 60656852Seric VA_END; 60758680Seric 60858120Seric if (tTd(18, 1) || Verbose) 60958151Seric nmessage(">>> %s", SmtpMsgBuffer); 61053740Seric if (mci->mci_out != NULL) 61158680Seric { 61253740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 61354967Seric m == NULL ? "\r\n" : m->m_eol); 61458680Seric } 61558680Seric else 61658725Seric { 61758680Seric syserr("smtpmessage: NULL mci_out"); 61858725Seric } 6194796Seric } 6205182Seric 62156795Seric # endif /* SMTP */ 622