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: }