Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1983 Eric P. Allman | |
6f14531a RG |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
15637ed4 RG |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #ifndef lint | |
6f14531a | 36 | static char sccsid[] = "@(#)savemail.c 8.1 (Berkeley) 6/7/93"; |
15637ed4 RG |
37 | #endif /* not lint */ |
38 | ||
15637ed4 RG |
39 | # include <pwd.h> |
40 | # include "sendmail.h" | |
41 | ||
42 | /* | |
43 | ** SAVEMAIL -- Save mail on error | |
44 | ** | |
45 | ** If mailing back errors, mail it back to the originator | |
46 | ** together with an error message; otherwise, just put it in | |
47 | ** dead.letter in the user's home directory (if he exists on | |
48 | ** this machine). | |
49 | ** | |
50 | ** Parameters: | |
51 | ** e -- the envelope containing the message in error. | |
52 | ** | |
53 | ** Returns: | |
54 | ** none | |
55 | ** | |
56 | ** Side Effects: | |
57 | ** Saves the letter, by writing or mailing it back to the | |
58 | ** sender, or by putting it in dead.letter in her home | |
59 | ** directory. | |
60 | */ | |
61 | ||
62 | /* defines for state machine */ | |
63 | # define ESM_REPORT 0 /* report to sender's terminal */ | |
64 | # define ESM_MAIL 1 /* mail back to sender */ | |
65 | # define ESM_QUIET 2 /* messages have already been returned */ | |
66 | # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ | |
67 | # define ESM_POSTMASTER 4 /* return to postmaster */ | |
68 | # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ | |
69 | # define ESM_PANIC 6 /* leave the locked queue/transcript files */ | |
70 | # define ESM_DONE 7 /* the message is successfully delivered */ | |
71 | ||
72 | ||
73 | savemail(e) | |
74 | register ENVELOPE *e; | |
75 | { | |
76 | register struct passwd *pw; | |
77 | register FILE *fp; | |
78 | int state; | |
6f14531a | 79 | auto ADDRESS *q = NULL; |
15637ed4 RG |
80 | char buf[MAXLINE+1]; |
81 | extern struct passwd *getpwnam(); | |
82 | register char *p; | |
83 | extern char *ttypath(); | |
84 | typedef int (*fnptr)(); | |
85 | ||
86 | if (tTd(6, 1)) | |
6f14531a RG |
87 | { |
88 | printf("\nsavemail, errormode = %c, id = %s\n e_from=", | |
89 | e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id); | |
90 | printaddr(&e->e_from, FALSE); | |
91 | } | |
15637ed4 | 92 | |
6f14531a | 93 | if (e->e_id == NULL) |
15637ed4 | 94 | { |
6f14531a | 95 | /* can't return a message with no id */ |
15637ed4 RG |
96 | return; |
97 | } | |
6f14531a | 98 | |
15637ed4 RG |
99 | e->e_flags &= ~EF_FATALERRS; |
100 | ||
101 | /* | |
102 | ** In the unhappy event we don't know who to return the mail | |
103 | ** to, make someone up. | |
104 | */ | |
105 | ||
106 | if (e->e_from.q_paddr == NULL) | |
107 | { | |
6f14531a RG |
108 | e->e_sender = "Postmaster"; |
109 | if (parseaddr(e->e_sender, &e->e_from, 0, '\0', NULL, e) == NULL) | |
15637ed4 | 110 | { |
6f14531a | 111 | syserr("553 Cannot parse Postmaster!"); |
15637ed4 RG |
112 | ExitStat = EX_SOFTWARE; |
113 | finis(); | |
114 | } | |
115 | } | |
116 | e->e_to = NULL; | |
117 | ||
118 | /* | |
119 | ** Basic state machine. | |
120 | ** | |
121 | ** This machine runs through the following states: | |
122 | ** | |
123 | ** ESM_QUIET Errors have already been printed iff the | |
124 | ** sender is local. | |
125 | ** ESM_REPORT Report directly to the sender's terminal. | |
126 | ** ESM_MAIL Mail response to the sender. | |
127 | ** ESM_DEADLETTER Save response in ~/dead.letter. | |
128 | ** ESM_POSTMASTER Mail response to the postmaster. | |
129 | ** ESM_PANIC Save response anywhere possible. | |
130 | */ | |
131 | ||
132 | /* determine starting state */ | |
6f14531a | 133 | switch (e->e_errormode) |
15637ed4 RG |
134 | { |
135 | case EM_WRITE: | |
136 | state = ESM_REPORT; | |
137 | break; | |
138 | ||
139 | case EM_BERKNET: | |
140 | /* mail back, but return o.k. exit status */ | |
141 | ExitStat = EX_OK; | |
142 | ||
143 | /* fall through.... */ | |
144 | ||
145 | case EM_MAIL: | |
146 | state = ESM_MAIL; | |
147 | break; | |
148 | ||
149 | case EM_PRINT: | |
150 | case '\0': | |
151 | state = ESM_QUIET; | |
152 | break; | |
153 | ||
154 | case EM_QUIET: | |
155 | /* no need to return anything at all */ | |
156 | return; | |
157 | ||
158 | default: | |
6f14531a | 159 | syserr("554 savemail: bogus errormode x%x\n", e->e_errormode); |
15637ed4 RG |
160 | state = ESM_MAIL; |
161 | break; | |
162 | } | |
163 | ||
6f14531a RG |
164 | /* if this is already an error response, send to postmaster */ |
165 | if (bitset(EF_RESPONSE, e->e_flags)) | |
166 | { | |
167 | if (e->e_parent != NULL && | |
168 | bitset(EF_RESPONSE, e->e_parent->e_flags)) | |
169 | { | |
170 | /* got an error sending a response -- can it */ | |
171 | return; | |
172 | } | |
173 | state = ESM_POSTMASTER; | |
174 | } | |
175 | ||
15637ed4 RG |
176 | while (state != ESM_DONE) |
177 | { | |
178 | if (tTd(6, 5)) | |
179 | printf(" state %d\n", state); | |
180 | ||
181 | switch (state) | |
182 | { | |
183 | case ESM_QUIET: | |
184 | if (e->e_from.q_mailer == LocalMailer) | |
185 | state = ESM_DEADLETTER; | |
186 | else | |
187 | state = ESM_MAIL; | |
188 | break; | |
189 | ||
190 | case ESM_REPORT: | |
191 | ||
192 | /* | |
193 | ** If the user is still logged in on the same terminal, | |
194 | ** then write the error messages back to hir (sic). | |
195 | */ | |
196 | ||
197 | p = ttypath(); | |
198 | if (p == NULL || freopen(p, "w", stdout) == NULL) | |
199 | { | |
200 | state = ESM_MAIL; | |
201 | break; | |
202 | } | |
203 | ||
6f14531a | 204 | expand("\201n", buf, &buf[sizeof buf - 1], e); |
15637ed4 RG |
205 | printf("\r\nMessage from %s...\r\n", buf); |
206 | printf("Errors occurred while sending mail.\r\n"); | |
207 | if (e->e_xfp != NULL) | |
208 | { | |
209 | (void) fflush(e->e_xfp); | |
210 | fp = fopen(queuename(e, 'x'), "r"); | |
211 | } | |
212 | else | |
213 | fp = NULL; | |
214 | if (fp == NULL) | |
215 | { | |
216 | syserr("Cannot open %s", queuename(e, 'x')); | |
217 | printf("Transcript of session is unavailable.\r\n"); | |
218 | } | |
219 | else | |
220 | { | |
221 | printf("Transcript follows:\r\n"); | |
222 | while (fgets(buf, sizeof buf, fp) != NULL && | |
223 | !ferror(stdout)) | |
224 | fputs(buf, stdout); | |
6f14531a | 225 | (void) xfclose(fp, "savemail transcript", e->e_id); |
15637ed4 RG |
226 | } |
227 | printf("Original message will be saved in dead.letter.\r\n"); | |
228 | state = ESM_DEADLETTER; | |
229 | break; | |
230 | ||
231 | case ESM_MAIL: | |
15637ed4 RG |
232 | /* |
233 | ** If mailing back, do it. | |
234 | ** Throw away all further output. Don't alias, | |
235 | ** since this could cause loops, e.g., if joe | |
236 | ** mails to joe@x, and for some reason the network | |
237 | ** for @x is down, then the response gets sent to | |
238 | ** joe@x, which gives a response, etc. Also force | |
239 | ** the mail to be delivered even if a version of | |
240 | ** it has already been sent to the sender. | |
241 | */ | |
242 | ||
6f14531a RG |
243 | if (strcmp(e->e_from.q_paddr, "<>") != 0) |
244 | (void) sendtolist(e->e_from.q_paddr, | |
245 | (ADDRESS *) NULL, | |
246 | &e->e_errorqueue, e); | |
247 | ||
248 | /* deliver a cc: to the postmaster if desired */ | |
249 | if (PostMasterCopy != NULL) | |
15637ed4 | 250 | { |
6f14531a RG |
251 | auto ADDRESS *rlist = NULL; |
252 | ||
253 | (void) sendtolist(PostMasterCopy, | |
254 | (ADDRESS *) NULL, | |
255 | &rlist, e); | |
256 | (void) returntosender(e->e_message, | |
257 | rlist, FALSE, e); | |
15637ed4 | 258 | } |
6f14531a RG |
259 | q = e->e_errorqueue; |
260 | if (q == NULL) | |
15637ed4 | 261 | { |
6f14531a RG |
262 | /* this is an error-error */ |
263 | state = ESM_POSTMASTER; | |
264 | break; | |
15637ed4 | 265 | } |
6f14531a RG |
266 | if (returntosender(e->e_message, |
267 | q, (e->e_class >= 0), e) == 0) | |
15637ed4 RG |
268 | { |
269 | state = ESM_DONE; | |
270 | break; | |
271 | } | |
272 | ||
6f14531a RG |
273 | /* didn't work -- return to postmaster */ |
274 | state = ESM_POSTMASTER; | |
275 | break; | |
276 | ||
277 | case ESM_POSTMASTER: | |
278 | /* | |
279 | ** Similar to previous case, but to system postmaster. | |
280 | */ | |
281 | ||
282 | q = NULL; | |
283 | if (sendtolist("postmaster", NULL, &q, e) <= 0) | |
284 | { | |
285 | syserr("553 cannot parse postmaster!"); | |
286 | ExitStat = EX_SOFTWARE; | |
287 | state = ESM_USRTMP; | |
288 | break; | |
289 | } | |
290 | if (returntosender(e->e_message, | |
291 | q, (e->e_class >= 0), e) == 0) | |
292 | { | |
293 | state = ESM_DONE; | |
294 | break; | |
295 | } | |
296 | ||
297 | /* didn't work -- last resort */ | |
298 | state = ESM_USRTMP; | |
15637ed4 RG |
299 | break; |
300 | ||
301 | case ESM_DEADLETTER: | |
302 | /* | |
303 | ** Save the message in dead.letter. | |
304 | ** If we weren't mailing back, and the user is | |
305 | ** local, we should save the message in | |
306 | ** ~/dead.letter so that the poor person doesn't | |
307 | ** have to type it over again -- and we all know | |
308 | ** what poor typists UNIX users are. | |
309 | */ | |
310 | ||
311 | p = NULL; | |
312 | if (e->e_from.q_mailer == LocalMailer) | |
313 | { | |
314 | if (e->e_from.q_home != NULL) | |
315 | p = e->e_from.q_home; | |
316 | else if ((pw = getpwnam(e->e_from.q_user)) != NULL) | |
317 | p = pw->pw_dir; | |
318 | } | |
319 | if (p == NULL) | |
320 | { | |
6f14531a | 321 | /* no local directory */ |
15637ed4 RG |
322 | state = ESM_MAIL; |
323 | break; | |
324 | } | |
325 | if (e->e_dfp != NULL) | |
326 | { | |
15637ed4 RG |
327 | bool oldverb = Verbose; |
328 | ||
329 | /* we have a home directory; open dead.letter */ | |
330 | define('z', p, e); | |
6f14531a | 331 | expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e); |
15637ed4 | 332 | Verbose = TRUE; |
6f14531a | 333 | message("Saving message in %s", buf); |
15637ed4 RG |
334 | Verbose = oldverb; |
335 | e->e_to = buf; | |
336 | q = NULL; | |
6f14531a | 337 | (void) sendtolist(buf, &e->e_from, &q, e); |
15637ed4 RG |
338 | if (deliver(e, q) == 0) |
339 | state = ESM_DONE; | |
340 | else | |
341 | state = ESM_MAIL; | |
342 | } | |
343 | else | |
344 | { | |
345 | /* no data file -- try mailing back */ | |
346 | state = ESM_MAIL; | |
347 | } | |
348 | break; | |
349 | ||
350 | case ESM_USRTMP: | |
351 | /* | |
352 | ** Log the mail in /usr/tmp/dead.letter. | |
353 | */ | |
354 | ||
6f14531a RG |
355 | if (e->e_class < 0) |
356 | { | |
357 | state = ESM_DONE; | |
358 | break; | |
359 | } | |
360 | ||
361 | fp = dfopen("/usr/tmp/dead.letter", | |
362 | O_WRONLY|O_CREAT|O_APPEND, FileMode); | |
15637ed4 RG |
363 | if (fp == NULL) |
364 | { | |
365 | state = ESM_PANIC; | |
366 | break; | |
367 | } | |
368 | ||
6f14531a RG |
369 | putfromline(fp, FileMailer, e); |
370 | (*e->e_puthdr)(fp, FileMailer, e); | |
371 | putline("\n", fp, FileMailer); | |
372 | (*e->e_putbody)(fp, FileMailer, e, NULL); | |
373 | putline("\n", fp, FileMailer); | |
15637ed4 RG |
374 | (void) fflush(fp); |
375 | state = ferror(fp) ? ESM_PANIC : ESM_DONE; | |
6f14531a | 376 | (void) xfclose(fp, "savemail", "/usr/tmp/dead.letter"); |
15637ed4 RG |
377 | break; |
378 | ||
379 | default: | |
6f14531a | 380 | syserr("554 savemail: unknown state %d", state); |
15637ed4 RG |
381 | |
382 | /* fall through ... */ | |
383 | ||
384 | case ESM_PANIC: | |
15637ed4 | 385 | /* leave the locked queue & transcript files around */ |
6f14531a | 386 | syserr("554 savemail: cannot save rejected email anywhere"); |
15637ed4 RG |
387 | exit(EX_SOFTWARE); |
388 | } | |
389 | } | |
390 | } | |
391 | \f/* | |
392 | ** RETURNTOSENDER -- return a message to the sender with an error. | |
393 | ** | |
394 | ** Parameters: | |
395 | ** msg -- the explanatory message. | |
396 | ** returnq -- the queue of people to send the message to. | |
397 | ** sendbody -- if TRUE, also send back the body of the | |
398 | ** message; otherwise just send the header. | |
6f14531a | 399 | ** e -- the current envelope. |
15637ed4 RG |
400 | ** |
401 | ** Returns: | |
402 | ** zero -- if everything went ok. | |
403 | ** else -- some error. | |
404 | ** | |
405 | ** Side Effects: | |
406 | ** Returns the current message to the sender via | |
407 | ** mail. | |
408 | */ | |
409 | ||
410 | static bool SendBody; | |
411 | ||
412 | #define MAXRETURNS 6 /* max depth of returning messages */ | |
6f14531a | 413 | #define ERRORFUDGE 100 /* nominal size of error message text */ |
15637ed4 | 414 | |
6f14531a | 415 | returntosender(msg, returnq, sendbody, e) |
15637ed4 RG |
416 | char *msg; |
417 | ADDRESS *returnq; | |
418 | bool sendbody; | |
6f14531a | 419 | register ENVELOPE *e; |
15637ed4 RG |
420 | { |
421 | char buf[MAXNAME]; | |
422 | extern putheader(), errbody(); | |
423 | register ENVELOPE *ee; | |
6f14531a | 424 | ENVELOPE *oldcur = CurEnv; |
15637ed4 RG |
425 | ENVELOPE errenvelope; |
426 | static int returndepth; | |
427 | register ADDRESS *q; | |
428 | ||
6f14531a RG |
429 | if (returnq == NULL) |
430 | return (-1); | |
431 | ||
432 | if (msg == NULL) | |
433 | msg = "Unable to deliver mail"; | |
434 | ||
15637ed4 RG |
435 | if (tTd(6, 1)) |
436 | { | |
6f14531a RG |
437 | printf("Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=", |
438 | msg, returndepth, e); | |
15637ed4 RG |
439 | printaddr(returnq, TRUE); |
440 | } | |
441 | ||
442 | if (++returndepth >= MAXRETURNS) | |
443 | { | |
444 | if (returndepth != MAXRETURNS) | |
6f14531a | 445 | syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr); |
15637ed4 RG |
446 | /* don't "unrecurse" and fake a clean exit */ |
447 | /* returndepth--; */ | |
448 | return (0); | |
449 | } | |
450 | ||
451 | SendBody = sendbody; | |
6f14531a RG |
452 | define('g', e->e_from.q_paddr, e); |
453 | ee = newenvelope(&errenvelope, e); | |
454 | define('a', "\201b", ee); | |
455 | define('r', "internal", ee); | |
456 | define('s', "localhost", ee); | |
457 | define('_', "localhost", ee); | |
15637ed4 RG |
458 | ee->e_puthdr = putheader; |
459 | ee->e_putbody = errbody; | |
460 | ee->e_flags |= EF_RESPONSE; | |
6f14531a | 461 | if (!bitset(EF_OLDSTYLE, e->e_flags)) |
15637ed4 RG |
462 | ee->e_flags &= ~EF_OLDSTYLE; |
463 | ee->e_sendqueue = returnq; | |
6f14531a | 464 | ee->e_msgsize = e->e_msgsize + ERRORFUDGE; |
15637ed4 RG |
465 | openxscript(ee); |
466 | for (q = returnq; q != NULL; q = q->q_next) | |
467 | { | |
6f14531a RG |
468 | if (bitset(QBADADDR, q->q_flags)) |
469 | continue; | |
470 | ||
471 | if (!bitset(QDONTSEND, q->q_flags)) | |
472 | ee->e_nrcpts++; | |
473 | ||
474 | if (!DontPruneRoutes && pruneroute(q->q_paddr)) | |
475 | parseaddr(q->q_paddr, q, 0, '\0', NULL, e); | |
476 | ||
15637ed4 | 477 | if (q->q_alias == NULL) |
6f14531a | 478 | addheader("To", q->q_paddr, ee); |
15637ed4 RG |
479 | } |
480 | ||
6f14531a RG |
481 | # ifdef LOG |
482 | if (LogLevel > 5) | |
483 | syslog(LOG_INFO, "%s: %s: return to sender: %s", | |
484 | e->e_id, ee->e_id, msg); | |
485 | # endif | |
486 | ||
15637ed4 | 487 | (void) sprintf(buf, "Returned mail: %s", msg); |
6f14531a RG |
488 | addheader("Subject", buf, ee); |
489 | if (SendMIMEErrors) | |
490 | { | |
491 | addheader("MIME-Version", "1.0", ee); | |
492 | (void) sprintf(buf, "%s.%ld/%s", | |
493 | ee->e_id, curtime(), MyHostName); | |
494 | ee->e_msgboundary = newstr(buf); | |
495 | (void) sprintf(buf, "multipart/mixed; boundary=\"%s\"", | |
496 | ee->e_msgboundary); | |
497 | addheader("Content-Type", buf, ee); | |
498 | } | |
15637ed4 RG |
499 | |
500 | /* fake up an address header for the from person */ | |
6f14531a RG |
501 | expand("\201n", buf, &buf[sizeof buf - 1], e); |
502 | if (parseaddr(buf, &ee->e_from, 1, '\0', NULL, e) == NULL) | |
15637ed4 | 503 | { |
6f14531a | 504 | syserr("553 Can't parse myself!"); |
15637ed4 RG |
505 | ExitStat = EX_SOFTWARE; |
506 | returndepth--; | |
507 | return (-1); | |
508 | } | |
6f14531a | 509 | ee->e_sender = ee->e_from.q_paddr; |
15637ed4 RG |
510 | |
511 | /* push state into submessage */ | |
512 | CurEnv = ee; | |
6f14531a | 513 | define('f', "\201n", ee); |
15637ed4 | 514 | define('x', "Mail Delivery Subsystem", ee); |
6f14531a | 515 | eatheader(ee, TRUE); |
15637ed4 RG |
516 | |
517 | /* actually deliver the error message */ | |
518 | sendall(ee, SM_DEFAULT); | |
519 | ||
520 | /* restore state */ | |
521 | dropenvelope(ee); | |
6f14531a | 522 | CurEnv = oldcur; |
15637ed4 RG |
523 | returndepth--; |
524 | ||
525 | /* should check for delivery errors here */ | |
526 | return (0); | |
527 | } | |
528 | \f/* | |
529 | ** ERRBODY -- output the body of an error message. | |
530 | ** | |
531 | ** Typically this is a copy of the transcript plus a copy of the | |
532 | ** original offending message. | |
533 | ** | |
534 | ** Parameters: | |
535 | ** fp -- the output file. | |
536 | ** m -- the mailer to output to. | |
537 | ** e -- the envelope we are working in. | |
538 | ** | |
539 | ** Returns: | |
540 | ** none | |
541 | ** | |
542 | ** Side Effects: | |
543 | ** Outputs the body of an error message. | |
544 | */ | |
545 | ||
546 | errbody(fp, m, e) | |
547 | register FILE *fp; | |
548 | register struct mailer *m; | |
549 | register ENVELOPE *e; | |
550 | { | |
551 | register FILE *xfile; | |
15637ed4 | 552 | char *p; |
6f14531a RG |
553 | register ADDRESS *q; |
554 | bool printheader; | |
555 | char buf[MAXLINE]; | |
556 | ||
557 | if (e->e_parent == NULL) | |
558 | { | |
559 | syserr("errbody: null parent"); | |
560 | putline(" ----- Original message lost -----\n", fp, m); | |
561 | return; | |
562 | } | |
563 | ||
564 | /* | |
565 | ** Output MIME header. | |
566 | */ | |
567 | ||
568 | if (e->e_msgboundary != NULL) | |
569 | { | |
570 | putline("This is a MIME-encapsulated message", fp, m); | |
571 | putline("", fp, m); | |
572 | (void) sprintf(buf, "--%s", e->e_msgboundary); | |
573 | putline(buf, fp, m); | |
574 | putline("", fp, m); | |
575 | } | |
576 | ||
577 | /* | |
578 | ** Output error message header (if specified and available). | |
579 | */ | |
580 | ||
581 | if (ErrMsgFile != NULL) | |
582 | { | |
583 | if (*ErrMsgFile == '/') | |
584 | { | |
585 | xfile = fopen(ErrMsgFile, "r"); | |
586 | if (xfile != NULL) | |
587 | { | |
588 | while (fgets(buf, sizeof buf, xfile) != NULL) | |
589 | { | |
590 | expand(buf, buf, &buf[sizeof buf - 1], e); | |
591 | putline(buf, fp, m); | |
592 | } | |
593 | (void) fclose(xfile); | |
594 | putline("\n", fp, m); | |
595 | } | |
596 | } | |
597 | else | |
598 | { | |
599 | expand(ErrMsgFile, buf, &buf[sizeof buf - 1], e); | |
600 | putline(buf, fp, m); | |
601 | putline("", fp, m); | |
602 | } | |
603 | } | |
604 | ||
605 | /* | |
606 | ** Output message introduction | |
607 | */ | |
608 | ||
609 | printheader = TRUE; | |
610 | for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) | |
611 | { | |
612 | if (bitset(QBADADDR, q->q_flags)) | |
613 | { | |
614 | if (printheader) | |
615 | { | |
616 | putline(" ----- The following addresses failed -----", | |
617 | fp, m); | |
618 | printheader = FALSE; | |
619 | } | |
620 | if (q->q_alias != NULL) | |
621 | putline(q->q_alias->q_paddr, fp, m); | |
622 | else | |
623 | putline(q->q_paddr, fp, m); | |
624 | } | |
625 | } | |
626 | if (!printheader) | |
627 | putline("\n", fp, m); | |
15637ed4 RG |
628 | |
629 | /* | |
630 | ** Output transcript of errors | |
631 | */ | |
632 | ||
633 | (void) fflush(stdout); | |
634 | p = queuename(e->e_parent, 'x'); | |
635 | if ((xfile = fopen(p, "r")) == NULL) | |
636 | { | |
637 | syserr("Cannot open %s", p); | |
6f14531a | 638 | putline(" ----- Transcript of session is unavailable -----\n", fp, m); |
15637ed4 RG |
639 | } |
640 | else | |
641 | { | |
6f14531a | 642 | putline(" ----- Transcript of session follows -----\n", fp, m); |
15637ed4 RG |
643 | if (e->e_xfp != NULL) |
644 | (void) fflush(e->e_xfp); | |
645 | while (fgets(buf, sizeof buf, xfile) != NULL) | |
646 | putline(buf, fp, m); | |
6f14531a | 647 | (void) xfclose(xfile, "errbody xscript", p); |
15637ed4 RG |
648 | } |
649 | errno = 0; | |
650 | ||
651 | /* | |
652 | ** Output text of original message | |
653 | */ | |
654 | ||
655 | if (NoReturn) | |
6f14531a RG |
656 | SendBody = FALSE; |
657 | putline("", fp, m); | |
658 | if (e->e_parent->e_df != NULL) | |
15637ed4 RG |
659 | { |
660 | if (SendBody) | |
15637ed4 | 661 | putline(" ----- Unsent message follows -----\n", fp, m); |
15637ed4 | 662 | else |
6f14531a RG |
663 | putline(" ----- Message header follows -----\n", fp, m); |
664 | (void) fflush(fp); | |
665 | ||
666 | if (e->e_msgboundary != NULL) | |
15637ed4 | 667 | { |
6f14531a RG |
668 | putline("", fp, m); |
669 | (void) sprintf(buf, "--%s", e->e_msgboundary); | |
670 | putline(buf, fp, m); | |
671 | putline("Content-Type: message/rfc822", fp, m); | |
672 | putline("", fp, m); | |
15637ed4 | 673 | } |
6f14531a RG |
674 | putheader(fp, m, e->e_parent); |
675 | putline("", fp, m); | |
676 | if (SendBody) | |
677 | putbody(fp, m, e->e_parent, e->e_msgboundary); | |
678 | else | |
679 | putline(" ----- Message body suppressed -----", fp, m); | |
15637ed4 RG |
680 | } |
681 | else | |
682 | { | |
15637ed4 | 683 | putline(" ----- No message was collected -----\n", fp, m); |
15637ed4 RG |
684 | } |
685 | ||
6f14531a RG |
686 | if (e->e_msgboundary != NULL) |
687 | { | |
688 | putline("", fp, m); | |
689 | (void) sprintf(buf, "--%s--", e->e_msgboundary); | |
690 | putline(buf, fp, m); | |
691 | } | |
692 | putline("", fp, m); | |
693 | ||
15637ed4 RG |
694 | /* |
695 | ** Cleanup and exit | |
696 | */ | |
697 | ||
698 | if (errno != 0) | |
699 | syserr("errbody: I/O error"); | |
700 | } | |
6f14531a RG |
701 | \f/* |
702 | ** PRUNEROUTE -- prune an RFC-822 source route | |
703 | ** | |
704 | ** Trims down a source route to the last internet-registered hop. | |
705 | ** This is encouraged by RFC 1123 section 5.3.3. | |
706 | ** | |
707 | ** Parameters: | |
708 | ** addr -- the address | |
709 | ** | |
710 | ** Returns: | |
711 | ** TRUE -- address was modified | |
712 | ** FALSE -- address could not be pruned | |
713 | ** | |
714 | ** Side Effects: | |
715 | ** modifies addr in-place | |
716 | */ | |
717 | ||
718 | pruneroute(addr) | |
719 | char *addr; | |
720 | { | |
721 | #ifdef NAMED_BIND | |
722 | char *start, *at, *comma; | |
723 | char c; | |
724 | int rcode; | |
725 | char hostbuf[BUFSIZ]; | |
726 | char *mxhosts[MAXMXHOSTS + 1]; | |
727 | ||
728 | /* check to see if this is really a route-addr */ | |
729 | if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') | |
730 | return FALSE; | |
731 | start = strchr(addr, ':'); | |
732 | at = strrchr(addr, '@'); | |
733 | if (start == NULL || at == NULL || at < start) | |
734 | return FALSE; | |
735 | ||
736 | /* slice off the angle brackets */ | |
737 | strcpy(hostbuf, at + 1); | |
738 | hostbuf[strlen(hostbuf) - 1] = '\0'; | |
739 | ||
740 | while (start) | |
741 | { | |
742 | if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0) | |
743 | { | |
744 | strcpy(addr + 1, start + 1); | |
745 | return TRUE; | |
746 | } | |
747 | c = *start; | |
748 | *start = '\0'; | |
749 | comma = strrchr(addr, ','); | |
750 | if (comma && comma[1] == '@') | |
751 | strcpy(hostbuf, comma + 2); | |
752 | else | |
753 | comma = 0; | |
754 | *start = c; | |
755 | start = comma; | |
756 | } | |
757 | #endif | |
758 | return FALSE; | |
759 | } |