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