1297Seric # include <pwd.h> 23313Seric # include "sendmail.h" 3297Seric 4*4599Seric static char SccsId[] = "@(#)savemail.c 3.20 10/23/81"; 5408Seric 6297Seric /* 7297Seric ** SAVEMAIL -- Save mail on error 8297Seric ** 9297Seric ** If the MailBack flag is set, mail it back to the originator 10297Seric ** together with an error message; otherwise, just put it in 11297Seric ** dead.letter in the user's home directory (if he exists on 12297Seric ** this machine). 13297Seric ** 14297Seric ** Parameters: 15297Seric ** none 16297Seric ** 17297Seric ** Returns: 18297Seric ** none 19297Seric ** 20297Seric ** Side Effects: 21297Seric ** Saves the letter, by writing or mailing it back to the 22297Seric ** sender, or by putting it in dead.letter in her home 23297Seric ** directory. 24297Seric */ 25297Seric 26297Seric savemail() 27297Seric { 28297Seric register struct passwd *pw; 29297Seric register FILE *xfile; 30297Seric char buf[MAXLINE+1]; 31297Seric extern errhdr(); 322973Seric auto ADDRESS to_addr; 33297Seric extern struct passwd *getpwnam(); 34297Seric register char *p; 35297Seric register int i; 36297Seric extern char *ttypath(); 37297Seric static int exclusive; 38297Seric 394199Seric if (exclusive++) 40297Seric return; 41297Seric 42297Seric /* 43297Seric ** In the unhappy event we don't know who to return the mail 44297Seric ** to, make someone up. 45297Seric */ 46297Seric 47297Seric if (From.q_paddr == NULL) 48297Seric { 49297Seric if (parse("root", &From, 0) == NULL) 50297Seric { 51297Seric syserr("Cannot parse root!"); 52297Seric ExitStat = EX_SOFTWARE; 53297Seric finis(); 54297Seric } 55297Seric } 564079Seric To = NULL; 57297Seric 58297Seric /* 59401Seric ** If called from Eric Schmidt's network, do special mailback. 60401Seric ** Fundamentally, this is the mailback case except that 61401Seric ** it returns an OK exit status (assuming the return 62401Seric ** worked). 63297Seric */ 64297Seric 65401Seric if (BerkNet) 66297Seric { 67401Seric ExitStat = EX_OK; 68297Seric MailBack++; 69297Seric } 70297Seric 71297Seric /* 72297Seric ** If writing back, do it. 73297Seric ** If the user is still logged in on the same terminal, 74297Seric ** then write the error messages back to hir (sic). 75297Seric ** If not, set the MailBack flag so that it will get 76297Seric ** mailed back instead. 77297Seric */ 78297Seric 79297Seric if (WriteBack) 80297Seric { 81297Seric p = ttypath(); 82297Seric if (p == NULL || freopen(p, "w", stdout) == NULL) 83297Seric { 84297Seric MailBack++; 85297Seric errno = 0; 86297Seric } 87297Seric else 88297Seric { 89401Seric xfile = fopen(Transcript, "r"); 90401Seric if (xfile == NULL) 91401Seric syserr("Cannot open %s", Transcript); 924086Seric (void) expand("$n", buf, &buf[sizeof buf - 1]); 934162Seric printf("\r\nMessage from %s...\r\n", buf); 944318Seric printf("Errors occurred while sending mail; transcript follows:\r\n"); 954086Seric while (fgets(buf, sizeof buf, xfile) != NULL && !ferror(stdout)) 96297Seric fputs(buf, stdout); 97297Seric if (ferror(stdout)) 984086Seric (void) syserr("savemail: stdout: write err"); 994086Seric (void) fclose(xfile); 100297Seric } 101297Seric } 102297Seric 103297Seric /* 104297Seric ** If mailing back, do it. 105297Seric ** Throw away all further output. Don't do aliases, since 106297Seric ** this could cause loops, e.g., if joe mails to x:joe, 107297Seric ** and for some reason the network for x: is down, then 108297Seric ** the response gets sent to x:joe, which gives a 109297Seric ** response, etc. Also force the mail to be delivered 110297Seric ** even if a version of it has already been sent to the 111297Seric ** sender. 112297Seric */ 113297Seric 1143048Seric if (MailBack) 115297Seric { 1164086Seric (void) freopen("/dev/null", "w", stdout); 117297Seric NoAlias++; 118297Seric ForceMail++; 119297Seric 120297Seric /* fake up an address header for the from person */ 121297Seric bmove((char *) &From, (char *) &to_addr, sizeof to_addr); 1224086Seric (void) expand("$n", buf, &buf[sizeof buf - 1]); 1234086Seric if (parse(buf, &From, -1) == NULL) 124297Seric { 125297Seric syserr("Can't parse myself!"); 126297Seric ExitStat = EX_SOFTWARE; 127297Seric finis(); 128297Seric } 1294318Seric to_addr.q_next = NULL; 130297Seric i = deliver(&to_addr, errhdr); 131297Seric bmove((char *) &to_addr, (char *) &From, sizeof From); 132297Seric if (i != 0) 133297Seric syserr("Can't return mail to %s", p); 134297Seric else 135297Seric return; 136297Seric } 137297Seric 138297Seric /* 139297Seric ** Save the message in dead.letter. 140297Seric ** If we weren't mailing back, and the user is local, we 141297Seric ** should save the message in dead.letter so that the 142297Seric ** poor person doesn't have to type it over again -- 143297Seric ** and we all know what poor typists programmers are. 144297Seric */ 145297Seric 1464162Seric if (ArpaMode != ARPA_NONE) 1474162Seric return; 1484079Seric p = NULL; 149*4599Seric if (From.q_mailer == LocalMailer) 150297Seric { 1514079Seric if (From.q_home != NULL) 1524079Seric p = From.q_home; 1534079Seric else if ((pw = getpwnam(From.q_user)) != NULL) 1544079Seric p = pw->pw_dir; 155297Seric } 1564079Seric if (p == NULL) 157297Seric { 1584079Seric syserr("Can't return mail to %s", From.q_paddr); 159297Seric # ifdef DEBUG 160297Seric p = "/usr/tmp"; 161297Seric # else 162297Seric p = NULL; 163297Seric # endif 164297Seric } 1654199Seric if (p != NULL && TempFile != NULL) 166297Seric { 167297Seric /* we have a home directory; open dead.letter */ 1684167Seric message(Arpa_Info, "Saving message in dead.letter"); 1694079Seric define('z', p); 1704086Seric (void) expand("$z/dead.letter", buf, &buf[sizeof buf - 1]); 1714066Seric To = buf; 1724398Seric i = mailfile(buf, &From); 173*4599Seric giveresponse(i, TRUE, LocalMailer); 174297Seric } 175297Seric 176297Seric /* add terminator to writeback message */ 177297Seric if (WriteBack) 178297Seric printf("-----\r\n"); 179297Seric } 180297Seric /* 181297Seric ** ERRHDR -- Output the header for error mail. 182297Seric ** 183297Seric ** This is the edit filter to error mailbacks. 184297Seric ** 185297Seric ** Algorithm: 186297Seric ** Output fixed header. 187297Seric ** Output the transcript part. 188297Seric ** Output the original message. 189297Seric ** 190297Seric ** Parameters: 191297Seric ** xfile -- the transcript file. 192297Seric ** fp -- the output file. 193297Seric ** 194297Seric ** Returns: 195297Seric ** none 196297Seric ** 197297Seric ** Side Effects: 198297Seric ** input from xfile 199297Seric ** output to fp 200297Seric ** 201297Seric ** Called By: 202297Seric ** deliver 203297Seric */ 204297Seric 205297Seric 2064318Seric errhdr(fp, m) 207297Seric register FILE *fp; 2084318Seric register struct mailer *m; 209297Seric { 2103189Seric char buf[MAXLINE]; 2113189Seric register FILE *xfile; 2124454Seric extern char *macvalue(); 2134454Seric char *oldfmac; 2144454Seric char *oldgmac; 215297Seric 2164454Seric oldfmac = macvalue('f'); 2174454Seric define('f', "$n"); 2184454Seric oldgmac = macvalue('g'); 2194454Seric define('g', m->m_from); 2204454Seric 2214086Seric (void) fflush(stdout); 2223189Seric if ((xfile = fopen(Transcript, "r")) == NULL) 223297Seric syserr("Cannot open %s", Transcript); 224297Seric errno = 0; 2254318Seric 2264318Seric /* 2274454Seric ** Output "From" line unless supressed 2284454Seric */ 2294454Seric 2304454Seric if (!bitset(M_NHDR, m->m_flags)) 2314454Seric { 2324454Seric (void) expand("$l", buf, &buf[sizeof buf - 1]); 2334454Seric fprintf(fp, "%s\n", buf); 2344454Seric } 2354454Seric 2364454Seric /* 2374318Seric ** Output header of error message. 2384318Seric */ 2394318Seric 2404318Seric if (bitset(M_NEEDDATE, m->m_flags)) 2414318Seric { 2424318Seric (void) expand("$b", buf, &buf[sizeof buf - 1]); 2434318Seric fprintf(fp, "Date: %s\n", buf); 2444318Seric } 2454318Seric if (bitset(M_NEEDFROM, m->m_flags)) 2464318Seric { 2474318Seric (void) expand("$g", buf, &buf[sizeof buf - 1]); 2484318Seric fprintf(fp, "From: %s (Mail Delivery Subsystem)\n", buf); 2494318Seric } 250297Seric fprintf(fp, "To: %s\n", To); 251297Seric fprintf(fp, "Subject: Unable to deliver mail\n"); 2524318Seric 2534318Seric /* 2544454Seric ** End of error message header 2554454Seric */ 2564454Seric 2574454Seric define('f', oldfmac); 2584454Seric define('g', oldgmac); 2594454Seric 2604454Seric /* 2614318Seric ** Output transcript of errors 2624318Seric */ 2634318Seric 264297Seric fprintf(fp, "\n ----- Transcript of session follows -----\n"); 2654086Seric while (fgets(buf, sizeof buf, xfile) != NULL) 2663189Seric fputs(buf, fp); 2674318Seric 2684318Seric /* 2694318Seric ** Output text of original message 2704318Seric */ 2714318Seric 2724289Seric if (NoReturn) 2734289Seric fprintf(fp, "\n ----- Return message suppressed -----\n\n"); 2744289Seric else if (TempFile != NULL) 2754199Seric { 2764199Seric fprintf(fp, "\n ----- Unsent message follows -----\n"); 2774199Seric (void) fflush(fp); 2784199Seric putmessage(fp, Mailer[1]); 2794199Seric } 2804199Seric else 2814199Seric fprintf(fp, "\n ----- No message was collected -----\n\n"); 2824318Seric 2834318Seric /* 2844318Seric ** Cleanup and exit 2854318Seric */ 2864318Seric 2874086Seric (void) fclose(xfile); 288297Seric if (errno != 0) 289297Seric syserr("errhdr: I/O error"); 290297Seric } 291