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