1*22711Sdist /* 2*22711Sdist ** Sendmail 3*22711Sdist ** Copyright (c) 1983 Eric P. Allman 4*22711Sdist ** Berkeley, California 5*22711Sdist ** 6*22711Sdist ** Copyright (c) 1983 Regents of the University of California. 7*22711Sdist ** All rights reserved. The Berkeley software License Agreement 8*22711Sdist ** specifies the terms and conditions for redistribution. 9*22711Sdist */ 10*22711Sdist 11*22711Sdist #ifndef lint 12*22711Sdist static char SccsId[] = "@(#)savemail.c 5.1 (Berkeley) 06/07/85"; 13*22711Sdist #endif not lint 14*22711Sdist 15297Seric # include <pwd.h> 163313Seric # include "sendmail.h" 17297Seric 18*22711Sdist SCCSID(@(#)savemail.c 5.1 06/07/85); 19408Seric 20297Seric /* 21297Seric ** SAVEMAIL -- Save mail on error 22297Seric ** 239375Seric ** If mailing back errors, mail it back to the originator 24297Seric ** together with an error message; otherwise, just put it in 25297Seric ** dead.letter in the user's home directory (if he exists on 26297Seric ** this machine). 27297Seric ** 28297Seric ** Parameters: 299337Seric ** e -- the envelope containing the message in error. 30297Seric ** 31297Seric ** Returns: 32297Seric ** none 33297Seric ** 34297Seric ** Side Effects: 35297Seric ** Saves the letter, by writing or mailing it back to the 36297Seric ** sender, or by putting it in dead.letter in her home 37297Seric ** directory. 38297Seric */ 39297Seric 409337Seric savemail(e) 419337Seric register ENVELOPE *e; 42297Seric { 43297Seric register struct passwd *pw; 44297Seric register FILE *xfile; 45297Seric char buf[MAXLINE+1]; 46297Seric extern struct passwd *getpwnam(); 47297Seric register char *p; 48297Seric extern char *ttypath(); 495846Seric typedef int (*fnptr)(); 50297Seric 517361Seric # ifdef DEBUG 527676Seric if (tTd(6, 1)) 539375Seric printf("\nsavemail\n"); 547361Seric # endif DEBUG 557361Seric 569375Seric if (bitset(EF_RESPONSE, e->e_flags)) 57297Seric return; 589337Seric if (e->e_class < 0) 596978Seric { 607053Seric message(Arpa_Info, "Dumping junk mail"); 616978Seric return; 626978Seric } 637053Seric ForceMail = TRUE; 649337Seric e->e_flags &= ~EF_FATALERRS; 65297Seric 66297Seric /* 67297Seric ** In the unhappy event we don't know who to return the mail 68297Seric ** to, make someone up. 69297Seric */ 70297Seric 719337Seric if (e->e_from.q_paddr == NULL) 72297Seric { 7311447Seric if (parseaddr("root", &e->e_from, 0, '\0') == NULL) 74297Seric { 75297Seric syserr("Cannot parse root!"); 76297Seric ExitStat = EX_SOFTWARE; 77297Seric finis(); 78297Seric } 79297Seric } 809337Seric e->e_to = NULL; 81297Seric 82297Seric /* 83401Seric ** If called from Eric Schmidt's network, do special mailback. 84401Seric ** Fundamentally, this is the mailback case except that 85401Seric ** it returns an OK exit status (assuming the return 86401Seric ** worked). 876989Seric ** Also, if the from address is not local, mail it back. 88297Seric */ 89297Seric 909375Seric if (ErrorMode == EM_BERKNET) 91297Seric { 92401Seric ExitStat = EX_OK; 939375Seric ErrorMode = EM_MAIL; 94297Seric } 9510683Seric if (!bitnset(M_LOCAL, e->e_from.q_mailer->m_flags)) 969375Seric ErrorMode = EM_MAIL; 97297Seric 98297Seric /* 99297Seric ** If writing back, do it. 100297Seric ** If the user is still logged in on the same terminal, 101297Seric ** then write the error messages back to hir (sic). 1029375Seric ** If not, mail back instead. 103297Seric */ 104297Seric 1059375Seric if (ErrorMode == EM_WRITE) 106297Seric { 107297Seric p = ttypath(); 108297Seric if (p == NULL || freopen(p, "w", stdout) == NULL) 109297Seric { 1109375Seric ErrorMode = EM_MAIL; 111297Seric errno = 0; 112297Seric } 113297Seric else 114297Seric { 11516152Seric expand("\001n", buf, &buf[sizeof buf - 1], e); 1169375Seric printf("\r\nMessage from %s...\r\n", buf); 1179375Seric printf("Errors occurred while sending mail.\r\n"); 1189542Seric if (e->e_xfp != NULL) 1199375Seric { 1209542Seric (void) fflush(e->e_xfp); 1219375Seric xfile = fopen(queuename(e, 'x'), "r"); 1229375Seric } 1239375Seric else 1249375Seric xfile = NULL; 125401Seric if (xfile == NULL) 1269375Seric { 1279337Seric syserr("Cannot open %s", queuename(e, 'x')); 1289375Seric printf("Transcript of session is unavailable.\r\n"); 1299375Seric } 1309375Seric else 1319375Seric { 1329375Seric printf("Transcript follows:\r\n"); 1339375Seric while (fgets(buf, sizeof buf, xfile) != NULL && 1349375Seric !ferror(stdout)) 1359375Seric fputs(buf, stdout); 1369375Seric (void) fclose(xfile); 1379375Seric } 138297Seric if (ferror(stdout)) 1394086Seric (void) syserr("savemail: stdout: write err"); 140297Seric } 141297Seric } 142297Seric 143297Seric /* 144297Seric ** If mailing back, do it. 145297Seric ** Throw away all further output. Don't do aliases, since 146297Seric ** this could cause loops, e.g., if joe mails to x:joe, 147297Seric ** and for some reason the network for x: is down, then 148297Seric ** the response gets sent to x:joe, which gives a 149297Seric ** response, etc. Also force the mail to be delivered 150297Seric ** even if a version of it has already been sent to the 151297Seric ** sender. 152297Seric */ 153297Seric 1549375Seric if (ErrorMode == EM_MAIL) 155297Seric { 1569337Seric if (e->e_errorqueue == NULL) 1579616Seric sendtolist(e->e_from.q_paddr, (ADDRESS *) NULL, 1589337Seric &e->e_errorqueue); 15910106Seric if (returntosender(e->e_message != NULL ? e->e_message : 16010106Seric "Unable to deliver mail", 1619337Seric e->e_errorqueue, TRUE) == 0) 162297Seric return; 163297Seric } 164297Seric 165297Seric /* 166297Seric ** Save the message in dead.letter. 167297Seric ** If we weren't mailing back, and the user is local, we 168297Seric ** should save the message in dead.letter so that the 169297Seric ** poor person doesn't have to type it over again -- 170297Seric ** and we all know what poor typists programmers are. 171297Seric */ 172297Seric 1734079Seric p = NULL; 1749337Seric if (e->e_from.q_mailer == LocalMailer) 175297Seric { 1769337Seric if (e->e_from.q_home != NULL) 1779337Seric p = e->e_from.q_home; 1789337Seric else if ((pw = getpwnam(e->e_from.q_user)) != NULL) 1794079Seric p = pw->pw_dir; 180297Seric } 1814079Seric if (p == NULL) 182297Seric { 1839337Seric syserr("Can't return mail to %s", e->e_from.q_paddr); 184297Seric # ifdef DEBUG 185297Seric p = "/usr/tmp"; 186297Seric # endif 187297Seric } 1889542Seric if (p != NULL && e->e_dfp != NULL) 189297Seric { 1905315Seric auto ADDRESS *q; 1917053Seric bool oldverb = Verbose; 1925315Seric 193297Seric /* we have a home directory; open dead.letter */ 1949375Seric define('z', p, e); 19516152Seric expand("\001z/dead.letter", buf, &buf[sizeof buf - 1], e); 1967053Seric Verbose = TRUE; 1979375Seric message(Arpa_Info, "Saving message in %s", buf); 1987053Seric Verbose = oldverb; 1999337Seric e->e_to = buf; 2005315Seric q = NULL; 2019616Seric sendtolist(buf, (ADDRESS *) NULL, &q); 2029375Seric (void) deliver(e, q); 203297Seric } 204297Seric 205297Seric /* add terminator to writeback message */ 2069375Seric if (ErrorMode == EM_WRITE) 207297Seric printf("-----\r\n"); 208297Seric } 209297Seric /* 2104633Seric ** RETURNTOSENDER -- return a message to the sender with an error. 2114633Seric ** 2124633Seric ** Parameters: 2134633Seric ** msg -- the explanatory message. 21416479Seric ** returnq -- the queue of people to send the message to. 2155984Seric ** sendbody -- if TRUE, also send back the body of the 2165984Seric ** message; otherwise just send the header. 2174633Seric ** 2184633Seric ** Returns: 2194633Seric ** zero -- if everything went ok. 2204633Seric ** else -- some error. 2214633Seric ** 2224633Seric ** Side Effects: 2234633Seric ** Returns the current message to the sender via 2244633Seric ** mail. 2254633Seric */ 2264633Seric 2275984Seric static bool SendBody; 2284633Seric 2297045Seric #define MAXRETURNS 6 /* max depth of returning messages */ 2307045Seric 23116479Seric returntosender(msg, returnq, sendbody) 2324633Seric char *msg; 23316479Seric ADDRESS *returnq; 2345984Seric bool sendbody; 2354633Seric { 2364633Seric char buf[MAXNAME]; 2376978Seric extern putheader(), errbody(); 2386978Seric register ENVELOPE *ee; 2396978Seric extern ENVELOPE *newenvelope(); 2406978Seric ENVELOPE errenvelope; 2417045Seric static int returndepth; 2429375Seric register ADDRESS *q; 2434633Seric 2447287Seric # ifdef DEBUG 2457676Seric if (tTd(6, 1)) 2467287Seric { 2477287Seric printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n", 2487287Seric msg, returndepth, CurEnv); 2497287Seric printf("\treturnto="); 25016479Seric printaddr(returnq, TRUE); 2517287Seric } 2527287Seric # endif DEBUG 2537287Seric 2547045Seric if (++returndepth >= MAXRETURNS) 2557045Seric { 2567045Seric if (returndepth != MAXRETURNS) 25716479Seric syserr("returntosender: infinite recursion on %s", returnq->q_paddr); 2587045Seric /* don't "unrecurse" and fake a clean exit */ 2597045Seric /* returndepth--; */ 2607045Seric return (0); 2617045Seric } 2627045Seric 2635984Seric SendBody = sendbody; 26416152Seric define('g', "\001f", CurEnv); 2656978Seric ee = newenvelope(&errenvelope); 2666978Seric ee->e_puthdr = putheader; 2676978Seric ee->e_putbody = errbody; 2689375Seric ee->e_flags |= EF_RESPONSE; 26916479Seric ee->e_sendqueue = returnq; 2709542Seric openxscript(ee); 27116479Seric for (q = returnq; q != NULL; q = q->q_next) 2729375Seric { 2739375Seric if (q->q_alias == NULL) 2749375Seric addheader("to", q->q_paddr, ee); 2759375Seric } 27610845Seric (void) sprintf(buf, "Returned mail: %s", msg); 27710106Seric addheader("subject", buf, ee); 2784633Seric 2794633Seric /* fake up an address header for the from person */ 28016152Seric expand("\001n", buf, &buf[sizeof buf - 1], CurEnv); 28111447Seric if (parseaddr(buf, &ee->e_from, -1, '\0') == NULL) 2824633Seric { 2834633Seric syserr("Can't parse myself!"); 2844633Seric ExitStat = EX_SOFTWARE; 2857045Seric returndepth--; 2864633Seric return (-1); 2874633Seric } 28816159Seric loweraddr(&ee->e_from); 2895984Seric 2906978Seric /* push state into submessage */ 2916978Seric CurEnv = ee; 29216152Seric define('f', "\001n", ee); 2939375Seric define('x', "Mail Delivery Subsystem", ee); 29411291Seric eatheader(ee); 2955984Seric 2966978Seric /* actually deliver the error message */ 29714876Seric sendall(ee, SM_DEFAULT); 2986978Seric 2996978Seric /* restore state */ 3007811Seric dropenvelope(ee); 3016978Seric CurEnv = CurEnv->e_parent; 3027045Seric returndepth--; 3036978Seric 3047045Seric /* should check for delivery errors here */ 3054633Seric return (0); 3064633Seric } 3074633Seric /* 3086978Seric ** ERRBODY -- output the body of an error message. 3096978Seric ** 3106978Seric ** Typically this is a copy of the transcript plus a copy of the 3116978Seric ** original offending message. 3126978Seric ** 313297Seric ** Parameters: 314297Seric ** fp -- the output file. 31510170Seric ** m -- the mailer to output to. 3169542Seric ** e -- the envelope we are working in. 317297Seric ** 318297Seric ** Returns: 319297Seric ** none 320297Seric ** 321297Seric ** Side Effects: 3226978Seric ** Outputs the body of an error message. 323297Seric */ 324297Seric 32510170Seric errbody(fp, m, e) 326297Seric register FILE *fp; 3274318Seric register struct mailer *m; 3289542Seric register ENVELOPE *e; 329297Seric { 3306978Seric register FILE *xfile; 3313189Seric char buf[MAXLINE]; 3329337Seric char *p; 333297Seric 3349057Seric /* 3359057Seric ** Output transcript of errors 3369057Seric */ 3379057Seric 3384086Seric (void) fflush(stdout); 3399542Seric p = queuename(e->e_parent, 'x'); 3409337Seric if ((xfile = fopen(p, "r")) == NULL) 3419057Seric { 3429337Seric syserr("Cannot open %s", p); 3439057Seric fprintf(fp, " ----- Transcript of session is unavailable -----\n"); 3449057Seric } 3459057Seric else 3469057Seric { 3479057Seric fprintf(fp, " ----- Transcript of session follows -----\n"); 3489542Seric if (e->e_xfp != NULL) 3499542Seric (void) fflush(e->e_xfp); 3509057Seric while (fgets(buf, sizeof buf, xfile) != NULL) 35110170Seric putline(buf, fp, m); 3529057Seric (void) fclose(xfile); 3539057Seric } 354297Seric errno = 0; 3554318Seric 3564318Seric /* 3574318Seric ** Output text of original message 3584318Seric */ 3594318Seric 3604289Seric if (NoReturn) 3614289Seric fprintf(fp, "\n ----- Return message suppressed -----\n\n"); 3629542Seric else if (e->e_parent->e_dfp != NULL) 3634199Seric { 3645984Seric if (SendBody) 3655984Seric { 36610170Seric putline("\n", fp, m); 36710170Seric putline(" ----- Unsent message follows -----\n", fp, m); 3685984Seric (void) fflush(fp); 36910170Seric putheader(fp, m, e->e_parent); 37010170Seric putline("\n", fp, m); 37110170Seric putbody(fp, m, e->e_parent); 3725984Seric } 3735984Seric else 3745984Seric { 37510170Seric putline("\n", fp, m); 37610170Seric putline(" ----- Message header follows -----\n", fp, m); 3775984Seric (void) fflush(fp); 37810170Seric putheader(fp, m, e->e_parent); 3795984Seric } 3804199Seric } 3814199Seric else 38210170Seric { 38310170Seric putline("\n", fp, m); 38410170Seric putline(" ----- No message was collected -----\n", fp, m); 38510170Seric putline("\n", fp, m); 38610170Seric } 3874318Seric 3884318Seric /* 3894318Seric ** Cleanup and exit 3904318Seric */ 3914318Seric 392297Seric if (errno != 0) 3936978Seric syserr("errbody: I/O error"); 394297Seric } 395