1 # include <pwd.h> 2 # include "sendmail.h" 3 4 SCCSID(@(#)savemail.c 3.31.1.1 06/06/82); 5 6 /* 7 ** SAVEMAIL -- Save mail on error 8 ** 9 ** If the MailBack flag is set, mail it back to the originator 10 ** together with an error message; otherwise, just put it in 11 ** dead.letter in the user's home directory (if he exists on 12 ** this machine). 13 ** 14 ** Parameters: 15 ** none 16 ** 17 ** Returns: 18 ** none 19 ** 20 ** Side Effects: 21 ** Saves the letter, by writing or mailing it back to the 22 ** sender, or by putting it in dead.letter in her home 23 ** directory. 24 */ 25 26 savemail() 27 { 28 register struct passwd *pw; 29 register FILE *xfile; 30 char buf[MAXLINE+1]; 31 extern struct passwd *getpwnam(); 32 register char *p; 33 extern char *ttypath(); 34 static int exclusive; 35 typedef int (*fnptr)(); 36 extern ENVELOPE *newenvelope(); 37 38 if (exclusive++) 39 return; 40 if (CurEnv->e_class <= PRI_JUNK) 41 { 42 if (Verbose) 43 message(Arpa_Info, "Dumping junk mail"); 44 return; 45 } 46 ForceMail = TRUE; 47 48 /* 49 ** In the unhappy event we don't know who to return the mail 50 ** to, make someone up. 51 */ 52 53 if (CurEnv->e_returnto == NULL) 54 { 55 CurEnv->e_returnto = parse("root", (ADDRESS *) NULL, 0); 56 if (CurEnv->e_returnto == NULL) 57 { 58 syserr("Cannot parse root!"); 59 ExitStat = EX_SOFTWARE; 60 finis(); 61 } 62 } 63 CurEnv->e_to = NULL; 64 65 /* 66 ** If called from Eric Schmidt's network, do special mailback. 67 ** Fundamentally, this is the mailback case except that 68 ** it returns an OK exit status (assuming the return 69 ** worked). 70 ** Also, if the from address is not local, mail it back. 71 */ 72 73 if (BerkNet) 74 { 75 ExitStat = EX_OK; 76 MailBack = TRUE; 77 } 78 if (!bitset(M_LOCAL, CurEnv->e_returnto->q_mailer->m_flags)) 79 MailBack = TRUE; 80 81 /* 82 ** If writing back, do it. 83 ** If the user is still logged in on the same terminal, 84 ** then write the error messages back to hir (sic). 85 ** If not, set the MailBack flag so that it will get 86 ** mailed back instead. 87 */ 88 89 if (WriteBack) 90 { 91 p = ttypath(); 92 if (p == NULL || freopen(p, "w", stdout) == NULL) 93 { 94 MailBack = TRUE; 95 errno = 0; 96 } 97 else 98 { 99 (void) fflush(Xscript); 100 xfile = fopen(Transcript, "r"); 101 if (xfile == NULL) 102 syserr("Cannot open %s", Transcript); 103 expand("$n", buf, &buf[sizeof buf - 1], CurEnv); 104 printf("\r\nMessage from %s...\r\n", buf); 105 printf("Errors occurred while sending mail; transcript follows:\r\n"); 106 while (fgets(buf, sizeof buf, xfile) != NULL && !ferror(stdout)) 107 fputs(buf, stdout); 108 if (ferror(stdout)) 109 (void) syserr("savemail: stdout: write err"); 110 (void) fclose(xfile); 111 } 112 } 113 114 /* 115 ** If mailing back, do it. 116 ** Throw away all further output. Don't do aliases, since 117 ** this could cause loops, e.g., if joe mails to x:joe, 118 ** and for some reason the network for x: is down, then 119 ** the response gets sent to x:joe, which gives a 120 ** response, etc. Also force the mail to be delivered 121 ** even if a version of it has already been sent to the 122 ** sender. 123 */ 124 125 if (MailBack) 126 { 127 if (returntosender("Unable to deliver mail", CurEnv->e_returnto, TRUE) == 0) 128 return; 129 } 130 131 /* 132 ** Save the message in dead.letter. 133 ** If we weren't mailing back, and the user is local, we 134 ** should save the message in dead.letter so that the 135 ** poor person doesn't have to type it over again -- 136 ** and we all know what poor typists programmers are. 137 */ 138 139 if (ArpaMode) 140 return; 141 p = NULL; 142 if (CurEnv->e_returnto->q_mailer == LocalMailer) 143 { 144 if (CurEnv->e_returnto->q_home != NULL) 145 p = CurEnv->e_returnto->q_home; 146 else if ((pw = getpwnam(CurEnv->e_returnto->q_user)) != NULL) 147 p = pw->pw_dir; 148 } 149 if (p == NULL) 150 { 151 syserr("Can't return mail to %s", CurEnv->e_returnto->q_paddr); 152 # ifdef DEBUG 153 p = "/usr/tmp"; 154 # else 155 p = NULL; 156 # endif 157 } 158 if (p != NULL && TempFile != NULL) 159 { 160 auto ADDRESS *q; 161 162 /* we have a home directory; open dead.letter */ 163 message(Arpa_Info, "Saving message in dead.letter"); 164 define('z', p); 165 expand("$z/dead.letter", buf, &buf[sizeof buf - 1], CurEnv); 166 CurEnv->e_to = buf; 167 q = NULL; 168 sendto(buf, -1, (ADDRESS *) NULL, &q); 169 (void) deliver(q); 170 } 171 172 /* add terminator to writeback message */ 173 if (WriteBack) 174 printf("-----\r\n"); 175 } 176 /* 177 ** RETURNTOSENDER -- return a message to the sender with an error. 178 ** 179 ** Parameters: 180 ** msg -- the explanatory message. 181 ** sendbody -- if TRUE, also send back the body of the 182 ** message; otherwise just send the header. 183 ** 184 ** Returns: 185 ** zero -- if everything went ok. 186 ** else -- some error. 187 ** 188 ** Side Effects: 189 ** Returns the current message to the sender via 190 ** mail. 191 */ 192 193 static bool SendBody; 194 195 returntosender(msg, returnto, sendbody) 196 char *msg; 197 ADDRESS *returnto; 198 bool sendbody; 199 { 200 ADDRESS to_addr; 201 char buf[MAXNAME]; 202 register int i; 203 extern putheader(), errbody(); 204 register ENVELOPE *ee; 205 extern ENVELOPE *newenvelope(); 206 ENVELOPE errenvelope; 207 208 NoAlias = TRUE; 209 SendBody = sendbody; 210 ee = newenvelope(&errenvelope); 211 ee->e_puthdr = putheader; 212 ee->e_putbody = errbody; 213 addheader("date", "$b", ee); 214 addheader("from", "$g (Mail Delivery Subsystem)", ee); 215 addheader("to", returnto->q_paddr, ee); 216 addheader("subject", msg, ee); 217 218 /* fake up an address header for the from person */ 219 bmove((char *) returnto, (char *) &to_addr, sizeof to_addr); 220 expand("$n", buf, &buf[sizeof buf - 1], CurEnv); 221 if (parse(buf, &ee->e_from, -1) == NULL) 222 { 223 syserr("Can't parse myself!"); 224 ExitStat = EX_SOFTWARE; 225 return (-1); 226 } 227 to_addr.q_next = NULL; 228 to_addr.q_flags &= ~QDONTSEND; 229 ee->e_sendqueue = &to_addr; 230 231 /* push state into submessage */ 232 CurEnv = ee; 233 define('f', "$n"); 234 define('x', "Mail Delivery Subsystem"); 235 236 /* actually deliver the error message */ 237 i = deliver(&to_addr); 238 239 /* if the error message was "queued", make that happen */ 240 if (bitset(QQUEUEUP, to_addr.q_flags)) 241 queueup(ee, FALSE); 242 243 /* restore state */ 244 CurEnv = CurEnv->e_parent; 245 246 if (i != 0) 247 { 248 syserr("Can't return mail to %s", to_addr.q_paddr); 249 return (-1); 250 } 251 return (0); 252 } 253 /* 254 ** ERRBODY -- output the body of an error message. 255 ** 256 ** Typically this is a copy of the transcript plus a copy of the 257 ** original offending message. 258 ** 259 ** Parameters: 260 ** xfile -- the transcript file. 261 ** fp -- the output file. 262 ** xdot -- if set, use the SMTP hidden dot algorithm. 263 ** 264 ** Returns: 265 ** none 266 ** 267 ** Side Effects: 268 ** Outputs the body of an error message. 269 */ 270 271 errbody(fp, m, xdot) 272 register FILE *fp; 273 register struct mailer *m; 274 bool xdot; 275 { 276 register FILE *xfile; 277 char buf[MAXLINE]; 278 279 (void) fflush(stdout); 280 if ((xfile = fopen(Transcript, "r")) == NULL) 281 syserr("Cannot open %s", Transcript); 282 errno = 0; 283 284 /* 285 ** Output transcript of errors 286 */ 287 288 fprintf(fp, " ----- Transcript of session follows -----\n"); 289 (void) fflush(Xscript); 290 while (fgets(buf, sizeof buf, xfile) != NULL) 291 fputs(buf, fp); 292 293 /* 294 ** Output text of original message 295 */ 296 297 if (NoReturn) 298 fprintf(fp, "\n ----- Return message suppressed -----\n\n"); 299 else if (TempFile != NULL) 300 { 301 if (SendBody) 302 { 303 fprintf(fp, "\n ----- Unsent message follows -----\n"); 304 (void) fflush(fp); 305 putheader(fp, m, CurEnv->e_parent); 306 fprintf(fp, "\n"); 307 putbody(fp, m, xdot); 308 } 309 else 310 { 311 fprintf(fp, "\n ----- Message header follows -----\n"); 312 (void) fflush(fp); 313 putheader(fp, m, CurEnv); 314 } 315 } 316 else 317 fprintf(fp, "\n ----- No message was collected -----\n\n"); 318 319 /* 320 ** Cleanup and exit 321 */ 322 323 (void) fclose(xfile); 324 if (errno != 0) 325 syserr("errbody: I/O error"); 326 } 327