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