1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 # include "sendmail.h"
10 
11 #ifndef lint
12 #ifdef SMTP
13 static char sccsid[] = "@(#)usersmtp.c	8.5 (Berkeley) 07/19/93 (with SMTP)";
14 #else
15 static char sccsid[] = "@(#)usersmtp.c	8.5 (Berkeley) 07/19/93 (without SMTP)";
16 #endif
17 #endif /* not lint */
18 
19 # include <sysexits.h>
20 # include <errno.h>
21 
22 # ifdef SMTP
23 
24 /*
25 **  USERSMTP -- run SMTP protocol from the user end.
26 **
27 **	This protocol is described in RFC821.
28 */
29 
30 #define REPLYTYPE(r)	((r) / 100)		/* first digit of reply code */
31 #define REPLYCLASS(r)	(((r) / 10) % 10)	/* second digit of reply code */
32 #define SMTPCLOSING	421			/* "Service Shutting Down" */
33 
34 char	SmtpMsgBuffer[MAXLINE];		/* buffer for commands */
35 char	SmtpReplyBuffer[MAXLINE];	/* buffer for replies */
36 char	SmtpError[MAXLINE] = "";	/* save failure error messages */
37 int	SmtpPid;			/* pid of mailer */
38 
39 #ifdef __STDC__
40 extern	smtpmessage(char *f, MAILER *m, MCI *mci, ...);
41 #endif
42 /*
43 **  SMTPINIT -- initialize SMTP.
44 **
45 **	Opens the connection and sends the initial protocol.
46 **
47 **	Parameters:
48 **		m -- mailer to create connection to.
49 **		pvp -- pointer to parameter vector to pass to
50 **			the mailer.
51 **
52 **	Returns:
53 **		none.
54 **
55 **	Side Effects:
56 **		creates connection and sends initial protocol.
57 */
58 
59 smtpinit(m, mci, e)
60 	struct mailer *m;
61 	register MCI *mci;
62 	ENVELOPE *e;
63 {
64 	register int r;
65 	register char *p;
66 	extern void esmtp_check();
67 	extern void helo_options();
68 
69 	if (tTd(18, 1))
70 	{
71 		printf("smtpinit ");
72 		mci_dump(mci);
73 	}
74 
75 	/*
76 	**  Open the connection to the mailer.
77 	*/
78 
79 	SmtpError[0] = '\0';
80 	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
81 	switch (mci->mci_state)
82 	{
83 	  case MCIS_ACTIVE:
84 		/* need to clear old information */
85 		smtprset(m, mci, e);
86 		/* fall through */
87 
88 	  case MCIS_OPEN:
89 		return;
90 
91 	  case MCIS_ERROR:
92 	  case MCIS_SSD:
93 		/* shouldn't happen */
94 		smtpquit(m, mci, e);
95 		/* fall through */
96 
97 	  case MCIS_CLOSED:
98 		syserr("451 smtpinit: state CLOSED");
99 		return;
100 
101 	  case MCIS_OPENING:
102 		break;
103 	}
104 
105 	mci->mci_state = MCIS_OPENING;
106 
107 	/*
108 	**  Get the greeting message.
109 	**	This should appear spontaneously.  Give it five minutes to
110 	**	happen.
111 	*/
112 
113 	SmtpPhase = mci->mci_phase = "client greeting";
114 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
115 	r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check);
116 	if (r < 0 || REPLYTYPE(r) != 2)
117 		goto tempfail1;
118 
119 	/*
120 	**  Send the HELO command.
121 	**	My mother taught me to always introduce myself.
122 	*/
123 
124 	if (bitnset(M_ESMTP, m->m_flags))
125 		mci->mci_flags |= MCIF_ESMTP;
126 
127 tryhelo:
128 	if (bitset(MCIF_ESMTP, mci->mci_flags))
129 	{
130 		smtpmessage("EHLO %s", m, mci, MyHostName);
131 		SmtpPhase = mci->mci_phase = "client EHLO";
132 	}
133 	else
134 	{
135 		smtpmessage("HELO %s", m, mci, MyHostName);
136 		SmtpPhase = mci->mci_phase = "client HELO";
137 	}
138 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
139 	r = reply(m, mci, e, TimeOuts.to_helo, helo_options);
140 	if (r < 0)
141 		goto tempfail1;
142 	else if (REPLYTYPE(r) == 5)
143 	{
144 		if (bitset(MCIF_ESMTP, mci->mci_flags))
145 		{
146 			/* try old SMTP instead */
147 			mci->mci_flags &= ~MCIF_ESMTP;
148 			goto tryhelo;
149 		}
150 		goto unavailable;
151 	}
152 	else if (REPLYTYPE(r) != 2)
153 		goto tempfail1;
154 
155 	/*
156 	**  Check to see if we actually ended up talking to ourself.
157 	**  This means we didn't know about an alias or MX, or we managed
158 	**  to connect to an echo server.
159 	*/
160 
161 	p = strchr(&SmtpReplyBuffer[4], ' ');
162 	if (p != NULL)
163 		*p = '\0';
164 	if (strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
165 	{
166 		syserr("553 %s config error: mail loops back to myself",
167 			MyHostName);
168 		mci->mci_exitstat = EX_CONFIG;
169 		mci->mci_errno = 0;
170 		smtpquit(m, mci, e);
171 		return;
172 	}
173 
174 	/*
175 	**  If this is expected to be another sendmail, send some internal
176 	**  commands.
177 	*/
178 
179 	if (bitnset(M_INTERNAL, m->m_flags))
180 	{
181 		/* tell it to be verbose */
182 		smtpmessage("VERB", m, mci);
183 		r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
184 		if (r < 0)
185 			goto tempfail2;
186 	}
187 
188 	mci->mci_state = MCIS_OPEN;
189 	return;
190 
191   tempfail1:
192   tempfail2:
193 	mci->mci_exitstat = EX_TEMPFAIL;
194 	if (mci->mci_errno == 0)
195 		mci->mci_errno = errno;
196 	if (mci->mci_state != MCIS_CLOSED)
197 		smtpquit(m, mci, e);
198 	return;
199 
200   unavailable:
201 	mci->mci_exitstat = EX_UNAVAILABLE;
202 	mci->mci_errno = errno;
203 	smtpquit(m, mci, e);
204 	return;
205 }
206 /*
207 **  ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
208 **
209 **
210 **	Parameters:
211 **		line -- the response line.
212 **		m -- the mailer.
213 **		mci -- the mailer connection info.
214 **		e -- the envelope.
215 **
216 **	Returns:
217 **		none.
218 */
219 
220 void
221 esmtp_check(line, m, mci, e)
222 	char *line;
223 	MAILER *m;
224 	register MCI *mci;
225 	ENVELOPE *e;
226 {
227 	if (strlen(line) < 5)
228 		return;
229 	line += 4;
230 	if (strncmp(line, "ESMTP ", 6) == 0)
231 		mci->mci_flags |= MCIF_ESMTP;
232 }
233 /*
234 **  HELO_OPTIONS -- process the options on a HELO line.
235 **
236 **	Parameters:
237 **		line -- the response line.
238 **		m -- the mailer.
239 **		mci -- the mailer connection info.
240 **		e -- the envelope.
241 **
242 **	Returns:
243 **		none.
244 */
245 
246 void
247 helo_options(line, m, mci, e)
248 	char *line;
249 	MAILER *m;
250 	register MCI *mci;
251 	ENVELOPE *e;
252 {
253 	register char *p;
254 
255 	if (strlen(line) < 5)
256 		return;
257 	line += 4;
258 	p = strchr(line, ' ');
259 	if (p != NULL)
260 		*p++ = '\0';
261 	if (strcasecmp(line, "size") == 0)
262 	{
263 		mci->mci_flags |= MCIF_SIZE;
264 		if (p != NULL)
265 			mci->mci_maxsize = atol(p);
266 	}
267 	else if (strcasecmp(line, "8bitmime") == 0)
268 		mci->mci_flags |= MCIF_8BITMIME;
269 	else if (strcasecmp(line, "expn") == 0)
270 		mci->mci_flags |= MCIF_EXPN;
271 }
272 /*
273 **  SMTPMAILFROM -- send MAIL command
274 **
275 **	Parameters:
276 **		m -- the mailer.
277 **		mci -- the mailer connection structure.
278 **		e -- the envelope (including the sender to specify).
279 */
280 
281 smtpmailfrom(m, mci, e)
282 	struct mailer *m;
283 	MCI *mci;
284 	ENVELOPE *e;
285 {
286 	int r;
287 	char buf[MAXNAME];
288 	char optbuf[MAXLINE];
289 
290 	if (tTd(18, 2))
291 		printf("smtpmailfrom: CurHost=%s\n", CurHostName);
292 
293 	/* set up appropriate options to include */
294 	if (bitset(MCIF_SIZE, mci->mci_flags))
295 		sprintf(optbuf, " SIZE=%ld", e->e_msgsize);
296 	else
297 		strcpy(optbuf, "");
298 
299 	/*
300 	**  Send the MAIL command.
301 	**	Designates the sender.
302 	*/
303 
304 	mci->mci_state = MCIS_ACTIVE;
305 
306 	if (bitset(EF_RESPONSE, e->e_flags) &&
307 	    !bitnset(M_NO_NULL_FROM, m->m_flags))
308 		(void) strcpy(buf, "");
309 	else
310 		expand("\201g", buf, &buf[sizeof buf - 1], e);
311 	if (e->e_from.q_mailer == LocalMailer ||
312 	    !bitnset(M_FROMPATH, m->m_flags))
313 	{
314 		smtpmessage("MAIL From:<%s>%s", m, mci, buf, optbuf);
315 	}
316 	else
317 	{
318 		smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
319 			buf[0] == '@' ? ',' : ':', buf, optbuf);
320 	}
321 	SmtpPhase = mci->mci_phase = "client MAIL";
322 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
323 	r = reply(m, mci, e, TimeOuts.to_mail, NULL);
324 	if (r < 0 || REPLYTYPE(r) == 4)
325 	{
326 		mci->mci_exitstat = EX_TEMPFAIL;
327 		mci->mci_errno = errno;
328 		smtpquit(m, mci, e);
329 		return EX_TEMPFAIL;
330 	}
331 	else if (r == 250)
332 	{
333 		mci->mci_exitstat = EX_OK;
334 		return EX_OK;
335 	}
336 	else if (r == 552)
337 	{
338 		/* signal service unavailable */
339 		mci->mci_exitstat = EX_UNAVAILABLE;
340 		smtpquit(m, mci, e);
341 		return EX_UNAVAILABLE;
342 	}
343 
344 #ifdef LOG
345 	if (LogLevel > 1)
346 	{
347 		syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s",
348 			e->e_id, SmtpReplyBuffer);
349 	}
350 #endif
351 
352 	/* protocol error -- close up */
353 	smtpquit(m, mci, e);
354 	mci->mci_exitstat = EX_PROTOCOL;
355 	return EX_PROTOCOL;
356 }
357 /*
358 **  SMTPRCPT -- designate recipient.
359 **
360 **	Parameters:
361 **		to -- address of recipient.
362 **		m -- the mailer we are sending to.
363 **		mci -- the connection info for this transaction.
364 **		e -- the envelope for this transaction.
365 **
366 **	Returns:
367 **		exit status corresponding to recipient status.
368 **
369 **	Side Effects:
370 **		Sends the mail via SMTP.
371 */
372 
373 smtprcpt(to, m, mci, e)
374 	ADDRESS *to;
375 	register MAILER *m;
376 	MCI *mci;
377 	ENVELOPE *e;
378 {
379 	register int r;
380 
381 	smtpmessage("RCPT To:<%s>", m, mci, to->q_user);
382 
383 	SmtpPhase = mci->mci_phase = "client RCPT";
384 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
385 	r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
386 	if (r < 0 || REPLYTYPE(r) == 4)
387 		return (EX_TEMPFAIL);
388 	else if (REPLYTYPE(r) == 2)
389 		return (EX_OK);
390 	else if (r == 550 || r == 551 || r == 553)
391 		return (EX_NOUSER);
392 	else if (r == 552 || r == 554)
393 		return (EX_UNAVAILABLE);
394 
395 #ifdef LOG
396 	if (LogLevel > 1)
397 	{
398 		syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s",
399 			e->e_id, SmtpReplyBuffer);
400 	}
401 #endif
402 
403 	return (EX_PROTOCOL);
404 }
405 /*
406 **  SMTPDATA -- send the data and clean up the transaction.
407 **
408 **	Parameters:
409 **		m -- mailer being sent to.
410 **		e -- the envelope for this message.
411 **
412 **	Returns:
413 **		exit status corresponding to DATA command.
414 **
415 **	Side Effects:
416 **		none.
417 */
418 
419 static jmp_buf	CtxDataTimeout;
420 static int	datatimeout();
421 
422 smtpdata(m, mci, e)
423 	struct mailer *m;
424 	register MCI *mci;
425 	register ENVELOPE *e;
426 {
427 	register int r;
428 	register EVENT *ev;
429 	time_t timeout;
430 
431 	/*
432 	**  Send the data.
433 	**	First send the command and check that it is ok.
434 	**	Then send the data.
435 	**	Follow it up with a dot to terminate.
436 	**	Finally get the results of the transaction.
437 	*/
438 
439 	/* send the command and check ok to proceed */
440 	smtpmessage("DATA", m, mci);
441 	SmtpPhase = mci->mci_phase = "client DATA 354";
442 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
443 	r = reply(m, mci, e, TimeOuts.to_datainit, NULL);
444 	if (r < 0 || REPLYTYPE(r) == 4)
445 	{
446 		smtpquit(m, mci, e);
447 		return (EX_TEMPFAIL);
448 	}
449 	else if (r == 554)
450 	{
451 		smtprset(m, mci, e);
452 		return (EX_UNAVAILABLE);
453 	}
454 	else if (r != 354)
455 	{
456 #ifdef LOG
457 		if (LogLevel > 1)
458 		{
459 			syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s",
460 				e->e_id, SmtpReplyBuffer);
461 		}
462 #endif
463 		smtprset(m, mci, e);
464 		return (EX_PROTOCOL);
465 	}
466 
467 	/*
468 	**  Set timeout around data writes.  Make it at least large
469 	**  enough for DNS timeouts on all recipients plus some fudge
470 	**  factor.  The main thing is that it should not be infinite.
471 	*/
472 
473 	if (setjmp(CtxDataTimeout) != 0)
474 	{
475 		mci->mci_errno = errno;
476 		mci->mci_exitstat = EX_TEMPFAIL;
477 		mci->mci_state = MCIS_ERROR;
478 		syserr("451 timeout writing message to %s", mci->mci_host);
479 		smtpquit(m, mci, e);
480 		return EX_TEMPFAIL;
481 	}
482 
483 	timeout = e->e_msgsize / 16;
484 	if (timeout < (time_t) 60)
485 		timeout = (time_t) 60;
486 	timeout += e->e_nrcpts * 90;
487 	ev = setevent(timeout, datatimeout, 0);
488 
489 	/* now output the actual message */
490 	(*e->e_puthdr)(mci->mci_out, m, e);
491 	putline("\n", mci->mci_out, m);
492 	(*e->e_putbody)(mci->mci_out, m, e, NULL);
493 
494 	clrevent(ev);
495 
496 	/* terminate the message */
497 	fprintf(mci->mci_out, ".%s", m->m_eol);
498 	if (TrafficLogFile != NULL)
499 		fprintf(TrafficLogFile, "%05d >>> .\n", getpid());
500 	if (Verbose)
501 		nmessage(">>> .");
502 
503 	/* check for the results of the transaction */
504 	SmtpPhase = mci->mci_phase = "client DATA 250";
505 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
506 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
507 	if (r < 0)
508 	{
509 		smtpquit(m, mci, e);
510 		return (EX_TEMPFAIL);
511 	}
512 	mci->mci_state = MCIS_OPEN;
513 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
514 	if (REPLYTYPE(r) == 4)
515 		return (EX_TEMPFAIL);
516 	else if (r == 250)
517 		return (EX_OK);
518 	else if (r == 552 || r == 554)
519 		return (EX_UNAVAILABLE);
520 #ifdef LOG
521 	if (LogLevel > 1)
522 	{
523 		syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s",
524 			e->e_id, SmtpReplyBuffer);
525 	}
526 #endif
527 	return (EX_PROTOCOL);
528 }
529 
530 
531 static int
532 datatimeout()
533 {
534 	longjmp(CtxDataTimeout, 1);
535 }
536 /*
537 **  SMTPQUIT -- close the SMTP connection.
538 **
539 **	Parameters:
540 **		m -- a pointer to the mailer.
541 **
542 **	Returns:
543 **		none.
544 **
545 **	Side Effects:
546 **		sends the final protocol and closes the connection.
547 */
548 
549 smtpquit(m, mci, e)
550 	register MAILER *m;
551 	register MCI *mci;
552 	ENVELOPE *e;
553 {
554 	int i;
555 
556 	/* send the quit message if we haven't gotten I/O error */
557 	if (mci->mci_state != MCIS_ERROR)
558 	{
559 		SmtpPhase = "client QUIT";
560 		smtpmessage("QUIT", m, mci);
561 		(void) reply(m, mci, e, TimeOuts.to_quit, NULL);
562 		if (mci->mci_state == MCIS_CLOSED)
563 			return;
564 	}
565 
566 	/* now actually close the connection and pick up the zombie */
567 	i = endmailer(mci, e, m->m_argv);
568 	if (i != EX_OK)
569 		syserr("451 smtpquit %s: stat %d", m->m_argv[0], i);
570 }
571 /*
572 **  SMTPRSET -- send a RSET (reset) command
573 */
574 
575 smtprset(m, mci, e)
576 	register MAILER *m;
577 	register MCI *mci;
578 	ENVELOPE *e;
579 {
580 	int r;
581 
582 	SmtpPhase = "client RSET";
583 	smtpmessage("RSET", m, mci);
584 	r = reply(m, mci, e, TimeOuts.to_rset, NULL);
585 	if (r < 0)
586 		mci->mci_state = MCIS_ERROR;
587 	else if (REPLYTYPE(r) == 2)
588 	{
589 		mci->mci_state = MCIS_OPEN;
590 		return;
591 	}
592 	smtpquit(m, mci, e);
593 }
594 /*
595 **  SMTPPROBE -- check the connection state
596 */
597 
598 smtpprobe(mci)
599 	register MCI *mci;
600 {
601 	int r;
602 	MAILER *m = mci->mci_mailer;
603 	extern ENVELOPE BlankEnvelope;
604 	ENVELOPE *e = &BlankEnvelope;
605 
606 	SmtpPhase = "client probe";
607 	smtpmessage("RSET", m, mci);
608 	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
609 	if (r < 0 || REPLYTYPE(r) != 2)
610 		smtpquit(m, mci, e);
611 	return r;
612 }
613 /*
614 **  REPLY -- read arpanet reply
615 **
616 **	Parameters:
617 **		m -- the mailer we are reading the reply from.
618 **		mci -- the mailer connection info structure.
619 **		e -- the current envelope.
620 **		timeout -- the timeout for reads.
621 **		pfunc -- processing function for second and subsequent
622 **			lines of response -- if null, no special
623 **			processing is done.
624 **
625 **	Returns:
626 **		reply code it reads.
627 **
628 **	Side Effects:
629 **		flushes the mail file.
630 */
631 
632 reply(m, mci, e, timeout, pfunc)
633 	MAILER *m;
634 	MCI *mci;
635 	ENVELOPE *e;
636 	time_t timeout;
637 	void (*pfunc)();
638 {
639 	register char *bufp;
640 	register int r;
641 	bool firstline = TRUE;
642 	char junkbuf[MAXLINE];
643 
644 	if (mci->mci_out != NULL)
645 		(void) fflush(mci->mci_out);
646 
647 	if (tTd(18, 1))
648 		printf("reply\n");
649 
650 	/*
651 	**  Read the input line, being careful not to hang.
652 	*/
653 
654 	for (bufp = SmtpReplyBuffer;; bufp = junkbuf)
655 	{
656 		register char *p;
657 		extern time_t curtime();
658 
659 		/* actually do the read */
660 		if (e->e_xfp != NULL)
661 			(void) fflush(e->e_xfp);	/* for debugging */
662 
663 		/* if we are in the process of closing just give the code */
664 		if (mci->mci_state == MCIS_CLOSED)
665 			return (SMTPCLOSING);
666 
667 		if (mci->mci_out != NULL)
668 			fflush(mci->mci_out);
669 
670 		/* get the line from the other side */
671 		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
672 		mci->mci_lastuse = curtime();
673 
674 		if (p == NULL)
675 		{
676 			bool oldholderrs;
677 			extern char MsgBuf[];		/* err.c */
678 
679 			/* if the remote end closed early, fake an error */
680 			if (errno == 0)
681 # ifdef ECONNRESET
682 				errno = ECONNRESET;
683 # else /* ECONNRESET */
684 				errno = EPIPE;
685 # endif /* ECONNRESET */
686 
687 			mci->mci_errno = errno;
688 			mci->mci_exitstat = EX_TEMPFAIL;
689 			oldholderrs = HoldErrs;
690 			HoldErrs = TRUE;
691 			usrerr("451 reply: read error from %s", mci->mci_host);
692 
693 			/* if debugging, pause so we can see state */
694 			if (tTd(18, 100))
695 				pause();
696 			mci->mci_state = MCIS_ERROR;
697 			smtpquit(m, mci, e);
698 #ifdef XDEBUG
699 			{
700 				char wbuf[MAXLINE];
701 				sprintf(wbuf, "%s... reply(%s) during %s",
702 					e->e_to, mci->mci_host, SmtpPhase);
703 				checkfd012(wbuf);
704 			}
705 #endif
706 			HoldErrs = oldholderrs;
707 			return (-1);
708 		}
709 		fixcrlf(bufp, TRUE);
710 
711 		/* EHLO failure is not a real error */
712 		if (e->e_xfp != NULL && (bufp[0] == '4' ||
713 		    (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
714 		{
715 			/* serious error -- log the previous command */
716 			if (SmtpMsgBuffer[0] != '\0')
717 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
718 			SmtpMsgBuffer[0] = '\0';
719 
720 			/* now log the message as from the other side */
721 			fprintf(e->e_xfp, "<<< %s\n", bufp);
722 		}
723 
724 		/* display the input for verbose mode */
725 		if (Verbose)
726 			nmessage("050 %s", bufp);
727 
728 		/* process the line */
729 		if (pfunc != NULL && !firstline)
730 			(*pfunc)(bufp, m, mci, e);
731 
732 		firstline = FALSE;
733 
734 		/* if continuation is required, we can go on */
735 		if (bufp[3] == '-')
736 			continue;
737 
738 		/* ignore improperly formated input */
739 		if (!(isascii(bufp[0]) && isdigit(bufp[0])))
740 			continue;
741 
742 		/* decode the reply code */
743 		r = atoi(bufp);
744 
745 		/* extra semantics: 0xx codes are "informational" */
746 		if (r >= 100)
747 			break;
748 	}
749 
750 	/*
751 	**  Now look at SmtpReplyBuffer -- only care about the first
752 	**  line of the response from here on out.
753 	*/
754 
755 	/* save temporary failure messages for posterity */
756 	if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
757 		(void) strcpy(SmtpError, SmtpReplyBuffer);
758 
759 	/* reply code 421 is "Service Shutting Down" */
760 	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
761 	{
762 		/* send the quit protocol */
763 		mci->mci_state = MCIS_SSD;
764 		smtpquit(m, mci, e);
765 	}
766 
767 	return (r);
768 }
769 /*
770 **  SMTPMESSAGE -- send message to server
771 **
772 **	Parameters:
773 **		f -- format
774 **		m -- the mailer to control formatting.
775 **		a, b, c -- parameters
776 **
777 **	Returns:
778 **		none.
779 **
780 **	Side Effects:
781 **		writes message to mci->mci_out.
782 */
783 
784 /*VARARGS1*/
785 #ifdef __STDC__
786 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
787 #else
788 smtpmessage(f, m, mci, va_alist)
789 	char *f;
790 	MAILER *m;
791 	MCI *mci;
792 	va_dcl
793 #endif
794 {
795 	VA_LOCAL_DECL
796 
797 	VA_START(mci);
798 	(void) vsprintf(SmtpMsgBuffer, f, ap);
799 	VA_END;
800 
801 	if (tTd(18, 1) || Verbose)
802 		nmessage(">>> %s", SmtpMsgBuffer);
803 	if (TrafficLogFile != NULL)
804 		fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer);
805 	if (mci->mci_out != NULL)
806 	{
807 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
808 			m == NULL ? "\r\n" : m->m_eol);
809 	}
810 	else if (tTd(18, 1))
811 	{
812 		printf("smtpmessage: NULL mci_out\n");
813 	}
814 }
815 
816 # endif /* SMTP */
817