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