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