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