1 /* 2 * Copyright (c) 1983, 1995 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.72 (Berkeley) 05/29/95"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 15 /* 16 ** SAVEMAIL -- Save mail on error 17 ** 18 ** If mailing back errors, mail it back to the originator 19 ** together with an error message; otherwise, just put it in 20 ** dead.letter in the user's home directory (if he exists on 21 ** this machine). 22 ** 23 ** Parameters: 24 ** e -- the envelope containing the message in error. 25 ** sendbody -- if TRUE, also send back the body of the 26 ** message; otherwise just send the header. 27 ** 28 ** Returns: 29 ** none 30 ** 31 ** Side Effects: 32 ** Saves the letter, by writing or mailing it back to the 33 ** sender, or by putting it in dead.letter in her home 34 ** directory. 35 */ 36 37 /* defines for state machine */ 38 # define ESM_REPORT 0 /* report to sender's terminal */ 39 # define ESM_MAIL 1 /* mail back to sender */ 40 # define ESM_QUIET 2 /* messages have already been returned */ 41 # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ 42 # define ESM_POSTMASTER 4 /* return to postmaster */ 43 # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ 44 # define ESM_PANIC 6 /* leave the locked queue/transcript files */ 45 # define ESM_DONE 7 /* the message is successfully delivered */ 46 47 # ifndef _PATH_VARTMP 48 # define _PATH_VARTMP "/usr/tmp/" 49 # endif 50 51 52 void 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 int sfflags; 64 char buf[MAXLINE+1]; 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 case EM_MAIL: 124 state = ESM_MAIL; 125 break; 126 127 case EM_PRINT: 128 case '\0': 129 state = ESM_QUIET; 130 break; 131 132 case EM_QUIET: 133 /* no need to return anything at all */ 134 return; 135 136 default: 137 syserr("554 savemail: bogus errormode x%x\n", e->e_errormode); 138 state = ESM_MAIL; 139 break; 140 } 141 142 /* if this is already an error response, send to postmaster */ 143 if (bitset(EF_RESPONSE, e->e_flags)) 144 { 145 if (e->e_parent != NULL && 146 bitset(EF_RESPONSE, e->e_parent->e_flags)) 147 { 148 /* got an error sending a response -- can it */ 149 return; 150 } 151 state = ESM_POSTMASTER; 152 } 153 154 while (state != ESM_DONE) 155 { 156 if (tTd(6, 5)) 157 printf(" state %d\n", state); 158 159 switch (state) 160 { 161 case ESM_QUIET: 162 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags)) 163 state = ESM_DEADLETTER; 164 else 165 state = ESM_MAIL; 166 break; 167 168 case ESM_REPORT: 169 170 /* 171 ** If the user is still logged in on the same terminal, 172 ** then write the error messages back to hir (sic). 173 */ 174 175 p = ttypath(); 176 if (p == NULL || freopen(p, "w", stdout) == NULL) 177 { 178 state = ESM_MAIL; 179 break; 180 } 181 182 expand("\201n", buf, sizeof buf, e); 183 printf("\r\nMessage from %s...\r\n", buf); 184 printf("Errors occurred while sending mail.\r\n"); 185 if (e->e_xfp != NULL) 186 { 187 (void) fflush(e->e_xfp); 188 fp = fopen(queuename(e, 'x'), "r"); 189 } 190 else 191 fp = NULL; 192 if (fp == NULL) 193 { 194 syserr("Cannot open %s", queuename(e, 'x')); 195 printf("Transcript of session is unavailable.\r\n"); 196 } 197 else 198 { 199 printf("Transcript follows:\r\n"); 200 while (fgets(buf, sizeof buf, fp) != NULL && 201 !ferror(stdout)) 202 fputs(buf, stdout); 203 (void) xfclose(fp, "savemail transcript", e->e_id); 204 } 205 printf("Original message will be saved in dead.letter.\r\n"); 206 state = ESM_DEADLETTER; 207 break; 208 209 case ESM_MAIL: 210 /* 211 ** If mailing back, do it. 212 ** Throw away all further output. Don't alias, 213 ** since this could cause loops, e.g., if joe 214 ** mails to joe@x, and for some reason the network 215 ** for @x is down, then the response gets sent to 216 ** joe@x, which gives a response, etc. Also force 217 ** the mail to be delivered even if a version of 218 ** it has already been sent to the sender. 219 ** 220 ** If this is a configuration or local software 221 ** error, send to the local postmaster as well, 222 ** since the originator can't do anything 223 ** about it anyway. Note that this is a full 224 ** copy of the message (intentionally) so that 225 ** the Postmaster can forward things along. 226 */ 227 228 if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE) 229 { 230 (void) sendtolist("postmaster", 231 NULLADDR, &e->e_errorqueue, 0, e); 232 } 233 if (!emptyaddr(&e->e_from)) 234 { 235 (void) sendtolist(e->e_from.q_paddr, 236 NULLADDR, &e->e_errorqueue, 0, e); 237 } 238 239 /* 240 ** Deliver a non-delivery report to the 241 ** Postmaster-designate (not necessarily 242 ** Postmaster). This does not include the 243 ** body of the message, for privacy reasons. 244 ** You really shouldn't need this. 245 */ 246 247 e->e_flags |= EF_PM_NOTIFY; 248 249 /* check to see if there are any good addresses */ 250 for (q = e->e_errorqueue; q != NULL; q = q->q_next) 251 if (!bitset(QBADADDR|QDONTSEND, q->q_flags)) 252 break; 253 if (q == NULL) 254 { 255 /* this is an error-error */ 256 state = ESM_POSTMASTER; 257 break; 258 } 259 if (returntosender(e->e_message, e->e_errorqueue, 260 sendbody, e) == 0) 261 { 262 state = ESM_DONE; 263 break; 264 } 265 266 /* didn't work -- return to postmaster */ 267 state = ESM_POSTMASTER; 268 break; 269 270 case ESM_POSTMASTER: 271 /* 272 ** Similar to previous case, but to system postmaster. 273 */ 274 275 q = NULL; 276 if (sendtolist("postmaster", NULL, &q, 0, e) <= 0) 277 { 278 syserr("553 cannot parse postmaster!"); 279 ExitStat = EX_SOFTWARE; 280 state = ESM_USRTMP; 281 break; 282 } 283 if (returntosender(e->e_message, q, sendbody, e) == 0) 284 { 285 state = ESM_DONE; 286 break; 287 } 288 289 /* didn't work -- last resort */ 290 state = ESM_USRTMP; 291 break; 292 293 case ESM_DEADLETTER: 294 /* 295 ** Save the message in dead.letter. 296 ** If we weren't mailing back, and the user is 297 ** local, we should save the message in 298 ** ~/dead.letter so that the poor person doesn't 299 ** have to type it over again -- and we all know 300 ** what poor typists UNIX users are. 301 */ 302 303 p = NULL; 304 if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags)) 305 { 306 if (e->e_from.q_home != NULL) 307 p = e->e_from.q_home; 308 else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL) 309 p = pw->pw_dir; 310 } 311 if (p == NULL || e->e_dfp == NULL) 312 { 313 /* no local directory or no data file */ 314 state = ESM_MAIL; 315 break; 316 } 317 318 /* we have a home directory; open dead.letter */ 319 define('z', p, e); 320 expand("\201z/dead.letter", buf, sizeof buf, e); 321 sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; 322 e->e_to = buf; 323 goto writefile; 324 325 case ESM_USRTMP: 326 /* 327 ** Log the mail in /usr/tmp/dead.letter. 328 */ 329 330 if (e->e_class < 0) 331 { 332 state = ESM_DONE; 333 break; 334 } 335 336 if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 337 { 338 state = ESM_PANIC; 339 break; 340 } 341 342 strcpy(buf, _PATH_VARTMP); 343 strcat(buf, "dead.letter"); 344 sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY; 345 346 writefile: 347 if (!writable(buf, q, sfflags) || 348 (fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND, 349 FileMode, sfflags)) == NULL) 350 { 351 if (state == ESM_USRTMP) 352 state = ESM_PANIC; 353 else 354 state = ESM_MAIL; 355 break; 356 } 357 358 bzero(&mcibuf, sizeof mcibuf); 359 mcibuf.mci_out = fp; 360 mcibuf.mci_mailer = FileMailer; 361 if (bitnset(M_7BITS, FileMailer->m_flags)) 362 mcibuf.mci_flags |= MCIF_7BIT; 363 364 putfromline(&mcibuf, e); 365 (*e->e_puthdr)(&mcibuf, e->e_header, e); 366 (*e->e_putbody)(&mcibuf, e, NULL); 367 putline("\n", &mcibuf); 368 (void) fflush(fp); 369 if (!ferror(fp)) 370 { 371 bool oldverb = Verbose; 372 373 Verbose = TRUE; 374 message("Saved message in %s", buf); 375 Verbose = oldverb; 376 state = ESM_DONE; 377 } 378 else if (state == ESM_USRTMP) 379 state = ESM_PANIC; 380 else 381 state = ESM_MAIL; 382 (void) xfclose(fp, "savemail", buf); 383 break; 384 385 default: 386 syserr("554 savemail: unknown state %d", state); 387 388 /* fall through ... */ 389 390 case ESM_PANIC: 391 /* leave the locked queue & transcript files around */ 392 loseqfile(e, "savemail panic"); 393 syserr("!554 savemail: cannot save rejected email anywhere"); 394 } 395 } 396 } 397 /* 398 ** RETURNTOSENDER -- return a message to the sender with an error. 399 ** 400 ** Parameters: 401 ** msg -- the explanatory message. 402 ** returnq -- the queue of people to send the message to. 403 ** sendbody -- if TRUE, also send back the body of the 404 ** message; otherwise just send the header. 405 ** e -- the current envelope. 406 ** 407 ** Returns: 408 ** zero -- if everything went ok. 409 ** else -- some error. 410 ** 411 ** Side Effects: 412 ** Returns the current message to the sender via 413 ** mail. 414 */ 415 416 #define MAXRETURNS 6 /* max depth of returning messages */ 417 #define ERRORFUDGE 100 /* nominal size of error message text */ 418 419 int 420 returntosender(msg, returnq, sendbody, e) 421 char *msg; 422 ADDRESS *returnq; 423 bool sendbody; 424 register ENVELOPE *e; 425 { 426 register ENVELOPE *ee; 427 ENVELOPE *oldcur = CurEnv; 428 ENVELOPE errenvelope; 429 static int returndepth; 430 register ADDRESS *q; 431 char *p; 432 char buf[MAXNAME + 1]; 433 extern void errbody __P((MCI *, ENVELOPE *, char *)); 434 435 if (returnq == NULL) 436 return (-1); 437 438 if (msg == NULL) 439 msg = "Unable to deliver mail"; 440 441 if (tTd(6, 1)) 442 { 443 printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=", 444 msg, returndepth, e); 445 printaddr(returnq, TRUE); 446 if (tTd(6, 20)) 447 { 448 printf("Sendq="); 449 printaddr(e->e_sendqueue, TRUE); 450 } 451 } 452 453 if (++returndepth >= MAXRETURNS) 454 { 455 if (returndepth != MAXRETURNS) 456 syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr); 457 /* don't "unrecurse" and fake a clean exit */ 458 /* returndepth--; */ 459 return (0); 460 } 461 462 define('g', e->e_from.q_paddr, e); 463 define('u', NULL, e); 464 465 /* initialize error envelope */ 466 ee = newenvelope(&errenvelope, e); 467 define('a', "\201b", ee); 468 define('r', "internal", ee); 469 define('s', "localhost", ee); 470 define('_', "localhost", ee); 471 ee->e_puthdr = putheader; 472 ee->e_putbody = errbody; 473 ee->e_flags |= EF_RESPONSE|EF_METOO; 474 if (!bitset(EF_OLDSTYLE, e->e_flags)) 475 ee->e_flags &= ~EF_OLDSTYLE; 476 ee->e_sendqueue = returnq; 477 ee->e_msgsize = ERRORFUDGE; 478 if (sendbody) 479 ee->e_msgsize += e->e_msgsize; 480 else 481 ee->e_flags |= EF_NO_BODY_RETN; 482 initsys(ee); 483 for (q = returnq; q != NULL; q = q->q_next) 484 { 485 if (bitset(QBADADDR, q->q_flags)) 486 continue; 487 488 if (!DontPruneRoutes && pruneroute(q->q_paddr)) 489 { 490 register ADDRESS *p; 491 492 parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e); 493 for (p = returnq; p != NULL; p = p->q_next) 494 { 495 if (p != q && sameaddr(p, q)) 496 q->q_flags |= QDONTSEND; 497 } 498 } 499 500 if (!bitset(QDONTSEND, q->q_flags)) 501 ee->e_nrcpts++; 502 503 if (q->q_alias == NULL) 504 addheader("To", q->q_paddr, &ee->e_header); 505 } 506 507 # ifdef LOG 508 if (LogLevel > 5) 509 syslog(LOG_INFO, "%s: %s: return to sender: %s", 510 e->e_id, ee->e_id, msg); 511 # endif 512 513 if (SendMIMEErrors) 514 { 515 addheader("MIME-Version", "1.0", &ee->e_header); 516 (void) sprintf(buf, "%s.%ld/%s", 517 ee->e_id, curtime(), MyHostName); 518 ee->e_msgboundary = newstr(buf); 519 (void) sprintf(buf, 520 #if DSN 521 "multipart/report; report-type=X-delivery-status-3 (Draft of May 5, 1995);\n\tboundary=\"%s\"", 522 #else 523 "multipart/mixed; boundary=\"%s\"", 524 #endif 525 ee->e_msgboundary); 526 addheader("Content-Type", buf, &ee->e_header); 527 } 528 if (strncmp(msg, "Warning:", 8) == 0) 529 { 530 addheader("Subject", msg, &ee->e_header); 531 p = "warning-timeout"; 532 } 533 else if (strcmp(msg, "Return receipt") == 0) 534 { 535 addheader("Subject", msg, &ee->e_header); 536 p = "return-receipt"; 537 } 538 else 539 { 540 sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg); 541 addheader("Subject", buf, &ee->e_header); 542 p = "failure"; 543 } 544 (void) sprintf(buf, "auto-generated (%s)", p); 545 addheader("Auto-Submitted", buf, &ee->e_header); 546 547 /* fake up an address header for the from person */ 548 expand("\201n", buf, sizeof buf, 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 void 598 errbody(mci, e, separator) 599 register MCI *mci; 600 register ENVELOPE *e; 601 char *separator; 602 { 603 register FILE *xfile; 604 char *p; 605 register ADDRESS *q; 606 bool printheader; 607 bool sendbody; 608 char buf[MAXLINE]; 609 extern char *xtextify(); 610 611 if (bitset(MCIF_INHEADER, mci->mci_flags)) 612 { 613 putline("", mci); 614 mci->mci_flags &= ~MCIF_INHEADER; 615 } 616 if (e->e_parent == NULL) 617 { 618 syserr("errbody: null parent"); 619 putline(" ----- Original message lost -----\n", mci); 620 return; 621 } 622 623 /* 624 ** Output MIME header. 625 */ 626 627 if (e->e_msgboundary != NULL) 628 { 629 putline("This is a MIME-encapsulated message", mci); 630 putline("", mci); 631 (void) sprintf(buf, "--%s", e->e_msgboundary); 632 putline(buf, mci); 633 putline("", mci); 634 } 635 636 /* 637 ** Output introductory information. 638 */ 639 640 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 641 if (bitset(QBADADDR, q->q_flags)) 642 break; 643 if (q == NULL && 644 !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) 645 { 646 putline(" **********************************************", 647 mci); 648 putline(" ** THIS IS A WARNING MESSAGE ONLY **", 649 mci); 650 putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **", 651 mci); 652 putline(" **********************************************", 653 mci); 654 putline("", mci); 655 } 656 sprintf(buf, "The original message was received at %s", 657 arpadate(ctime(&e->e_parent->e_ctime))); 658 putline(buf, mci); 659 expand("from \201_", buf, sizeof buf, e->e_parent); 660 putline(buf, mci); 661 putline("", mci); 662 663 /* 664 ** Output error message header (if specified and available). 665 */ 666 667 if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags)) 668 { 669 if (*ErrMsgFile == '/') 670 { 671 xfile = fopen(ErrMsgFile, "r"); 672 if (xfile != NULL) 673 { 674 while (fgets(buf, sizeof buf, xfile) != NULL) 675 { 676 expand(buf, buf, sizeof buf, e); 677 putline(buf, mci); 678 } 679 (void) fclose(xfile); 680 putline("\n", mci); 681 } 682 } 683 else 684 { 685 expand(ErrMsgFile, buf, sizeof buf, e); 686 putline(buf, mci); 687 putline("", mci); 688 } 689 } 690 691 /* 692 ** Output message introduction 693 */ 694 695 printheader = TRUE; 696 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 697 { 698 if (bitset(QBADADDR, q->q_flags)) 699 { 700 if (!bitset(QPINGONFAILURE, q->q_flags)) 701 continue; 702 p = "unrecoverable error"; 703 } 704 else if (!bitset(QPRIMARY, q->q_flags)) 705 continue; 706 else if (bitset(QRELAYED, q->q_flags)) 707 p = "relayed to non-DSN-aware mailer"; 708 else if (bitset(QDELIVERED, q->q_flags)) 709 { 710 if (bitset(QEXPANDED, q->q_flags)) 711 p = "successfully delivered to mailing list"; 712 else 713 p = "successfully delivered to mailbox"; 714 } 715 else if (bitset(QEXPANDED, q->q_flags)) 716 p = "expanded by alias"; 717 else if (bitset(QDELAYED, q->q_flags)) 718 p = "transient failure"; 719 else 720 continue; 721 722 if (printheader) 723 { 724 putline(" ----- The following addresses have delivery notifications -----", 725 mci); 726 printheader = FALSE; 727 } 728 729 sprintf(buf, "%s (%s)", q->q_paddr, p); 730 putline(buf, mci); 731 if (q->q_alias != NULL) 732 { 733 strcpy(buf, " (expanded from: "); 734 strcat(buf, q->q_alias->q_paddr); 735 strcat(buf, ")"); 736 putline(buf, mci); 737 } 738 } 739 if (!printheader) 740 putline("\n", mci); 741 742 /* 743 ** Output transcript of errors 744 */ 745 746 (void) fflush(stdout); 747 p = queuename(e->e_parent, 'x'); 748 if ((xfile = fopen(p, "r")) == NULL) 749 { 750 syserr("Cannot open %s", p); 751 putline(" ----- Transcript of session is unavailable -----\n", mci); 752 } 753 else 754 { 755 printheader = TRUE; 756 if (e->e_xfp != NULL) 757 (void) fflush(e->e_xfp); 758 while (fgets(buf, sizeof buf, xfile) != NULL) 759 { 760 if (printheader) 761 putline(" ----- Transcript of session follows -----\n", mci); 762 printheader = FALSE; 763 putline(buf, mci); 764 } 765 (void) xfclose(xfile, "errbody xscript", p); 766 } 767 errno = 0; 768 769 #if DSN 770 /* 771 ** Output machine-readable version. 772 */ 773 774 if (e->e_msgboundary != NULL) 775 { 776 putline("", mci); 777 (void) sprintf(buf, "--%s", e->e_msgboundary); 778 putline(buf, mci); 779 putline("Content-Type: message/X-delivery-status-04a (Draft of April 4, 1995)", mci); 780 putline("", mci); 781 782 /* 783 ** Output per-message information. 784 */ 785 786 /* original envelope id from MAIL FROM: line */ 787 if (e->e_parent->e_envid != NULL) 788 { 789 (void) sprintf(buf, "Original-Envelope-Id: %s", 790 xtextify(e->e_parent->e_envid)); 791 putline(buf, mci); 792 } 793 794 /* Reporting-MTA: is us (required) */ 795 (void) sprintf(buf, "Reporting-MTA: dns; %s", 796 xtextify(MyHostName)); 797 putline(buf, mci); 798 799 /* DSN-Gateway: not relevant since we are not translating */ 800 801 /* Received-From-MTA: shows where we got this message from */ 802 if (RealHostName != NULL) 803 { 804 /* XXX use $s for type? */ 805 p = e->e_parent->e_from.q_mailer->m_mtatype; 806 if (p == NULL) 807 p = "dns"; 808 (void) sprintf(buf, "Received-From-MTA: %s; %s", 809 p, xtextify(RealHostName)); 810 putline(buf, mci); 811 } 812 813 /* Arrival-Date: -- when it arrived here */ 814 (void) sprintf(buf, "Arrival-Date: %s", 815 arpadate(ctime(&e->e_parent->e_ctime))); 816 putline(buf, mci); 817 818 /* 819 ** Output per-address information. 820 */ 821 822 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 823 { 824 register ADDRESS *r; 825 char *action; 826 827 if (bitset(QBADADDR, q->q_flags)) 828 action = "failed"; 829 else if (!bitset(QPRIMARY, q->q_flags)) 830 continue; 831 else if (bitset(QDELIVERED, q->q_flags)) 832 { 833 if (bitset(QEXPANDED, q->q_flags)) 834 action = "delivered (to mailing list)"; 835 else 836 action = "delivered (to mailbox)"; 837 } 838 else if (bitset(QRELAYED, q->q_flags)) 839 action = "relayed (to non-DSN-aware mailer)"; 840 else if (bitset(QEXPANDED, q->q_flags)) 841 action = "expanded (to multi-recipient alias)"; 842 else if (bitset(QDELAYED, q->q_flags)) 843 action = "delayed"; 844 else 845 continue; 846 847 putline("", mci); 848 849 /* Original-Recipient: -- passed from on high */ 850 if (q->q_orcpt != NULL) 851 { 852 (void) sprintf(buf, "Original-Recipient: %s", 853 xtextify(q->q_orcpt)); 854 putline(buf, mci); 855 } 856 857 /* Final-Recipient: -- the name from the RCPT command */ 858 p = e->e_parent->e_from.q_mailer->m_addrtype; 859 if (p == NULL) 860 p = "rfc822"; 861 for (r = q; r->q_alias != NULL; r = r->q_alias) 862 continue; 863 if (strchr(r->q_user, '@') == NULL) 864 { 865 (void) sprintf(buf, "Final-Recipient: %s; %s@", 866 p, xtextify(r->q_user)); 867 strcat(buf, xtextify(MyHostName)); 868 } 869 else 870 { 871 (void) sprintf(buf, "Final-Recipient: %s; %s", 872 p, xtextify(r->q_user)); 873 } 874 putline(buf, mci); 875 876 /* X-Actual-Recipient: -- the real problem address */ 877 if (r != q) 878 { 879 if (strchr(q->q_user, '@') == NULL) 880 { 881 (void) sprintf(buf, "X-Actual-Recipient: %s; %s@", 882 p, xtextify(q->q_user)); 883 strcat(buf, xtextify(MyHostName)); 884 } 885 else 886 { 887 (void) sprintf(buf, "X-Actual-Recipient: %s; %s", 888 p, xtextify(q->q_user)); 889 } 890 putline(buf, mci); 891 } 892 893 /* Action: -- what happened? */ 894 sprintf(buf, "Action: %s", action); 895 putline(buf, mci); 896 897 /* Status: -- what _really_ happened? */ 898 strcpy(buf, "Status: "); 899 if (q->q_status != NULL) 900 strcat(buf, q->q_status); 901 else if (bitset(QBADADDR, q->q_flags)) 902 strcat(buf, "5.0.0"); 903 else if (bitset(QQUEUEUP, q->q_flags)) 904 strcat(buf, "4.0.0"); 905 else 906 strcat(buf, "2.0.0"); 907 putline(buf, mci); 908 909 /* Remote-MTA: -- who was I talking to? */ 910 p = q->q_mailer->m_mtatype; 911 if (p == NULL) 912 p = "dns"; 913 (void) sprintf(buf, "Remote-MTA: %s; ", p); 914 if (q->q_statmta != NULL) 915 p = q->q_statmta; 916 else if (q->q_host != NULL && q->q_host[0] != '\0') 917 p = q->q_host; 918 else 919 p = NULL; 920 if (p != NULL) 921 { 922 strcat(buf, p); 923 p = &buf[strlen(buf) - 1]; 924 if (*p == '.') 925 *p = '\0'; 926 putline(buf, mci); 927 } 928 929 /* Diagnostic-Code: -- actual result from other end */ 930 if (q->q_rstatus != NULL) 931 { 932 p = q->q_mailer->m_diagtype; 933 if (p == NULL) 934 p = "smtp"; 935 (void) sprintf(buf, "Diagnostic-Code: %s; %s", 936 p, xtextify(q->q_rstatus)); 937 putline(buf, mci); 938 } 939 940 /* Last-Attempt-Date: -- fine granularity */ 941 if (q->q_statdate == (time_t) 0L) 942 q->q_statdate = curtime(); 943 (void) sprintf(buf, "Last-Attempt-Date: %s", 944 arpadate(ctime(&q->q_statdate))); 945 putline(buf, mci); 946 947 /* Will-Retry-Until: -- for delayed messages only */ 948 if (bitset(QQUEUEUP, q->q_flags) && 949 !bitset(QBADADDR, q->q_flags)) 950 { 951 time_t xdate; 952 953 xdate = e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]; 954 sprintf(buf, "Will-Retry-Until: %s", 955 arpadate(ctime(&xdate))); 956 putline(buf, mci); 957 } 958 } 959 } 960 #endif 961 962 /* 963 ** Output text of original message 964 */ 965 966 putline("", mci); 967 if (bitset(EF_HAS_DF, e->e_parent->e_flags)) 968 { 969 sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) && 970 !bitset(EF_NO_BODY_RETN, e->e_flags); 971 972 if (e->e_msgboundary == NULL) 973 { 974 if (sendbody) 975 putline(" ----- Original message follows -----\n", mci); 976 else 977 putline(" ----- Message header follows -----\n", mci); 978 (void) fflush(mci->mci_out); 979 } 980 else 981 { 982 (void) sprintf(buf, "--%s", e->e_msgboundary); 983 putline(buf, mci); 984 (void) sprintf(buf, "Content-Type: %s", 985 sendbody ? "message/rfc822" 986 : "text/rfc822-headers"); 987 putline(buf, mci); 988 } 989 putline("", mci); 990 putheader(mci, e->e_parent->e_header, e->e_parent); 991 if (sendbody) 992 putbody(mci, e->e_parent, e->e_msgboundary); 993 else if (e->e_msgboundary == NULL) 994 { 995 putline("", mci); 996 putline(" ----- Message body suppressed -----", mci); 997 } 998 } 999 else if (e->e_msgboundary == NULL) 1000 { 1001 putline(" ----- No message was collected -----\n", mci); 1002 } 1003 1004 if (e->e_msgboundary != NULL) 1005 { 1006 putline("", mci); 1007 (void) sprintf(buf, "--%s--", e->e_msgboundary); 1008 putline(buf, mci); 1009 } 1010 putline("", mci); 1011 1012 /* 1013 ** Cleanup and exit 1014 */ 1015 1016 if (errno != 0) 1017 syserr("errbody: I/O error"); 1018 } 1019 /* 1020 ** SMTPTODSN -- convert SMTP to DSN status code 1021 ** 1022 ** Parameters: 1023 ** smtpstat -- the smtp status code (e.g., 550). 1024 ** 1025 ** Returns: 1026 ** The DSN version of the status code. 1027 */ 1028 1029 char * 1030 smtptodsn(smtpstat) 1031 int smtpstat; 1032 { 1033 if (smtpstat < 0) 1034 return "4.4.2"; 1035 1036 switch (smtpstat) 1037 { 1038 case 450: /* Req mail action not taken: mailbox unavailable */ 1039 return "4.2.0"; 1040 1041 case 451: /* Req action aborted: local error in processing */ 1042 return "4.3.0"; 1043 1044 case 452: /* Req action not taken: insufficient sys storage */ 1045 return "4.3.1"; 1046 1047 case 500: /* Syntax error, command unrecognized */ 1048 return "5.5.2"; 1049 1050 case 501: /* Syntax error in parameters or arguments */ 1051 return "5.5.4"; 1052 1053 case 502: /* Command not implemented */ 1054 return "5.5.1"; 1055 1056 case 503: /* Bad sequence of commands */ 1057 return "5.5.1"; 1058 1059 case 504: /* Command parameter not implemented */ 1060 return "5.5.4"; 1061 1062 case 550: /* Req mail action not taken: mailbox unavailable */ 1063 return "5.2.0"; 1064 1065 case 551: /* User not local; please try <...> */ 1066 return "5.1.6"; 1067 1068 case 552: /* Req mail action aborted: exceeded storage alloc */ 1069 return "5.2.2"; 1070 1071 case 553: /* Req action not taken: mailbox name not allowed */ 1072 return "5.1.3"; 1073 1074 case 554: /* Transaction failed */ 1075 return "5.0.0"; 1076 } 1077 1078 if ((smtpstat / 100) == 2) 1079 return "2.0.0"; 1080 if ((smtpstat / 100) == 4) 1081 return "4.0.0"; 1082 return "5.0.0"; 1083 } 1084 /* 1085 ** XTEXTIFY -- take regular text and turn it into DSN-style xtext 1086 ** 1087 ** Parameters: 1088 ** t -- the text to convert. 1089 ** 1090 ** Returns: 1091 ** The xtext-ified version of the same string. 1092 */ 1093 1094 char * 1095 xtextify(t) 1096 register char *t; 1097 { 1098 register char *p; 1099 int l; 1100 int nbogus; 1101 static char *bp = NULL; 1102 static int bplen = 0; 1103 1104 /* figure out how long this xtext will have to be */ 1105 nbogus = l = 0; 1106 for (p = t; *p != '\0'; p++) 1107 { 1108 register int c = (*p & 0xff); 1109 1110 /* ASCII dependence here -- this is the way the spec words it */ 1111 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') 1112 nbogus++; 1113 l++; 1114 } 1115 if (nbogus == 0) 1116 return t; 1117 l += nbogus * 2 + 1; 1118 1119 /* now allocate space if necessary for the new string */ 1120 if (l > bplen) 1121 { 1122 if (bp != NULL) 1123 free(bp); 1124 bp = xalloc(l); 1125 bplen = l; 1126 } 1127 1128 /* ok, copy the text with byte expansion */ 1129 for (p = bp; *t != '\0'; ) 1130 { 1131 register int c = (*t++ & 0xff); 1132 1133 /* ASCII dependence here -- this is the way the spec words it */ 1134 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') 1135 { 1136 *p++ = '+'; 1137 *p++ = "0123456789abcdef"[c >> 4]; 1138 *p++ = "0123456789abcdef"[c & 0xf]; 1139 } 1140 else 1141 *p++ = c; 1142 } 1143 *p = '\0'; 1144 return bp; 1145 } 1146 /* 1147 ** XTEXTOK -- check if a string is legal xtext 1148 ** 1149 ** Xtext is used in Delivery Status Notifications. The spec was 1150 ** taken from draft-ietf-notary-mime-delivery-04.txt. 1151 ** 1152 ** Parameters: 1153 ** s -- the string to check. 1154 ** 1155 ** Returns: 1156 ** TRUE -- if 's' is legal xtext. 1157 ** FALSE -- if it has any illegal characters in it. 1158 */ 1159 1160 bool 1161 xtextok(s) 1162 char *s; 1163 { 1164 int c; 1165 1166 while ((c = *s++) != '\0') 1167 { 1168 if (c == '+') 1169 { 1170 c = *s++; 1171 if (!isascii(c) || !isxdigit(c)) 1172 return FALSE; 1173 c = *s++; 1174 if (!isascii(c) || !isxdigit(c)) 1175 return FALSE; 1176 } 1177 else if (c < '!' || c > '~' || c == '\\' || c == '(') 1178 return FALSE; 1179 } 1180 return TRUE; 1181 } 1182 /* 1183 ** PRUNEROUTE -- prune an RFC-822 source route 1184 ** 1185 ** Trims down a source route to the last internet-registered hop. 1186 ** This is encouraged by RFC 1123 section 5.3.3. 1187 ** 1188 ** Parameters: 1189 ** addr -- the address 1190 ** 1191 ** Returns: 1192 ** TRUE -- address was modified 1193 ** FALSE -- address could not be pruned 1194 ** 1195 ** Side Effects: 1196 ** modifies addr in-place 1197 */ 1198 1199 bool 1200 pruneroute(addr) 1201 char *addr; 1202 { 1203 #if NAMED_BIND 1204 char *start, *at, *comma; 1205 char c; 1206 int rcode; 1207 char hostbuf[BUFSIZ]; 1208 char *mxhosts[MAXMXHOSTS + 1]; 1209 1210 /* check to see if this is really a route-addr */ 1211 if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') 1212 return FALSE; 1213 start = strchr(addr, ':'); 1214 at = strrchr(addr, '@'); 1215 if (start == NULL || at == NULL || at < start) 1216 return FALSE; 1217 1218 /* slice off the angle brackets */ 1219 strcpy(hostbuf, at + 1); 1220 hostbuf[strlen(hostbuf) - 1] = '\0'; 1221 1222 while (start) 1223 { 1224 if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0) 1225 { 1226 strcpy(addr + 1, start + 1); 1227 return TRUE; 1228 } 1229 c = *start; 1230 *start = '\0'; 1231 comma = strrchr(addr, ','); 1232 if (comma && comma[1] == '@') 1233 strcpy(hostbuf, comma + 2); 1234 else 1235 comma = 0; 1236 *start = c; 1237 start = comma; 1238 } 1239 #endif 1240 return FALSE; 1241 } 1242