1*297Seric # include <stdio.h> 2*297Seric # include <pwd.h> 3*297Seric # include "dlvrmail.h" 4*297Seric 5*297Seric /* 6*297Seric ** SAVEMAIL -- Save mail on error 7*297Seric ** 8*297Seric ** If the MailBack flag is set, mail it back to the originator 9*297Seric ** together with an error message; otherwise, just put it in 10*297Seric ** dead.letter in the user's home directory (if he exists on 11*297Seric ** this machine). 12*297Seric ** 13*297Seric ** Parameters: 14*297Seric ** none 15*297Seric ** 16*297Seric ** Returns: 17*297Seric ** none 18*297Seric ** 19*297Seric ** Side Effects: 20*297Seric ** Saves the letter, by writing or mailing it back to the 21*297Seric ** sender, or by putting it in dead.letter in her home 22*297Seric ** directory. 23*297Seric ** 24*297Seric ** WARNING: the user id is reset to the original user. 25*297Seric ** 26*297Seric ** Requires: 27*297Seric ** fopen (sys) 28*297Seric ** bmove 29*297Seric ** parse 30*297Seric ** deliver 31*297Seric ** strcpy (sys) 32*297Seric ** strcat (sys) 33*297Seric ** fclose (sys) 34*297Seric ** fgets (sys) 35*297Seric ** fputs (sys) 36*297Seric ** setpwent (sys) 37*297Seric ** getuid (sys) 38*297Seric ** setuid (sys) 39*297Seric ** getgid (sys) 40*297Seric ** setgid (sys) 41*297Seric ** getpwnam (sys) 42*297Seric ** fprintf (sys) 43*297Seric ** ttypath 44*297Seric ** freopen (sys) 45*297Seric ** printf (sys) 46*297Seric ** syserr 47*297Seric ** rewind (sys) 48*297Seric ** time (sys) 49*297Seric ** ferror (sys) 50*297Seric ** 51*297Seric ** Called By: 52*297Seric ** finis 53*297Seric ** 54*297Seric ** History: 55*297Seric ** 12/30/79 -- written. 56*297Seric */ 57*297Seric 58*297Seric # define MY_NAME "~MAILER~DAEMON~" 59*297Seric 60*297Seric savemail() 61*297Seric { 62*297Seric register struct passwd *pw; 63*297Seric register FILE *xfile; 64*297Seric char buf[MAXLINE+1]; 65*297Seric extern errhdr(); 66*297Seric auto addrq to_addr; 67*297Seric extern struct passwd *getpwnam(); 68*297Seric register char *p; 69*297Seric register int i; 70*297Seric auto long tim; 71*297Seric extern int errno; 72*297Seric extern char *ttypath(); 73*297Seric extern char *ctime(); 74*297Seric extern addrq *parse(); 75*297Seric static int exclusive; 76*297Seric 77*297Seric if (exclusive++) 78*297Seric return; 79*297Seric 80*297Seric /* 81*297Seric ** In the unhappy event we don't know who to return the mail 82*297Seric ** to, make someone up. 83*297Seric */ 84*297Seric 85*297Seric if (From.q_paddr == NULL) 86*297Seric { 87*297Seric if (parse("root", &From, 0) == NULL) 88*297Seric { 89*297Seric syserr("Cannot parse root!"); 90*297Seric ExitStat = EX_SOFTWARE; 91*297Seric finis(); 92*297Seric } 93*297Seric } 94*297Seric 95*297Seric /* 96*297Seric ** If echoing the bad mail, do it. 97*297Seric ** Output the transcript and a message saying that the 98*297Seric ** message will be mailed back; then fall through to 99*297Seric ** the MailBack case. 100*297Seric */ 101*297Seric 102*297Seric if (EchoBack || WriteBack) 103*297Seric { 104*297Seric xfile = fopen(Transcript, "r"); 105*297Seric if (xfile == NULL) 106*297Seric syserr("Cannot open %s", Transcript); 107*297Seric fflush(stdout); 108*297Seric } 109*297Seric else 110*297Seric xfile = NULL; 111*297Seric 112*297Seric if (EchoBack) 113*297Seric { 114*297Seric while (fgets(buf, sizeof buf, xfile) != NULL) 115*297Seric fputs(buf, stderr); 116*297Seric fprintf(stderr, "\nThe unsent mail will be returned to you\n"); 117*297Seric MailBack++; 118*297Seric } 119*297Seric 120*297Seric /* 121*297Seric ** If writing back, do it. 122*297Seric ** If the user is still logged in on the same terminal, 123*297Seric ** then write the error messages back to hir (sic). 124*297Seric ** If not, set the MailBack flag so that it will get 125*297Seric ** mailed back instead. 126*297Seric */ 127*297Seric 128*297Seric if (WriteBack) 129*297Seric { 130*297Seric p = ttypath(); 131*297Seric if (p == NULL || freopen(p, "w", stdout) == NULL) 132*297Seric { 133*297Seric MailBack++; 134*297Seric errno = 0; 135*297Seric } 136*297Seric else 137*297Seric { 138*297Seric printf("\r\nMessage from %s\r\n", MY_NAME); 139*297Seric printf("Errors occurred while sending mail, transcript follows:\r\n"); 140*297Seric while (fgets(buf, sizeof buf, xfile) && !ferror(stdout)) 141*297Seric fputs(buf, stdout); 142*297Seric if (ferror(stdout)) 143*297Seric syserr("savemail: stdout: write err"); 144*297Seric } 145*297Seric } 146*297Seric 147*297Seric if (xfile != NULL) 148*297Seric fclose(xfile); 149*297Seric 150*297Seric /* 151*297Seric ** If mailing back, do it. 152*297Seric ** Throw away all further output. Don't do aliases, since 153*297Seric ** this could cause loops, e.g., if joe mails to x:joe, 154*297Seric ** and for some reason the network for x: is down, then 155*297Seric ** the response gets sent to x:joe, which gives a 156*297Seric ** response, etc. Also force the mail to be delivered 157*297Seric ** even if a version of it has already been sent to the 158*297Seric ** sender. 159*297Seric */ 160*297Seric 161*297Seric if (MailBack || From.q_mailer != &Mailer[0]) 162*297Seric { 163*297Seric freopen("/dev/null", "w", stdout); 164*297Seric NoAlias++; 165*297Seric ForceMail++; 166*297Seric 167*297Seric /* fake up an address header for the from person */ 168*297Seric bmove((char *) &From, (char *) &to_addr, sizeof to_addr); 169*297Seric if (parse(MY_NAME, &From, -1) == NULL) 170*297Seric { 171*297Seric syserr("Can't parse myself!"); 172*297Seric ExitStat = EX_SOFTWARE; 173*297Seric finis(); 174*297Seric } 175*297Seric i = deliver(&to_addr, errhdr); 176*297Seric bmove((char *) &to_addr, (char *) &From, sizeof From); 177*297Seric if (i != 0) 178*297Seric syserr("Can't return mail to %s", p); 179*297Seric else 180*297Seric return; 181*297Seric } 182*297Seric 183*297Seric /* 184*297Seric ** Save the message in dead.letter. 185*297Seric ** If we weren't mailing back, and the user is local, we 186*297Seric ** should save the message in dead.letter so that the 187*297Seric ** poor person doesn't have to type it over again -- 188*297Seric ** and we all know what poor typists programmers are. 189*297Seric */ 190*297Seric 191*297Seric setuid(getuid()); 192*297Seric setgid(getgid()); 193*297Seric setpwent(); 194*297Seric if (From.q_mailer == &Mailer[0] && (pw = getpwnam(From.q_user)) != NULL) 195*297Seric { 196*297Seric /* user has a home directory */ 197*297Seric p = pw->pw_dir; 198*297Seric } 199*297Seric else 200*297Seric { 201*297Seric syserr("Can't return mail to %s (pw=%u)", From.q_paddr, pw); 202*297Seric # ifdef DEBUG 203*297Seric p = "/usr/tmp"; 204*297Seric # else 205*297Seric p = NULL; 206*297Seric # endif 207*297Seric } 208*297Seric if (p != NULL) 209*297Seric { 210*297Seric /* we have a home directory; open dead.letter */ 211*297Seric strcpy(buf, p); 212*297Seric strcat(buf, "/dead.letter"); 213*297Seric xfile = fopen(buf, "a"); 214*297Seric if (xfile == NULL) 215*297Seric printf("Cannot save mail, sorry\n"); 216*297Seric else 217*297Seric { 218*297Seric rewind(stdin); 219*297Seric errno = 0; 220*297Seric time(&tim); 221*297Seric fprintf(xfile, "----- Mail saved at %s", ctime(&tim)); 222*297Seric while (fgets(buf, sizeof buf, stdin) && !ferror(xfile)) 223*297Seric fputs(buf, xfile); 224*297Seric fputs("\n", xfile); 225*297Seric if (ferror(xfile)) 226*297Seric syserr("savemail: dead.letter: write err"); 227*297Seric fclose(xfile); 228*297Seric printf("Letter saved in dead.letter\n"); 229*297Seric } 230*297Seric } 231*297Seric else 232*297Seric 233*297Seric /* add terminator to writeback message */ 234*297Seric if (WriteBack) 235*297Seric printf("-----\r\n"); 236*297Seric } 237*297Seric /* 238*297Seric ** ERRHDR -- Output the header for error mail. 239*297Seric ** 240*297Seric ** This is the edit filter to error mailbacks. 241*297Seric ** 242*297Seric ** Algorithm: 243*297Seric ** Output fixed header. 244*297Seric ** Output the transcript part. 245*297Seric ** Output the original message. 246*297Seric ** 247*297Seric ** Parameters: 248*297Seric ** xfile -- the transcript file. 249*297Seric ** fp -- the output file. 250*297Seric ** 251*297Seric ** Returns: 252*297Seric ** none 253*297Seric ** 254*297Seric ** Side Effects: 255*297Seric ** input from xfile 256*297Seric ** output to fp 257*297Seric ** 258*297Seric ** Requires: 259*297Seric ** read (sys) 260*297Seric ** write (sys) 261*297Seric ** open (sys) 262*297Seric ** close (sys) 263*297Seric ** syserr 264*297Seric ** rewind (sys) 265*297Seric ** fflush (sys) 266*297Seric ** fprintf (sys) 267*297Seric ** fileno (sys) 268*297Seric ** 269*297Seric ** Called By: 270*297Seric ** deliver 271*297Seric ** 272*297Seric ** History: 273*297Seric ** 12/28/79 -- written. 274*297Seric */ 275*297Seric 276*297Seric 277*297Seric errhdr(fp) 278*297Seric register FILE *fp; 279*297Seric { 280*297Seric char copybuf[512]; 281*297Seric register int i; 282*297Seric register int xfile; 283*297Seric extern int errno; 284*297Seric 285*297Seric if ((xfile = open(Transcript, 0)) < 0) 286*297Seric syserr("Cannot open %s", Transcript); 287*297Seric fflush(stdout); 288*297Seric errno = 0; 289*297Seric fprintf(fp, "To: %s\n", To); 290*297Seric fprintf(fp, "Subject: Unable to deliver mail\n"); 291*297Seric fprintf(fp, "\n ----- Transcript of session follows -----\n"); 292*297Seric fflush(fp); 293*297Seric while ((i = read(xfile, copybuf, sizeof copybuf)) > 0) 294*297Seric write(fileno(fp), copybuf, i); 295*297Seric fprintf(fp, "\n ----- Unsent message follows -----\n"); 296*297Seric fflush(fp); 297*297Seric rewind(stdin); 298*297Seric while ((i = read(fileno(stdin), copybuf, sizeof copybuf)) > 0) 299*297Seric write(fileno(fp), copybuf, i); 300*297Seric close(xfile); 301*297Seric if (errno != 0) 302*297Seric syserr("errhdr: I/O error"); 303*297Seric } 304