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