1297Seric # include <stdio.h> 2297Seric # include <pwd.h> 3297Seric # include "dlvrmail.h" 4297Seric 5*2098Seric static char SccsId[] = "@(#)savemail.c 2.2 01/10/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(); 35297Seric auto addrq 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(); 42297Seric extern char *ctime(); 43297Seric extern addrq *parse(); 44297Seric static int exclusive; 45*2098Seric extern char *DaemonName; 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 } 64297Seric 65297Seric /* 66401Seric ** If called from Eric Schmidt's network, do special mailback. 67401Seric ** Fundamentally, this is the mailback case except that 68401Seric ** it returns an OK exit status (assuming the return 69401Seric ** worked). 70297Seric */ 71297Seric 72401Seric if (BerkNet) 73297Seric { 74401Seric ExitStat = EX_OK; 75297Seric MailBack++; 76297Seric } 77297Seric 78297Seric /* 79297Seric ** If writing back, do it. 80297Seric ** If the user is still logged in on the same terminal, 81297Seric ** then write the error messages back to hir (sic). 82297Seric ** If not, set the MailBack flag so that it will get 83297Seric ** mailed back instead. 84297Seric */ 85297Seric 86297Seric if (WriteBack) 87297Seric { 88297Seric p = ttypath(); 89297Seric if (p == NULL || freopen(p, "w", stdout) == NULL) 90297Seric { 91297Seric MailBack++; 92297Seric errno = 0; 93297Seric } 94297Seric else 95297Seric { 96401Seric xfile = fopen(Transcript, "r"); 97401Seric if (xfile == NULL) 98401Seric syserr("Cannot open %s", Transcript); 99*2098Seric printf("\r\nMessage from %s\r\n", DaemonName); 100297Seric printf("Errors occurred while sending mail, transcript follows:\r\n"); 101297Seric while (fgets(buf, sizeof buf, xfile) && !ferror(stdout)) 102297Seric fputs(buf, stdout); 103297Seric if (ferror(stdout)) 104297Seric syserr("savemail: stdout: write err"); 105401Seric fclose(xfile); 106297Seric } 107297Seric } 108297Seric 109297Seric /* 110297Seric ** If mailing back, do it. 111297Seric ** Throw away all further output. Don't do aliases, since 112297Seric ** this could cause loops, e.g., if joe mails to x:joe, 113297Seric ** and for some reason the network for x: is down, then 114297Seric ** the response gets sent to x:joe, which gives a 115297Seric ** response, etc. Also force the mail to be delivered 116297Seric ** even if a version of it has already been sent to the 117297Seric ** sender. 118297Seric */ 119297Seric 120297Seric if (MailBack || From.q_mailer != &Mailer[0]) 121297Seric { 122297Seric freopen("/dev/null", "w", stdout); 123297Seric NoAlias++; 124297Seric ForceMail++; 125297Seric 126297Seric /* fake up an address header for the from person */ 127297Seric bmove((char *) &From, (char *) &to_addr, sizeof to_addr); 128*2098Seric if (parse(DaemonName, &From, -1) == NULL) 129297Seric { 130297Seric syserr("Can't parse myself!"); 131297Seric ExitStat = EX_SOFTWARE; 132297Seric finis(); 133297Seric } 134297Seric i = deliver(&to_addr, errhdr); 135297Seric bmove((char *) &to_addr, (char *) &From, sizeof From); 136297Seric if (i != 0) 137297Seric syserr("Can't return mail to %s", p); 138297Seric else 139297Seric return; 140297Seric } 141297Seric 142297Seric /* 143297Seric ** Save the message in dead.letter. 144297Seric ** If we weren't mailing back, and the user is local, we 145297Seric ** should save the message in dead.letter so that the 146297Seric ** poor person doesn't have to type it over again -- 147297Seric ** and we all know what poor typists programmers are. 148297Seric */ 149297Seric 150297Seric setuid(getuid()); 151297Seric setgid(getgid()); 152297Seric setpwent(); 153297Seric if (From.q_mailer == &Mailer[0] && (pw = getpwnam(From.q_user)) != NULL) 154297Seric { 155297Seric /* user has a home directory */ 156297Seric p = pw->pw_dir; 157297Seric } 158297Seric else 159297Seric { 160297Seric syserr("Can't return mail to %s (pw=%u)", From.q_paddr, pw); 161297Seric # ifdef DEBUG 162297Seric p = "/usr/tmp"; 163297Seric # else 164297Seric p = NULL; 165297Seric # endif 166297Seric } 167297Seric if (p != NULL) 168297Seric { 169297Seric /* we have a home directory; open dead.letter */ 170297Seric strcpy(buf, p); 171297Seric strcat(buf, "/dead.letter"); 172297Seric xfile = fopen(buf, "a"); 173297Seric if (xfile == NULL) 174297Seric printf("Cannot save mail, sorry\n"); 175297Seric else 176297Seric { 177297Seric rewind(stdin); 178297Seric errno = 0; 179297Seric time(&tim); 180297Seric fprintf(xfile, "----- Mail saved at %s", ctime(&tim)); 181297Seric while (fgets(buf, sizeof buf, stdin) && !ferror(xfile)) 182297Seric fputs(buf, xfile); 183297Seric fputs("\n", xfile); 184297Seric if (ferror(xfile)) 185297Seric syserr("savemail: dead.letter: write err"); 186297Seric fclose(xfile); 187297Seric printf("Letter saved in dead.letter\n"); 188297Seric } 189297Seric } 190297Seric else 191297Seric 192297Seric /* add terminator to writeback message */ 193297Seric if (WriteBack) 194297Seric printf("-----\r\n"); 195297Seric } 196297Seric /* 197297Seric ** ERRHDR -- Output the header for error mail. 198297Seric ** 199297Seric ** This is the edit filter to error mailbacks. 200297Seric ** 201297Seric ** Algorithm: 202297Seric ** Output fixed header. 203297Seric ** Output the transcript part. 204297Seric ** Output the original message. 205297Seric ** 206297Seric ** Parameters: 207297Seric ** xfile -- the transcript file. 208297Seric ** fp -- the output file. 209297Seric ** 210297Seric ** Returns: 211297Seric ** none 212297Seric ** 213297Seric ** Side Effects: 214297Seric ** input from xfile 215297Seric ** output to fp 216297Seric ** 217297Seric ** Called By: 218297Seric ** deliver 219297Seric */ 220297Seric 221297Seric 222297Seric errhdr(fp) 223297Seric register FILE *fp; 224297Seric { 225297Seric char copybuf[512]; 226297Seric register int i; 227297Seric register int xfile; 228297Seric extern int errno; 229297Seric 230297Seric if ((xfile = open(Transcript, 0)) < 0) 231297Seric syserr("Cannot open %s", Transcript); 232297Seric fflush(stdout); 233297Seric errno = 0; 234297Seric fprintf(fp, "To: %s\n", To); 235297Seric fprintf(fp, "Subject: Unable to deliver mail\n"); 236297Seric fprintf(fp, "\n ----- Transcript of session follows -----\n"); 237297Seric fflush(fp); 238297Seric while ((i = read(xfile, copybuf, sizeof copybuf)) > 0) 239297Seric write(fileno(fp), copybuf, i); 240297Seric fprintf(fp, "\n ----- Unsent message follows -----\n"); 241297Seric fflush(fp); 242297Seric rewind(stdin); 243297Seric while ((i = read(fileno(stdin), copybuf, sizeof copybuf)) > 0) 244297Seric write(fileno(fp), copybuf, i); 245297Seric close(xfile); 246297Seric if (errno != 0) 247297Seric syserr("errhdr: I/O error"); 248297Seric } 249