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