1297Seric # include <stdio.h> 2297Seric # include <pwd.h> 3297Seric # include "dlvrmail.h" 4297Seric 5*408Seric static char SccsId[] = "@(#)savemail.c 1.3 07/25/80"; 6*408Seric 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 ** Requires: 29297Seric ** fopen (sys) 30297Seric ** bmove 31297Seric ** parse 32297Seric ** deliver 33297Seric ** strcpy (sys) 34297Seric ** strcat (sys) 35297Seric ** fclose (sys) 36297Seric ** fgets (sys) 37297Seric ** fputs (sys) 38297Seric ** setpwent (sys) 39297Seric ** getuid (sys) 40297Seric ** setuid (sys) 41297Seric ** getgid (sys) 42297Seric ** setgid (sys) 43297Seric ** getpwnam (sys) 44297Seric ** fprintf (sys) 45297Seric ** ttypath 46297Seric ** freopen (sys) 47297Seric ** printf (sys) 48297Seric ** syserr 49297Seric ** rewind (sys) 50297Seric ** time (sys) 51297Seric ** ferror (sys) 52297Seric ** 53297Seric ** Called By: 54297Seric ** finis 55297Seric ** 56297Seric ** History: 57297Seric ** 12/30/79 -- written. 58297Seric */ 59297Seric 60297Seric # define MY_NAME "~MAILER~DAEMON~" 61297Seric 62297Seric savemail() 63297Seric { 64297Seric register struct passwd *pw; 65297Seric register FILE *xfile; 66297Seric char buf[MAXLINE+1]; 67297Seric extern errhdr(); 68297Seric auto addrq to_addr; 69297Seric extern struct passwd *getpwnam(); 70297Seric register char *p; 71297Seric register int i; 72297Seric auto long tim; 73297Seric extern int errno; 74297Seric extern char *ttypath(); 75297Seric extern char *ctime(); 76297Seric extern addrq *parse(); 77297Seric static int exclusive; 78297Seric 79297Seric if (exclusive++) 80297Seric return; 81297Seric 82297Seric /* 83297Seric ** In the unhappy event we don't know who to return the mail 84297Seric ** to, make someone up. 85297Seric */ 86297Seric 87297Seric if (From.q_paddr == NULL) 88297Seric { 89297Seric if (parse("root", &From, 0) == NULL) 90297Seric { 91297Seric syserr("Cannot parse root!"); 92297Seric ExitStat = EX_SOFTWARE; 93297Seric finis(); 94297Seric } 95297Seric } 96297Seric 97297Seric /* 98401Seric ** If called from Eric Schmidt's network, do special mailback. 99401Seric ** Fundamentally, this is the mailback case except that 100401Seric ** it returns an OK exit status (assuming the return 101401Seric ** worked). 102297Seric */ 103297Seric 104401Seric if (BerkNet) 105297Seric { 106401Seric ExitStat = EX_OK; 107297Seric MailBack++; 108297Seric } 109297Seric 110297Seric /* 111297Seric ** If writing back, do it. 112297Seric ** If the user is still logged in on the same terminal, 113297Seric ** then write the error messages back to hir (sic). 114297Seric ** If not, set the MailBack flag so that it will get 115297Seric ** mailed back instead. 116297Seric */ 117297Seric 118297Seric if (WriteBack) 119297Seric { 120297Seric p = ttypath(); 121297Seric if (p == NULL || freopen(p, "w", stdout) == NULL) 122297Seric { 123297Seric MailBack++; 124297Seric errno = 0; 125297Seric } 126297Seric else 127297Seric { 128401Seric xfile = fopen(Transcript, "r"); 129401Seric if (xfile == NULL) 130401Seric syserr("Cannot open %s", Transcript); 131297Seric printf("\r\nMessage from %s\r\n", MY_NAME); 132297Seric printf("Errors occurred while sending mail, transcript follows:\r\n"); 133297Seric while (fgets(buf, sizeof buf, xfile) && !ferror(stdout)) 134297Seric fputs(buf, stdout); 135297Seric if (ferror(stdout)) 136297Seric syserr("savemail: stdout: write err"); 137401Seric fclose(xfile); 138297Seric } 139297Seric } 140297Seric 141297Seric /* 142297Seric ** If mailing back, do it. 143297Seric ** Throw away all further output. Don't do aliases, since 144297Seric ** this could cause loops, e.g., if joe mails to x:joe, 145297Seric ** and for some reason the network for x: is down, then 146297Seric ** the response gets sent to x:joe, which gives a 147297Seric ** response, etc. Also force the mail to be delivered 148297Seric ** even if a version of it has already been sent to the 149297Seric ** sender. 150297Seric */ 151297Seric 152297Seric if (MailBack || From.q_mailer != &Mailer[0]) 153297Seric { 154297Seric freopen("/dev/null", "w", stdout); 155297Seric NoAlias++; 156297Seric ForceMail++; 157297Seric 158297Seric /* fake up an address header for the from person */ 159297Seric bmove((char *) &From, (char *) &to_addr, sizeof to_addr); 160297Seric if (parse(MY_NAME, &From, -1) == NULL) 161297Seric { 162297Seric syserr("Can't parse myself!"); 163297Seric ExitStat = EX_SOFTWARE; 164297Seric finis(); 165297Seric } 166297Seric i = deliver(&to_addr, errhdr); 167297Seric bmove((char *) &to_addr, (char *) &From, sizeof From); 168297Seric if (i != 0) 169297Seric syserr("Can't return mail to %s", p); 170297Seric else 171297Seric return; 172297Seric } 173297Seric 174297Seric /* 175297Seric ** Save the message in dead.letter. 176297Seric ** If we weren't mailing back, and the user is local, we 177297Seric ** should save the message in dead.letter so that the 178297Seric ** poor person doesn't have to type it over again -- 179297Seric ** and we all know what poor typists programmers are. 180297Seric */ 181297Seric 182297Seric setuid(getuid()); 183297Seric setgid(getgid()); 184297Seric setpwent(); 185297Seric if (From.q_mailer == &Mailer[0] && (pw = getpwnam(From.q_user)) != NULL) 186297Seric { 187297Seric /* user has a home directory */ 188297Seric p = pw->pw_dir; 189297Seric } 190297Seric else 191297Seric { 192297Seric syserr("Can't return mail to %s (pw=%u)", From.q_paddr, pw); 193297Seric # ifdef DEBUG 194297Seric p = "/usr/tmp"; 195297Seric # else 196297Seric p = NULL; 197297Seric # endif 198297Seric } 199297Seric if (p != NULL) 200297Seric { 201297Seric /* we have a home directory; open dead.letter */ 202297Seric strcpy(buf, p); 203297Seric strcat(buf, "/dead.letter"); 204297Seric xfile = fopen(buf, "a"); 205297Seric if (xfile == NULL) 206297Seric printf("Cannot save mail, sorry\n"); 207297Seric else 208297Seric { 209297Seric rewind(stdin); 210297Seric errno = 0; 211297Seric time(&tim); 212297Seric fprintf(xfile, "----- Mail saved at %s", ctime(&tim)); 213297Seric while (fgets(buf, sizeof buf, stdin) && !ferror(xfile)) 214297Seric fputs(buf, xfile); 215297Seric fputs("\n", xfile); 216297Seric if (ferror(xfile)) 217297Seric syserr("savemail: dead.letter: write err"); 218297Seric fclose(xfile); 219297Seric printf("Letter saved in dead.letter\n"); 220297Seric } 221297Seric } 222297Seric else 223297Seric 224297Seric /* add terminator to writeback message */ 225297Seric if (WriteBack) 226297Seric printf("-----\r\n"); 227297Seric } 228297Seric /* 229297Seric ** ERRHDR -- Output the header for error mail. 230297Seric ** 231297Seric ** This is the edit filter to error mailbacks. 232297Seric ** 233297Seric ** Algorithm: 234297Seric ** Output fixed header. 235297Seric ** Output the transcript part. 236297Seric ** Output the original message. 237297Seric ** 238297Seric ** Parameters: 239297Seric ** xfile -- the transcript file. 240297Seric ** fp -- the output file. 241297Seric ** 242297Seric ** Returns: 243297Seric ** none 244297Seric ** 245297Seric ** Side Effects: 246297Seric ** input from xfile 247297Seric ** output to fp 248297Seric ** 249297Seric ** Requires: 250297Seric ** read (sys) 251297Seric ** write (sys) 252297Seric ** open (sys) 253297Seric ** close (sys) 254297Seric ** syserr 255297Seric ** rewind (sys) 256297Seric ** fflush (sys) 257297Seric ** fprintf (sys) 258297Seric ** fileno (sys) 259297Seric ** 260297Seric ** Called By: 261297Seric ** deliver 262297Seric ** 263297Seric ** History: 264297Seric ** 12/28/79 -- written. 265297Seric */ 266297Seric 267297Seric 268297Seric errhdr(fp) 269297Seric register FILE *fp; 270297Seric { 271297Seric char copybuf[512]; 272297Seric register int i; 273297Seric register int xfile; 274297Seric extern int errno; 275297Seric 276297Seric if ((xfile = open(Transcript, 0)) < 0) 277297Seric syserr("Cannot open %s", Transcript); 278297Seric fflush(stdout); 279297Seric errno = 0; 280297Seric fprintf(fp, "To: %s\n", To); 281297Seric fprintf(fp, "Subject: Unable to deliver mail\n"); 282297Seric fprintf(fp, "\n ----- Transcript of session follows -----\n"); 283297Seric fflush(fp); 284297Seric while ((i = read(xfile, copybuf, sizeof copybuf)) > 0) 285297Seric write(fileno(fp), copybuf, i); 286297Seric fprintf(fp, "\n ----- Unsent message follows -----\n"); 287297Seric fflush(fp); 288297Seric rewind(stdin); 289297Seric while ((i = read(fileno(stdin), copybuf, sizeof copybuf)) > 0) 290297Seric write(fileno(fp), copybuf, i); 291297Seric close(xfile); 292297Seric if (errno != 0) 293297Seric syserr("errhdr: I/O error"); 294297Seric } 295