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