1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)savemail.c 8.39 (Berkeley) 11/20/94"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <pwd.h> 15 16 /* 17 ** SAVEMAIL -- Save mail on error 18 ** 19 ** If mailing back errors, mail it back to the originator 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: 25 ** e -- the envelope containing the message in error. 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. 34 */ 35 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 # ifndef _PATH_VARTMP 47 # define _PATH_VARTMP "/usr/tmp/" 48 # endif 49 50 51 savemail(e) 52 register ENVELOPE *e; 53 { 54 register struct passwd *pw; 55 register FILE *fp; 56 int state; 57 auto ADDRESS *q = NULL; 58 register char *p; 59 MCI mcibuf; 60 char buf[MAXLINE+1]; 61 extern struct passwd *getpwnam(); 62 extern char *ttypath(); 63 typedef int (*fnptr)(); 64 extern bool writable(); 65 66 if (tTd(6, 1)) 67 { 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); 71 printaddr(&e->e_from, FALSE); 72 } 73 74 if (e->e_id == NULL) 75 { 76 /* can't return a message with no id */ 77 return; 78 } 79 80 /* 81 ** In the unhappy event we don't know who to return the mail 82 ** to, make someone up. 83 */ 84 85 if (e->e_from.q_paddr == NULL) 86 { 87 e->e_sender = "Postmaster"; 88 if (parseaddr(e->e_sender, &e->e_from, 89 RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL) 90 { 91 syserr("553 Cannot parse Postmaster!"); 92 ExitStat = EX_SOFTWARE; 93 finis(); 94 } 95 } 96 e->e_to = NULL; 97 98 /* 99 ** Basic state machine. 100 ** 101 ** This machine runs through the following states: 102 ** 103 ** ESM_QUIET Errors have already been printed iff the 104 ** sender is local. 105 ** ESM_REPORT Report directly to the sender's terminal. 106 ** ESM_MAIL Mail response to the sender. 107 ** ESM_DEADLETTER Save response in ~/dead.letter. 108 ** ESM_POSTMASTER Mail response to the postmaster. 109 ** ESM_PANIC Save response anywhere possible. 110 */ 111 112 /* determine starting state */ 113 switch (e->e_errormode) 114 { 115 case EM_WRITE: 116 state = ESM_REPORT; 117 break; 118 119 case EM_BERKNET: 120 /* mail back, but return o.k. exit status */ 121 ExitStat = EX_OK; 122 123 /* fall through.... */ 124 125 case EM_MAIL: 126 state = ESM_MAIL; 127 break; 128 129 case EM_PRINT: 130 case '\0': 131 state = ESM_QUIET; 132 break; 133 134 case EM_QUIET: 135 /* no need to return anything at all */ 136 return; 137 138 default: 139 syserr("554 savemail: bogus errormode x%x\n", e->e_errormode); 140 state = ESM_MAIL; 141 break; 142 } 143 144 /* if this is already an error response, send to postmaster */ 145 if (bitset(EF_RESPONSE, e->e_flags)) 146 { 147 if (e->e_parent != NULL && 148 bitset(EF_RESPONSE, e->e_parent->e_flags)) 149 { 150 /* got an error sending a response -- can it */ 151 return; 152 } 153 state = ESM_POSTMASTER; 154 } 155 156 while (state != ESM_DONE) 157 { 158 if (tTd(6, 5)) 159 printf(" state %d\n", state); 160 161 switch (state) 162 { 163 case ESM_QUIET: 164 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags)) 165 state = ESM_DEADLETTER; 166 else 167 state = ESM_MAIL; 168 break; 169 170 case ESM_REPORT: 171 172 /* 173 ** If the user is still logged in on the same terminal, 174 ** then write the error messages back to hir (sic). 175 */ 176 177 p = ttypath(); 178 if (p == NULL || freopen(p, "w", stdout) == NULL) 179 { 180 state = ESM_MAIL; 181 break; 182 } 183 184 expand("\201n", buf, &buf[sizeof buf - 1], e); 185 printf("\r\nMessage from %s...\r\n", buf); 186 printf("Errors occurred while sending mail.\r\n"); 187 if (e->e_xfp != NULL) 188 { 189 (void) fflush(e->e_xfp); 190 fp = fopen(queuename(e, 'x'), "r"); 191 } 192 else 193 fp = NULL; 194 if (fp == NULL) 195 { 196 syserr("Cannot open %s", queuename(e, 'x')); 197 printf("Transcript of session is unavailable.\r\n"); 198 } 199 else 200 { 201 printf("Transcript follows:\r\n"); 202 while (fgets(buf, sizeof buf, fp) != NULL && 203 !ferror(stdout)) 204 fputs(buf, stdout); 205 (void) xfclose(fp, "savemail transcript", e->e_id); 206 } 207 printf("Original message will be saved in dead.letter.\r\n"); 208 state = ESM_DEADLETTER; 209 break; 210 211 case ESM_MAIL: 212 /* 213 ** If mailing back, do it. 214 ** Throw away all further output. Don't alias, 215 ** since this could cause loops, e.g., if joe 216 ** mails to joe@x, and for some reason the network 217 ** for @x is down, then the response gets sent to 218 ** joe@x, which gives a response, etc. Also force 219 ** the mail to be delivered even if a version of 220 ** it has already been sent to the sender. 221 ** 222 ** If this is a configuration or local software 223 ** error, send to the local postmaster as well, 224 ** since the originator can't do anything 225 ** about it anyway. Note that this is a full 226 ** copy of the message (intentionally) so that 227 ** the Postmaster can forward things along. 228 */ 229 230 if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE) 231 { 232 (void) sendtolist("postmaster", 233 NULLADDR, &e->e_errorqueue, e); 234 } 235 if (!emptyaddr(&e->e_from)) 236 { 237 (void) sendtolist(e->e_from.q_paddr, 238 NULLADDR, &e->e_errorqueue, e); 239 } 240 241 /* 242 ** Deliver a non-delivery report to the 243 ** Postmaster-designate (not necessarily 244 ** Postmaster). This does not include the 245 ** body of the message, for privacy reasons. 246 ** You really shouldn't need this. 247 */ 248 249 e->e_flags |= EF_PM_NOTIFY; 250 251 /* check to see if there are any good addresses */ 252 for (q = e->e_errorqueue; q != NULL; q = q->q_next) 253 if (!bitset(QBADADDR|QDONTSEND, q->q_flags)) 254 break; 255 if (q == NULL) 256 { 257 /* this is an error-error */ 258 state = ESM_POSTMASTER; 259 break; 260 } 261 if (returntosender(e->e_message, e->e_errorqueue, 262 (e->e_class >= 0), e) == 0) 263 { 264 state = ESM_DONE; 265 break; 266 } 267 268 /* didn't work -- return to postmaster */ 269 state = ESM_POSTMASTER; 270 break; 271 272 case ESM_POSTMASTER: 273 /* 274 ** Similar to previous case, but to system postmaster. 275 */ 276 277 q = NULL; 278 if (sendtolist("postmaster", NULL, &q, e) <= 0) 279 { 280 syserr("553 cannot parse postmaster!"); 281 ExitStat = EX_SOFTWARE; 282 state = ESM_USRTMP; 283 break; 284 } 285 if (returntosender(e->e_message, 286 q, (e->e_class >= 0), e) == 0) 287 { 288 state = ESM_DONE; 289 break; 290 } 291 292 /* didn't work -- last resort */ 293 state = ESM_USRTMP; 294 break; 295 296 case ESM_DEADLETTER: 297 /* 298 ** Save the message in dead.letter. 299 ** If we weren't mailing back, and the user is 300 ** local, we should save the message in 301 ** ~/dead.letter so that the poor person doesn't 302 ** have to type it over again -- and we all know 303 ** what poor typists UNIX users are. 304 */ 305 306 p = NULL; 307 if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags)) 308 { 309 if (e->e_from.q_home != NULL) 310 p = e->e_from.q_home; 311 else if ((pw = getpwnam(e->e_from.q_user)) != NULL) 312 p = pw->pw_dir; 313 } 314 if (p == NULL) 315 { 316 /* no local directory */ 317 state = ESM_MAIL; 318 break; 319 } 320 if (e->e_dfp != NULL) 321 { 322 bool oldverb = Verbose; 323 324 /* we have a home directory; open dead.letter */ 325 define('z', p, e); 326 expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e); 327 Verbose = TRUE; 328 message("Saving message in %s", buf); 329 Verbose = oldverb; 330 e->e_to = buf; 331 q = NULL; 332 (void) sendtolist(buf, &e->e_from, &q, e); 333 if (q != NULL && 334 !bitset(QBADADDR, q->q_flags) && 335 deliver(e, q) == 0) 336 state = ESM_DONE; 337 else 338 state = ESM_MAIL; 339 } 340 else 341 { 342 /* no data file -- try mailing back */ 343 state = ESM_MAIL; 344 } 345 break; 346 347 case ESM_USRTMP: 348 /* 349 ** Log the mail in /usr/tmp/dead.letter. 350 */ 351 352 if (e->e_class < 0) 353 { 354 state = ESM_DONE; 355 break; 356 } 357 358 strcpy(buf, _PATH_VARTMP); 359 strcat(buf, "dead.letter"); 360 if (!writable(buf, NULLADDR, SFF_NOSLINK)) 361 { 362 state = ESM_PANIC; 363 break; 364 } 365 fp = dfopen(buf, O_WRONLY|O_CREAT|O_APPEND, FileMode); 366 if (fp == NULL) 367 { 368 state = ESM_PANIC; 369 break; 370 } 371 372 bzero(&mcibuf, sizeof mcibuf); 373 mcibuf.mci_out = fp; 374 mcibuf.mci_mailer = FileMailer; 375 if (bitnset(M_7BITS, FileMailer->m_flags)) 376 mcibuf.mci_flags |= MCIF_7BIT; 377 378 putfromline(&mcibuf, e); 379 (*e->e_puthdr)(&mcibuf, e->e_header, e, 0); 380 (*e->e_putbody)(&mcibuf, e, NULL, 0); 381 putline("\n", &mcibuf); 382 (void) fflush(fp); 383 state = ferror(fp) ? ESM_PANIC : ESM_DONE; 384 (void) xfclose(fp, "savemail", buf); 385 break; 386 387 default: 388 syserr("554 savemail: unknown state %d", state); 389 390 /* fall through ... */ 391 392 case ESM_PANIC: 393 /* leave the locked queue & transcript files around */ 394 syserr("!554 savemail: cannot save rejected email anywhere"); 395 } 396 } 397 } 398 /* 399 ** RETURNTOSENDER -- return a message to the sender with an error. 400 ** 401 ** Parameters: 402 ** msg -- the explanatory message. 403 ** returnq -- the queue of people to send the message to. 404 ** sendbody -- if TRUE, also send back the body of the 405 ** message; otherwise just send the header. 406 ** e -- the current envelope. 407 ** 408 ** Returns: 409 ** zero -- if everything went ok. 410 ** else -- some error. 411 ** 412 ** Side Effects: 413 ** Returns the current message to the sender via 414 ** mail. 415 */ 416 417 static bool SendBody; 418 419 #define MAXRETURNS 6 /* max depth of returning messages */ 420 #define ERRORFUDGE 100 /* nominal size of error message text */ 421 422 returntosender(msg, returnq, sendbody, e) 423 char *msg; 424 ADDRESS *returnq; 425 bool sendbody; 426 register ENVELOPE *e; 427 { 428 char buf[MAXNAME]; 429 extern putheader(), errbody(); 430 register ENVELOPE *ee; 431 ENVELOPE *oldcur = CurEnv; 432 ENVELOPE errenvelope; 433 static int returndepth; 434 register ADDRESS *q; 435 436 if (returnq == NULL) 437 return (-1); 438 439 if (msg == NULL) 440 msg = "Unable to deliver mail"; 441 442 if (tTd(6, 1)) 443 { 444 printf("Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=", 445 msg, returndepth, e); 446 printaddr(returnq, TRUE); 447 } 448 449 if (++returndepth >= MAXRETURNS) 450 { 451 if (returndepth != MAXRETURNS) 452 syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr); 453 /* don't "unrecurse" and fake a clean exit */ 454 /* returndepth--; */ 455 return (0); 456 } 457 458 SendBody = sendbody; 459 define('g', e->e_from.q_paddr, e); 460 define('u', NULL, e); 461 462 /* initialize error envelope */ 463 ee = newenvelope(&errenvelope, e); 464 define('a', "\201b", ee); 465 define('r', "internal", ee); 466 define('s', "localhost", ee); 467 define('_', "localhost", ee); 468 ee->e_puthdr = putheader; 469 ee->e_putbody = errbody; 470 ee->e_flags |= EF_RESPONSE|EF_METOO; 471 if (!bitset(EF_OLDSTYLE, e->e_flags)) 472 ee->e_flags &= ~EF_OLDSTYLE; 473 ee->e_sendqueue = returnq; 474 ee->e_msgsize = ERRORFUDGE; 475 if (!bitset(EF_NORETURN, e->e_flags)) 476 ee->e_msgsize += e->e_msgsize; 477 initsys(ee); 478 for (q = returnq; q != NULL; q = q->q_next) 479 { 480 if (bitset(QBADADDR, q->q_flags)) 481 continue; 482 483 if (!bitset(QDONTSEND, q->q_flags)) 484 ee->e_nrcpts++; 485 486 if (!DontPruneRoutes && pruneroute(q->q_paddr)) 487 parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e); 488 489 if (q->q_alias == NULL) 490 addheader("To", q->q_paddr, &ee->e_header); 491 } 492 493 # ifdef LOG 494 if (LogLevel > 5) 495 syslog(LOG_INFO, "%s: %s: return to sender: %s", 496 e->e_id, ee->e_id, msg); 497 # endif 498 499 if (strncmp(msg, "Warning:", 8) == 0) 500 { 501 addheader("Subject", msg, ee); 502 addheader("Precedence", "autoreply warning-timeout", &ee->e_header); 503 } 504 else if (strcmp(msg, "Return receipt") == 0) 505 { 506 addheader("Subject", msg, ee); 507 addheader("Precedence", "autoreply return-receipt", &ee->e_header); 508 } 509 else 510 { 511 sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg); 512 addheader("Subject", buf, &ee->e_header); 513 addheader("Precedence", "autoreply failure-message", &ee->e_header); 514 } 515 if (SendMIMEErrors) 516 { 517 addheader("MIME-Version", "1.0", &ee->e_header); 518 (void) sprintf(buf, "%s.%ld/%s", 519 ee->e_id, curtime(), MyHostName); 520 ee->e_msgboundary = newstr(buf); 521 (void) sprintf(buf, 522 "multipart/report; report-type=delivery-status; boundary=\"%s\"", 523 ee->e_msgboundary); 524 addheader("Content-Type", buf, &ee->e_header); 525 } 526 527 /* fake up an address header for the from person */ 528 expand("\201n", buf, &buf[sizeof buf - 1], e); 529 if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL) 530 { 531 syserr("553 Can't parse myself!"); 532 ExitStat = EX_SOFTWARE; 533 returndepth--; 534 return (-1); 535 } 536 ee->e_sender = ee->e_from.q_paddr; 537 538 /* push state into submessage */ 539 CurEnv = ee; 540 define('f', "\201n", ee); 541 define('x', "Mail Delivery Subsystem", ee); 542 eatheader(ee, TRUE); 543 544 /* mark statistics */ 545 markstats(ee, NULLADDR); 546 547 /* actually deliver the error message */ 548 sendall(ee, SM_DEFAULT); 549 550 /* restore state */ 551 dropenvelope(ee); 552 CurEnv = oldcur; 553 returndepth--; 554 555 /* should check for delivery errors here */ 556 return (0); 557 } 558 /* 559 ** ERRBODY -- output the body of an error message. 560 ** 561 ** Typically this is a copy of the transcript plus a copy of the 562 ** original offending message. 563 ** 564 ** Parameters: 565 ** mci -- the mailer connection information. 566 ** e -- the envelope we are working in. 567 ** separator -- any possible MIME separator. 568 ** flags -- to modify the behaviour. 569 ** 570 ** Returns: 571 ** none 572 ** 573 ** Side Effects: 574 ** Outputs the body of an error message. 575 */ 576 577 errbody(mci, e, separator, flags) 578 register MCI *mci; 579 register ENVELOPE *e; 580 char *separator; 581 { 582 register FILE *xfile; 583 char *p; 584 register ADDRESS *q; 585 bool printheader; 586 int pflags = flags; 587 char buf[MAXLINE]; 588 589 if (bitset(MCIF_INHEADER, mci->mci_flags)) 590 { 591 putline("", mci); 592 mci->mci_flags &= ~MCIF_INHEADER; 593 } 594 if (e->e_parent == NULL) 595 { 596 syserr("errbody: null parent"); 597 putline(" ----- Original message lost -----\n", mci); 598 return; 599 } 600 601 /* 602 ** Output MIME header. 603 */ 604 605 if (e->e_msgboundary != NULL) 606 { 607 putline("This is a MIME-encapsulated message", mci); 608 putline("", mci); 609 (void) sprintf(buf, "--%s", e->e_msgboundary); 610 putline(buf, mci); 611 putline("", mci); 612 } 613 614 /* 615 ** Output introductory information. 616 */ 617 618 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 619 if (bitset(QBADADDR, q->q_flags)) 620 break; 621 if (q == NULL && 622 !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) 623 { 624 putline(" **********************************************", 625 mci); 626 putline(" ** THIS IS A WARNING MESSAGE ONLY **", 627 mci); 628 putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **", 629 mci); 630 putline(" **********************************************", 631 mci); 632 putline("", mci); 633 } 634 sprintf(buf, "The original message was received at %s", 635 arpadate(ctime(&e->e_parent->e_ctime))); 636 putline(buf, mci); 637 expand("from \201_", buf, &buf[sizeof buf - 1], e->e_parent); 638 putline(buf, mci); 639 putline("", mci); 640 641 /* 642 ** Output error message header (if specified and available). 643 */ 644 645 if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags)) 646 { 647 if (*ErrMsgFile == '/') 648 { 649 xfile = fopen(ErrMsgFile, "r"); 650 if (xfile != NULL) 651 { 652 while (fgets(buf, sizeof buf, xfile) != NULL) 653 { 654 expand(buf, buf, &buf[sizeof buf - 1], e); 655 putline(buf, mci); 656 } 657 (void) fclose(xfile); 658 putline("\n", mci); 659 } 660 } 661 else 662 { 663 expand(ErrMsgFile, buf, &buf[sizeof buf - 1], e); 664 putline(buf, mci); 665 putline("", mci); 666 } 667 } 668 669 /* 670 ** Output message introduction 671 */ 672 673 printheader = TRUE; 674 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 675 { 676 if (bitset(QBADADDR|QREPORT, q->q_flags)) 677 { 678 if (printheader) 679 { 680 putline(" ----- The following addresses have delivery notifications -----", 681 mci); 682 printheader = FALSE; 683 } 684 strcpy(buf, q->q_paddr); 685 if (bitset(QBADADDR, q->q_flags)) 686 strcat(buf, " (unrecoverable error)"); 687 else if (bitset(QSENT, q->q_flags)) 688 strcat(buf, " (successfully delivered)"); 689 else 690 strcat(buf, " (transient failure)"); 691 putline(buf, mci); 692 if (q->q_alias != NULL) 693 { 694 strcpy(buf, " (expanded from: "); 695 strcat(buf, q->q_alias->q_paddr); 696 strcat(buf, ")"); 697 putline(buf, mci); 698 } 699 } 700 } 701 if (!printheader) 702 putline("\n", mci); 703 704 /* 705 ** Output transcript of errors 706 */ 707 708 (void) fflush(stdout); 709 p = queuename(e->e_parent, 'x'); 710 if ((xfile = fopen(p, "r")) == NULL) 711 { 712 syserr("Cannot open %s", p); 713 putline(" ----- Transcript of session is unavailable -----\n", mci); 714 } 715 else 716 { 717 putline(" ----- Transcript of session follows -----\n", mci); 718 if (e->e_xfp != NULL) 719 (void) fflush(e->e_xfp); 720 while (fgets(buf, sizeof buf, xfile) != NULL) 721 putline(buf, mci); 722 (void) xfclose(xfile, "errbody xscript", p); 723 } 724 errno = 0; 725 726 /* 727 ** Output machine-readable version. 728 */ 729 730 if (e->e_msgboundary != NULL) 731 { 732 putline("", mci); 733 (void) sprintf(buf, "--%s", e->e_msgboundary); 734 putline(buf, mci); 735 putline("Content-Type: message/delivery-status", mci); 736 putline("", mci); 737 738 /* 739 ** Output per-message information. 740 */ 741 742 /* Original-MTS-Type: is optional */ 743 744 /* original envelope id from MAIL FROM: line */ 745 if (e->e_parent->e_envid != NULL) 746 { 747 (void) sprintf(buf, "Original-Envelope-Id: %s", 748 e->e_parent->e_envid); 749 putline(buf, mci); 750 } 751 752 /* Final-MTS-Type: is optional (always INET?) */ 753 754 /* Final-MTA: seems silly -- this is in the From: line */ 755 (void) sprintf(buf, "Final-MTA: %s", MyHostName); 756 putline(buf, mci); 757 758 /* 759 ** Output per-address information. 760 */ 761 762 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 763 { 764 register ADDRESS *r; 765 766 if (!bitset(QBADADDR|QREPORT|QRELAYED, q->q_flags)) 767 continue; 768 putline("", mci); 769 770 /* Rcpt: -- the name from the RCPT command */ 771 for (r = q; r->q_alias != NULL; r = r->q_alias) 772 continue; 773 (void) sprintf(buf, "Rcpt: %s", r->q_paddr); 774 putline(buf, mci); 775 776 /* Action: -- what happened? */ 777 if (bitset(QBADADDR, q->q_flags)) 778 putline("Action: failed", mci); 779 else if (bitset(QQUEUEUP, q->q_flags)) 780 putline("Action: delayed", mci); 781 else if (bitset(QRELAYED, q->q_flags)) 782 putline("Action: relayed", mci); 783 else 784 putline("Action: delivered", mci); 785 786 /* Status: -- what _really_ happened? */ 787 strcpy(buf, "Status: "); 788 if (q->q_status != NULL) 789 strcat(buf, q->q_status); 790 else if (bitset(QBADADDR, q->q_flags)) 791 strcat(buf, "500"); 792 else if (bitset(QQUEUEUP, q->q_flags)) 793 strcat(buf, "400"); 794 else if (bitset(QRELAYED, q->q_flags)) 795 strcat(buf, "601"); 796 else 797 strcat(buf, "200"); 798 putline(buf, mci); 799 800 /* Date: -- fine granularity */ 801 if (q->q_statdate == (time_t) 0L) 802 q->q_statdate = curtime(); 803 (void) sprintf(buf, "Date: %s", 804 arpadate(ctime(&q->q_statdate))); 805 putline(buf, mci); 806 807 /* Final-Log-Id: -- why isn't this per-message? */ 808 (void) sprintf(buf, "Final-Log-Id: %s", e->e_id); 809 putline(buf, mci); 810 811 /* Original-Rcpt: -- passed from on high */ 812 if (q->q_orcpt != NULL) 813 { 814 (void) sprintf(buf, "Original-Rcpt: %s", 815 q->q_orcpt); 816 putline(buf, mci); 817 } 818 819 /* Final-Rcpt: -- if through alias */ 820 if (q->q_alias != NULL) 821 { 822 (void) sprintf(buf, "Final-Rcpt: %s", 823 q->q_paddr); 824 putline(buf, mci); 825 } 826 827 /* Final-Status: -- same as Status? XXX */ 828 829 /* Remote-MTS-Type: -- always INET? XXX */ 830 831 /* Remote-MTA: -- who was I talking to? */ 832 if (q->q_statmta != NULL) 833 { 834 (void) sprintf(buf, "Remote-MTA: %s", 835 q->q_statmta); 836 putline(buf, mci); 837 } 838 839 /* Remote-Rcpt: -- same as Final-Rcpt? XXX */ 840 841 /* Remote-Status: -- same as Final-Status? XXX */ 842 } 843 } 844 845 /* 846 ** Output text of original message 847 */ 848 849 if (bitset(EF_NORETURN, e->e_parent->e_flags)) 850 SendBody = FALSE; 851 if (!SendBody && e->e_msgboundary != NULL) 852 pflags |= PF_DELETEMIMEHDRS; 853 putline("", mci); 854 if (e->e_parent->e_df != NULL) 855 { 856 if (e->e_msgboundary == NULL) 857 { 858 if (SendBody) 859 putline(" ----- Original message follows -----\n", mci); 860 else 861 putline(" ----- Message header follows -----\n", mci); 862 (void) fflush(mci->mci_out); 863 } 864 else 865 { 866 putline("", mci); 867 (void) sprintf(buf, "--%s", e->e_msgboundary); 868 putline(buf, mci); 869 putline("Content-Type: message/rfc822", mci); 870 putline("", mci); 871 } 872 putheader(mci, e->e_parent->e_header, e->e_parent, pflags); 873 if (SendBody) 874 putbody(mci, e->e_parent, e->e_msgboundary, pflags); 875 else 876 { 877 putline("", mci); 878 putline(" ----- Message body suppressed -----", mci); 879 } 880 } 881 else 882 { 883 putline(" ----- No message was collected -----\n", mci); 884 } 885 886 if (e->e_msgboundary != NULL) 887 { 888 putline("", mci); 889 (void) sprintf(buf, "--%s--", e->e_msgboundary); 890 putline(buf, mci); 891 } 892 putline("", mci); 893 894 /* 895 ** Cleanup and exit 896 */ 897 898 if (errno != 0) 899 syserr("errbody: I/O error"); 900 } 901 /* 902 ** PRUNEROUTE -- prune an RFC-822 source route 903 ** 904 ** Trims down a source route to the last internet-registered hop. 905 ** This is encouraged by RFC 1123 section 5.3.3. 906 ** 907 ** Parameters: 908 ** addr -- the address 909 ** 910 ** Returns: 911 ** TRUE -- address was modified 912 ** FALSE -- address could not be pruned 913 ** 914 ** Side Effects: 915 ** modifies addr in-place 916 */ 917 918 pruneroute(addr) 919 char *addr; 920 { 921 #if NAMED_BIND 922 char *start, *at, *comma; 923 char c; 924 int rcode; 925 char hostbuf[BUFSIZ]; 926 char *mxhosts[MAXMXHOSTS + 1]; 927 928 /* check to see if this is really a route-addr */ 929 if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') 930 return FALSE; 931 start = strchr(addr, ':'); 932 at = strrchr(addr, '@'); 933 if (start == NULL || at == NULL || at < start) 934 return FALSE; 935 936 /* slice off the angle brackets */ 937 strcpy(hostbuf, at + 1); 938 hostbuf[strlen(hostbuf) - 1] = '\0'; 939 940 while (start) 941 { 942 if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0) 943 { 944 strcpy(addr + 1, start + 1); 945 return TRUE; 946 } 947 c = *start; 948 *start = '\0'; 949 comma = strrchr(addr, ','); 950 if (comma && comma[1] == '@') 951 strcpy(hostbuf, comma + 2); 952 else 953 comma = 0; 954 *start = c; 955 start = comma; 956 } 957 #endif 958 return FALSE; 959 } 960