|
|
1.1 ! root 1: # include <pwd.h> ! 2: # include "sendmail.h" ! 3: ! 4: SCCSID(@(#)savemail.c 4.2 8/28/83); ! 5: ! 6: /* ! 7: ** SAVEMAIL -- Save mail on error ! 8: ** ! 9: ** If mailing back errors, mail it back to the originator ! 10: ** together with an error message; otherwise, just put it in ! 11: ** dead.letter in the user's home directory (if he exists on ! 12: ** this machine). ! 13: ** ! 14: ** Parameters: ! 15: ** e -- the envelope containing the message in error. ! 16: ** ! 17: ** Returns: ! 18: ** none ! 19: ** ! 20: ** Side Effects: ! 21: ** Saves the letter, by writing or mailing it back to the ! 22: ** sender, or by putting it in dead.letter in her home ! 23: ** directory. ! 24: */ ! 25: ! 26: savemail(e) ! 27: register ENVELOPE *e; ! 28: { ! 29: register struct passwd *pw; ! 30: register FILE *xfile; ! 31: char buf[MAXLINE+1]; ! 32: extern struct passwd *getpwnam(); ! 33: register char *p; ! 34: extern char *ttypath(); ! 35: typedef int (*fnptr)(); ! 36: ! 37: # ifdef DEBUG ! 38: if (tTd(6, 1)) ! 39: printf("\nsavemail\n"); ! 40: # endif DEBUG ! 41: ! 42: if (bitset(EF_RESPONSE, e->e_flags)) ! 43: return; ! 44: if (e->e_class < 0) ! 45: { ! 46: message(Arpa_Info, "Dumping junk mail"); ! 47: return; ! 48: } ! 49: ForceMail = TRUE; ! 50: e->e_flags &= ~EF_FATALERRS; ! 51: ! 52: /* ! 53: ** In the unhappy event we don't know who to return the mail ! 54: ** to, make someone up. ! 55: */ ! 56: ! 57: if (e->e_from.q_paddr == NULL) ! 58: { ! 59: if (parseaddr("root", &e->e_from, 0, '\0') == NULL) ! 60: { ! 61: syserr("Cannot parse root!"); ! 62: ExitStat = EX_SOFTWARE; ! 63: finis(); ! 64: } ! 65: } ! 66: e->e_to = NULL; ! 67: ! 68: /* ! 69: ** If called from Eric Schmidt's network, do special mailback. ! 70: ** Fundamentally, this is the mailback case except that ! 71: ** it returns an OK exit status (assuming the return ! 72: ** worked). ! 73: ** Also, if the from address is not local, mail it back. ! 74: */ ! 75: ! 76: if (ErrorMode == EM_BERKNET) ! 77: { ! 78: ExitStat = EX_OK; ! 79: ErrorMode = EM_MAIL; ! 80: } ! 81: if (!bitnset(M_LOCAL, e->e_from.q_mailer->m_flags)) ! 82: ErrorMode = EM_MAIL; ! 83: ! 84: /* ! 85: ** If writing back, do it. ! 86: ** If the user is still logged in on the same terminal, ! 87: ** then write the error messages back to hir (sic). ! 88: ** If not, mail back instead. ! 89: */ ! 90: ! 91: if (ErrorMode == EM_WRITE) ! 92: { ! 93: p = ttypath(); ! 94: if (p == NULL || freopen(p, "w", stdout) == NULL) ! 95: { ! 96: ErrorMode = EM_MAIL; ! 97: errno = 0; ! 98: } ! 99: else ! 100: { ! 101: expand("$n", buf, &buf[sizeof buf - 1], e); ! 102: printf("\r\nMessage from %s...\r\n", buf); ! 103: printf("Errors occurred while sending mail.\r\n"); ! 104: if (e->e_xfp != NULL) ! 105: { ! 106: (void) fflush(e->e_xfp); ! 107: xfile = fopen(queuename(e, 'x'), "r"); ! 108: } ! 109: else ! 110: xfile = NULL; ! 111: if (xfile == NULL) ! 112: { ! 113: syserr("Cannot open %s", queuename(e, 'x')); ! 114: printf("Transcript of session is unavailable.\r\n"); ! 115: } ! 116: else ! 117: { ! 118: printf("Transcript follows:\r\n"); ! 119: while (fgets(buf, sizeof buf, xfile) != NULL && ! 120: !ferror(stdout)) ! 121: fputs(buf, stdout); ! 122: (void) fclose(xfile); ! 123: } ! 124: if (ferror(stdout)) ! 125: (void) syserr("savemail: stdout: write err"); ! 126: } ! 127: } ! 128: ! 129: /* ! 130: ** If mailing back, do it. ! 131: ** Throw away all further output. Don't do aliases, since ! 132: ** this could cause loops, e.g., if joe mails to x:joe, ! 133: ** and for some reason the network for x: is down, then ! 134: ** the response gets sent to x:joe, which gives a ! 135: ** response, etc. Also force the mail to be delivered ! 136: ** even if a version of it has already been sent to the ! 137: ** sender. ! 138: */ ! 139: ! 140: if (ErrorMode == EM_MAIL) ! 141: { ! 142: if (e->e_errorqueue == NULL) ! 143: sendtolist(e->e_from.q_paddr, (ADDRESS *) NULL, ! 144: &e->e_errorqueue); ! 145: if (returntosender(e->e_message != NULL ? e->e_message : ! 146: "Unable to deliver mail", ! 147: e->e_errorqueue, TRUE) == 0) ! 148: return; ! 149: } ! 150: ! 151: /* ! 152: ** Save the message in dead.letter. ! 153: ** If we weren't mailing back, and the user is local, we ! 154: ** should save the message in dead.letter so that the ! 155: ** poor person doesn't have to type it over again -- ! 156: ** and we all know what poor typists programmers are. ! 157: */ ! 158: ! 159: p = NULL; ! 160: if (e->e_from.q_mailer == LocalMailer) ! 161: { ! 162: if (e->e_from.q_home != NULL) ! 163: p = e->e_from.q_home; ! 164: else if ((pw = getpwnam(e->e_from.q_user)) != NULL) ! 165: p = pw->pw_dir; ! 166: } ! 167: if (p == NULL) ! 168: { ! 169: syserr("Can't return mail to %s", e->e_from.q_paddr); ! 170: # ifdef DEBUG ! 171: p = "/usr/tmp"; ! 172: # endif ! 173: } ! 174: if (p != NULL && e->e_dfp != NULL) ! 175: { ! 176: auto ADDRESS *q; ! 177: bool oldverb = Verbose; ! 178: ! 179: /* we have a home directory; open dead.letter */ ! 180: define('z', p, e); ! 181: expand("$z/dead.letter", buf, &buf[sizeof buf - 1], e); ! 182: Verbose = TRUE; ! 183: message(Arpa_Info, "Saving message in %s", buf); ! 184: Verbose = oldverb; ! 185: e->e_to = buf; ! 186: q = NULL; ! 187: sendtolist(buf, (ADDRESS *) NULL, &q); ! 188: (void) deliver(e, q); ! 189: } ! 190: ! 191: /* add terminator to writeback message */ ! 192: if (ErrorMode == EM_WRITE) ! 193: printf("-----\r\n"); ! 194: } ! 195: /* ! 196: ** RETURNTOSENDER -- return a message to the sender with an error. ! 197: ** ! 198: ** Parameters: ! 199: ** msg -- the explanatory message. ! 200: ** returnto -- the queue of people to send the message to. ! 201: ** sendbody -- if TRUE, also send back the body of the ! 202: ** message; otherwise just send the header. ! 203: ** ! 204: ** Returns: ! 205: ** zero -- if everything went ok. ! 206: ** else -- some error. ! 207: ** ! 208: ** Side Effects: ! 209: ** Returns the current message to the sender via ! 210: ** mail. ! 211: */ ! 212: ! 213: static bool SendBody; ! 214: ! 215: #define MAXRETURNS 6 /* max depth of returning messages */ ! 216: ! 217: returntosender(msg, returnto, sendbody) ! 218: char *msg; ! 219: ADDRESS *returnto; ! 220: bool sendbody; ! 221: { ! 222: char buf[MAXNAME]; ! 223: extern putheader(), errbody(); ! 224: register ENVELOPE *ee; ! 225: extern ENVELOPE *newenvelope(); ! 226: ENVELOPE errenvelope; ! 227: static int returndepth; ! 228: register ADDRESS *q; ! 229: ! 230: # ifdef DEBUG ! 231: if (tTd(6, 1)) ! 232: { ! 233: printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n", ! 234: msg, returndepth, CurEnv); ! 235: printf("\treturnto="); ! 236: printaddr(returnto, TRUE); ! 237: } ! 238: # endif DEBUG ! 239: ! 240: if (++returndepth >= MAXRETURNS) ! 241: { ! 242: if (returndepth != MAXRETURNS) ! 243: syserr("returntosender: infinite recursion on %s", returnto->q_paddr); ! 244: /* don't "unrecurse" and fake a clean exit */ ! 245: /* returndepth--; */ ! 246: return (0); ! 247: } ! 248: ! 249: SendBody = sendbody; ! 250: define('g', "$f", CurEnv); ! 251: ee = newenvelope(&errenvelope); ! 252: ee->e_puthdr = putheader; ! 253: ee->e_putbody = errbody; ! 254: ee->e_flags |= EF_RESPONSE; ! 255: ee->e_sendqueue = returnto; ! 256: openxscript(ee); ! 257: for (q = returnto; q != NULL; q = q->q_next) ! 258: { ! 259: if (q->q_alias == NULL) ! 260: addheader("to", q->q_paddr, ee); ! 261: } ! 262: (void) sprintf(buf, "Returned mail: %s", msg); ! 263: addheader("subject", buf, ee); ! 264: ! 265: /* fake up an address header for the from person */ ! 266: expand("$n", buf, &buf[sizeof buf - 1], CurEnv); ! 267: if (parseaddr(buf, &ee->e_from, -1, '\0') == NULL) ! 268: { ! 269: syserr("Can't parse myself!"); ! 270: ExitStat = EX_SOFTWARE; ! 271: returndepth--; ! 272: return (-1); ! 273: } ! 274: ! 275: /* push state into submessage */ ! 276: CurEnv = ee; ! 277: define('f', "$n", ee); ! 278: define('x', "Mail Delivery Subsystem", ee); ! 279: eatheader(ee); ! 280: ! 281: /* actually deliver the error message */ ! 282: sendall(ee, SM_DEFAULT); ! 283: ! 284: /* restore state */ ! 285: dropenvelope(ee); ! 286: CurEnv = CurEnv->e_parent; ! 287: returndepth--; ! 288: ! 289: /* should check for delivery errors here */ ! 290: return (0); ! 291: } ! 292: /* ! 293: ** ERRBODY -- output the body of an error message. ! 294: ** ! 295: ** Typically this is a copy of the transcript plus a copy of the ! 296: ** original offending message. ! 297: ** ! 298: ** Parameters: ! 299: ** fp -- the output file. ! 300: ** m -- the mailer to output to. ! 301: ** e -- the envelope we are working in. ! 302: ** ! 303: ** Returns: ! 304: ** none ! 305: ** ! 306: ** Side Effects: ! 307: ** Outputs the body of an error message. ! 308: */ ! 309: ! 310: errbody(fp, m, e) ! 311: register FILE *fp; ! 312: register struct mailer *m; ! 313: register ENVELOPE *e; ! 314: { ! 315: register FILE *xfile; ! 316: char buf[MAXLINE]; ! 317: char *p; ! 318: ! 319: /* ! 320: ** Output transcript of errors ! 321: */ ! 322: ! 323: (void) fflush(stdout); ! 324: p = queuename(e->e_parent, 'x'); ! 325: if ((xfile = fopen(p, "r")) == NULL) ! 326: { ! 327: syserr("Cannot open %s", p); ! 328: fprintf(fp, " ----- Transcript of session is unavailable -----\n"); ! 329: } ! 330: else ! 331: { ! 332: fprintf(fp, " ----- Transcript of session follows -----\n"); ! 333: if (e->e_xfp != NULL) ! 334: (void) fflush(e->e_xfp); ! 335: while (fgets(buf, sizeof buf, xfile) != NULL) ! 336: putline(buf, fp, m); ! 337: (void) fclose(xfile); ! 338: } ! 339: errno = 0; ! 340: ! 341: /* ! 342: ** Output text of original message ! 343: */ ! 344: ! 345: if (NoReturn) ! 346: fprintf(fp, "\n ----- Return message suppressed -----\n\n"); ! 347: else if (e->e_parent->e_dfp != NULL) ! 348: { ! 349: if (SendBody) ! 350: { ! 351: putline("\n", fp, m); ! 352: putline(" ----- Unsent message follows -----\n", fp, m); ! 353: (void) fflush(fp); ! 354: putheader(fp, m, e->e_parent); ! 355: putline("\n", fp, m); ! 356: putbody(fp, m, e->e_parent); ! 357: } ! 358: else ! 359: { ! 360: putline("\n", fp, m); ! 361: putline(" ----- Message header follows -----\n", fp, m); ! 362: (void) fflush(fp); ! 363: putheader(fp, m, e->e_parent); ! 364: } ! 365: } ! 366: else ! 367: { ! 368: putline("\n", fp, m); ! 369: putline(" ----- No message was collected -----\n", fp, m); ! 370: putline("\n", fp, m); ! 371: } ! 372: ! 373: /* ! 374: ** Cleanup and exit ! 375: */ ! 376: ! 377: if (errno != 0) ! 378: syserr("errbody: I/O error"); ! 379: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.