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