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