1297Seric # include <stdio.h> 2297Seric # include <pwd.h> 33313Seric # include "sendmail.h" 4297Seric 5*4079Seric static char SccsId[] = "@(#)savemail.c 3.9 08/09/81"; 6408Seric 7297Seric /* 8297Seric ** SAVEMAIL -- Save mail on error 9297Seric ** 10297Seric ** If the MailBack flag is set, mail it back to the originator 11297Seric ** together with an error message; otherwise, just put it in 12297Seric ** dead.letter in the user's home directory (if he exists on 13297Seric ** this machine). 14297Seric ** 15297Seric ** Parameters: 16297Seric ** none 17297Seric ** 18297Seric ** Returns: 19297Seric ** none 20297Seric ** 21297Seric ** Side Effects: 22297Seric ** Saves the letter, by writing or mailing it back to the 23297Seric ** sender, or by putting it in dead.letter in her home 24297Seric ** directory. 25297Seric ** 26297Seric ** WARNING: the user id is reset to the original user. 27297Seric */ 28297Seric 29297Seric savemail() 30297Seric { 31297Seric register struct passwd *pw; 32297Seric register FILE *xfile; 33297Seric char buf[MAXLINE+1]; 34297Seric extern errhdr(); 352973Seric auto ADDRESS to_addr; 36297Seric extern struct passwd *getpwnam(); 37297Seric register char *p; 38297Seric register int i; 39297Seric auto long tim; 40297Seric extern int errno; 41297Seric extern char *ttypath(); 422973Seric extern ADDRESS *parse(); 43297Seric static int exclusive; 442991Seric extern char *strcpy(), *strcat(); 453189Seric extern char *expand(); 46297Seric 47297Seric if (exclusive++) 48297Seric return; 49297Seric 50297Seric /* 51297Seric ** In the unhappy event we don't know who to return the mail 52297Seric ** to, make someone up. 53297Seric */ 54297Seric 55297Seric if (From.q_paddr == NULL) 56297Seric { 57297Seric if (parse("root", &From, 0) == NULL) 58297Seric { 59297Seric syserr("Cannot parse root!"); 60297Seric ExitStat = EX_SOFTWARE; 61297Seric finis(); 62297Seric } 63297Seric } 64*4079Seric To = NULL; 65297Seric 66297Seric /* 67401Seric ** If called from Eric Schmidt's network, do special mailback. 68401Seric ** Fundamentally, this is the mailback case except that 69401Seric ** it returns an OK exit status (assuming the return 70401Seric ** worked). 71297Seric */ 72297Seric 73401Seric if (BerkNet) 74297Seric { 75401Seric ExitStat = EX_OK; 76297Seric MailBack++; 77297Seric } 78297Seric 79297Seric /* 80297Seric ** If writing back, do it. 81297Seric ** If the user is still logged in on the same terminal, 82297Seric ** then write the error messages back to hir (sic). 83297Seric ** If not, set the MailBack flag so that it will get 84297Seric ** mailed back instead. 85297Seric */ 86297Seric 87297Seric if (WriteBack) 88297Seric { 89297Seric p = ttypath(); 90297Seric if (p == NULL || freopen(p, "w", stdout) == NULL) 91297Seric { 92297Seric MailBack++; 93297Seric errno = 0; 94297Seric } 95297Seric else 96297Seric { 97401Seric xfile = fopen(Transcript, "r"); 98401Seric if (xfile == NULL) 99401Seric syserr("Cannot open %s", Transcript); 1003189Seric printf("\r\nMessage from %s\r\n", expand("$n", buf, &buf[sizeof buf - 1])); 101297Seric printf("Errors occurred while sending mail, transcript follows:\r\n"); 102297Seric while (fgets(buf, sizeof buf, xfile) && !ferror(stdout)) 103297Seric fputs(buf, stdout); 104297Seric if (ferror(stdout)) 105297Seric syserr("savemail: stdout: write err"); 106401Seric fclose(xfile); 107297Seric } 108297Seric } 109297Seric 110297Seric /* 111297Seric ** If mailing back, do it. 112297Seric ** Throw away all further output. Don't do aliases, since 113297Seric ** this could cause loops, e.g., if joe mails to x:joe, 114297Seric ** and for some reason the network for x: is down, then 115297Seric ** the response gets sent to x:joe, which gives a 116297Seric ** response, etc. Also force the mail to be delivered 117297Seric ** even if a version of it has already been sent to the 118297Seric ** sender. 119297Seric */ 120297Seric 1213048Seric if (MailBack) 122297Seric { 123297Seric freopen("/dev/null", "w", stdout); 124297Seric NoAlias++; 125297Seric ForceMail++; 126297Seric 127297Seric /* fake up an address header for the from person */ 128297Seric bmove((char *) &From, (char *) &to_addr, sizeof to_addr); 1293189Seric if (parse(expand("$n", buf, &buf[sizeof buf - 1]), &From, -1) == NULL) 130297Seric { 131297Seric syserr("Can't parse myself!"); 132297Seric ExitStat = EX_SOFTWARE; 133297Seric finis(); 134297Seric } 135297Seric i = deliver(&to_addr, errhdr); 136297Seric bmove((char *) &to_addr, (char *) &From, sizeof From); 137297Seric if (i != 0) 138297Seric syserr("Can't return mail to %s", p); 139297Seric else 140297Seric return; 141297Seric } 142297Seric 143297Seric /* 144297Seric ** Save the message in dead.letter. 145297Seric ** If we weren't mailing back, and the user is local, we 146297Seric ** should save the message in dead.letter so that the 147297Seric ** poor person doesn't have to type it over again -- 148297Seric ** and we all know what poor typists programmers are. 149297Seric */ 150297Seric 151297Seric setuid(getuid()); 152297Seric setgid(getgid()); 153297Seric setpwent(); 154*4079Seric p = NULL; 155*4079Seric if (From.q_mailer == M_LOCAL) 156297Seric { 157*4079Seric if (From.q_home != NULL) 158*4079Seric p = From.q_home; 159*4079Seric else if ((pw = getpwnam(From.q_user)) != NULL) 160*4079Seric p = pw->pw_dir; 161297Seric } 162*4079Seric if (p == NULL) 163297Seric { 164*4079Seric syserr("Can't return mail to %s", From.q_paddr); 165297Seric # ifdef DEBUG 166297Seric p = "/usr/tmp"; 167297Seric # else 168297Seric p = NULL; 169297Seric # endif 170297Seric } 171297Seric if (p != NULL) 172297Seric { 173297Seric /* we have a home directory; open dead.letter */ 174*4079Seric message("050", "Saving message in dead.letter"); 175*4079Seric define('z', p); 176*4079Seric expand("$z/dead.letter", buf, &buf[sizeof buf - 1]); 1774066Seric To = buf; 1784066Seric i = mailfile(buf); 179*4079Seric giveresponse(i, TRUE, Mailer[M_LOCAL]); 180297Seric } 181297Seric 182297Seric /* add terminator to writeback message */ 183297Seric if (WriteBack) 184297Seric printf("-----\r\n"); 185297Seric } 186297Seric /* 187297Seric ** ERRHDR -- Output the header for error mail. 188297Seric ** 189297Seric ** This is the edit filter to error mailbacks. 190297Seric ** 191297Seric ** Algorithm: 192297Seric ** Output fixed header. 193297Seric ** Output the transcript part. 194297Seric ** Output the original message. 195297Seric ** 196297Seric ** Parameters: 197297Seric ** xfile -- the transcript file. 198297Seric ** fp -- the output file. 199297Seric ** 200297Seric ** Returns: 201297Seric ** none 202297Seric ** 203297Seric ** Side Effects: 204297Seric ** input from xfile 205297Seric ** output to fp 206297Seric ** 207297Seric ** Called By: 208297Seric ** deliver 209297Seric */ 210297Seric 211297Seric 212297Seric errhdr(fp) 213297Seric register FILE *fp; 214297Seric { 2153189Seric char buf[MAXLINE]; 2163189Seric register FILE *xfile; 217297Seric extern int errno; 218297Seric 2193189Seric fflush(stdout); 2203189Seric if ((xfile = fopen(Transcript, "r")) == NULL) 221297Seric syserr("Cannot open %s", Transcript); 222297Seric errno = 0; 223297Seric fprintf(fp, "To: %s\n", To); 224297Seric fprintf(fp, "Subject: Unable to deliver mail\n"); 225297Seric fprintf(fp, "\n ----- Transcript of session follows -----\n"); 2263189Seric while (fgets(xfile, buf, sizeof buf) != NULL) 2273189Seric fputs(buf, fp); 228297Seric fprintf(fp, "\n ----- Unsent message follows -----\n"); 229297Seric fflush(fp); 2303189Seric putmessage(fp, Mailer[1]); 231297Seric close(xfile); 232297Seric if (errno != 0) 233297Seric syserr("errhdr: I/O error"); 234297Seric } 235