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.3 (Berkeley) 07/11/93 (with SMTP)";
14 #else
15 static char sccsid[] = "@(#)usersmtp.c	8.3 (Berkeley) 07/11/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 
421 smtpdata(m, mci, e)
422 	struct mailer *m;
423 	register MCI *mci;
424 	register ENVELOPE *e;
425 {
426 	register int r;
427 	register EVENT *ev;
428 	time_t timeout;
429 	time_t mintimeout;
430 	static int datatimeout();
431 
432 	/*
433 	**  Send the data.
434 	**	First send the command and check that it is ok.
435 	**	Then send the data.
436 	**	Follow it up with a dot to terminate.
437 	**	Finally get the results of the transaction.
438 	*/
439 
440 	/* send the command and check ok to proceed */
441 	smtpmessage("DATA", m, mci);
442 	SmtpPhase = mci->mci_phase = "client DATA 354";
443 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
444 	r = reply(m, mci, e, TimeOuts.to_datainit, NULL);
445 	if (r < 0 || REPLYTYPE(r) == 4)
446 	{
447 		smtpquit(m, mci, e);
448 		return (EX_TEMPFAIL);
449 	}
450 	else if (r == 554)
451 	{
452 		smtprset(m, mci, e);
453 		return (EX_UNAVAILABLE);
454 	}
455 	else if (r != 354)
456 	{
457 #ifdef LOG
458 		if (LogLevel > 1)
459 		{
460 			syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s",
461 				e->e_id, SmtpReplyBuffer);
462 		}
463 #endif
464 		smtprset(m, mci, e);
465 		return (EX_PROTOCOL);
466 	}
467 
468 	/*
469 	**  Set timeout around data writes.  Make it at least large
470 	**  enough for DNS timeouts on all recipients plus some fudge
471 	**  factor.  The main thing is that it should not be infinite.
472 	*/
473 
474 	if (setjmp(CtxDataTimeout) != 0)
475 	{
476 		mci->mci_errno = errno;
477 		mci->mci_exitstat = EX_TEMPFAIL;
478 		mci->mci_state = MCIS_ERROR;
479 		syserr("451 timeout writing message to %s", mci->mci_host);
480 		smtpquit(m, mci, e);
481 		return EX_TEMPFAIL;
482 	}
483 
484 	timeout = e->e_msgsize / 64;
485 	mintimeout = e->e_nrcpts * 90 + 60;
486 	if (timeout < mintimeout)
487 		timeout = mintimeout;
488 	ev = setevent(timeout, datatimeout, 0);
489 
490 	/* now output the actual message */
491 	(*e->e_puthdr)(mci->mci_out, m, e);
492 	putline("\n", mci->mci_out, m);
493 	(*e->e_putbody)(mci->mci_out, m, e, NULL);
494 
495 	clrevent(ev);
496 
497 	/* terminate the message */
498 	fprintf(mci->mci_out, ".%s", m->m_eol);
499 	if (TrafficLogFile != NULL)
500 		fprintf(TrafficLogFile, "%05d >>> .\n", getpid());
501 	if (Verbose)
502 		nmessage(">>> .");
503 
504 	/* check for the results of the transaction */
505 	SmtpPhase = mci->mci_phase = "client DATA 250";
506 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
507 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
508 	if (r < 0)
509 	{
510 		smtpquit(m, mci, e);
511 		return (EX_TEMPFAIL);
512 	}
513 	mci->mci_state = MCIS_OPEN;
514 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
515 	if (REPLYTYPE(r) == 4)
516 		return (EX_TEMPFAIL);
517 	else if (r == 250)
518 		return (EX_OK);
519 	else if (r == 552 || r == 554)
520 		return (EX_UNAVAILABLE);
521 #ifdef LOG
522 	if (LogLevel > 1)
523 	{
524 		syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s",
525 			e->e_id, SmtpReplyBuffer);
526 	}
527 #endif
528 	return (EX_PROTOCOL);
529 }
530 
531 
532 static int
533 datatimeout()
534 {
535 	longjmp(CtxDataTimeout, 1);
536 }
537 /*
538 **  SMTPQUIT -- close the SMTP connection.
539 **
540 **	Parameters:
541 **		m -- a pointer to the mailer.
542 **
543 **	Returns:
544 **		none.
545 **
546 **	Side Effects:
547 **		sends the final protocol and closes the connection.
548 */
549 
550 smtpquit(m, mci, e)
551 	register MAILER *m;
552 	register MCI *mci;
553 	ENVELOPE *e;
554 {
555 	int i;
556 
557 	/* send the quit message if we haven't gotten I/O error */
558 	if (mci->mci_state != MCIS_ERROR)
559 	{
560 		SmtpPhase = "client QUIT";
561 		smtpmessage("QUIT", m, mci);
562 		(void) reply(m, mci, e, TimeOuts.to_quit, NULL);
563 		if (mci->mci_state == MCIS_CLOSED)
564 			return;
565 	}
566 
567 	/* now actually close the connection and pick up the zombie */
568 	i = endmailer(mci, e, m->m_argv);
569 	if (i != EX_OK)
570 		syserr("451 smtpquit %s: stat %d", m->m_argv[0], i);
571 }
572 /*
573 **  SMTPRSET -- send a RSET (reset) command
574 */
575 
576 smtprset(m, mci, e)
577 	register MAILER *m;
578 	register MCI *mci;
579 	ENVELOPE *e;
580 {
581 	int r;
582 
583 	SmtpPhase = "client RSET";
584 	smtpmessage("RSET", m, mci);
585 	r = reply(m, mci, e, TimeOuts.to_rset, NULL);
586 	if (r < 0)
587 		mci->mci_state = MCIS_ERROR;
588 	else if (REPLYTYPE(r) == 2)
589 	{
590 		mci->mci_state = MCIS_OPEN;
591 		return;
592 	}
593 	smtpquit(m, mci, e);
594 }
595 /*
596 **  SMTPPROBE -- check the connection state
597 */
598 
599 smtpprobe(mci)
600 	register MCI *mci;
601 {
602 	int r;
603 	MAILER *m = mci->mci_mailer;
604 	extern ENVELOPE BlankEnvelope;
605 	ENVELOPE *e = &BlankEnvelope;
606 
607 	SmtpPhase = "client probe";
608 	smtpmessage("RSET", m, mci);
609 	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
610 	if (r < 0 || REPLYTYPE(r) != 2)
611 		smtpquit(m, mci, e);
612 	return r;
613 }
614 /*
615 **  REPLY -- read arpanet reply
616 **
617 **	Parameters:
618 **		m -- the mailer we are reading the reply from.
619 **		mci -- the mailer connection info structure.
620 **		e -- the current envelope.
621 **		timeout -- the timeout for reads.
622 **		pfunc -- processing function for second and subsequent
623 **			lines of response -- if null, no special
624 **			processing is done.
625 **
626 **	Returns:
627 **		reply code it reads.
628 **
629 **	Side Effects:
630 **		flushes the mail file.
631 */
632 
633 reply(m, mci, e, timeout, pfunc)
634 	MAILER *m;
635 	MCI *mci;
636 	ENVELOPE *e;
637 	time_t timeout;
638 	void (*pfunc)();
639 {
640 	register char *bufp;
641 	register int r;
642 	bool firstline = TRUE;
643 	char junkbuf[MAXLINE];
644 
645 	if (mci->mci_out != NULL)
646 		(void) fflush(mci->mci_out);
647 
648 	if (tTd(18, 1))
649 		printf("reply\n");
650 
651 	/*
652 	**  Read the input line, being careful not to hang.
653 	*/
654 
655 	for (bufp = SmtpReplyBuffer;; bufp = junkbuf)
656 	{
657 		register char *p;
658 		extern time_t curtime();
659 
660 		/* actually do the read */
661 		if (e->e_xfp != NULL)
662 			(void) fflush(e->e_xfp);	/* for debugging */
663 
664 		/* if we are in the process of closing just give the code */
665 		if (mci->mci_state == MCIS_CLOSED)
666 			return (SMTPCLOSING);
667 
668 		if (mci->mci_out != NULL)
669 			fflush(mci->mci_out);
670 
671 		/* get the line from the other side */
672 		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
673 		mci->mci_lastuse = curtime();
674 
675 		if (p == NULL)
676 		{
677 			bool oldholderrs;
678 			extern char MsgBuf[];		/* err.c */
679 
680 			/* if the remote end closed early, fake an error */
681 			if (errno == 0)
682 # ifdef ECONNRESET
683 				errno = ECONNRESET;
684 # else /* ECONNRESET */
685 				errno = EPIPE;
686 # endif /* ECONNRESET */
687 
688 			mci->mci_errno = errno;
689 			mci->mci_exitstat = EX_TEMPFAIL;
690 			oldholderrs = HoldErrs;
691 			HoldErrs = TRUE;
692 			usrerr("451 reply: read error from %s", mci->mci_host);
693 
694 			/* if debugging, pause so we can see state */
695 			if (tTd(18, 100))
696 				pause();
697 			mci->mci_state = MCIS_ERROR;
698 			smtpquit(m, mci, e);
699 #ifdef XDEBUG
700 			{
701 				char wbuf[MAXLINE];
702 				sprintf(wbuf, "%s... reply(%s) during %s",
703 					e->e_to, mci->mci_host, SmtpPhase);
704 				checkfd012(wbuf);
705 			}
706 #endif
707 			HoldErrs = oldholderrs;
708 			return (-1);
709 		}
710 		fixcrlf(bufp, TRUE);
711 
712 		/* EHLO failure is not a real error */
713 		if (e->e_xfp != NULL && (bufp[0] == '4' ||
714 		    (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
715 		{
716 			/* serious error -- log the previous command */
717 			if (SmtpMsgBuffer[0] != '\0')
718 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
719 			SmtpMsgBuffer[0] = '\0';
720 
721 			/* now log the message as from the other side */
722 			fprintf(e->e_xfp, "<<< %s\n", bufp);
723 		}
724 
725 		/* display the input for verbose mode */
726 		if (Verbose)
727 			nmessage("050 %s", bufp);
728 
729 		/* process the line */
730 		if (pfunc != NULL && !firstline)
731 			(*pfunc)(bufp, m, mci, e);
732 
733 		firstline = FALSE;
734 
735 		/* if continuation is required, we can go on */
736 		if (bufp[3] == '-')
737 			continue;
738 
739 		/* ignore improperly formated input */
740 		if (!(isascii(bufp[0]) && isdigit(bufp[0])))
741 			continue;
742 
743 		/* decode the reply code */
744 		r = atoi(bufp);
745 
746 		/* extra semantics: 0xx codes are "informational" */
747 		if (r >= 100)
748 			break;
749 	}
750 
751 	/*
752 	**  Now look at SmtpReplyBuffer -- only care about the first
753 	**  line of the response from here on out.
754 	*/
755 
756 	/* save temporary failure messages for posterity */
757 	if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
758 		(void) strcpy(SmtpError, SmtpReplyBuffer);
759 
760 	/* reply code 421 is "Service Shutting Down" */
761 	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
762 	{
763 		/* send the quit protocol */
764 		mci->mci_state = MCIS_SSD;
765 		smtpquit(m, mci, e);
766 	}
767 
768 	return (r);
769 }
770 /*
771 **  SMTPMESSAGE -- send message to server
772 **
773 **	Parameters:
774 **		f -- format
775 **		m -- the mailer to control formatting.
776 **		a, b, c -- parameters
777 **
778 **	Returns:
779 **		none.
780 **
781 **	Side Effects:
782 **		writes message to mci->mci_out.
783 */
784 
785 /*VARARGS1*/
786 #ifdef __STDC__
787 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
788 #else
789 smtpmessage(f, m, mci, va_alist)
790 	char *f;
791 	MAILER *m;
792 	MCI *mci;
793 	va_dcl
794 #endif
795 {
796 	VA_LOCAL_DECL
797 
798 	VA_START(mci);
799 	(void) vsprintf(SmtpMsgBuffer, f, ap);
800 	VA_END;
801 
802 	if (tTd(18, 1) || Verbose)
803 		nmessage(">>> %s", SmtpMsgBuffer);
804 	if (TrafficLogFile != NULL)
805 		fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer);
806 	if (mci->mci_out != NULL)
807 	{
808 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
809 			m == NULL ? "\r\n" : m->m_eol);
810 	}
811 	else if (tTd(18, 1))
812 	{
813 		printf("smtpmessage: NULL mci_out\n");
814 	}
815 }
816 
817 # endif /* SMTP */
818