Commit | Line | Data |
---|---|---|
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 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 DF |
8 | |
9 | #ifndef lint | |
8a684747 | 10 | static char sccsid[] = "@(#)savemail.c 8.34 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
b2a81223 | 12 | |
96faada8 | 13 | # include "sendmail.h" |
e6cb9fc4 | 14 | # include <pwd.h> |
b3cbe40f EA |
15 | |
16 | /* | |
17 | ** SAVEMAIL -- Save mail on error | |
18 | ** | |
7338e3d4 | 19 | ** If mailing back errors, mail it back to the originator |
b3cbe40f EA |
20 | ** together with an error message; otherwise, just put it in |
21 | ** dead.letter in the user's home directory (if he exists on | |
22 | ** this machine). | |
23 | ** | |
24 | ** Parameters: | |
e6f08ab1 | 25 | ** e -- the envelope containing the message in error. |
b3cbe40f EA |
26 | ** |
27 | ** Returns: | |
28 | ** none | |
29 | ** | |
30 | ** Side Effects: | |
31 | ** Saves the letter, by writing or mailing it back to the | |
32 | ** sender, or by putting it in dead.letter in her home | |
33 | ** directory. | |
b3cbe40f EA |
34 | */ |
35 | ||
2e3062fe EA |
36 | /* defines for state machine */ |
37 | # define ESM_REPORT 0 /* report to sender's terminal */ | |
38 | # define ESM_MAIL 1 /* mail back to sender */ | |
39 | # define ESM_QUIET 2 /* messages have already been returned */ | |
40 | # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ | |
41 | # define ESM_POSTMASTER 4 /* return to postmaster */ | |
42 | # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ | |
43 | # define ESM_PANIC 6 /* leave the locked queue/transcript files */ | |
44 | # define ESM_DONE 7 /* the message is successfully delivered */ | |
45 | ||
b1b2b4a2 EA |
46 | # ifndef _PATH_VARTMP |
47 | # define _PATH_VARTMP "/usr/tmp/" | |
48 | # endif | |
49 | ||
2e3062fe | 50 | |
e6f08ab1 EA |
51 | savemail(e) |
52 | register ENVELOPE *e; | |
b3cbe40f EA |
53 | { |
54 | register struct passwd *pw; | |
2e3062fe EA |
55 | register FILE *fp; |
56 | int state; | |
83a871a1 | 57 | auto ADDRESS *q = NULL; |
23fafb99 EA |
58 | register char *p; |
59 | MCI mcibuf; | |
b3cbe40f | 60 | char buf[MAXLINE+1]; |
b3cbe40f | 61 | extern struct passwd *getpwnam(); |
b3cbe40f | 62 | extern char *ttypath(); |
40e27d12 | 63 | typedef int (*fnptr)(); |
06b12081 | 64 | extern bool writable(); |
b3cbe40f | 65 | |
9678c96d | 66 | if (tTd(6, 1)) |
bc854e30 | 67 | { |
8a1f82bc EA |
68 | printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=", |
69 | e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id, | |
70 | ExitStat); | |
bc854e30 EA |
71 | printaddr(&e->e_from, FALSE); |
72 | } | |
ae945718 | 73 | |
c87034b7 EA |
74 | if (e->e_id == NULL) |
75 | { | |
76 | /* can't return a message with no id */ | |
77 | return; | |
78 | } | |
79 | ||
b3cbe40f EA |
80 | /* |
81 | ** In the unhappy event we don't know who to return the mail | |
82 | ** to, make someone up. | |
83 | */ | |
84 | ||
1bcdf0a2 | 85 | if (CurEnv->e_returnto == NULL) |
b3cbe40f | 86 | { |
1bcdf0a2 EA |
87 | CurEnv->e_returnto = parse("root", (ADDRESS *) NULL, 0); |
88 | if (CurEnv->e_returnto == NULL) | |
b3cbe40f | 89 | { |
e0b81669 | 90 | syserr("553 Cannot parse Postmaster!"); |
b3cbe40f EA |
91 | ExitStat = EX_SOFTWARE; |
92 | finis(); | |
93 | } | |
94 | } | |
e6f08ab1 | 95 | e->e_to = NULL; |
b3cbe40f EA |
96 | |
97 | /* | |
2e3062fe EA |
98 | ** Basic state machine. |
99 | ** | |
100 | ** This machine runs through the following states: | |
101 | ** | |
102 | ** ESM_QUIET Errors have already been printed iff the | |
103 | ** sender is local. | |
104 | ** ESM_REPORT Report directly to the sender's terminal. | |
105 | ** ESM_MAIL Mail response to the sender. | |
106 | ** ESM_DEADLETTER Save response in ~/dead.letter. | |
107 | ** ESM_POSTMASTER Mail response to the postmaster. | |
108 | ** ESM_PANIC Save response anywhere possible. | |
b3cbe40f EA |
109 | */ |
110 | ||
2e3062fe | 111 | /* determine starting state */ |
8c8e8e94 | 112 | switch (e->e_errormode) |
b3cbe40f | 113 | { |
2e3062fe EA |
114 | case EM_WRITE: |
115 | state = ESM_REPORT; | |
116 | break; | |
117 | ||
118 | case EM_BERKNET: | |
119 | /* mail back, but return o.k. exit status */ | |
3b661a43 | 120 | ExitStat = EX_OK; |
b3cbe40f | 121 | |
2e3062fe EA |
122 | /* fall through.... */ |
123 | ||
124 | case EM_MAIL: | |
125 | state = ESM_MAIL; | |
126 | break; | |
127 | ||
128 | case EM_PRINT: | |
f4b05990 | 129 | case '\0': |
2e3062fe EA |
130 | state = ESM_QUIET; |
131 | break; | |
b3cbe40f | 132 | |
2e3062fe EA |
133 | case EM_QUIET: |
134 | /* no need to return anything at all */ | |
135 | return; | |
f4b05990 EA |
136 | |
137 | default: | |
8c8e8e94 | 138 | syserr("554 savemail: bogus errormode x%x\n", e->e_errormode); |
f4b05990 EA |
139 | state = ESM_MAIL; |
140 | break; | |
2e3062fe EA |
141 | } |
142 | ||
d6776f09 EA |
143 | /* if this is already an error response, send to postmaster */ |
144 | if (bitset(EF_RESPONSE, e->e_flags)) | |
145 | { | |
146 | if (e->e_parent != NULL && | |
147 | bitset(EF_RESPONSE, e->e_parent->e_flags)) | |
148 | { | |
149 | /* got an error sending a response -- can it */ | |
150 | return; | |
151 | } | |
152 | state = ESM_POSTMASTER; | |
153 | } | |
154 | ||
2e3062fe | 155 | while (state != ESM_DONE) |
b3cbe40f | 156 | { |
f4b05990 EA |
157 | if (tTd(6, 5)) |
158 | printf(" state %d\n", state); | |
f4b05990 | 159 | |
2e3062fe | 160 | switch (state) |
b3cbe40f | 161 | { |
f4b05990 | 162 | case ESM_QUIET: |
2bade550 | 163 | if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags)) |
f4b05990 EA |
164 | state = ESM_DEADLETTER; |
165 | else | |
166 | state = ESM_MAIL; | |
167 | break; | |
168 | ||
2e3062fe EA |
169 | case ESM_REPORT: |
170 | ||
171 | /* | |
172 | ** If the user is still logged in on the same terminal, | |
173 | ** then write the error messages back to hir (sic). | |
174 | */ | |
175 | ||
176 | p = ttypath(); | |
177 | if (p == NULL || freopen(p, "w", stdout) == NULL) | |
178 | { | |
179 | state = ESM_MAIL; | |
180 | break; | |
181 | } | |
182 | ||
2bee003d | 183 | expand("\201n", buf, &buf[sizeof buf - 1], e); |
7338e3d4 EA |
184 | printf("\r\nMessage from %s...\r\n", buf); |
185 | printf("Errors occurred while sending mail.\r\n"); | |
912acb74 | 186 | if (e->e_xfp != NULL) |
7338e3d4 | 187 | { |
912acb74 | 188 | (void) fflush(e->e_xfp); |
2e3062fe | 189 | fp = fopen(queuename(e, 'x'), "r"); |
7338e3d4 EA |
190 | } |
191 | else | |
2e3062fe EA |
192 | fp = NULL; |
193 | if (fp == NULL) | |
7338e3d4 | 194 | { |
e6f08ab1 | 195 | syserr("Cannot open %s", queuename(e, 'x')); |
7338e3d4 EA |
196 | printf("Transcript of session is unavailable.\r\n"); |
197 | } | |
198 | else | |
199 | { | |
200 | printf("Transcript follows:\r\n"); | |
2e3062fe | 201 | while (fgets(buf, sizeof buf, fp) != NULL && |
7338e3d4 EA |
202 | !ferror(stdout)) |
203 | fputs(buf, stdout); | |
bc854e30 | 204 | (void) xfclose(fp, "savemail transcript", e->e_id); |
7338e3d4 | 205 | } |
2e3062fe | 206 | printf("Original message will be saved in dead.letter.\r\n"); |
2e3062fe EA |
207 | state = ESM_DEADLETTER; |
208 | break; | |
b3cbe40f | 209 | |
2e3062fe | 210 | case ESM_MAIL: |
2e3062fe EA |
211 | /* |
212 | ** If mailing back, do it. | |
213 | ** Throw away all further output. Don't alias, | |
214 | ** since this could cause loops, e.g., if joe | |
215 | ** mails to joe@x, and for some reason the network | |
216 | ** for @x is down, then the response gets sent to | |
217 | ** joe@x, which gives a response, etc. Also force | |
218 | ** the mail to be delivered even if a version of | |
219 | ** it has already been sent to the sender. | |
d385f2ac EA |
220 | ** |
221 | ** If this is a configuration or local software | |
222 | ** error, send to the local postmaster as well, | |
223 | ** since the originator can't do anything | |
224 | ** about it anyway. Note that this is a full | |
225 | ** copy of the message (intentionally) so that | |
226 | ** the Postmaster can forward things along. | |
2e3062fe | 227 | */ |
b3cbe40f | 228 | |
d385f2ac EA |
229 | if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE) |
230 | { | |
231 | (void) sendtolist("postmaster", | |
28f94061 | 232 | NULLADDR, &e->e_errorqueue, e); |
d385f2ac | 233 | } |
bc854e30 | 234 | if (strcmp(e->e_from.q_paddr, "<>") != 0) |
d385f2ac | 235 | { |
bc854e30 | 236 | (void) sendtolist(e->e_from.q_paddr, |
28f94061 | 237 | NULLADDR, &e->e_errorqueue, e); |
d385f2ac EA |
238 | } |
239 | ||
240 | /* | |
241 | ** Deliver a non-delivery report to the | |
242 | ** Postmaster-designate (not necessarily | |
243 | ** Postmaster). This does not include the | |
244 | ** body of the message, for privacy reasons. | |
245 | ** You really shouldn't need this. | |
246 | */ | |
bc854e30 | 247 | |
37288e8e | 248 | e->e_flags |= EF_PM_NOTIFY; |
d385f2ac | 249 | |
feed5c80 EA |
250 | /* check to see if there are any good addresses */ |
251 | for (q = e->e_errorqueue; q != NULL; q = q->q_next) | |
252 | if (!bitset(QBADADDR|QDONTSEND, q->q_flags)) | |
253 | break; | |
bc854e30 EA |
254 | if (q == NULL) |
255 | { | |
256 | /* this is an error-error */ | |
257 | state = ESM_POSTMASTER; | |
258 | break; | |
259 | } | |
e7f42bdd EA |
260 | if (returntosender(e->e_message, e->e_errorqueue, |
261 | (e->e_class >= 0), e) == 0) | |
bc854e30 EA |
262 | { |
263 | state = ESM_DONE; | |
264 | break; | |
265 | } | |
a0225d08 | 266 | |
bc854e30 EA |
267 | /* didn't work -- return to postmaster */ |
268 | state = ESM_POSTMASTER; | |
269 | break; | |
ab0b3f7d | 270 | |
bc854e30 EA |
271 | case ESM_POSTMASTER: |
272 | /* | |
273 | ** Similar to previous case, but to system postmaster. | |
274 | */ | |
275 | ||
f553db48 EA |
276 | q = NULL; |
277 | if (sendtolist("postmaster", NULL, &q, e) <= 0) | |
2e3062fe | 278 | { |
bc854e30 EA |
279 | syserr("553 cannot parse postmaster!"); |
280 | ExitStat = EX_SOFTWARE; | |
281 | state = ESM_USRTMP; | |
282 | break; | |
2e3062fe | 283 | } |
35b698c6 | 284 | if (returntosender(e->e_message, |
abccefc9 | 285 | q, (e->e_class >= 0), e) == 0) |
2e3062fe EA |
286 | { |
287 | state = ESM_DONE; | |
288 | break; | |
289 | } | |
b3cbe40f | 290 | |
bc854e30 EA |
291 | /* didn't work -- last resort */ |
292 | state = ESM_USRTMP; | |
2e3062fe | 293 | break; |
b3cbe40f | 294 | |
2e3062fe EA |
295 | case ESM_DEADLETTER: |
296 | /* | |
297 | ** Save the message in dead.letter. | |
298 | ** If we weren't mailing back, and the user is | |
299 | ** local, we should save the message in | |
300 | ** ~/dead.letter so that the poor person doesn't | |
301 | ** have to type it over again -- and we all know | |
302 | ** what poor typists UNIX users are. | |
303 | */ | |
b3cbe40f | 304 | |
2e3062fe | 305 | p = NULL; |
2bade550 | 306 | if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags)) |
2e3062fe EA |
307 | { |
308 | if (e->e_from.q_home != NULL) | |
309 | p = e->e_from.q_home; | |
310 | else if ((pw = getpwnam(e->e_from.q_user)) != NULL) | |
311 | p = pw->pw_dir; | |
312 | } | |
313 | if (p == NULL) | |
314 | { | |
0f8f3490 | 315 | /* no local directory */ |
2e3062fe EA |
316 | state = ESM_MAIL; |
317 | break; | |
318 | } | |
319 | if (e->e_dfp != NULL) | |
320 | { | |
2e3062fe EA |
321 | bool oldverb = Verbose; |
322 | ||
323 | /* we have a home directory; open dead.letter */ | |
324 | define('z', p, e); | |
2bee003d | 325 | expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e); |
2e3062fe | 326 | Verbose = TRUE; |
b6edea3d | 327 | message("Saving message in %s", buf); |
2e3062fe EA |
328 | Verbose = oldverb; |
329 | e->e_to = buf; | |
330 | q = NULL; | |
1c7897ef | 331 | (void) sendtolist(buf, &e->e_from, &q, e); |
626f8601 EA |
332 | if (q != NULL && |
333 | !bitset(QBADADDR, q->q_flags) && | |
334 | deliver(e, q) == 0) | |
2e3062fe EA |
335 | state = ESM_DONE; |
336 | else | |
337 | state = ESM_MAIL; | |
338 | } | |
577bce94 EA |
339 | else |
340 | { | |
341 | /* no data file -- try mailing back */ | |
342 | state = ESM_MAIL; | |
343 | } | |
2e3062fe EA |
344 | break; |
345 | ||
346 | case ESM_USRTMP: | |
347 | /* | |
348 | ** Log the mail in /usr/tmp/dead.letter. | |
349 | */ | |
350 | ||
abccefc9 EA |
351 | if (e->e_class < 0) |
352 | { | |
353 | state = ESM_DONE; | |
354 | break; | |
355 | } | |
356 | ||
b1b2b4a2 EA |
357 | strcpy(buf, _PATH_VARTMP); |
358 | strcat(buf, "dead.letter"); | |
75cdfff0 | 359 | if (!writable(buf, NULLADDR, SFF_NOSLINK)) |
06b12081 EA |
360 | { |
361 | state = ESM_PANIC; | |
362 | break; | |
363 | } | |
364 | fp = dfopen(buf, O_WRONLY|O_CREAT|O_APPEND, FileMode); | |
2e3062fe EA |
365 | if (fp == NULL) |
366 | { | |
367 | state = ESM_PANIC; | |
368 | break; | |
369 | } | |
370 | ||
23fafb99 EA |
371 | bzero(&mcibuf, sizeof mcibuf); |
372 | mcibuf.mci_out = fp; | |
373 | mcibuf.mci_mailer = FileMailer; | |
374 | if (bitnset(M_7BITS, FileMailer->m_flags)) | |
375 | mcibuf.mci_flags |= MCIF_7BIT; | |
376 | ||
377 | putfromline(&mcibuf, e); | |
c23930c0 | 378 | (*e->e_puthdr)(&mcibuf, e->e_header, e); |
23fafb99 EA |
379 | (*e->e_putbody)(&mcibuf, e, NULL); |
380 | putline("\n", &mcibuf); | |
2e3062fe EA |
381 | (void) fflush(fp); |
382 | state = ferror(fp) ? ESM_PANIC : ESM_DONE; | |
bc854e30 | 383 | (void) xfclose(fp, "savemail", "/usr/tmp/dead.letter"); |
2e3062fe EA |
384 | break; |
385 | ||
386 | default: | |
b6edea3d | 387 | syserr("554 savemail: unknown state %d", state); |
2e3062fe EA |
388 | |
389 | /* fall through ... */ | |
390 | ||
391 | case ESM_PANIC: | |
2e3062fe | 392 | /* leave the locked queue & transcript files around */ |
48fb557e | 393 | syserr("!554 savemail: cannot save rejected email anywhere"); |
2e3062fe EA |
394 | } |
395 | } | |
b3cbe40f EA |
396 | } |
397 | \f/* | |
aba51985 EA |
398 | ** RETURNTOSENDER -- return a message to the sender with an error. |
399 | ** | |
400 | ** Parameters: | |
401 | ** msg -- the explanatory message. | |
7a079701 | 402 | ** returnq -- the queue of people to send the message to. |
79bd7c07 EA |
403 | ** sendbody -- if TRUE, also send back the body of the |
404 | ** message; otherwise just send the header. | |
a4076aed | 405 | ** e -- the current envelope. |
aba51985 EA |
406 | ** |
407 | ** Returns: | |
408 | ** zero -- if everything went ok. | |
409 | ** else -- some error. | |
410 | ** | |
411 | ** Side Effects: | |
412 | ** Returns the current message to the sender via | |
413 | ** mail. | |
414 | */ | |
415 | ||
79bd7c07 | 416 | static bool SendBody; |
aba51985 | 417 | |
3c7fe765 | 418 | #define MAXRETURNS 6 /* max depth of returning messages */ |
0f104940 | 419 | #define ERRORFUDGE 100 /* nominal size of error message text */ |
3c7fe765 | 420 | |
a4076aed | 421 | returntosender(msg, returnq, sendbody, e) |
aba51985 | 422 | char *msg; |
7a079701 | 423 | ADDRESS *returnq; |
79bd7c07 | 424 | bool sendbody; |
a4076aed | 425 | register ENVELOPE *e; |
aba51985 | 426 | { |
aba51985 | 427 | char buf[MAXNAME]; |
dd1fe05b EA |
428 | extern putheader(), errbody(); |
429 | register ENVELOPE *ee; | |
bc854e30 | 430 | ENVELOPE *oldcur = CurEnv; |
dd1fe05b | 431 | ENVELOPE errenvelope; |
3c7fe765 | 432 | static int returndepth; |
7338e3d4 | 433 | register ADDRESS *q; |
3c7fe765 | 434 | |
cbfdff7c EA |
435 | if (returnq == NULL) |
436 | return (-1); | |
437 | ||
35b698c6 EA |
438 | if (msg == NULL) |
439 | msg = "Unable to deliver mail"; | |
440 | ||
9678c96d | 441 | if (tTd(6, 1)) |
e4d966b5 | 442 | { |
bc854e30 | 443 | printf("Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=", |
a4076aed | 444 | msg, returndepth, e); |
7a079701 | 445 | printaddr(returnq, TRUE); |
e4d966b5 | 446 | } |
e4d966b5 | 447 | |
3c7fe765 EA |
448 | if (++returndepth >= MAXRETURNS) |
449 | { | |
450 | if (returndepth != MAXRETURNS) | |
b6edea3d | 451 | syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr); |
3c7fe765 EA |
452 | /* don't "unrecurse" and fake a clean exit */ |
453 | /* returndepth--; */ | |
454 | return (0); | |
455 | } | |
aba51985 | 456 | |
79bd7c07 | 457 | SendBody = sendbody; |
bc854e30 | 458 | define('g', e->e_from.q_paddr, e); |
659d287a | 459 | define('u', NULL, e); |
fda58daa | 460 | ee = newenvelope(&errenvelope, e); |
2bee003d | 461 | define('a', "\201b", ee); |
0257ba6d EA |
462 | define('r', "internal", ee); |
463 | define('s', "localhost", ee); | |
464 | define('_', "localhost", ee); | |
dd1fe05b EA |
465 | ee->e_puthdr = putheader; |
466 | ee->e_putbody = errbody; | |
61e75b16 | 467 | ee->e_flags |= EF_RESPONSE|EF_METOO; |
a4076aed | 468 | if (!bitset(EF_OLDSTYLE, e->e_flags)) |
839ae7fa | 469 | ee->e_flags &= ~EF_OLDSTYLE; |
7a079701 | 470 | ee->e_sendqueue = returnq; |
54e571e9 | 471 | ee->e_msgsize = ERRORFUDGE; |
2bade550 | 472 | if (!bitset(EF_NORETURN, e->e_flags)) |
54e571e9 | 473 | ee->e_msgsize += e->e_msgsize; |
5af8d6d0 | 474 | initsys(ee); |
7a079701 | 475 | for (q = returnq; q != NULL; q = q->q_next) |
7338e3d4 | 476 | { |
68491765 | 477 | if (bitset(QBADADDR, q->q_flags)) |
0f104940 EA |
478 | continue; |
479 | ||
68491765 EA |
480 | if (!bitset(QDONTSEND, q->q_flags)) |
481 | ee->e_nrcpts++; | |
0f104940 | 482 | |
63d473ff | 483 | if (!DontPruneRoutes && pruneroute(q->q_paddr)) |
28f94061 | 484 | parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e); |
63d473ff | 485 | |
7338e3d4 | 486 | if (q->q_alias == NULL) |
c23930c0 | 487 | addheader("To", q->q_paddr, &ee->e_header); |
7338e3d4 | 488 | } |
2e3062fe | 489 | |
6e99f903 | 490 | # ifdef LOG |
68f7099c | 491 | if (LogLevel > 5) |
25414557 | 492 | syslog(LOG_INFO, "%s: %s: returntosender: %s", |
6e99f903 EA |
493 | e->e_id, ee->e_id, msg); |
494 | # endif | |
495 | ||
25414557 EA |
496 | if (strncasecmp(msg, "warning:", 8) != 0) |
497 | { | |
498 | (void) sprintf(buf, "Returned mail: %s", msg); | |
499 | msg = buf; | |
500 | } | |
501 | addheader("Subject", msg, ee); | |
2f6a8a78 EA |
502 | if (SendMIMEErrors) |
503 | { | |
c23930c0 | 504 | addheader("MIME-Version", "1.0", &ee->e_header); |
2f6a8a78 EA |
505 | (void) sprintf(buf, "%s.%ld/%s", |
506 | ee->e_id, curtime(), MyHostName); | |
507 | ee->e_msgboundary = newstr(buf); | |
508 | (void) sprintf(buf, "multipart/mixed; boundary=\"%s\"", | |
509 | ee->e_msgboundary); | |
c23930c0 | 510 | addheader("Content-Type", buf, &ee->e_header); |
2f6a8a78 | 511 | } |
aba51985 EA |
512 | |
513 | /* fake up an address header for the from person */ | |
2bee003d | 514 | expand("\201n", buf, &buf[sizeof buf - 1], e); |
28f94061 | 515 | if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL) |
aba51985 | 516 | { |
b6edea3d | 517 | syserr("553 Can't parse myself!"); |
aba51985 | 518 | ExitStat = EX_SOFTWARE; |
3c7fe765 | 519 | returndepth--; |
aba51985 EA |
520 | return (-1); |
521 | } | |
4a2da288 | 522 | ee->e_sender = ee->e_from.q_paddr; |
79bd7c07 | 523 | |
dd1fe05b EA |
524 | /* push state into submessage */ |
525 | CurEnv = ee; | |
2bee003d | 526 | define('f', "\201n", ee); |
7338e3d4 | 527 | define('x', "Mail Delivery Subsystem", ee); |
959cf51d | 528 | eatheader(ee, TRUE); |
dd1fe05b | 529 | |
8e5c6745 | 530 | /* mark statistics */ |
28f94061 | 531 | markstats(ee, NULLADDR); |
8e5c6745 | 532 | |
dd1fe05b | 533 | /* actually deliver the error message */ |
f7e74083 | 534 | sendall(ee, SM_DEFAULT); |
dd1fe05b | 535 | |
dd1fe05b | 536 | /* restore state */ |
2cce0c26 | 537 | dropenvelope(ee); |
bc854e30 | 538 | CurEnv = oldcur; |
3c7fe765 | 539 | returndepth--; |
79bd7c07 | 540 | |
3c7fe765 | 541 | /* should check for delivery errors here */ |
aba51985 EA |
542 | return (0); |
543 | } | |
544 | \f/* | |
dd1fe05b | 545 | ** ERRBODY -- output the body of an error message. |
b3cbe40f | 546 | ** |
dd1fe05b EA |
547 | ** Typically this is a copy of the transcript plus a copy of the |
548 | ** original offending message. | |
b3cbe40f | 549 | ** |
b3cbe40f | 550 | ** Parameters: |
23fafb99 | 551 | ** mci -- the mailer connection information. |
912acb74 | 552 | ** e -- the envelope we are working in. |
c23930c0 | 553 | ** separator -- any possible MIME separator. |
b3cbe40f EA |
554 | ** |
555 | ** Returns: | |
556 | ** none | |
557 | ** | |
558 | ** Side Effects: | |
dd1fe05b | 559 | ** Outputs the body of an error message. |
b3cbe40f EA |
560 | */ |
561 | ||
c23930c0 | 562 | errbody(mci, e, separator) |
23fafb99 | 563 | register MCI *mci; |
912acb74 | 564 | register ENVELOPE *e; |
c23930c0 | 565 | char *separator; |
b3cbe40f | 566 | { |
9e3c0a28 | 567 | register FILE *xfile; |
e6f08ab1 | 568 | char *p; |
7800dbe0 EA |
569 | register ADDRESS *q; |
570 | bool printheader; | |
571 | char buf[MAXLINE]; | |
b3cbe40f | 572 | |
c23930c0 EA |
573 | if (bitset(MCIF_INHEADER, mci->mci_flags)) |
574 | { | |
575 | putline("", mci); | |
576 | mci->mci_flags &= ~MCIF_INHEADER; | |
577 | } | |
bc854e30 EA |
578 | if (e->e_parent == NULL) |
579 | { | |
580 | syserr("errbody: null parent"); | |
23fafb99 | 581 | putline(" ----- Original message lost -----\n", mci); |
bc854e30 EA |
582 | return; |
583 | } | |
584 | ||
2f6a8a78 EA |
585 | /* |
586 | ** Output MIME header. | |
587 | */ | |
588 | ||
589 | if (e->e_msgboundary != NULL) | |
590 | { | |
23fafb99 EA |
591 | putline("This is a MIME-encapsulated message", mci); |
592 | putline("", mci); | |
2f6a8a78 | 593 | (void) sprintf(buf, "--%s", e->e_msgboundary); |
23fafb99 EA |
594 | putline(buf, mci); |
595 | putline("", mci); | |
2f6a8a78 EA |
596 | } |
597 | ||
329d6249 EA |
598 | /* |
599 | ** Output introductory information. | |
600 | */ | |
601 | ||
fe3849ea EA |
602 | for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) |
603 | if (bitset(QBADADDR, q->q_flags)) | |
604 | break; | |
763a56e2 EA |
605 | if (q == NULL && |
606 | !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) | |
fe3849ea EA |
607 | { |
608 | putline(" **********************************************", | |
23fafb99 | 609 | mci); |
fe3849ea | 610 | putline(" ** THIS IS A WARNING MESSAGE ONLY **", |
23fafb99 | 611 | mci); |
fe3849ea | 612 | putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **", |
23fafb99 | 613 | mci); |
fe3849ea | 614 | putline(" **********************************************", |
23fafb99 EA |
615 | mci); |
616 | putline("", mci); | |
fe3849ea EA |
617 | } |
618 | sprintf(buf, "The original message was received at %s", | |
619 | arpadate(ctime(&e->e_parent->e_ctime))); | |
23fafb99 | 620 | putline(buf, mci); |
78813dfb | 621 | expand("from \201_", buf, &buf[sizeof buf - 1], e->e_parent); |
23fafb99 EA |
622 | putline(buf, mci); |
623 | putline("", mci); | |
329d6249 | 624 | |
44967af8 EA |
625 | /* |
626 | ** Output error message header (if specified and available). | |
627 | */ | |
628 | ||
8a684747 | 629 | if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags)) |
44967af8 EA |
630 | { |
631 | if (*ErrMsgFile == '/') | |
632 | { | |
633 | xfile = fopen(ErrMsgFile, "r"); | |
634 | if (xfile != NULL) | |
635 | { | |
636 | while (fgets(buf, sizeof buf, xfile) != NULL) | |
5d99721e EA |
637 | { |
638 | expand(buf, buf, &buf[sizeof buf - 1], e); | |
23fafb99 | 639 | putline(buf, mci); |
5d99721e | 640 | } |
44967af8 | 641 | (void) fclose(xfile); |
23fafb99 | 642 | putline("\n", mci); |
44967af8 EA |
643 | } |
644 | } | |
645 | else | |
646 | { | |
5d99721e | 647 | expand(ErrMsgFile, buf, &buf[sizeof buf - 1], e); |
23fafb99 EA |
648 | putline(buf, mci); |
649 | putline("", mci); | |
44967af8 EA |
650 | } |
651 | } | |
652 | ||
7800dbe0 EA |
653 | /* |
654 | ** Output message introduction | |
655 | */ | |
656 | ||
657 | printheader = TRUE; | |
658 | for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) | |
659 | { | |
fd57f063 | 660 | if (bitset(QBADADDR|QREPORT, q->q_flags)) |
7800dbe0 EA |
661 | { |
662 | if (printheader) | |
663 | { | |
fd57f063 | 664 | putline(" ----- The following addresses had delivery problems -----", |
23fafb99 | 665 | mci); |
7800dbe0 EA |
666 | printheader = FALSE; |
667 | } | |
37288e8e | 668 | strcpy(buf, q->q_paddr); |
fd57f063 | 669 | if (bitset(QBADADDR, q->q_flags)) |
37288e8e | 670 | strcat(buf, " (unrecoverable error)"); |
9cdb0b30 | 671 | else |
37288e8e | 672 | strcat(buf, " (transient failure)"); |
23fafb99 | 673 | putline(buf, mci); |
37288e8e EA |
674 | if (q->q_alias != NULL) |
675 | { | |
676 | strcpy(buf, " (expanded from: "); | |
677 | strcat(buf, q->q_alias->q_paddr); | |
678 | strcat(buf, ")"); | |
23fafb99 | 679 | putline(buf, mci); |
37288e8e | 680 | } |
7800dbe0 EA |
681 | } |
682 | } | |
683 | if (!printheader) | |
23fafb99 | 684 | putline("\n", mci); |
7800dbe0 | 685 | |
74c5fe7c EA |
686 | /* |
687 | ** Output transcript of errors | |
688 | */ | |
689 | ||
be2fcca9 | 690 | (void) fflush(stdout); |
912acb74 | 691 | p = queuename(e->e_parent, 'x'); |
e6f08ab1 | 692 | if ((xfile = fopen(p, "r")) == NULL) |
be2fcca9 | 693 | { |
e6f08ab1 | 694 | syserr("Cannot open %s", p); |
23fafb99 | 695 | putline(" ----- Transcript of session is unavailable -----\n", mci); |
be2fcca9 EA |
696 | } |
697 | else | |
698 | { | |
23fafb99 | 699 | putline(" ----- Transcript of session follows -----\n", mci); |
912acb74 EA |
700 | if (e->e_xfp != NULL) |
701 | (void) fflush(e->e_xfp); | |
be2fcca9 | 702 | while (fgets(buf, sizeof buf, xfile) != NULL) |
23fafb99 | 703 | putline(buf, mci); |
bc854e30 | 704 | (void) xfclose(xfile, "errbody xscript", p); |
be2fcca9 EA |
705 | } |
706 | errno = 0; | |
74c5fe7c EA |
707 | |
708 | /* | |
709 | ** Output text of original message | |
710 | */ | |
711 | ||
2bade550 | 712 | if (bitset(EF_NORETURN, e->e_flags)) |
09f53401 | 713 | SendBody = FALSE; |
23fafb99 | 714 | putline("", mci); |
bc854e30 | 715 | if (e->e_parent->e_df != NULL) |
738043e8 | 716 | { |
79bd7c07 | 717 | if (SendBody) |
23fafb99 | 718 | putline(" ----- Original message follows -----\n", mci); |
79bd7c07 | 719 | else |
23fafb99 EA |
720 | putline(" ----- Message header follows -----\n", mci); |
721 | (void) fflush(mci->mci_out); | |
2f6a8a78 EA |
722 | |
723 | if (e->e_msgboundary != NULL) | |
724 | { | |
23fafb99 | 725 | putline("", mci); |
2f6a8a78 | 726 | (void) sprintf(buf, "--%s", e->e_msgboundary); |
23fafb99 EA |
727 | putline(buf, mci); |
728 | putline("Content-Type: message/rfc822", mci); | |
729 | putline("", mci); | |
2f6a8a78 | 730 | } |
c23930c0 | 731 | putheader(mci, e->e_parent->e_header, e->e_parent); |
2f6a8a78 | 732 | if (SendBody) |
23fafb99 | 733 | putbody(mci, e->e_parent, e->e_msgboundary); |
58645b30 | 734 | else |
c23930c0 EA |
735 | { |
736 | putline("", mci); | |
23fafb99 | 737 | putline(" ----- Message body suppressed -----", mci); |
c23930c0 | 738 | } |
738043e8 EA |
739 | } |
740 | else | |
4db45bf1 | 741 | { |
23fafb99 | 742 | putline(" ----- No message was collected -----\n", mci); |
4db45bf1 | 743 | } |
74c5fe7c | 744 | |
cbfdff7c EA |
745 | if (e->e_msgboundary != NULL) |
746 | { | |
23fafb99 | 747 | putline("", mci); |
cbfdff7c | 748 | (void) sprintf(buf, "--%s--", e->e_msgboundary); |
23fafb99 | 749 | putline(buf, mci); |
cbfdff7c | 750 | } |
23fafb99 | 751 | putline("", mci); |
2f6a8a78 | 752 | |
74c5fe7c EA |
753 | /* |
754 | ** Cleanup and exit | |
755 | */ | |
756 | ||
b3cbe40f | 757 | if (errno != 0) |
dd1fe05b | 758 | syserr("errbody: I/O error"); |
b3cbe40f | 759 | } |
63d473ff EA |
760 | \f/* |
761 | ** PRUNEROUTE -- prune an RFC-822 source route | |
762 | ** | |
763 | ** Trims down a source route to the last internet-registered hop. | |
764 | ** This is encouraged by RFC 1123 section 5.3.3. | |
765 | ** | |
766 | ** Parameters: | |
767 | ** addr -- the address | |
768 | ** | |
769 | ** Returns: | |
770 | ** TRUE -- address was modified | |
771 | ** FALSE -- address could not be pruned | |
772 | ** | |
773 | ** Side Effects: | |
774 | ** modifies addr in-place | |
775 | */ | |
776 | ||
777 | pruneroute(addr) | |
778 | char *addr; | |
779 | { | |
efe7f723 | 780 | #if NAMED_BIND |
63d473ff EA |
781 | char *start, *at, *comma; |
782 | char c; | |
783 | int rcode; | |
784 | char hostbuf[BUFSIZ]; | |
785 | char *mxhosts[MAXMXHOSTS + 1]; | |
786 | ||
787 | /* check to see if this is really a route-addr */ | |
788 | if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') | |
789 | return FALSE; | |
790 | start = strchr(addr, ':'); | |
791 | at = strrchr(addr, '@'); | |
792 | if (start == NULL || at == NULL || at < start) | |
793 | return FALSE; | |
794 | ||
795 | /* slice off the angle brackets */ | |
796 | strcpy(hostbuf, at + 1); | |
797 | hostbuf[strlen(hostbuf) - 1] = '\0'; | |
798 | ||
799 | while (start) | |
800 | { | |
c3577cd6 | 801 | if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0) |
63d473ff EA |
802 | { |
803 | strcpy(addr + 1, start + 1); | |
804 | return TRUE; | |
805 | } | |
806 | c = *start; | |
807 | *start = '\0'; | |
808 | comma = strrchr(addr, ','); | |
809 | if (comma && comma[1] == '@') | |
810 | strcpy(hostbuf, comma + 2); | |
811 | else | |
812 | comma = 0; | |
813 | *start = c; | |
814 | start = comma; | |
815 | } | |
816 | #endif | |
817 | return FALSE; | |
818 | } |