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*58867Seric static char sccsid[] = "@(#)usersmtp.c	6.20 (Berkeley) 03/30/93 (with SMTP)";
1433731Sbostic #else
15*58867Seric static char sccsid[] = "@(#)usersmtp.c	6.20 (Berkeley) 03/30/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;
36158856Seric 	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 /*
434*58867Seric **  SMTPPROBE -- check the connection state
43554967Seric */
43654967Seric 
437*58867Seric smtpprobe(mci)
43854967Seric 	register MCI *mci;
43954967Seric {
44054967Seric 	int r;
44154967Seric 	MAILER *m = mci->mci_mailer;
44254967Seric 	extern ENVELOPE BlankEnvelope;
44354967Seric 	ENVELOPE *e = &BlankEnvelope;
44454967Seric 
445*58867Seric 	smtpmessage("RSET", 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