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*58008Seric static char sccsid[] = "@(#)usersmtp.c	6.7 (Berkeley) 02/15/93 (with SMTP)";
1433731Sbostic #else
15*58008Seric static char sccsid[] = "@(#)usersmtp.c	6.7 (Berkeley) 02/15/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 */
389391Seric /*
394865Seric **  SMTPINIT -- initialize SMTP.
404684Seric **
414865Seric **	Opens the connection and sends the initial protocol.
424684Seric **
434684Seric **	Parameters:
444865Seric **		m -- mailer to create connection to.
454865Seric **		pvp -- pointer to parameter vector to pass to
464865Seric **			the mailer.
474684Seric **
484684Seric **	Returns:
4954967Seric **		none.
504684Seric **
514684Seric **	Side Effects:
524865Seric **		creates connection and sends initial protocol.
534684Seric */
544684Seric 
5554967Seric smtpinit(m, mci, e)
564865Seric 	struct mailer *m;
5754967Seric 	register MCI *mci;
5853751Seric 	ENVELOPE *e;
594684Seric {
604865Seric 	register int r;
6114886Seric 	EVENT *gte;
6252107Seric 	extern STAB *stab();
634684Seric 
6457379Seric 	if (tTd(17, 1))
6557379Seric 	{
6657379Seric 		printf("smtpinit ");
6757379Seric 		mci_dump(mci);
6857379Seric 	}
6957379Seric 
704865Seric 	/*
714865Seric 	**  Open the connection to the mailer.
724865Seric 	*/
734684Seric 
7421065Seric 	SmtpError[0] = '\0';
7557379Seric 	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
7654967Seric 	switch (mci->mci_state)
776051Seric 	{
7854967Seric 	  case MCIS_ACTIVE:
7954967Seric 		/* need to clear old information */
8054967Seric 		smtprset(m, mci, e);
8157734Seric 		/* fall through */
8215139Seric 
8354967Seric 	  case MCIS_OPEN:
8454967Seric 		return;
8554967Seric 
8654967Seric 	  case MCIS_ERROR:
8754967Seric 	  case MCIS_SSD:
8854967Seric 		/* shouldn't happen */
8954967Seric 		smtpquit(m, mci, e);
9057734Seric 		/* fall through */
9154967Seric 
9254967Seric 	  case MCIS_CLOSED:
9354967Seric 		syserr("smtpinit: state CLOSED");
9454967Seric 		return;
9554967Seric 
9654967Seric 	  case MCIS_OPENING:
9754967Seric 		break;
986051Seric 	}
994796Seric 
10057379Seric 	SmtpPhase = mci->mci_phase = "user open";
10154967Seric 	mci->mci_state = MCIS_OPENING;
10254967Seric 
1034865Seric 	/*
1044865Seric 	**  Get the greeting message.
10514913Seric 	**	This should appear spontaneously.  Give it five minutes to
10614886Seric 	**	happen.
1074865Seric 	*/
1084797Seric 
10957379Seric 	SmtpPhase = mci->mci_phase = "greeting wait";
11053751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
11157379Seric 	r = reply(m, mci, e, (time_t) 300);
1128005Seric 	if (r < 0 || REPLYTYPE(r) != 2)
11352104Seric 		goto tempfail1;
1144684Seric 
1154865Seric 	/*
1164976Seric 	**  Send the HELO command.
1177963Seric 	**	My mother taught me to always introduce myself.
1184976Seric 	*/
1194976Seric 
12053751Seric 	smtpmessage("HELO %s", m, mci, MyHostName);
12157379Seric 	SmtpPhase = mci->mci_phase = "HELO wait";
12253751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
12357379Seric 	r = reply(m, mci, e, ReadTimeout);
1248005Seric 	if (r < 0)
12552104Seric 		goto tempfail1;
1268005Seric 	else if (REPLYTYPE(r) == 5)
12714913Seric 		goto unavailable;
1287963Seric 	else if (REPLYTYPE(r) != 2)
12952104Seric 		goto tempfail1;
1304976Seric 
1314976Seric 	/*
1329315Seric 	**  If this is expected to be another sendmail, send some internal
1339315Seric 	**  commands.
1349315Seric 	*/
1359315Seric 
13610688Seric 	if (bitnset(M_INTERNAL, m->m_flags))
1379315Seric 	{
1389315Seric 		/* tell it to be verbose */
13953751Seric 		smtpmessage("VERB", m, mci);
14057379Seric 		r = reply(m, mci, e, ReadTimeout);
1419315Seric 		if (r < 0)
14252104Seric 			goto tempfail2;
1439315Seric 	}
1449315Seric 
14553751Seric 	mci->mci_state = MCIS_OPEN;
14654967Seric 	return;
14753751Seric 
14853751Seric   tempfail1:
14953751Seric   tempfail2:
15053751Seric 	mci->mci_exitstat = EX_TEMPFAIL;
15157379Seric 	if (mci->mci_errno == 0)
15257379Seric 		mci->mci_errno = errno;
15357379Seric 	if (mci->mci_state != MCIS_CLOSED)
15457379Seric 		smtpquit(m, mci, e);
15554967Seric 	return;
15653751Seric 
15753751Seric   unavailable:
15853751Seric 	mci->mci_exitstat = EX_UNAVAILABLE;
15953751Seric 	mci->mci_errno = errno;
16053751Seric 	smtpquit(m, mci, e);
16154967Seric 	return;
16253751Seric }
16353751Seric 
16453751Seric smtpmailfrom(m, mci, e)
16553751Seric 	struct mailer *m;
16654967Seric 	MCI *mci;
16753751Seric 	ENVELOPE *e;
16853751Seric {
16953751Seric 	int r;
17053751Seric 	char buf[MAXNAME];
17153751Seric 
17257943Seric 	if (tTd(17, 2))
17357943Seric 		printf("smtpmailfrom: CurHost=%s\n", CurHostName);
17457943Seric 
1759315Seric 	/*
1764865Seric 	**  Send the MAIL command.
1774865Seric 	**	Designates the sender.
1784865Seric 	*/
1794796Seric 
18053751Seric 	mci->mci_state = MCIS_ACTIVE;
18153751Seric 
18253751Seric 	expand("\001<", buf, &buf[sizeof buf - 1], e);
18353751Seric 	if (e->e_from.q_mailer == LocalMailer ||
18410688Seric 	    !bitnset(M_FROMPATH, m->m_flags))
1858436Seric 	{
18653751Seric 		smtpmessage("MAIL From:<%s>", m, mci, buf);
1878436Seric 	}
1888436Seric 	else
1898436Seric 	{
19053751Seric 		smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName,
19110308Seric 			buf[0] == '@' ? ',' : ':', buf);
1928436Seric 	}
19357379Seric 	SmtpPhase = mci->mci_phase = "MAIL wait";
19453751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
19557379Seric 	r = reply(m, mci, e, ReadTimeout);
1968005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
19753751Seric 	{
19853751Seric 		mci->mci_exitstat = EX_TEMPFAIL;
19953751Seric 		mci->mci_errno = errno;
20053751Seric 		smtpquit(m, mci, e);
20153751Seric 		return EX_TEMPFAIL;
20253751Seric 	}
2037963Seric 	else if (r == 250)
20453751Seric 	{
20553751Seric 		mci->mci_exitstat = EX_OK;
20653751Seric 		return EX_OK;
20753751Seric 	}
2087963Seric 	else if (r == 552)
20953751Seric 	{
21053751Seric 		/* signal service unavailable */
21153751Seric 		mci->mci_exitstat = EX_UNAVAILABLE;
21253751Seric 		smtpquit(m, mci, e);
21353751Seric 		return EX_UNAVAILABLE;
21453751Seric 	}
21514913Seric 
216*58008Seric #ifdef LOG
217*58008Seric 	if (LogLevel >= 4)
218*58008Seric 	{
219*58008Seric 		syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s",
220*58008Seric 			e->e_id, SmtpReplyBuffer);
221*58008Seric 	}
222*58008Seric #endif
223*58008Seric 
22414913Seric 	/* protocol error -- close up */
22553751Seric 	smtpquit(m, mci, e);
22653751Seric 	mci->mci_exitstat = EX_PROTOCOL;
22753751Seric 	return EX_PROTOCOL;
2284684Seric }
2294684Seric /*
2304976Seric **  SMTPRCPT -- designate recipient.
2314797Seric **
2324797Seric **	Parameters:
2334865Seric **		to -- address of recipient.
23410175Seric **		m -- the mailer we are sending to.
23557379Seric **		mci -- the connection info for this transaction.
23657379Seric **		e -- the envelope for this transaction.
2374797Seric **
2384797Seric **	Returns:
2394865Seric **		exit status corresponding to recipient status.
2404797Seric **
2414797Seric **	Side Effects:
2424865Seric **		Sends the mail via SMTP.
2434797Seric */
2444797Seric 
24553751Seric smtprcpt(to, m, mci, e)
2464865Seric 	ADDRESS *to;
24710175Seric 	register MAILER *m;
24854967Seric 	MCI *mci;
24953751Seric 	ENVELOPE *e;
2504797Seric {
2514797Seric 	register int r;
2524797Seric 
25353751Seric 	smtpmessage("RCPT To:<%s>", m, mci, to->q_user);
2544865Seric 
25557379Seric 	SmtpPhase = mci->mci_phase = "RCPT wait";
25653751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
25757379Seric 	r = reply(m, mci, e, ReadTimeout);
2588005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
2594865Seric 		return (EX_TEMPFAIL);
2607963Seric 	else if (REPLYTYPE(r) == 2)
2617963Seric 		return (EX_OK);
2627964Seric 	else if (r == 550 || r == 551 || r == 553)
2637964Seric 		return (EX_NOUSER);
2647964Seric 	else if (r == 552 || r == 554)
2657964Seric 		return (EX_UNAVAILABLE);
266*58008Seric 
267*58008Seric #ifdef LOG
268*58008Seric 	if (LogLevel >= 4)
269*58008Seric 	{
270*58008Seric 		syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s",
271*58008Seric 			e->e_id, SmtpReplyBuffer);
272*58008Seric 	}
273*58008Seric #endif
274*58008Seric 
2757964Seric 	return (EX_PROTOCOL);
2764797Seric }
2774797Seric /*
27810175Seric **  SMTPDATA -- send the data and clean up the transaction.
2794684Seric **
2804684Seric **	Parameters:
2814865Seric **		m -- mailer being sent to.
2826980Seric **		e -- the envelope for this message.
2834684Seric **
2844684Seric **	Returns:
2854976Seric **		exit status corresponding to DATA command.
2864684Seric **
2874684Seric **	Side Effects:
2884865Seric **		none.
2894684Seric */
2904684Seric 
29153740Seric smtpdata(m, mci, e)
2924865Seric 	struct mailer *m;
29354967Seric 	register MCI *mci;
2946980Seric 	register ENVELOPE *e;
2954684Seric {
2964684Seric 	register int r;
2974684Seric 
2984797Seric 	/*
2994797Seric 	**  Send the data.
30010175Seric 	**	First send the command and check that it is ok.
30110175Seric 	**	Then send the data.
30210175Seric 	**	Follow it up with a dot to terminate.
30310175Seric 	**	Finally get the results of the transaction.
3044797Seric 	*/
3054797Seric 
30610175Seric 	/* send the command and check ok to proceed */
30753751Seric 	smtpmessage("DATA", m, mci);
30857379Seric 	SmtpPhase = mci->mci_phase = "DATA wait";
30953751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
31057379Seric 	r = reply(m, mci, e, ReadTimeout);
3118005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
31257990Seric 	{
31357990Seric 		smtpquit(m, mci, e);
3144797Seric 		return (EX_TEMPFAIL);
31557990Seric 	}
3167963Seric 	else if (r == 554)
31757990Seric 	{
31857990Seric 		smtprset(m, mci, e);
3197963Seric 		return (EX_UNAVAILABLE);
32057990Seric 	}
3217963Seric 	else if (r != 354)
32257990Seric 	{
323*58008Seric #ifdef LOG
324*58008Seric 		if (LogLevel >= 4)
325*58008Seric 		{
326*58008Seric 			syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s",
327*58008Seric 				e->e_id, SmtpReplyBuffer);
328*58008Seric 		}
329*58008Seric #endif
33057990Seric 		smtprset(m, mci, e);
3317964Seric 		return (EX_PROTOCOL);
33257990Seric 	}
33310175Seric 
33410175Seric 	/* now output the actual message */
33553751Seric 	(*e->e_puthdr)(mci->mci_out, m, e);
33653740Seric 	putline("\n", mci->mci_out, m);
33753751Seric 	(*e->e_putbody)(mci->mci_out, m, e);
33810175Seric 
33910175Seric 	/* terminate the message */
34053740Seric 	fprintf(mci->mci_out, ".%s", m->m_eol);
34110215Seric 	if (Verbose && !HoldErrs)
34210215Seric 		nmessage(Arpa_Info, ">>> .");
34310175Seric 
34410175Seric 	/* check for the results of the transaction */
34557379Seric 	SmtpPhase = mci->mci_phase = "result wait";
34653751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
34757379Seric 	r = reply(m, mci, e, ReadTimeout);
34853751Seric 	if (r < 0)
34957990Seric 	{
35057990Seric 		smtpquit(m, mci, e);
3514797Seric 		return (EX_TEMPFAIL);
35257990Seric 	}
35353751Seric 	mci->mci_state = MCIS_OPEN;
35453751Seric 	if (REPLYTYPE(r) == 4)
35553751Seric 		return (EX_TEMPFAIL);
3567963Seric 	else if (r == 250)
3577963Seric 		return (EX_OK);
3587963Seric 	else if (r == 552 || r == 554)
3597963Seric 		return (EX_UNAVAILABLE);
360*58008Seric #ifdef LOG
361*58008Seric 	if (LogLevel >= 4)
362*58008Seric 	{
363*58008Seric 		syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s",
364*58008Seric 			e->e_id, SmtpReplyBuffer);
365*58008Seric 	}
366*58008Seric #endif
3677964Seric 	return (EX_PROTOCOL);
3684684Seric }
3694684Seric /*
3704865Seric **  SMTPQUIT -- close the SMTP connection.
3714865Seric **
3724865Seric **	Parameters:
37315535Seric **		m -- a pointer to the mailer.
3744865Seric **
3754865Seric **	Returns:
3764865Seric **		none.
3774865Seric **
3784865Seric **	Side Effects:
3794865Seric **		sends the final protocol and closes the connection.
3804865Seric */
3814865Seric 
38253751Seric smtpquit(m, mci, e)
38353751Seric 	register MAILER *m;
38454967Seric 	register MCI *mci;
38553751Seric 	ENVELOPE *e;
3864865Seric {
3879391Seric 	int i;
3884865Seric 
38954967Seric 	/* send the quit message if we haven't gotten I/O error */
39053751Seric 	if (mci->mci_state != MCIS_ERROR)
3919391Seric 	{
39253751Seric 		smtpmessage("QUIT", m, mci);
39357379Seric 		(void) reply(m, mci, e, ReadTimeout);
39453740Seric 		if (mci->mci_state == MCIS_CLOSED)
39510159Seric 			return;
3969391Seric 	}
3979391Seric 
39852676Seric 	/* now actually close the connection and pick up the zombie */
39952676Seric 	i = endmailer(mci, m->m_argv[0]);
4009391Seric 	if (i != EX_OK)
40115535Seric 		syserr("smtpquit %s: stat %d", m->m_argv[0], i);
4024865Seric }
4034865Seric /*
40454967Seric **  SMTPRSET -- send a RSET (reset) command
40554967Seric */
40654967Seric 
40754967Seric smtprset(m, mci, e)
40854967Seric 	register MAILER *m;
40954967Seric 	register MCI *mci;
41054967Seric 	ENVELOPE *e;
41154967Seric {
41254967Seric 	int r;
41354967Seric 
41454967Seric 	smtpmessage("RSET", m, mci);
41557734Seric 	r = reply(m, mci, e, (time_t) 300);
41657734Seric 	if (r < 0)
41757734Seric 		mci->mci_state = MCIS_ERROR;
41854967Seric 	else if (REPLYTYPE(r) == 2)
41957734Seric 	{
42057734Seric 		mci->mci_state = MCIS_OPEN;
42157734Seric 		return;
42257734Seric 	}
42357734Seric 	smtpquit(m, mci, e);
42454967Seric }
42554967Seric /*
42654967Seric **  SMTPNOOP -- send a NOOP (no operation) command to check the connection state
42754967Seric */
42854967Seric 
42954967Seric smtpnoop(mci)
43054967Seric 	register MCI *mci;
43154967Seric {
43254967Seric 	int r;
43354967Seric 	MAILER *m = mci->mci_mailer;
43454967Seric 	extern ENVELOPE BlankEnvelope;
43554967Seric 	ENVELOPE *e = &BlankEnvelope;
43654967Seric 
43754967Seric 	smtpmessage("NOOP", m, mci);
43857379Seric 	r = reply(m, mci, e, ReadTimeout);
43954967Seric 	if (REPLYTYPE(r) != 2)
44054967Seric 		smtpquit(m, mci, e);
44154967Seric 	return r;
44254967Seric }
44354967Seric /*
4444684Seric **  REPLY -- read arpanet reply
4454684Seric **
4464684Seric **	Parameters:
44710175Seric **		m -- the mailer we are reading the reply from.
44857379Seric **		mci -- the mailer connection info structure.
44957379Seric **		e -- the current envelope.
45057379Seric **		timeout -- the timeout for reads.
4514684Seric **
4524684Seric **	Returns:
4534684Seric **		reply code it reads.
4544684Seric **
4554684Seric **	Side Effects:
4564684Seric **		flushes the mail file.
4574684Seric */
4584684Seric 
45957379Seric reply(m, mci, e, timeout)
46053751Seric 	MAILER *m;
46154967Seric 	MCI *mci;
46253751Seric 	ENVELOPE *e;
4634684Seric {
46457379Seric 	if (mci->mci_out != NULL)
46557379Seric 		(void) fflush(mci->mci_out);
4664684Seric 
4677677Seric 	if (tTd(18, 1))
4684796Seric 		printf("reply\n");
4694796Seric 
4707356Seric 	/*
4717356Seric 	**  Read the input line, being careful not to hang.
4727356Seric 	*/
4737356Seric 
4744684Seric 	for (;;)
4754684Seric 	{
4764684Seric 		register int r;
4777356Seric 		register char *p;
47853751Seric 		extern time_t curtime();
4794684Seric 
4807685Seric 		/* actually do the read */
48153751Seric 		if (e->e_xfp != NULL)
48253751Seric 			(void) fflush(e->e_xfp);	/* for debugging */
4837356Seric 
48410054Seric 		/* if we are in the process of closing just give the code */
48553740Seric 		if (mci->mci_state == MCIS_CLOSED)
48610054Seric 			return (SMTPCLOSING);
48710054Seric 
48810054Seric 		/* get the line from the other side */
48957379Seric 		p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in,
49057379Seric 			   timeout);
49153751Seric 		mci->mci_lastuse = curtime();
49253751Seric 
49310054Seric 		if (p == NULL)
49410131Seric 		{
49510148Seric 			extern char MsgBuf[];		/* err.c */
49610148Seric 			extern char Arpa_TSyserr[];	/* conf.c */
49710148Seric 
49821065Seric 			/* if the remote end closed early, fake an error */
49921065Seric 			if (errno == 0)
50021065Seric # ifdef ECONNRESET
50121065Seric 				errno = ECONNRESET;
50256795Seric # else /* ECONNRESET */
50321065Seric 				errno = EPIPE;
50456795Seric # endif /* ECONNRESET */
50521065Seric 
50657379Seric 			mci->mci_errno = errno;
50757642Seric 			mci->mci_exitstat = EX_TEMPFAIL;
50857642Seric 			message(Arpa_TSyserr, "%s: reply: read error from %s",
50957642Seric 				e->e_id == NULL ? "NOQUEUE" : e->e_id,
51057203Seric 				mci->mci_host);
51110420Seric 			/* if debugging, pause so we can see state */
51210420Seric 			if (tTd(18, 100))
51310420Seric 				pause();
51410148Seric # ifdef LOG
51557203Seric 			if (LogLevel > 0)
51657203Seric 				syslog(LOG_INFO, "%s", &MsgBuf[4]);
51756795Seric # endif /* LOG */
51854967Seric 			mci->mci_state = MCIS_ERROR;
51953751Seric 			smtpquit(m, mci, e);
52010054Seric 			return (-1);
52110131Seric 		}
52210054Seric 		fixcrlf(SmtpReplyBuffer, TRUE);
52310054Seric 
52456795Seric 		if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL)
52514900Seric 		{
52614900Seric 			/* serious error -- log the previous command */
52714900Seric 			if (SmtpMsgBuffer[0] != '\0')
52853751Seric 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
52914900Seric 			SmtpMsgBuffer[0] = '\0';
53014900Seric 
53114900Seric 			/* now log the message as from the other side */
53253751Seric 			fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer);
53314900Seric 		}
53414900Seric 
53514900Seric 		/* display the input for verbose mode */
5367229Seric 		if (Verbose && !HoldErrs)
5379391Seric 			nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
5387356Seric 
5397356Seric 		/* if continuation is required, we can go on */
5409391Seric 		if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
5414684Seric 			continue;
5427356Seric 
5437356Seric 		/* decode the reply code */
5449391Seric 		r = atoi(SmtpReplyBuffer);
5457356Seric 
5467356Seric 		/* extra semantics: 0xx codes are "informational" */
5474684Seric 		if (r < 100)
5484684Seric 			continue;
5497356Seric 
5509391Seric 		/* reply code 421 is "Service Shutting Down" */
55153740Seric 		if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
5529391Seric 		{
55310054Seric 			/* send the quit protocol */
55453740Seric 			mci->mci_state = MCIS_SSD;
55553751Seric 			smtpquit(m, mci, e);
5569391Seric 		}
5579391Seric 
55821065Seric 		/* save temporary failure messages for posterity */
55921065Seric 		if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
56021065Seric 			(void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
56121065Seric 
5624684Seric 		return (r);
5634684Seric 	}
5644684Seric }
5654796Seric /*
5664865Seric **  SMTPMESSAGE -- send message to server
5674796Seric **
5684796Seric **	Parameters:
5694796Seric **		f -- format
57010175Seric **		m -- the mailer to control formatting.
5714796Seric **		a, b, c -- parameters
5724796Seric **
5734796Seric **	Returns:
5744796Seric **		none.
5754796Seric **
5764796Seric **	Side Effects:
57753740Seric **		writes message to mci->mci_out.
5784796Seric */
5794796Seric 
5804865Seric /*VARARGS1*/
58157642Seric #ifdef __STDC__
58257642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...)
58357642Seric #else
58457642Seric smtpmessage(f, m, mci, va_alist)
5854796Seric 	char *f;
58610175Seric 	MAILER *m;
58754967Seric 	MCI *mci;
58857642Seric 	va_dcl
58957642Seric #endif
5904796Seric {
59156852Seric 	VA_LOCAL_DECL
59256852Seric 
59357135Seric 	VA_START(mci);
59456852Seric 	(void) vsprintf(SmtpMsgBuffer, f, ap);
59556852Seric 	VA_END;
5967677Seric 	if (tTd(18, 1) || (Verbose && !HoldErrs))
59714900Seric 		nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
59853740Seric 	if (mci->mci_out != NULL)
59953740Seric 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
60054967Seric 			m == NULL ? "\r\n" : m->m_eol);
6014796Seric }
6025182Seric 
60356795Seric # endif /* SMTP */
604