|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted ! 7: * provided that the above copyright notice and this paragraph are ! 8: * duplicated in all such forms and that any documentation, ! 9: * advertising materials, and other materials related to such ! 10: * distribution and use acknowledge that the software was developed ! 11: * by the University of California, Berkeley. The name of the ! 12: * University may not be used to endorse or promote products derived ! 13: * from this software without specific prior written permission. ! 14: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 15: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 16: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 17: */ ! 18: ! 19: #ifndef lint ! 20: static char sccsid[] = "@(#)savemail.c 5.9 (Berkeley) 6/30/88"; ! 21: #endif /* not lint */ ! 22: ! 23: # include <pwd.h> ! 24: # include "sendmail.h" ! 25: ! 26: /* ! 27: ** SAVEMAIL -- Save mail on error ! 28: ** ! 29: ** If mailing back errors, mail it back to the originator ! 30: ** together with an error message; otherwise, just put it in ! 31: ** dead.letter in the user's home directory (if he exists on ! 32: ** this machine). ! 33: ** ! 34: ** Parameters: ! 35: ** e -- the envelope containing the message in error. ! 36: ** ! 37: ** Returns: ! 38: ** none ! 39: ** ! 40: ** Side Effects: ! 41: ** Saves the letter, by writing or mailing it back to the ! 42: ** sender, or by putting it in dead.letter in her home ! 43: ** directory. ! 44: */ ! 45: ! 46: /* defines for state machine */ ! 47: # define ESM_REPORT 0 /* report to sender's terminal */ ! 48: # define ESM_MAIL 1 /* mail back to sender */ ! 49: # define ESM_QUIET 2 /* messages have already been returned */ ! 50: # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ ! 51: # define ESM_POSTMASTER 4 /* return to postmaster */ ! 52: # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ ! 53: # define ESM_PANIC 6 /* leave the locked queue/transcript files */ ! 54: # define ESM_DONE 7 /* the message is successfully delivered */ ! 55: ! 56: ! 57: savemail(e) ! 58: register ENVELOPE *e; ! 59: { ! 60: register struct passwd *pw; ! 61: register FILE *fp; ! 62: int state; ! 63: auto ADDRESS *q; ! 64: char buf[MAXLINE+1]; ! 65: extern struct passwd *getpwnam(); ! 66: register char *p; ! 67: extern char *ttypath(); ! 68: typedef int (*fnptr)(); ! 69: ! 70: # ifdef DEBUG ! 71: if (tTd(6, 1)) ! 72: printf("\nsavemail, ErrorMode = %c\n", ErrorMode); ! 73: # endif DEBUG ! 74: ! 75: if (bitset(EF_RESPONSE, e->e_flags)) ! 76: return; ! 77: if (e->e_class < 0) ! 78: { ! 79: message(Arpa_Info, "Dumping junk mail"); ! 80: return; ! 81: } ! 82: ForceMail = TRUE; ! 83: e->e_flags &= ~EF_FATALERRS; ! 84: ! 85: /* ! 86: ** In the unhappy event we don't know who to return the mail ! 87: ** to, make someone up. ! 88: */ ! 89: ! 90: if (e->e_from.q_paddr == NULL) ! 91: { ! 92: if (parseaddr("root", &e->e_from, 0, '\0') == NULL) ! 93: { ! 94: syserr("Cannot parse root!"); ! 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 (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("savemail: ErrorMode x%x\n"); ! 143: state = ESM_MAIL; ! 144: break; ! 145: } ! 146: ! 147: while (state != ESM_DONE) ! 148: { ! 149: # ifdef DEBUG ! 150: if (tTd(6, 5)) ! 151: printf(" state %d\n", state); ! 152: # endif DEBUG ! 153: ! 154: switch (state) ! 155: { ! 156: case ESM_QUIET: ! 157: if (e->e_from.q_mailer == LocalMailer) ! 158: state = ESM_DEADLETTER; ! 159: else ! 160: state = ESM_MAIL; ! 161: break; ! 162: ! 163: case ESM_REPORT: ! 164: ! 165: /* ! 166: ** If the user is still logged in on the same terminal, ! 167: ** then write the error messages back to hir (sic). ! 168: */ ! 169: ! 170: p = ttypath(); ! 171: if (p == NULL || freopen(p, "w", stdout) == NULL) ! 172: { ! 173: state = ESM_MAIL; ! 174: break; ! 175: } ! 176: ! 177: expand("\001n", buf, &buf[sizeof buf - 1], e); ! 178: printf("\r\nMessage from %s...\r\n", buf); ! 179: printf("Errors occurred while sending mail.\r\n"); ! 180: if (e->e_xfp != NULL) ! 181: { ! 182: (void) fflush(e->e_xfp); ! 183: fp = fopen(queuename(e, 'x'), "r"); ! 184: } ! 185: else ! 186: fp = NULL; ! 187: if (fp == NULL) ! 188: { ! 189: syserr("Cannot open %s", queuename(e, 'x')); ! 190: printf("Transcript of session is unavailable.\r\n"); ! 191: } ! 192: else ! 193: { ! 194: printf("Transcript follows:\r\n"); ! 195: while (fgets(buf, sizeof buf, fp) != NULL && ! 196: !ferror(stdout)) ! 197: fputs(buf, stdout); ! 198: (void) fclose(fp); ! 199: } ! 200: printf("Original message will be saved in dead.letter.\r\n"); ! 201: if (ferror(stdout)) ! 202: (void) syserr("savemail: stdout: write err"); ! 203: state = ESM_DEADLETTER; ! 204: break; ! 205: ! 206: case ESM_MAIL: ! 207: case ESM_POSTMASTER: ! 208: /* ! 209: ** If mailing back, do it. ! 210: ** Throw away all further output. Don't alias, ! 211: ** since this could cause loops, e.g., if joe ! 212: ** mails to joe@x, and for some reason the network ! 213: ** for @x is down, then the response gets sent to ! 214: ** joe@x, which gives a response, etc. Also force ! 215: ** the mail to be delivered even if a version of ! 216: ** it has already been sent to the sender. ! 217: */ ! 218: ! 219: if (state == ESM_MAIL) ! 220: { ! 221: if (e->e_errorqueue == NULL) ! 222: sendtolist(e->e_from.q_paddr, ! 223: (ADDRESS *) NULL, ! 224: &e->e_errorqueue); ! 225: ! 226: /* deliver a cc: to the postmaster if desired */ ! 227: if (PostMasterCopy != NULL) ! 228: sendtolist(PostMasterCopy, ! 229: (ADDRESS *) NULL, ! 230: &e->e_errorqueue); ! 231: q = e->e_errorqueue; ! 232: } ! 233: else ! 234: { ! 235: if (parseaddr("postmaster", q, 0, '\0') == NULL) ! 236: { ! 237: syserr("cannot parse postmaster!"); ! 238: ExitStat = EX_SOFTWARE; ! 239: state = ESM_USRTMP; ! 240: break; ! 241: } ! 242: } ! 243: if (returntosender(e->e_message != NULL ? e->e_message : ! 244: "Unable to deliver mail", ! 245: q, TRUE) == 0) ! 246: { ! 247: state = ESM_DONE; ! 248: break; ! 249: } ! 250: ! 251: state = state == ESM_MAIL ? ESM_POSTMASTER : ESM_USRTMP; ! 252: break; ! 253: ! 254: case ESM_DEADLETTER: ! 255: /* ! 256: ** Save the message in dead.letter. ! 257: ** If we weren't mailing back, and the user is ! 258: ** local, we should save the message in ! 259: ** ~/dead.letter so that the poor person doesn't ! 260: ** have to type it over again -- and we all know ! 261: ** what poor typists UNIX users are. ! 262: */ ! 263: ! 264: p = NULL; ! 265: if (e->e_from.q_mailer == LocalMailer) ! 266: { ! 267: if (e->e_from.q_home != NULL) ! 268: p = e->e_from.q_home; ! 269: else if ((pw = getpwnam(e->e_from.q_user)) != NULL) ! 270: p = pw->pw_dir; ! 271: } ! 272: if (p == NULL) ! 273: { ! 274: syserr("Can't return mail to %s", e->e_from.q_paddr); ! 275: state = ESM_MAIL; ! 276: break; ! 277: } ! 278: if (e->e_dfp != NULL) ! 279: { ! 280: auto ADDRESS *q; ! 281: bool oldverb = Verbose; ! 282: ! 283: /* we have a home directory; open dead.letter */ ! 284: define('z', p, e); ! 285: expand("\001z/dead.letter", buf, &buf[sizeof buf - 1], e); ! 286: Verbose = TRUE; ! 287: message(Arpa_Info, "Saving message in %s", buf); ! 288: Verbose = oldverb; ! 289: e->e_to = buf; ! 290: q = NULL; ! 291: sendtolist(buf, (ADDRESS *) NULL, &q); ! 292: if (deliver(e, q) == 0) ! 293: state = ESM_DONE; ! 294: else ! 295: state = ESM_MAIL; ! 296: } ! 297: else ! 298: { ! 299: /* no data file -- try mailing back */ ! 300: state = ESM_MAIL; ! 301: } ! 302: break; ! 303: ! 304: case ESM_USRTMP: ! 305: /* ! 306: ** Log the mail in /usr/tmp/dead.letter. ! 307: */ ! 308: ! 309: fp = dfopen("/usr/tmp/dead.letter", "a"); ! 310: if (fp == NULL) ! 311: { ! 312: state = ESM_PANIC; ! 313: break; ! 314: } ! 315: ! 316: putfromline(fp, ProgMailer); ! 317: (*e->e_puthdr)(fp, ProgMailer, e); ! 318: putline("\n", fp, ProgMailer); ! 319: (*e->e_putbody)(fp, ProgMailer, e); ! 320: putline("\n", fp, ProgMailer); ! 321: (void) fflush(fp); ! 322: state = ferror(fp) ? ESM_PANIC : ESM_DONE; ! 323: (void) fclose(fp); ! 324: break; ! 325: ! 326: default: ! 327: syserr("savemail: unknown state %d", state); ! 328: ! 329: /* fall through ... */ ! 330: ! 331: case ESM_PANIC: ! 332: syserr("savemail: HELP!!!!"); ! 333: # ifdef LOG ! 334: if (LogLevel >= 1) ! 335: syslog(LOG_ALERT, "savemail: HELP!!!!"); ! 336: # endif LOG ! 337: ! 338: /* leave the locked queue & transcript files around */ ! 339: exit(EX_SOFTWARE); ! 340: } ! 341: } ! 342: } ! 343: /* ! 344: ** RETURNTOSENDER -- return a message to the sender with an error. ! 345: ** ! 346: ** Parameters: ! 347: ** msg -- the explanatory message. ! 348: ** returnq -- the queue of people to send the message to. ! 349: ** sendbody -- if TRUE, also send back the body of the ! 350: ** message; otherwise just send the header. ! 351: ** ! 352: ** Returns: ! 353: ** zero -- if everything went ok. ! 354: ** else -- some error. ! 355: ** ! 356: ** Side Effects: ! 357: ** Returns the current message to the sender via ! 358: ** mail. ! 359: */ ! 360: ! 361: static bool SendBody; ! 362: ! 363: #define MAXRETURNS 6 /* max depth of returning messages */ ! 364: ! 365: returntosender(msg, returnq, sendbody) ! 366: char *msg; ! 367: ADDRESS *returnq; ! 368: bool sendbody; ! 369: { ! 370: char buf[MAXNAME]; ! 371: extern putheader(), errbody(); ! 372: register ENVELOPE *ee; ! 373: extern ENVELOPE *newenvelope(); ! 374: ENVELOPE errenvelope; ! 375: static int returndepth; ! 376: register ADDRESS *q; ! 377: ! 378: # ifdef DEBUG ! 379: if (tTd(6, 1)) ! 380: { ! 381: printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n", ! 382: msg, returndepth, CurEnv); ! 383: printf("\treturnq="); ! 384: printaddr(returnq, TRUE); ! 385: } ! 386: # endif DEBUG ! 387: ! 388: if (++returndepth >= MAXRETURNS) ! 389: { ! 390: if (returndepth != MAXRETURNS) ! 391: syserr("returntosender: infinite recursion on %s", returnq->q_paddr); ! 392: /* don't "unrecurse" and fake a clean exit */ ! 393: /* returndepth--; */ ! 394: return (0); ! 395: } ! 396: ! 397: SendBody = sendbody; ! 398: define('g', "\001f", CurEnv); ! 399: ee = newenvelope(&errenvelope); ! 400: define('a', "\001b", ee); ! 401: ee->e_puthdr = putheader; ! 402: ee->e_putbody = errbody; ! 403: ee->e_flags |= EF_RESPONSE; ! 404: ee->e_sendqueue = returnq; ! 405: openxscript(ee); ! 406: for (q = returnq; q != NULL; q = q->q_next) ! 407: { ! 408: if (q->q_alias == NULL) ! 409: addheader("to", q->q_paddr, ee); ! 410: } ! 411: ! 412: (void) sprintf(buf, "Returned mail: %s", msg); ! 413: addheader("subject", buf, ee); ! 414: ! 415: /* fake up an address header for the from person */ ! 416: expand("\001n", buf, &buf[sizeof buf - 1], CurEnv); ! 417: if (parseaddr(buf, &ee->e_from, -1, '\0') == NULL) ! 418: { ! 419: syserr("Can't parse myself!"); ! 420: ExitStat = EX_SOFTWARE; ! 421: returndepth--; ! 422: return (-1); ! 423: } ! 424: loweraddr(&ee->e_from); ! 425: ! 426: /* push state into submessage */ ! 427: CurEnv = ee; ! 428: define('f', "\001n", ee); ! 429: define('x', "Mail Delivery Subsystem", ee); ! 430: eatheader(ee); ! 431: ! 432: /* actually deliver the error message */ ! 433: sendall(ee, SM_DEFAULT); ! 434: ! 435: /* restore state */ ! 436: dropenvelope(ee); ! 437: CurEnv = CurEnv->e_parent; ! 438: returndepth--; ! 439: ! 440: /* should check for delivery errors here */ ! 441: return (0); ! 442: } ! 443: /* ! 444: ** ERRBODY -- output the body of an error message. ! 445: ** ! 446: ** Typically this is a copy of the transcript plus a copy of the ! 447: ** original offending message. ! 448: ** ! 449: ** Parameters: ! 450: ** fp -- the output file. ! 451: ** m -- the mailer to output to. ! 452: ** e -- the envelope we are working in. ! 453: ** ! 454: ** Returns: ! 455: ** none ! 456: ** ! 457: ** Side Effects: ! 458: ** Outputs the body of an error message. ! 459: */ ! 460: ! 461: errbody(fp, m, e) ! 462: register FILE *fp; ! 463: register struct mailer *m; ! 464: register ENVELOPE *e; ! 465: { ! 466: register FILE *xfile; ! 467: char buf[MAXLINE]; ! 468: char *p; ! 469: ! 470: /* ! 471: ** Output transcript of errors ! 472: */ ! 473: ! 474: (void) fflush(stdout); ! 475: p = queuename(e->e_parent, 'x'); ! 476: if ((xfile = fopen(p, "r")) == NULL) ! 477: { ! 478: syserr("Cannot open %s", p); ! 479: fprintf(fp, " ----- Transcript of session is unavailable -----\n"); ! 480: } ! 481: else ! 482: { ! 483: fprintf(fp, " ----- Transcript of session follows -----\n"); ! 484: if (e->e_xfp != NULL) ! 485: (void) fflush(e->e_xfp); ! 486: while (fgets(buf, sizeof buf, xfile) != NULL) ! 487: putline(buf, fp, m); ! 488: (void) fclose(xfile); ! 489: } ! 490: errno = 0; ! 491: ! 492: /* ! 493: ** Output text of original message ! 494: */ ! 495: ! 496: if (NoReturn) ! 497: fprintf(fp, "\n ----- Return message suppressed -----\n\n"); ! 498: else if (e->e_parent->e_dfp != NULL) ! 499: { ! 500: if (SendBody) ! 501: { ! 502: putline("\n", fp, m); ! 503: putline(" ----- Unsent message follows -----\n", fp, m); ! 504: (void) fflush(fp); ! 505: putheader(fp, m, e->e_parent); ! 506: putline("\n", fp, m); ! 507: putbody(fp, m, e->e_parent); ! 508: } ! 509: else ! 510: { ! 511: putline("\n", fp, m); ! 512: putline(" ----- Message header follows -----\n", fp, m); ! 513: (void) fflush(fp); ! 514: putheader(fp, m, e->e_parent); ! 515: } ! 516: } ! 517: else ! 518: { ! 519: putline("\n", fp, m); ! 520: putline(" ----- No message was collected -----\n", fp, m); ! 521: putline("\n", fp, m); ! 522: } ! 523: ! 524: /* ! 525: ** Cleanup and exit ! 526: */ ! 527: ! 528: if (errno != 0) ! 529: syserr("errbody: I/O error"); ! 530: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.