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