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