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