1 /* 2 ** Sendmail 3 ** Copyright (c) 1983 Eric P. Allman 4 ** Berkeley, California 5 ** 6 ** Copyright (c) 1983 Regents of the University of California. 7 ** All rights reserved. The Berkeley software License Agreement 8 ** specifies the terms and conditions for redistribution. 9 */ 10 11 #ifndef lint 12 static char SccsId[] = "@(#)savemail.c 5.2 (Berkeley) 06/07/85"; 13 #endif not lint 14 15 # include <pwd.h> 16 # include "sendmail.h" 17 18 /* 19 ** SAVEMAIL -- Save mail on error 20 ** 21 ** If mailing back errors, mail it back to the originator 22 ** together with an error message; otherwise, just put it in 23 ** dead.letter in the user's home directory (if he exists on 24 ** this machine). 25 ** 26 ** Parameters: 27 ** e -- the envelope containing the message in error. 28 ** 29 ** Returns: 30 ** none 31 ** 32 ** Side Effects: 33 ** Saves the letter, by writing or mailing it back to the 34 ** sender, or by putting it in dead.letter in her home 35 ** directory. 36 */ 37 38 savemail(e) 39 register ENVELOPE *e; 40 { 41 register struct passwd *pw; 42 register FILE *xfile; 43 char buf[MAXLINE+1]; 44 extern struct passwd *getpwnam(); 45 register char *p; 46 extern char *ttypath(); 47 typedef int (*fnptr)(); 48 49 # ifdef DEBUG 50 if (tTd(6, 1)) 51 printf("\nsavemail\n"); 52 # endif DEBUG 53 54 if (bitset(EF_RESPONSE, e->e_flags)) 55 return; 56 if (e->e_class < 0) 57 { 58 message(Arpa_Info, "Dumping junk mail"); 59 return; 60 } 61 ForceMail = TRUE; 62 e->e_flags &= ~EF_FATALERRS; 63 64 /* 65 ** In the unhappy event we don't know who to return the mail 66 ** to, make someone up. 67 */ 68 69 if (e->e_from.q_paddr == NULL) 70 { 71 if (parseaddr("root", &e->e_from, 0, '\0') == NULL) 72 { 73 syserr("Cannot parse root!"); 74 ExitStat = EX_SOFTWARE; 75 finis(); 76 } 77 } 78 e->e_to = NULL; 79 80 /* 81 ** If called from Eric Schmidt's network, do special mailback. 82 ** Fundamentally, this is the mailback case except that 83 ** it returns an OK exit status (assuming the return 84 ** worked). 85 ** Also, if the from address is not local, mail it back. 86 */ 87 88 if (ErrorMode == EM_BERKNET) 89 { 90 ExitStat = EX_OK; 91 ErrorMode = EM_MAIL; 92 } 93 if (!bitnset(M_LOCAL, e->e_from.q_mailer->m_flags)) 94 ErrorMode = EM_MAIL; 95 96 /* 97 ** If writing back, do it. 98 ** If the user is still logged in on the same terminal, 99 ** then write the error messages back to hir (sic). 100 ** If not, mail back instead. 101 */ 102 103 if (ErrorMode == EM_WRITE) 104 { 105 p = ttypath(); 106 if (p == NULL || freopen(p, "w", stdout) == NULL) 107 { 108 ErrorMode = EM_MAIL; 109 errno = 0; 110 } 111 else 112 { 113 expand("\001n", buf, &buf[sizeof buf - 1], e); 114 printf("\r\nMessage from %s...\r\n", buf); 115 printf("Errors occurred while sending mail.\r\n"); 116 if (e->e_xfp != NULL) 117 { 118 (void) fflush(e->e_xfp); 119 xfile = fopen(queuename(e, 'x'), "r"); 120 } 121 else 122 xfile = NULL; 123 if (xfile == NULL) 124 { 125 syserr("Cannot open %s", queuename(e, 'x')); 126 printf("Transcript of session is unavailable.\r\n"); 127 } 128 else 129 { 130 printf("Transcript follows:\r\n"); 131 while (fgets(buf, sizeof buf, xfile) != NULL && 132 !ferror(stdout)) 133 fputs(buf, stdout); 134 (void) fclose(xfile); 135 } 136 if (ferror(stdout)) 137 (void) syserr("savemail: stdout: write err"); 138 } 139 } 140 141 /* 142 ** If mailing back, do it. 143 ** Throw away all further output. Don't do aliases, since 144 ** this could cause loops, e.g., if joe mails to x:joe, 145 ** and for some reason the network for x: is down, then 146 ** the response gets sent to x:joe, which gives a 147 ** response, etc. Also force the mail to be delivered 148 ** even if a version of it has already been sent to the 149 ** sender. 150 */ 151 152 if (ErrorMode == EM_MAIL) 153 { 154 if (e->e_errorqueue == NULL) 155 sendtolist(e->e_from.q_paddr, (ADDRESS *) NULL, 156 &e->e_errorqueue); 157 if (returntosender(e->e_message != NULL ? e->e_message : 158 "Unable to deliver mail", 159 e->e_errorqueue, TRUE) == 0) 160 return; 161 } 162 163 /* 164 ** Save the message in dead.letter. 165 ** If we weren't mailing back, and the user is local, we 166 ** should save the message in dead.letter so that the 167 ** poor person doesn't have to type it over again -- 168 ** and we all know what poor typists programmers are. 169 */ 170 171 p = NULL; 172 if (e->e_from.q_mailer == LocalMailer) 173 { 174 if (e->e_from.q_home != NULL) 175 p = e->e_from.q_home; 176 else if ((pw = getpwnam(e->e_from.q_user)) != NULL) 177 p = pw->pw_dir; 178 } 179 if (p == NULL) 180 { 181 syserr("Can't return mail to %s", e->e_from.q_paddr); 182 # ifdef DEBUG 183 p = "/usr/tmp"; 184 # endif 185 } 186 if (p != NULL && e->e_dfp != NULL) 187 { 188 auto ADDRESS *q; 189 bool oldverb = Verbose; 190 191 /* we have a home directory; open dead.letter */ 192 define('z', p, e); 193 expand("\001z/dead.letter", buf, &buf[sizeof buf - 1], e); 194 Verbose = TRUE; 195 message(Arpa_Info, "Saving message in %s", buf); 196 Verbose = oldverb; 197 e->e_to = buf; 198 q = NULL; 199 sendtolist(buf, (ADDRESS *) NULL, &q); 200 (void) deliver(e, q); 201 } 202 203 /* add terminator to writeback message */ 204 if (ErrorMode == EM_WRITE) 205 printf("-----\r\n"); 206 } 207 /* 208 ** RETURNTOSENDER -- return a message to the sender with an error. 209 ** 210 ** Parameters: 211 ** msg -- the explanatory message. 212 ** returnq -- the queue of people to send the message to. 213 ** sendbody -- if TRUE, also send back the body of the 214 ** message; otherwise just send the header. 215 ** 216 ** Returns: 217 ** zero -- if everything went ok. 218 ** else -- some error. 219 ** 220 ** Side Effects: 221 ** Returns the current message to the sender via 222 ** mail. 223 */ 224 225 static bool SendBody; 226 227 #define MAXRETURNS 6 /* max depth of returning messages */ 228 229 returntosender(msg, returnq, sendbody) 230 char *msg; 231 ADDRESS *returnq; 232 bool sendbody; 233 { 234 char buf[MAXNAME]; 235 extern putheader(), errbody(); 236 register ENVELOPE *ee; 237 extern ENVELOPE *newenvelope(); 238 ENVELOPE errenvelope; 239 static int returndepth; 240 register ADDRESS *q; 241 242 # ifdef DEBUG 243 if (tTd(6, 1)) 244 { 245 printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n", 246 msg, returndepth, CurEnv); 247 printf("\treturnto="); 248 printaddr(returnq, TRUE); 249 } 250 # endif DEBUG 251 252 if (++returndepth >= MAXRETURNS) 253 { 254 if (returndepth != MAXRETURNS) 255 syserr("returntosender: infinite recursion on %s", returnq->q_paddr); 256 /* don't "unrecurse" and fake a clean exit */ 257 /* returndepth--; */ 258 return (0); 259 } 260 261 SendBody = sendbody; 262 define('g', "\001f", CurEnv); 263 ee = newenvelope(&errenvelope); 264 ee->e_puthdr = putheader; 265 ee->e_putbody = errbody; 266 ee->e_flags |= EF_RESPONSE; 267 ee->e_sendqueue = returnq; 268 openxscript(ee); 269 for (q = returnq; q != NULL; q = q->q_next) 270 { 271 if (q->q_alias == NULL) 272 addheader("to", q->q_paddr, ee); 273 } 274 (void) sprintf(buf, "Returned mail: %s", msg); 275 addheader("subject", buf, ee); 276 277 /* fake up an address header for the from person */ 278 expand("\001n", buf, &buf[sizeof buf - 1], CurEnv); 279 if (parseaddr(buf, &ee->e_from, -1, '\0') == NULL) 280 { 281 syserr("Can't parse myself!"); 282 ExitStat = EX_SOFTWARE; 283 returndepth--; 284 return (-1); 285 } 286 loweraddr(&ee->e_from); 287 288 /* push state into submessage */ 289 CurEnv = ee; 290 define('f', "\001n", ee); 291 define('x', "Mail Delivery Subsystem", ee); 292 eatheader(ee); 293 294 /* actually deliver the error message */ 295 sendall(ee, SM_DEFAULT); 296 297 /* restore state */ 298 dropenvelope(ee); 299 CurEnv = CurEnv->e_parent; 300 returndepth--; 301 302 /* should check for delivery errors here */ 303 return (0); 304 } 305 /* 306 ** ERRBODY -- output the body of an error message. 307 ** 308 ** Typically this is a copy of the transcript plus a copy of the 309 ** original offending message. 310 ** 311 ** Parameters: 312 ** fp -- the output file. 313 ** m -- the mailer to output to. 314 ** e -- the envelope we are working in. 315 ** 316 ** Returns: 317 ** none 318 ** 319 ** Side Effects: 320 ** Outputs the body of an error message. 321 */ 322 323 errbody(fp, m, e) 324 register FILE *fp; 325 register struct mailer *m; 326 register ENVELOPE *e; 327 { 328 register FILE *xfile; 329 char buf[MAXLINE]; 330 char *p; 331 332 /* 333 ** Output transcript of errors 334 */ 335 336 (void) fflush(stdout); 337 p = queuename(e->e_parent, 'x'); 338 if ((xfile = fopen(p, "r")) == NULL) 339 { 340 syserr("Cannot open %s", p); 341 fprintf(fp, " ----- Transcript of session is unavailable -----\n"); 342 } 343 else 344 { 345 fprintf(fp, " ----- Transcript of session follows -----\n"); 346 if (e->e_xfp != NULL) 347 (void) fflush(e->e_xfp); 348 while (fgets(buf, sizeof buf, xfile) != NULL) 349 putline(buf, fp, m); 350 (void) fclose(xfile); 351 } 352 errno = 0; 353 354 /* 355 ** Output text of original message 356 */ 357 358 if (NoReturn) 359 fprintf(fp, "\n ----- Return message suppressed -----\n\n"); 360 else if (e->e_parent->e_dfp != NULL) 361 { 362 if (SendBody) 363 { 364 putline("\n", fp, m); 365 putline(" ----- Unsent message follows -----\n", fp, m); 366 (void) fflush(fp); 367 putheader(fp, m, e->e_parent); 368 putline("\n", fp, m); 369 putbody(fp, m, e->e_parent); 370 } 371 else 372 { 373 putline("\n", fp, m); 374 putline(" ----- Message header follows -----\n", fp, m); 375 (void) fflush(fp); 376 putheader(fp, m, e->e_parent); 377 } 378 } 379 else 380 { 381 putline("\n", fp, m); 382 putline(" ----- No message was collected -----\n", fp, m); 383 putline("\n", fp, m); 384 } 385 386 /* 387 ** Cleanup and exit 388 */ 389 390 if (errno != 0) 391 syserr("errbody: I/O error"); 392 } 393