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.60 (Berkeley) 03/27/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, sizeof buf, 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, sizeof buf, 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 if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 361 { 362 state = ESM_PANIC; 363 break; 364 } 365 366 strcpy(buf, _PATH_VARTMP); 367 strcat(buf, "dead.letter"); 368 if (!writable(buf, NULLADDR, SFF_NOSLINK|SFF_CREAT)) 369 { 370 state = ESM_PANIC; 371 break; 372 } 373 fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND, 374 FileMode, SFF_NOSLINK|SFF_REGONLY); 375 if (fp == NULL) 376 { 377 state = ESM_PANIC; 378 break; 379 } 380 381 bzero(&mcibuf, sizeof mcibuf); 382 mcibuf.mci_out = fp; 383 mcibuf.mci_mailer = FileMailer; 384 if (bitnset(M_7BITS, FileMailer->m_flags)) 385 mcibuf.mci_flags |= MCIF_7BIT; 386 387 putfromline(&mcibuf, e); 388 (*e->e_puthdr)(&mcibuf, e->e_header, e); 389 (*e->e_putbody)(&mcibuf, e, NULL); 390 putline("\n", &mcibuf); 391 (void) fflush(fp); 392 state = ferror(fp) ? ESM_PANIC : ESM_DONE; 393 (void) xfclose(fp, "savemail", buf); 394 break; 395 396 default: 397 syserr("554 savemail: unknown state %d", state); 398 399 /* fall through ... */ 400 401 case ESM_PANIC: 402 /* leave the locked queue & transcript files around */ 403 loseqfile(e, "savemail panic"); 404 syserr("!554 savemail: cannot save rejected email anywhere"); 405 } 406 } 407 } 408 /* 409 ** RETURNTOSENDER -- return a message to the sender with an error. 410 ** 411 ** Parameters: 412 ** msg -- the explanatory message. 413 ** returnq -- the queue of people to send the message to. 414 ** sendbody -- if TRUE, also send back the body of the 415 ** message; otherwise just send the header. 416 ** e -- the current envelope. 417 ** 418 ** Returns: 419 ** zero -- if everything went ok. 420 ** else -- some error. 421 ** 422 ** Side Effects: 423 ** Returns the current message to the sender via 424 ** mail. 425 */ 426 427 #define MAXRETURNS 6 /* max depth of returning messages */ 428 #define ERRORFUDGE 100 /* nominal size of error message text */ 429 430 returntosender(msg, returnq, sendbody, e) 431 char *msg; 432 ADDRESS *returnq; 433 bool sendbody; 434 register ENVELOPE *e; 435 { 436 char buf[MAXNAME + 1]; 437 extern putheader(), errbody(); 438 register ENVELOPE *ee; 439 ENVELOPE *oldcur = CurEnv; 440 ENVELOPE errenvelope; 441 static int returndepth; 442 register ADDRESS *q; 443 char *p; 444 445 if (returnq == NULL) 446 return (-1); 447 448 if (msg == NULL) 449 msg = "Unable to deliver mail"; 450 451 if (tTd(6, 1)) 452 { 453 printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=", 454 msg, returndepth, e); 455 printaddr(returnq, TRUE); 456 if (tTd(6, 20)) 457 { 458 printf("Sendq="); 459 printaddr(e->e_sendqueue, TRUE); 460 } 461 } 462 463 if (++returndepth >= MAXRETURNS) 464 { 465 if (returndepth != MAXRETURNS) 466 syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr); 467 /* don't "unrecurse" and fake a clean exit */ 468 /* returndepth--; */ 469 return (0); 470 } 471 472 define('g', e->e_from.q_paddr, e); 473 define('u', NULL, e); 474 475 /* initialize error envelope */ 476 ee = newenvelope(&errenvelope, e); 477 define('a', "\201b", ee); 478 define('r', "internal", ee); 479 define('s', "localhost", ee); 480 define('_', "localhost", ee); 481 ee->e_puthdr = putheader; 482 ee->e_putbody = errbody; 483 ee->e_flags |= EF_RESPONSE|EF_METOO; 484 if (!bitset(EF_OLDSTYLE, e->e_flags)) 485 ee->e_flags &= ~EF_OLDSTYLE; 486 ee->e_sendqueue = returnq; 487 ee->e_msgsize = ERRORFUDGE; 488 if (sendbody) 489 ee->e_msgsize += e->e_msgsize; 490 initsys(ee); 491 for (q = returnq; q != NULL; q = q->q_next) 492 { 493 if (bitset(QBADADDR, q->q_flags)) 494 continue; 495 496 if (!DontPruneRoutes && pruneroute(q->q_paddr)) 497 { 498 register ADDRESS *p; 499 500 parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e); 501 for (p = returnq; p != NULL; p = p->q_next) 502 { 503 if (p != q && sameaddr(p, q)) 504 q->q_flags |= QDONTSEND; 505 } 506 } 507 508 if (!bitset(QDONTSEND, q->q_flags)) 509 ee->e_nrcpts++; 510 511 if (q->q_alias == NULL) 512 addheader("To", q->q_paddr, &ee->e_header); 513 } 514 515 # ifdef LOG 516 if (LogLevel > 5) 517 syslog(LOG_INFO, "%s: %s: return to sender: %s", 518 e->e_id, ee->e_id, msg); 519 # endif 520 521 if (SendMIMEErrors) 522 { 523 addheader("MIME-Version", "1.0", &ee->e_header); 524 (void) sprintf(buf, "%s.%ld/%s", 525 ee->e_id, curtime(), MyHostName); 526 ee->e_msgboundary = newstr(buf); 527 (void) sprintf(buf, 528 #ifdef DSN 529 "multipart/report; report-type=X-delivery-status-1; boundary=\"%s\"", 530 #else 531 "multipart/mixed; boundary=\"%s\"", 532 #endif 533 ee->e_msgboundary); 534 addheader("Content-Type", buf, &ee->e_header); 535 } 536 if (strncmp(msg, "Warning:", 8) == 0) 537 { 538 addheader("Subject", msg, ee); 539 p = "warning-timeout"; 540 } 541 else if (strcmp(msg, "Return receipt") == 0) 542 { 543 addheader("Subject", msg, ee); 544 p = "return-receipt"; 545 } 546 else 547 { 548 sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg); 549 addheader("Subject", buf, &ee->e_header); 550 p = "failure"; 551 } 552 (void) sprintf(buf, "auto-generated (%s)", p); 553 addheader("Auto-Submitted", buf, &ee->e_header); 554 555 /* fake up an address header for the from person */ 556 expand("\201n", buf, sizeof buf, e); 557 if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL) 558 { 559 syserr("553 Can't parse myself!"); 560 ExitStat = EX_SOFTWARE; 561 returndepth--; 562 return (-1); 563 } 564 ee->e_sender = ee->e_from.q_paddr; 565 566 /* push state into submessage */ 567 CurEnv = ee; 568 define('f', "\201n", ee); 569 define('x', "Mail Delivery Subsystem", ee); 570 eatheader(ee, TRUE); 571 572 /* mark statistics */ 573 markstats(ee, NULLADDR); 574 575 /* actually deliver the error message */ 576 sendall(ee, SM_DEFAULT); 577 578 /* restore state */ 579 dropenvelope(ee); 580 CurEnv = oldcur; 581 returndepth--; 582 583 /* should check for delivery errors here */ 584 return (0); 585 } 586 /* 587 ** ERRBODY -- output the body of an error message. 588 ** 589 ** Typically this is a copy of the transcript plus a copy of the 590 ** original offending message. 591 ** 592 ** Parameters: 593 ** mci -- the mailer connection information. 594 ** e -- the envelope we are working in. 595 ** separator -- any possible MIME separator. 596 ** flags -- to modify the behaviour. 597 ** 598 ** Returns: 599 ** none 600 ** 601 ** Side Effects: 602 ** Outputs the body of an error message. 603 */ 604 605 errbody(mci, e, separator) 606 register MCI *mci; 607 register ENVELOPE *e; 608 char *separator; 609 { 610 register FILE *xfile; 611 char *p; 612 register ADDRESS *q; 613 bool printheader; 614 bool sendbody; 615 char buf[MAXLINE]; 616 extern char *xtextify(); 617 618 if (bitset(MCIF_INHEADER, mci->mci_flags)) 619 { 620 putline("", mci); 621 mci->mci_flags &= ~MCIF_INHEADER; 622 } 623 if (e->e_parent == NULL) 624 { 625 syserr("errbody: null parent"); 626 putline(" ----- Original message lost -----\n", mci); 627 return; 628 } 629 630 /* 631 ** Output MIME header. 632 */ 633 634 if (e->e_msgboundary != NULL) 635 { 636 putline("This is a MIME-encapsulated message", mci); 637 putline("", mci); 638 (void) sprintf(buf, "--%s", e->e_msgboundary); 639 putline(buf, mci); 640 putline("", mci); 641 } 642 643 /* 644 ** Output introductory information. 645 */ 646 647 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 648 if (bitset(QBADADDR, q->q_flags)) 649 break; 650 if (q == NULL && 651 !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) 652 { 653 putline(" **********************************************", 654 mci); 655 putline(" ** THIS IS A WARNING MESSAGE ONLY **", 656 mci); 657 putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **", 658 mci); 659 putline(" **********************************************", 660 mci); 661 putline("", mci); 662 } 663 sprintf(buf, "The original message was received at %s", 664 arpadate(ctime(&e->e_parent->e_ctime))); 665 putline(buf, mci); 666 expand("from \201_", buf, sizeof buf, e->e_parent); 667 putline(buf, mci); 668 putline("", mci); 669 670 /* 671 ** Output error message header (if specified and available). 672 */ 673 674 if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags)) 675 { 676 if (*ErrMsgFile == '/') 677 { 678 xfile = fopen(ErrMsgFile, "r"); 679 if (xfile != NULL) 680 { 681 while (fgets(buf, sizeof buf, xfile) != NULL) 682 { 683 expand(buf, buf, sizeof buf, e); 684 putline(buf, mci); 685 } 686 (void) fclose(xfile); 687 putline("\n", mci); 688 } 689 } 690 else 691 { 692 expand(ErrMsgFile, buf, sizeof buf, e); 693 putline(buf, mci); 694 putline("", mci); 695 } 696 } 697 698 /* 699 ** Output message introduction 700 */ 701 702 printheader = TRUE; 703 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 704 { 705 if (bitset(QBADADDR|QREPORT|QRELAYED|QEXPLODED, q->q_flags)) 706 { 707 strcpy(buf, q->q_paddr); 708 if (bitset(QBADADDR, q->q_flags)) 709 strcat(buf, " (unrecoverable error)"); 710 else if (!bitset(QPRIMARY, q->q_flags)) 711 continue; 712 else if (bitset(QRELAYED, q->q_flags)) 713 strcat(buf, " (relayed to non-DSN-aware mailer)"); 714 else if (bitset(QSENT, q->q_flags)) 715 strcat(buf, " (successfully delivered)"); 716 else if (bitset(QEXPLODED, q->q_flags)) 717 strcat(buf, " (expanded by mailing list)"); 718 else 719 strcat(buf, " (transient failure)"); 720 if (printheader) 721 { 722 putline(" ----- The following addresses have delivery notifications -----", 723 mci); 724 printheader = FALSE; 725 } 726 putline(buf, mci); 727 if (q->q_alias != NULL) 728 { 729 strcpy(buf, " (expanded from: "); 730 strcat(buf, q->q_alias->q_paddr); 731 strcat(buf, ")"); 732 putline(buf, mci); 733 } 734 } 735 } 736 if (!printheader) 737 putline("\n", mci); 738 739 /* 740 ** Output transcript of errors 741 */ 742 743 (void) fflush(stdout); 744 p = queuename(e->e_parent, 'x'); 745 if ((xfile = fopen(p, "r")) == NULL) 746 { 747 syserr("Cannot open %s", p); 748 putline(" ----- Transcript of session is unavailable -----\n", mci); 749 } 750 else 751 { 752 putline(" ----- Transcript of session follows -----\n", mci); 753 if (e->e_xfp != NULL) 754 (void) fflush(e->e_xfp); 755 while (fgets(buf, sizeof buf, xfile) != NULL) 756 putline(buf, mci); 757 (void) xfclose(xfile, "errbody xscript", p); 758 } 759 errno = 0; 760 761 #ifdef DSN 762 /* 763 ** Output machine-readable version. 764 */ 765 766 if (e->e_msgboundary != NULL) 767 { 768 putline("", mci); 769 (void) sprintf(buf, "--%s", e->e_msgboundary); 770 putline(buf, mci); 771 putline("Content-Type: message/X-delivery-status-2 (Draft of 20 January 1995)", mci); 772 putline("", mci); 773 774 /* 775 ** Output per-message information. 776 */ 777 778 /* original envelope id from MAIL FROM: line */ 779 if (e->e_parent->e_envid != NULL) 780 { 781 (void) sprintf(buf, "Original-Envelope-Id: %s", 782 xtextify(e->e_parent->e_envid)); 783 putline(buf, mci); 784 } 785 786 /* Reporting-MTA: is us (required) */ 787 p = e->e_parent->e_from.q_mailer->m_mtatype; 788 if (p == NULL) 789 p = "dns"; 790 (void) sprintf(buf, "Reporting-MTA: %s; %s", p, 791 xtextify(MyHostName)); 792 putline(buf, mci); 793 794 /* Received-From-MTA: shows where we got this message from */ 795 if (RealHostName != NULL) 796 { 797 /* XXX use $s for type? */ 798 p = e->e_parent->e_from.q_mailer->m_mtatype; 799 if (p == NULL) 800 p = "dns"; 801 (void) sprintf(buf, "Received-From-MTA: %s; %s", 802 p, xtextify(RealHostName)); 803 putline(buf, mci); 804 } 805 806 /* Arrival-Date: -- when it arrived here */ 807 (void) sprintf(buf, "Arrival-Date: %s", 808 arpadate(ctime(&e->e_parent->e_ctime))); 809 putline(buf, mci); 810 811 /* 812 ** Output per-address information. 813 */ 814 815 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 816 { 817 register ADDRESS *r; 818 char *action; 819 820 if (bitset(QBADADDR, q->q_flags)) 821 action = "failure"; 822 else if (!bitset(QPRIMARY, q->q_flags)) 823 continue; 824 else if (bitset(QRELAYED, q->q_flags)) 825 action = "relayed"; 826 else if (bitset(QEXPLODED, q->q_flags)) 827 action = "delivered (to mailing list)"; 828 else if (bitset(QSENT, q->q_flags) && 829 bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) 830 action = "delivered (final delivery)"; 831 else if (bitset(QREPORT, q->q_flags)) 832 action = "delayed"; 833 else 834 continue; 835 836 putline("", mci); 837 838 /* Original-Recipient: -- passed from on high */ 839 if (q->q_orcpt != NULL) 840 { 841 (void) sprintf(buf, "Original-Recipient: %s", 842 xtextify(q->q_orcpt)); 843 putline(buf, mci); 844 } 845 846 /* Final-Recipient: -- the name from the RCPT command */ 847 p = e->e_parent->e_from.q_mailer->m_addrtype; 848 if (p == NULL) 849 p = "rfc822"; 850 for (r = q; r->q_alias != NULL; r = r->q_alias) 851 continue; 852 if (strchr(r->q_user, '@') == NULL) 853 { 854 (void) sprintf(buf, "Final-Recipient: %s; %s@", 855 p, xtextify(r->q_user)); 856 strcat(buf, xtextify(MyHostName)); 857 } 858 else 859 { 860 (void) sprintf(buf, "Final-Recipient: %s; %s", 861 p, xtextify(r->q_user)); 862 } 863 putline(buf, mci); 864 865 /* X-Actual-Recipient: -- the real problem address */ 866 if (r != q) 867 { 868 if (strchr(q->q_user, '@') == NULL) 869 { 870 (void) sprintf(buf, "X-Actual-Recipient: %s; %s@", 871 p, xtextify(q->q_user)); 872 strcat(buf, xtextify(MyHostName)); 873 } 874 else 875 { 876 (void) sprintf(buf, "X-Actual-Recipient: %s; %s", 877 p, xtextify(q->q_user)); 878 } 879 putline(buf, mci); 880 } 881 882 /* Action: -- what happened? */ 883 sprintf(buf, "Action: %s", action); 884 putline(buf, mci); 885 886 /* Status: -- what _really_ happened? */ 887 strcpy(buf, "Status: "); 888 if (q->q_status != NULL) 889 strcat(buf, q->q_status); 890 else if (bitset(QBADADDR, q->q_flags)) 891 strcat(buf, "5.0.0"); 892 else if (bitset(QQUEUEUP, q->q_flags)) 893 strcat(buf, "4.0.0"); 894 else 895 strcat(buf, "2.0.0"); 896 putline(buf, mci); 897 898 /* Remote-MTA: -- who was I talking to? */ 899 p = q->q_mailer->m_mtatype; 900 if (p == NULL) 901 p = "dns"; 902 (void) sprintf(buf, "Remote-MTA: %s; ", p); 903 if (q->q_statmta != NULL) 904 p = q->q_statmta; 905 else if (q->q_host != NULL && q->q_host[0] != '\0') 906 p = q->q_host; 907 else 908 p = NULL; 909 if (p != NULL) 910 { 911 strcat(buf, p); 912 p = &buf[strlen(buf) - 1]; 913 if (*p == '.') 914 *p = '\0'; 915 putline(buf, mci); 916 } 917 918 /* Diagnostic-Code: -- actual result from other end */ 919 if (q->q_rstatus != NULL) 920 { 921 p = q->q_mailer->m_diagtype; 922 if (p == NULL) 923 p = "smtp"; 924 (void) sprintf(buf, "Diagnostic-Code: %s; %s", 925 p, q->q_rstatus); 926 putline(buf, mci); 927 } 928 929 /* Last-Attempt-Date: -- fine granularity */ 930 if (q->q_statdate == (time_t) 0L) 931 q->q_statdate = curtime(); 932 (void) sprintf(buf, "Last-Attempt-Date: %s", 933 arpadate(ctime(&q->q_statdate))); 934 putline(buf, mci); 935 936 /* Expiry-Date: -- for delayed messages only */ 937 if (bitset(QQUEUEUP, q->q_flags) && 938 !bitset(QBADADDR, q->q_flags)) 939 { 940 time_t xdate; 941 942 xdate = e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]; 943 sprintf(buf, "Expiry-Date: %s", 944 arpadate(ctime(&xdate))); 945 putline(buf, mci); 946 } 947 } 948 } 949 #endif 950 951 /* 952 ** Output text of original message 953 */ 954 955 putline("", mci); 956 if (bitset(EF_HAS_DF, e->e_parent->e_flags)) 957 { 958 sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags); 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 (void) sprintf(buf, "Content-Type: message/rfc822%s", 973 mci, sendbody ? "" : "-headers"); 974 putline(buf, mci); 975 } 976 putline("", mci); 977 putheader(mci, e->e_parent->e_header, e->e_parent); 978 if (sendbody) 979 putbody(mci, e->e_parent, e->e_msgboundary); 980 else if (e->e_msgboundary == NULL) 981 { 982 putline("", mci); 983 putline(" ----- Message body suppressed -----", mci); 984 } 985 } 986 else if (e->e_msgboundary == NULL) 987 { 988 putline(" ----- No message was collected -----\n", mci); 989 } 990 991 if (e->e_msgboundary != NULL) 992 { 993 putline("", mci); 994 (void) sprintf(buf, "--%s--", e->e_msgboundary); 995 putline(buf, mci); 996 } 997 putline("", mci); 998 999 /* 1000 ** Cleanup and exit 1001 */ 1002 1003 if (errno != 0) 1004 syserr("errbody: I/O error"); 1005 } 1006 /* 1007 ** SMTPTODSN -- convert SMTP to DSN status code 1008 ** 1009 ** Parameters: 1010 ** smtpstat -- the smtp status code (e.g., 550). 1011 ** 1012 ** Returns: 1013 ** The DSN version of the status code. 1014 */ 1015 1016 char * 1017 smtptodsn(smtpstat) 1018 int smtpstat; 1019 { 1020 switch (smtpstat) 1021 { 1022 case 450: /* Req mail action not taken: mailbox unavailable */ 1023 return "4.2.0"; 1024 1025 case 451: /* Req action aborted: local error in processing */ 1026 return "4.3.0"; 1027 1028 case 452: /* Req action not taken: insufficient sys storage */ 1029 return "4.3.1"; 1030 1031 case 500: /* Syntax error, command unrecognized */ 1032 return "5.5.2"; 1033 1034 case 501: /* Syntax error in parameters or arguments */ 1035 return "5.5.4"; 1036 1037 case 502: /* Command not implemented */ 1038 return "5.5.1"; 1039 1040 case 503: /* Bad sequence of commands */ 1041 return "5.5.1"; 1042 1043 case 504: /* Command parameter not implemented */ 1044 return "5.5.4"; 1045 1046 case 550: /* Req mail action not taken: mailbox unavailable */ 1047 return "5.2.0"; 1048 1049 case 551: /* User not local; please try <...> */ 1050 return "5.1.6"; 1051 1052 case 552: /* Req mail action aborted: exceeded storage alloc */ 1053 return "5.2.2"; 1054 1055 case 553: /* Req action not taken: mailbox name not allowed */ 1056 return "5.1.3"; 1057 1058 case 554: /* Transaction failed */ 1059 return "5.0.0"; 1060 } 1061 1062 if ((smtpstat / 100) == 2) 1063 return "2.0.0"; 1064 if ((smtpstat / 100) == 4) 1065 return "4.0.0"; 1066 return "5.0.0"; 1067 } 1068 /* 1069 ** XTEXTIFY -- take regular text and turn it into DSN-style xtext 1070 ** 1071 ** Parameters: 1072 ** t -- the text to convert. 1073 ** 1074 ** Returns: 1075 ** The xtext-ified version of the same string. 1076 */ 1077 1078 char * 1079 xtextify(t) 1080 register char *t; 1081 { 1082 register char *p; 1083 int l; 1084 int nbogus; 1085 static char *bp = NULL; 1086 static int bplen = 0; 1087 1088 /* figure out how long this xtext will have to be */ 1089 nbogus = l = 0; 1090 for (p = t; *p != '\0'; p++) 1091 { 1092 register int c = (*p & 0xff); 1093 1094 /* ASCII dependence here -- this is the way the spec words it */ 1095 if ((c < ' ' || c > '~' || c == '+' || c == '\\' || c == '(') && 1096 c != '\t') 1097 nbogus++; 1098 l++; 1099 } 1100 if (nbogus == 0) 1101 return t; 1102 l += nbogus * 2 + 1; 1103 1104 /* now allocate space if necessary for the new string */ 1105 if (l > bplen) 1106 { 1107 if (bp != NULL) 1108 free(bp); 1109 bp = xalloc(l); 1110 bplen = l; 1111 } 1112 1113 /* ok, copy the text with byte expansion */ 1114 for (p = bp; *t != '\0'; ) 1115 { 1116 register int c = (*t++ & 0xff); 1117 1118 /* ASCII dependence here -- this is the way the spec words it */ 1119 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') 1120 { 1121 *p++ = '+'; 1122 *p++ = "0123456789abcdef"[c >> 4]; 1123 *p++ = "0123456789abcdef"[c & 0xf]; 1124 } 1125 else 1126 *p++ = c; 1127 } 1128 *p = '\0'; 1129 return bp; 1130 } 1131 /* 1132 ** XTEXTOK -- check if a string is legal xtext 1133 ** 1134 ** Xtext is used in Delivery Status Notifications. The spec was 1135 ** taken from draft-ietf-notary-mime-delivery-04.txt. 1136 ** 1137 ** Parameters: 1138 ** s -- the string to check. 1139 ** 1140 ** Returns: 1141 ** TRUE -- if 's' is legal xtext. 1142 ** FALSE -- if it has any illegal characters in it. 1143 */ 1144 1145 bool 1146 xtextok(s) 1147 char *s; 1148 { 1149 int c; 1150 1151 while ((c = *s++) != '\0') 1152 { 1153 if (c == '+') 1154 { 1155 c = *s++; 1156 if (!isascii(c) || !isxdigit(c)) 1157 return FALSE; 1158 c = *s++; 1159 if (!isascii(c) || !isxdigit(c)) 1160 return FALSE; 1161 } 1162 else if (c < '!' || c > '~' || c == '\\' || c == '(') 1163 return FALSE; 1164 } 1165 return TRUE; 1166 } 1167 /* 1168 ** PRUNEROUTE -- prune an RFC-822 source route 1169 ** 1170 ** Trims down a source route to the last internet-registered hop. 1171 ** This is encouraged by RFC 1123 section 5.3.3. 1172 ** 1173 ** Parameters: 1174 ** addr -- the address 1175 ** 1176 ** Returns: 1177 ** TRUE -- address was modified 1178 ** FALSE -- address could not be pruned 1179 ** 1180 ** Side Effects: 1181 ** modifies addr in-place 1182 */ 1183 1184 pruneroute(addr) 1185 char *addr; 1186 { 1187 #if NAMED_BIND 1188 char *start, *at, *comma; 1189 char c; 1190 int rcode; 1191 char hostbuf[BUFSIZ]; 1192 char *mxhosts[MAXMXHOSTS + 1]; 1193 1194 /* check to see if this is really a route-addr */ 1195 if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') 1196 return FALSE; 1197 start = strchr(addr, ':'); 1198 at = strrchr(addr, '@'); 1199 if (start == NULL || at == NULL || at < start) 1200 return FALSE; 1201 1202 /* slice off the angle brackets */ 1203 strcpy(hostbuf, at + 1); 1204 hostbuf[strlen(hostbuf) - 1] = '\0'; 1205 1206 while (start) 1207 { 1208 if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0) 1209 { 1210 strcpy(addr + 1, start + 1); 1211 return TRUE; 1212 } 1213 c = *start; 1214 *start = '\0'; 1215 comma = strrchr(addr, ','); 1216 if (comma && comma[1] == '@') 1217 strcpy(hostbuf, comma + 2); 1218 else 1219 comma = 0; 1220 *start = c; 1221 start = comma; 1222 } 1223 #endif 1224 return FALSE; 1225 } 1226