1 /*
2  * Copyright (c) 1983, 1995 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.47 (Berkeley) 04/22/95 (with SMTP)";
14 #else
15 static char sccsid[] = "@(#)usersmtp.c	8.47 (Berkeley) 04/22/95 (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, FALSE);
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 	if (CurHostName == NULL)
83 		CurHostName = MyHostName;
84 	SmtpNeedIntro = TRUE;
85 	switch (mci->mci_state)
86 	{
87 	  case MCIS_ACTIVE:
88 		/* need to clear old information */
89 		smtprset(m, mci, e);
90 		/* fall through */
91 
92 	  case MCIS_OPEN:
93 		return;
94 
95 	  case MCIS_ERROR:
96 	  case MCIS_SSD:
97 		/* shouldn't happen */
98 		smtpquit(m, mci, e);
99 		/* fall through */
100 
101 	  case MCIS_CLOSED:
102 		syserr("451 smtpinit: state CLOSED");
103 		return;
104 
105 	  case MCIS_OPENING:
106 		break;
107 	}
108 
109 	mci->mci_state = MCIS_OPENING;
110 
111 	/*
112 	**  Get the greeting message.
113 	**	This should appear spontaneously.  Give it five minutes to
114 	**	happen.
115 	*/
116 
117 	SmtpPhase = mci->mci_phase = "client greeting";
118 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
119 	r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check);
120 	if (r < 0 || REPLYTYPE(r) == 4)
121 		goto tempfail1;
122 	if (REPLYTYPE(r) != 2)
123 		goto unavailable;
124 
125 	/*
126 	**  Send the HELO command.
127 	**	My mother taught me to always introduce myself.
128 	*/
129 
130 	if (bitnset(M_ESMTP, m->m_flags))
131 		mci->mci_flags |= MCIF_ESMTP;
132 
133 tryhelo:
134 	if (bitset(MCIF_ESMTP, mci->mci_flags))
135 	{
136 		smtpmessage("EHLO %s", m, mci, MyHostName);
137 		SmtpPhase = mci->mci_phase = "client EHLO";
138 	}
139 	else
140 	{
141 		smtpmessage("HELO %s", m, mci, MyHostName);
142 		SmtpPhase = mci->mci_phase = "client HELO";
143 	}
144 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
145 	r = reply(m, mci, e, TimeOuts.to_helo, helo_options);
146 	if (r < 0)
147 		goto tempfail1;
148 	else if (REPLYTYPE(r) == 5)
149 	{
150 		if (bitset(MCIF_ESMTP, mci->mci_flags))
151 		{
152 			/* try old SMTP instead */
153 			mci->mci_flags &= ~MCIF_ESMTP;
154 			goto tryhelo;
155 		}
156 		goto unavailable;
157 	}
158 	else if (REPLYTYPE(r) != 2)
159 		goto tempfail1;
160 
161 	/*
162 	**  Check to see if we actually ended up talking to ourself.
163 	**  This means we didn't know about an alias or MX, or we managed
164 	**  to connect to an echo server.
165 	*/
166 
167 	p = strchr(&SmtpReplyBuffer[4], ' ');
168 	if (p != NULL)
169 		*p = '\0';
170 	if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
171 	    strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
172 	{
173 		syserr("553 %s config error: mail loops back to myself",
174 			MyHostName);
175 		mci->mci_exitstat = EX_CONFIG;
176 		mci->mci_errno = 0;
177 		smtpquit(m, mci, e);
178 		return;
179 	}
180 
181 	/*
182 	**  If this is expected to be another sendmail, send some internal
183 	**  commands.
184 	*/
185 
186 	if (bitnset(M_INTERNAL, m->m_flags))
187 	{
188 		/* tell it to be verbose */
189 		smtpmessage("VERB", m, mci);
190 		r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
191 		if (r < 0)
192 			goto tempfail2;
193 	}
194 
195 	if (mci->mci_state != MCIS_CLOSED)
196 	{
197 		mci->mci_state = MCIS_OPEN;
198 		return;
199 	}
200 
201 	/* got a 421 error code during startup */
202 
203   tempfail1:
204   tempfail2:
205 	mci->mci_exitstat = EX_TEMPFAIL;
206 	if (mci->mci_errno == 0)
207 		mci->mci_errno = errno;
208 	if (mci->mci_state != MCIS_CLOSED)
209 		smtpquit(m, mci, e);
210 	return;
211 
212   unavailable:
213 	mci->mci_exitstat = EX_UNAVAILABLE;
214 	mci->mci_errno = errno;
215 	smtpquit(m, mci, e);
216 	return;
217 }
218 /*
219 **  ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
220 **
221 **	Parameters:
222 **		line -- the response line.
223 **		firstline -- set if this is the first line of the reply.
224 **		m -- the mailer.
225 **		mci -- the mailer connection info.
226 **		e -- the envelope.
227 **
228 **	Returns:
229 **		none.
230 */
231 
232 void
233 esmtp_check(line, firstline, m, mci, e)
234 	char *line;
235 	bool firstline;
236 	MAILER *m;
237 	register MCI *mci;
238 	ENVELOPE *e;
239 {
240 	register char *l;
241 
242 	for (l = line; (l = strchr(++l, 'E')) != NULL; )
243 	{
244 		if (strncmp(l, "ESMTP ", 6) == 0)
245 		{
246 			mci->mci_flags |= MCIF_ESMTP;
247 			break;
248 		}
249 	}
250 	for (l = line; (l = strchr(++l, '8')) != NULL; )
251 	{
252 		if (strncmp(l, "8BIT OK", 7) == 0)
253 		{
254 			mci->mci_flags |= MCIF_8BITOK;
255 			break;
256 		}
257 	}
258 }
259 /*
260 **  HELO_OPTIONS -- process the options on a HELO line.
261 **
262 **	Parameters:
263 **		line -- the response line.
264 **		firstline -- set if this is the first line of the reply.
265 **		m -- the mailer.
266 **		mci -- the mailer connection info.
267 **		e -- the envelope.
268 **
269 **	Returns:
270 **		none.
271 */
272 
273 void
274 helo_options(line, firstline, m, mci, e)
275 	char *line;
276 	bool firstline;
277 	MAILER *m;
278 	register MCI *mci;
279 	ENVELOPE *e;
280 {
281 	register char *p;
282 
283 	if (firstline)
284 		return;
285 
286 	if (strlen(line) < (SIZE_T) 5)
287 		return;
288 	line += 4;
289 	p = strchr(line, ' ');
290 	if (p != NULL)
291 		*p++ = '\0';
292 	if (strcasecmp(line, "size") == 0)
293 	{
294 		mci->mci_flags |= MCIF_SIZE;
295 		if (p != NULL)
296 			mci->mci_maxsize = atol(p);
297 	}
298 	else if (strcasecmp(line, "8bitmime") == 0)
299 	{
300 		mci->mci_flags |= MCIF_8BITMIME;
301 		mci->mci_flags &= ~MCIF_7BIT;
302 	}
303 	else if (strcasecmp(line, "expn") == 0)
304 		mci->mci_flags |= MCIF_EXPN;
305 	else if (strcasecmp(line, "x-dsn-03") == 0)
306 		mci->mci_flags |= MCIF_DSN;
307 }
308 /*
309 **  SMTPMAILFROM -- send MAIL command
310 **
311 **	Parameters:
312 **		m -- the mailer.
313 **		mci -- the mailer connection structure.
314 **		e -- the envelope (including the sender to specify).
315 */
316 
317 smtpmailfrom(m, mci, e)
318 	struct mailer *m;
319 	MCI *mci;
320 	ENVELOPE *e;
321 {
322 	int r;
323 	char *bufp;
324 	char *bodytype;
325 	char buf[MAXNAME + 1];
326 	char optbuf[MAXLINE];
327 
328 	if (tTd(18, 2))
329 		printf("smtpmailfrom: CurHost=%s\n", CurHostName);
330 
331 	/* set up appropriate options to include */
332 	if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
333 		sprintf(optbuf, " SIZE=%ld", e->e_msgsize);
334 	else
335 		strcpy(optbuf, "");
336 
337 	bodytype = e->e_bodytype;
338 	if (bitset(MCIF_8BITMIME, mci->mci_flags))
339 	{
340 		if (bodytype == NULL &&
341 		    bitset(MM_MIME8BIT, MimeMode) &&
342 		    bitset(EF_HAS8BIT, e->e_flags) &&
343 		    !bitnset(M_8BITS, m->m_flags))
344 			bodytype = "8BITMIME";
345 		if (bodytype != NULL)
346 		{
347 			strcat(optbuf, " BODY=");
348 			strcat(optbuf, bodytype);
349 		}
350 	}
351 	else if (bitnset(M_8BITS, m->m_flags) ||
352 		 !bitset(EF_HAS8BIT, e->e_flags) ||
353 		 (e->e_bodytype != NULL &&
354 		  strcasecmp(e->e_bodytype, "7bit") == 0))
355 	{
356 		/* just pass it through */
357 	}
358 	else if (bitset(MM_CVTMIME, MimeMode) &&
359 		 (e->e_bodytype != NULL || !bitset(MM_PASS8BIT, MimeMode)))
360 	{
361 		/* must convert from 8bit MIME format to 7bit encoded */
362 		mci->mci_flags |= MCIF_CVT8TO7;
363 	}
364 	else if (!bitset(MM_PASS8BIT, MimeMode))
365 	{
366 		/* cannot just send a 8-bit version */
367 		usrerr("%s does not support 8BITMIME", mci->mci_host);
368 		mci->mci_status = "5.6.3";
369 		return EX_DATAERR;
370 	}
371 
372 	if (bitset(MCIF_DSN, mci->mci_flags))
373 	{
374 		if (e->e_envid != NULL)
375 		{
376 			strcat(optbuf, " ENVID=");
377 			strcat(optbuf, e->e_envid);
378 		}
379 
380 		/* RET= parameter */
381 		if (bitset(EF_RET_PARAM, e->e_flags))
382 		{
383 			strcat(optbuf, " RET=");
384 			if (bitset(EF_NO_BODY_RETN, e->e_flags))
385 				strcat(optbuf, "HDRS");
386 			else
387 				strcat(optbuf, "FULL");
388 		}
389 	}
390 
391 	/*
392 	**  Send the MAIL command.
393 	**	Designates the sender.
394 	*/
395 
396 	mci->mci_state = MCIS_ACTIVE;
397 
398 	if (bitset(EF_RESPONSE, e->e_flags) &&
399 	    !bitnset(M_NO_NULL_FROM, m->m_flags))
400 		(void) strcpy(buf, "");
401 	else
402 		expand("\201g", buf, sizeof buf, e);
403 	if (buf[0] == '<')
404 	{
405 		/* strip off <angle brackets> (put back on below) */
406 		bufp = &buf[strlen(buf) - 1];
407 		if (*bufp == '>')
408 			*bufp = '\0';
409 		bufp = &buf[1];
410 	}
411 	else
412 		bufp = buf;
413 	if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
414 	    !bitnset(M_FROMPATH, m->m_flags))
415 	{
416 		smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
417 	}
418 	else
419 	{
420 		smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
421 			*bufp == '@' ? ',' : ':', bufp, optbuf);
422 	}
423 	SmtpPhase = mci->mci_phase = "client MAIL";
424 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
425 	r = reply(m, mci, e, TimeOuts.to_mail, NULL);
426 	if (r < 0 || r == 421)
427 	{
428 		/* communications failure/service shutting down */
429 		mci->mci_exitstat = EX_TEMPFAIL;
430 		mci->mci_errno = errno;
431 		smtpquit(m, mci, e);
432 		return EX_TEMPFAIL;
433 	}
434 	else if (REPLYTYPE(r) == 4)
435 	{
436 		return EX_TEMPFAIL;
437 	}
438 	else if (r == 250)
439 	{
440 		return EX_OK;
441 	}
442 	else if (r == 501)
443 	{
444 		/* syntax error in arguments */
445 		mci->mci_status = "5.5.2";
446 		return EX_DATAERR;
447 	}
448 	else if (r == 553)
449 	{
450 		/* mailbox name not allowed */
451 		mci->mci_status = "5.1.3";
452 		return EX_DATAERR;
453 	}
454 	else if (r == 552)
455 	{
456 		/* exceeded storage allocation */
457 		mci->mci_status = "5.2.2";
458 		return EX_UNAVAILABLE;
459 	}
460 
461 #ifdef LOG
462 	if (LogLevel > 1)
463 	{
464 		syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s",
465 			e->e_id, mci->mci_host, SmtpReplyBuffer);
466 	}
467 #endif
468 
469 	/* protocol error -- close up */
470 	smtpquit(m, mci, e);
471 	return EX_PROTOCOL;
472 }
473 /*
474 **  SMTPRCPT -- designate recipient.
475 **
476 **	Parameters:
477 **		to -- address of recipient.
478 **		m -- the mailer we are sending to.
479 **		mci -- the connection info for this transaction.
480 **		e -- the envelope for this transaction.
481 **
482 **	Returns:
483 **		exit status corresponding to recipient status.
484 **
485 **	Side Effects:
486 **		Sends the mail via SMTP.
487 */
488 
489 smtprcpt(to, m, mci, e)
490 	ADDRESS *to;
491 	register MAILER *m;
492 	MCI *mci;
493 	ENVELOPE *e;
494 {
495 	register int r;
496 	char optbuf[MAXLINE];
497 	extern char *smtptodsn();
498 
499 	strcpy(optbuf, "");
500 	if (bitset(MCIF_DSN, mci->mci_flags))
501 	{
502 		/* NOTIFY= parameter */
503 		if (bitset(QHASNOTIFY, to->q_flags) &&
504 		    bitset(QPRIMARY, to->q_flags))
505 		{
506 			bool firstone = TRUE;
507 
508 			strcat(optbuf, " NOTIFY=");
509 			if (bitset(QPINGONSUCCESS, to->q_flags))
510 			{
511 				strcat(optbuf, "SUCCESS");
512 				firstone = FALSE;
513 			}
514 			if (bitset(QPINGONFAILURE, to->q_flags))
515 			{
516 				if (!firstone)
517 					strcat(optbuf, ",");
518 				strcat(optbuf, "FAILURE");
519 				firstone = FALSE;
520 			}
521 			if (bitset(QPINGONDELAY, to->q_flags))
522 			{
523 				if (!firstone)
524 					strcat(optbuf, ",");
525 				strcat(optbuf, "DELAY");
526 				firstone = FALSE;
527 			}
528 			if (firstone)
529 				strcat(optbuf, "NEVER");
530 		}
531 
532 		/* ORCPT= parameter */
533 		if (to->q_orcpt != NULL)
534 		{
535 			strcat(optbuf, " ORCPT=");
536 			strcat(optbuf, to->q_orcpt);
537 		}
538 	}
539 
540 	smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
541 
542 	SmtpPhase = mci->mci_phase = "client RCPT";
543 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
544 	r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
545 	setstatus(to, SmtpReplyBuffer);
546 	to->q_status = smtptodsn(r);
547 	if (r < 0 || REPLYTYPE(r) == 4)
548 		return EX_TEMPFAIL;
549 	else if (REPLYTYPE(r) == 2)
550 		return EX_OK;
551 	else if (r == 550 || r == 551 || r == 553)
552 		return EX_NOUSER;
553 	else if (r == 552 || r == 554)
554 		return EX_UNAVAILABLE;
555 
556 #ifdef LOG
557 	if (LogLevel > 1)
558 	{
559 		syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s",
560 			e->e_id, mci->mci_host, SmtpReplyBuffer);
561 	}
562 #endif
563 
564 	return (EX_PROTOCOL);
565 }
566 /*
567 **  SMTPDATA -- send the data and clean up the transaction.
568 **
569 **	Parameters:
570 **		m -- mailer being sent to.
571 **		e -- the envelope for this message.
572 **
573 **	Returns:
574 **		exit status corresponding to DATA command.
575 **
576 **	Side Effects:
577 **		none.
578 */
579 
580 static jmp_buf	CtxDataTimeout;
581 static void	datatimeout();
582 
583 smtpdata(m, mci, e)
584 	struct mailer *m;
585 	register MCI *mci;
586 	register ENVELOPE *e;
587 {
588 	register int r;
589 	register EVENT *ev;
590 	time_t timeout;
591 
592 	/*
593 	**  Send the data.
594 	**	First send the command and check that it is ok.
595 	**	Then send the data.
596 	**	Follow it up with a dot to terminate.
597 	**	Finally get the results of the transaction.
598 	*/
599 
600 	/* send the command and check ok to proceed */
601 	smtpmessage("DATA", m, mci);
602 	SmtpPhase = mci->mci_phase = "client DATA 354";
603 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
604 	r = reply(m, mci, e, TimeOuts.to_datainit, NULL);
605 	if (r < 0 || REPLYTYPE(r) == 4)
606 	{
607 		smtpquit(m, mci, e);
608 		return (EX_TEMPFAIL);
609 	}
610 	else if (r == 554)
611 	{
612 		smtprset(m, mci, e);
613 		return (EX_UNAVAILABLE);
614 	}
615 	else if (r != 354)
616 	{
617 #ifdef LOG
618 		if (LogLevel > 1)
619 		{
620 			syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s",
621 				e->e_id, mci->mci_host, SmtpReplyBuffer);
622 		}
623 #endif
624 		smtprset(m, mci, e);
625 		return (EX_PROTOCOL);
626 	}
627 
628 	/*
629 	**  Set timeout around data writes.  Make it at least large
630 	**  enough for DNS timeouts on all recipients plus some fudge
631 	**  factor.  The main thing is that it should not be infinite.
632 	*/
633 
634 	if (setjmp(CtxDataTimeout) != 0)
635 	{
636 		mci->mci_errno = errno;
637 		mci->mci_exitstat = EX_TEMPFAIL;
638 		mci->mci_state = MCIS_ERROR;
639 		syserr("451 timeout writing message to %s", mci->mci_host);
640 		smtpquit(m, mci, e);
641 		return EX_TEMPFAIL;
642 	}
643 
644 	timeout = e->e_msgsize / 16;
645 	if (timeout < (time_t) 600)
646 		timeout = (time_t) 600;
647 	timeout += e->e_nrcpts * 300;
648 	ev = setevent(timeout, datatimeout, 0);
649 
650 	/*
651 	**  Output the actual message.
652 	*/
653 
654 	(*e->e_puthdr)(mci, e->e_header, e);
655 	(*e->e_putbody)(mci, e, NULL);
656 
657 	/*
658 	**  Cleanup after sending message.
659 	*/
660 
661 	clrevent(ev);
662 
663 	if (ferror(mci->mci_out))
664 	{
665 		/* error during processing -- don't send the dot */
666 		mci->mci_errno = EIO;
667 		mci->mci_exitstat = EX_IOERR;
668 		mci->mci_state = MCIS_ERROR;
669 		smtpquit(m, mci, e);
670 		return EX_IOERR;
671 	}
672 
673 	/* terminate the message */
674 	fprintf(mci->mci_out, ".%s", m->m_eol);
675 	if (TrafficLogFile != NULL)
676 		fprintf(TrafficLogFile, "%05d >>> .\n", getpid());
677 	if (Verbose)
678 		nmessage(">>> .");
679 
680 	/* check for the results of the transaction */
681 	SmtpPhase = mci->mci_phase = "client DATA 250";
682 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
683 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
684 	if (r < 0)
685 	{
686 		smtpquit(m, mci, e);
687 		return (EX_TEMPFAIL);
688 	}
689 	mci->mci_state = MCIS_OPEN;
690 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
691 	if (REPLYTYPE(r) == 4)
692 		return (EX_TEMPFAIL);
693 	else if (r == 250)
694 		return (EX_OK);
695 	else if (r == 552 || r == 554)
696 		return (EX_UNAVAILABLE);
697 #ifdef LOG
698 	if (LogLevel > 1)
699 	{
700 		syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s",
701 			e->e_id, mci->mci_host, SmtpReplyBuffer);
702 	}
703 #endif
704 	return (EX_PROTOCOL);
705 }
706 
707 
708 static void
709 datatimeout()
710 {
711 	longjmp(CtxDataTimeout, 1);
712 }
713 /*
714 **  SMTPQUIT -- close the SMTP connection.
715 **
716 **	Parameters:
717 **		m -- a pointer to the mailer.
718 **
719 **	Returns:
720 **		none.
721 **
722 **	Side Effects:
723 **		sends the final protocol and closes the connection.
724 */
725 
726 smtpquit(m, mci, e)
727 	register MAILER *m;
728 	register MCI *mci;
729 	ENVELOPE *e;
730 {
731 	bool oldSuprErrs = SuprErrs;
732 
733 	/*
734 	**	Suppress errors here -- we may be processing a different
735 	**	job when we do the quit connection, and we don't want the
736 	**	new job to be penalized for something that isn't it's
737 	**	problem.
738 	*/
739 
740 	SuprErrs = TRUE;
741 
742 	/* send the quit message if we haven't gotten I/O error */
743 	if (mci->mci_state != MCIS_ERROR)
744 	{
745 		SmtpPhase = "client QUIT";
746 		smtpmessage("QUIT", m, mci);
747 		(void) reply(m, mci, e, TimeOuts.to_quit, NULL);
748 		SuprErrs = oldSuprErrs;
749 		if (mci->mci_state == MCIS_CLOSED)
750 		{
751 			SuprErrs = oldSuprErrs;
752 			return;
753 		}
754 	}
755 
756 	/* now actually close the connection and pick up the zombie */
757 	(void) endmailer(mci, e, NULL);
758 
759 	SuprErrs = oldSuprErrs;
760 }
761 /*
762 **  SMTPRSET -- send a RSET (reset) command
763 */
764 
765 smtprset(m, mci, e)
766 	register MAILER *m;
767 	register MCI *mci;
768 	ENVELOPE *e;
769 {
770 	int r;
771 
772 	SmtpPhase = "client RSET";
773 	smtpmessage("RSET", m, mci);
774 	r = reply(m, mci, e, TimeOuts.to_rset, NULL);
775 	if (r < 0)
776 		mci->mci_state = MCIS_ERROR;
777 	else if (REPLYTYPE(r) == 2)
778 	{
779 		mci->mci_state = MCIS_OPEN;
780 		return;
781 	}
782 	smtpquit(m, mci, e);
783 }
784 /*
785 **  SMTPPROBE -- check the connection state
786 */
787 
788 smtpprobe(mci)
789 	register MCI *mci;
790 {
791 	int r;
792 	MAILER *m = mci->mci_mailer;
793 	extern ENVELOPE BlankEnvelope;
794 	ENVELOPE *e = &BlankEnvelope;
795 
796 	SmtpPhase = "client probe";
797 	smtpmessage("RSET", m, mci);
798 	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
799 	if (r < 0 || REPLYTYPE(r) != 2)
800 		smtpquit(m, mci, e);
801 	return r;
802 }
803 /*
804 **  REPLY -- read arpanet reply
805 **
806 **	Parameters:
807 **		m -- the mailer we are reading the reply from.
808 **		mci -- the mailer connection info structure.
809 **		e -- the current envelope.
810 **		timeout -- the timeout for reads.
811 **		pfunc -- processing function for second and subsequent
812 **			lines of response -- if null, no special
813 **			processing is done.
814 **
815 **	Returns:
816 **		reply code it reads.
817 **
818 **	Side Effects:
819 **		flushes the mail file.
820 */
821 
822 reply(m, mci, e, timeout, pfunc)
823 	MAILER *m;
824 	MCI *mci;
825 	ENVELOPE *e;
826 	time_t timeout;
827 	void (*pfunc)();
828 {
829 	register char *bufp;
830 	register int r;
831 	bool firstline = TRUE;
832 	char junkbuf[MAXLINE];
833 
834 	if (mci->mci_out != NULL)
835 		(void) fflush(mci->mci_out);
836 
837 	if (tTd(18, 1))
838 		printf("reply\n");
839 
840 	/*
841 	**  Read the input line, being careful not to hang.
842 	*/
843 
844 	for (bufp = SmtpReplyBuffer;; bufp = junkbuf)
845 	{
846 		register char *p;
847 		extern time_t curtime();
848 
849 		/* actually do the read */
850 		if (e->e_xfp != NULL)
851 			(void) fflush(e->e_xfp);	/* for debugging */
852 
853 		/* if we are in the process of closing just give the code */
854 		if (mci->mci_state == MCIS_CLOSED)
855 			return (SMTPCLOSING);
856 
857 		if (mci->mci_out != NULL)
858 			fflush(mci->mci_out);
859 
860 		/* get the line from the other side */
861 		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
862 		mci->mci_lastuse = curtime();
863 
864 		if (p == NULL)
865 		{
866 			bool oldholderrs;
867 			extern char MsgBuf[];		/* err.c */
868 
869 			/* if the remote end closed early, fake an error */
870 			if (errno == 0)
871 # ifdef ECONNRESET
872 				errno = ECONNRESET;
873 # else /* ECONNRESET */
874 				errno = EPIPE;
875 # endif /* ECONNRESET */
876 
877 			mci->mci_errno = errno;
878 			mci->mci_exitstat = EX_TEMPFAIL;
879 			oldholderrs = HoldErrs;
880 			HoldErrs = TRUE;
881 			usrerr("451 reply: read error from %s", mci->mci_host);
882 
883 			/* if debugging, pause so we can see state */
884 			if (tTd(18, 100))
885 				pause();
886 			mci->mci_state = MCIS_ERROR;
887 			smtpquit(m, mci, e);
888 #ifdef XDEBUG
889 			{
890 				char wbuf[MAXLINE];
891 				char *p = wbuf;
892 				if (e->e_to != NULL)
893 				{
894 					sprintf(p, "%s... ", e->e_to);
895 					p += strlen(p);
896 				}
897 				sprintf(p, "reply(%s) during %s",
898 					mci->mci_host, SmtpPhase);
899 				checkfd012(wbuf);
900 			}
901 #endif
902 			HoldErrs = oldholderrs;
903 			return (-1);
904 		}
905 		fixcrlf(bufp, TRUE);
906 
907 		/* EHLO failure is not a real error */
908 		if (e->e_xfp != NULL && (bufp[0] == '4' ||
909 		    (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
910 		{
911 			/* serious error -- log the previous command */
912 			if (SmtpNeedIntro)
913 			{
914 				/* inform user who we are chatting with */
915 				fprintf(CurEnv->e_xfp,
916 					"... while talking to %s:\n",
917 					CurHostName);
918 				SmtpNeedIntro = FALSE;
919 			}
920 			if (SmtpMsgBuffer[0] != '\0')
921 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
922 			SmtpMsgBuffer[0] = '\0';
923 
924 			/* now log the message as from the other side */
925 			fprintf(e->e_xfp, "<<< %s\n", bufp);
926 		}
927 
928 		/* display the input for verbose mode */
929 		if (Verbose)
930 			nmessage("050 %s", bufp);
931 
932 		/* process the line */
933 		if (pfunc != NULL)
934 			(*pfunc)(bufp, firstline, m, mci, e);
935 
936 		firstline = FALSE;
937 
938 		/* if continuation is required, we can go on */
939 		if (bufp[3] == '-')
940 			continue;
941 
942 		/* ignore improperly formated input */
943 		if (!(isascii(bufp[0]) && isdigit(bufp[0])))
944 			continue;
945 
946 		/* decode the reply code */
947 		r = atoi(bufp);
948 
949 		/* extra semantics: 0xx codes are "informational" */
950 		if (r >= 100)
951 			break;
952 	}
953 
954 	/*
955 	**  Now look at SmtpReplyBuffer -- only care about the first
956 	**  line of the response from here on out.
957 	*/
958 
959 	/* save temporary failure messages for posterity */
960 	if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
961 		(void) strcpy(SmtpError, SmtpReplyBuffer);
962 
963 	/* reply code 421 is "Service Shutting Down" */
964 	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
965 	{
966 		/* send the quit protocol */
967 		mci->mci_state = MCIS_SSD;
968 		smtpquit(m, mci, e);
969 	}
970 
971 	return (r);
972 }
973 /*
974 **  SMTPMESSAGE -- send message to server
975 **
976 **	Parameters:
977 **		f -- format
978 **		m -- the mailer to control formatting.
979 **		a, b, c -- parameters
980 **
981 **	Returns:
982 **		none.
983 **
984 **	Side Effects:
985 **		writes message to mci->mci_out.
986 */
987 
988 /*VARARGS1*/
989 #ifdef __STDC__
990 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
991 #else
992 smtpmessage(f, m, mci, va_alist)
993 	char *f;
994 	MAILER *m;
995 	MCI *mci;
996 	va_dcl
997 #endif
998 {
999 	VA_LOCAL_DECL
1000 
1001 	VA_START(mci);
1002 	(void) vsprintf(SmtpMsgBuffer, f, ap);
1003 	VA_END;
1004 
1005 	if (tTd(18, 1) || Verbose)
1006 		nmessage(">>> %s", SmtpMsgBuffer);
1007 	if (TrafficLogFile != NULL)
1008 		fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer);
1009 	if (mci->mci_out != NULL)
1010 	{
1011 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
1012 			m == NULL ? "\r\n" : m->m_eol);
1013 	}
1014 	else if (tTd(18, 1))
1015 	{
1016 		printf("smtpmessage: NULL mci_out\n");
1017 	}
1018 }
1019 
1020 # endif /* SMTP */
1021