1: /*
   2:  * Copyright (c) 1988 Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms are permitted
   6:  * provided that this notice is preserved and that due credit is given
   7:  * to the University of California at Berkeley. The name of the University
   8:  * may not be used to endorse or promote products derived from this
   9:  * software without specific prior written permission. This software
  10:  * is provided ``as is'' without express or implied warranty.
  11:  *
  12:  *  Sendmail
  13:  *  Copyright (c) 1983  Eric P. Allman
  14:  *  Berkeley, California
  15:  */
  16: 
  17: #if !defined(lint) && !defined(NOSCCS)
  18: static char sccsid[] = "@(#)savemail.c	5.8 (Berkeley) 3/13/88";
  19: #endif /* not lint */
  20: 
  21: # include <pwd.h>
  22: # include "sendmail.h"
  23: 
  24: /*
  25: **  SAVEMAIL -- Save mail on error
  26: **
  27: **	If mailing back errors, mail it back to the originator
  28: **	together with an error message; otherwise, just put it in
  29: **	dead.letter in the user's home directory (if he exists on
  30: **	this machine).
  31: **
  32: **	Parameters:
  33: **		e -- the envelope containing the message in error.
  34: **
  35: **	Returns:
  36: **		none
  37: **
  38: **	Side Effects:
  39: **		Saves the letter, by writing or mailing it back to the
  40: **		sender, or by putting it in dead.letter in her home
  41: **		directory.
  42: */
  43: 
  44: /* defines for state machine */
  45: # define ESM_REPORT 0   /* report to sender's terminal */
  46: # define ESM_MAIL   1   /* mail back to sender */
  47: # define ESM_QUIET  2   /* messages have already been returned */
  48: # define ESM_DEADLETTER 3   /* save in ~/dead.letter */
  49: # define ESM_POSTMASTER 4   /* return to postmaster */
  50: # define ESM_USRTMP 5   /* save in /usr/tmp/dead.letter */
  51: # define ESM_PANIC  6   /* leave the locked queue/transcript files */
  52: # define ESM_DONE   7   /* the message is successfully delivered */
  53: 
  54: 
  55: savemail(e)
  56:     register ENVELOPE *e;
  57: {
  58:     register struct passwd *pw;
  59:     register FILE *fp;
  60:     int state;
  61:     auto ADDRESS *q;
  62:     char buf[MAXLINE+1];
  63:     extern struct passwd *getpwnam();
  64:     register char *p;
  65:     extern char *ttypath();
  66:     typedef int (*fnptr)();
  67: 
  68: # ifdef DEBUG
  69:     if (tTd(6, 1))
  70:         printf("\nsavemail, ErrorMode = %c\n", ErrorMode);
  71: # endif DEBUG
  72: 
  73:     if (bitset(EF_RESPONSE, e->e_flags))
  74:         return;
  75:     if (e->e_class < 0)
  76:     {
  77:         message(Arpa_Info, "Dumping junk mail");
  78:         return;
  79:     }
  80:     ForceMail = TRUE;
  81:     e->e_flags &= ~EF_FATALERRS;
  82: 
  83:     /*
  84: 	**  In the unhappy event we don't know who to return the mail
  85: 	**  to, make someone up.
  86: 	*/
  87: 
  88:     if (e->e_from.q_paddr == NULL)
  89:     {
  90:         if (parseaddr("root", &e->e_from, 0, '\0') == NULL)
  91:         {
  92:             syserr("Cannot parse root!");
  93:             ExitStat = EX_SOFTWARE;
  94:             finis();
  95:         }
  96:     }
  97:     e->e_to = NULL;
  98: 
  99:     /*
 100: 	**  Basic state machine.
 101: 	**
 102: 	**	This machine runs through the following states:
 103: 	**
 104: 	**	ESM_QUIET	Errors have already been printed iff the
 105: 	**			sender is local.
 106: 	**	ESM_REPORT	Report directly to the sender's terminal.
 107: 	**	ESM_MAIL	Mail response to the sender.
 108: 	**	ESM_DEADLETTER	Save response in ~/dead.letter.
 109: 	**	ESM_POSTMASTER	Mail response to the postmaster.
 110: 	**	ESM_PANIC	Save response anywhere possible.
 111: 	*/
 112: 
 113:     /* determine starting state */
 114:     switch (ErrorMode)
 115:     {
 116:       case EM_WRITE:
 117:         state = ESM_REPORT;
 118:         break;
 119: 
 120:       case EM_BERKNET:
 121:         /* mail back, but return o.k. exit status */
 122:         ExitStat = EX_OK;
 123: 
 124:         /* fall through.... */
 125: 
 126:       case EM_MAIL:
 127:         state = ESM_MAIL;
 128:         break;
 129: 
 130:       case EM_PRINT:
 131:       case '\0':
 132:         state = ESM_QUIET;
 133:         break;
 134: 
 135:       case EM_QUIET:
 136:         /* no need to return anything at all */
 137:         return;
 138: 
 139:       default:
 140:         syserr("savemail: ErrorMode x%x\n");
 141:         state = ESM_MAIL;
 142:         break;
 143:     }
 144: 
 145:     while (state != ESM_DONE)
 146:     {
 147: # ifdef DEBUG
 148:         if (tTd(6, 5))
 149:             printf("  state %d\n", state);
 150: # endif DEBUG
 151: 
 152:         switch (state)
 153:         {
 154:           case ESM_QUIET:
 155:             if (e->e_from.q_mailer == LocalMailer)
 156:                 state = ESM_DEADLETTER;
 157:             else
 158:                 state = ESM_MAIL;
 159:             break;
 160: 
 161:           case ESM_REPORT:
 162: 
 163:             /*
 164: 			**  If the user is still logged in on the same terminal,
 165: 			**  then write the error messages back to hir (sic).
 166: 			*/
 167: 
 168:             p = ttypath();
 169:             if (p == NULL || freopen(p, "w", stdout) == NULL)
 170:             {
 171:                 state = ESM_MAIL;
 172:                 break;
 173:             }
 174: 
 175:             expand("\001n", buf, &buf[sizeof buf - 1], e);
 176:             printf("\r\nMessage from %s...\r\n", buf);
 177:             printf("Errors occurred while sending mail.\r\n");
 178:             if (e->e_xfp != NULL)
 179:             {
 180:                 (void) fflush(e->e_xfp);
 181:                 fp = fopen(queuename(e, 'x'), "r");
 182:             }
 183:             else
 184:                 fp = NULL;
 185:             if (fp == NULL)
 186:             {
 187:                 syserr("Cannot open %s", queuename(e, 'x'));
 188:                 printf("Transcript of session is unavailable.\r\n");
 189:             }
 190:             else
 191:             {
 192:                 printf("Transcript follows:\r\n");
 193:                 while (fgets(buf, sizeof buf, fp) != NULL &&
 194:                        !ferror(stdout))
 195:                     fputs(buf, stdout);
 196:                 (void) fclose(fp);
 197:             }
 198:             printf("Original message will be saved in dead.letter.\r\n");
 199:             if (ferror(stdout))
 200:                 (void) syserr("savemail: stdout: write err");
 201:             state = ESM_DEADLETTER;
 202:             break;
 203: 
 204:           case ESM_MAIL:
 205:           case ESM_POSTMASTER:
 206:             /*
 207: 			**  If mailing back, do it.
 208: 			**	Throw away all further output.  Don't alias,
 209: 			**	since this could cause loops, e.g., if joe
 210: 			**	mails to joe@x, and for some reason the network
 211: 			**	for @x is down, then the response gets sent to
 212: 			**	joe@x, which gives a response, etc.  Also force
 213: 			**	the mail to be delivered even if a version of
 214: 			**	it has already been sent to the sender.
 215: 			*/
 216: 
 217:             if (state == ESM_MAIL)
 218:             {
 219:                 if (e->e_errorqueue == NULL)
 220:                     sendtolist(e->e_from.q_paddr,
 221:                         (ADDRESS *) NULL,
 222:                         &e->e_errorqueue);
 223: 
 224:                 /* deliver a cc: to the postmaster if desired */
 225:                 if (PostMasterCopy != NULL)
 226:                     sendtolist(PostMasterCopy,
 227:                         (ADDRESS *) NULL,
 228:                         &e->e_errorqueue);
 229:                 q = e->e_errorqueue;
 230:             }
 231:             else
 232:             {
 233:                 if (parseaddr("postmaster", q, 0, '\0') == NULL)
 234:                 {
 235:                     syserr("cannot parse postmaster!");
 236:                     ExitStat = EX_SOFTWARE;
 237:                     state = ESM_USRTMP;
 238:                     break;
 239:                 }
 240:             }
 241:             if (returntosender(e->e_message != NULL ? e->e_message :
 242:                        "Unable to deliver mail",
 243:                        q, TRUE) == 0)
 244:             {
 245:                 state = ESM_DONE;
 246:                 break;
 247:             }
 248: 
 249:             state = state == ESM_MAIL ? ESM_POSTMASTER : ESM_USRTMP;
 250:             break;
 251: 
 252:           case ESM_DEADLETTER:
 253:             /*
 254: 			**  Save the message in dead.letter.
 255: 			**	If we weren't mailing back, and the user is
 256: 			**	local, we should save the message in
 257: 			**	~/dead.letter so that the poor person doesn't
 258: 			**	have to type it over again -- and we all know
 259: 			**	what poor typists UNIX users are.
 260: 			*/
 261: 
 262:             p = NULL;
 263:             if (e->e_from.q_mailer == LocalMailer)
 264:             {
 265:                 if (e->e_from.q_home != NULL)
 266:                     p = e->e_from.q_home;
 267:                 else if ((pw = getpwnam(e->e_from.q_user)) != NULL)
 268:                     p = pw->pw_dir;
 269:             }
 270:             if (p == NULL)
 271:             {
 272:                 syserr("Can't return mail to %s", e->e_from.q_paddr);
 273:                 state = ESM_MAIL;
 274:                 break;
 275:             }
 276:             if (e->e_dfp != NULL)
 277:             {
 278:                 auto ADDRESS *q;
 279:                 bool oldverb = Verbose;
 280: 
 281:                 /* we have a home directory; open dead.letter */
 282:                 define('z', p, e);
 283:                 expand("\001z/dead.letter", buf, &buf[sizeof buf - 1], e);
 284:                 Verbose = TRUE;
 285:                 message(Arpa_Info, "Saving message in %s", buf);
 286:                 Verbose = oldverb;
 287:                 e->e_to = buf;
 288:                 q = NULL;
 289:                 sendtolist(buf, (ADDRESS *) NULL, &q);
 290:                 if (deliver(e, q) == 0)
 291:                     state = ESM_DONE;
 292:                 else
 293:                     state = ESM_MAIL;
 294:             }
 295:             else
 296:             {
 297:                 /* no data file -- try mailing back */
 298:                 state = ESM_MAIL;
 299:             }
 300:             break;
 301: 
 302:           case ESM_USRTMP:
 303:             /*
 304: 			**  Log the mail in /usr/tmp/dead.letter.
 305: 			*/
 306: 
 307:             fp = dfopen("/usr/tmp/dead.letter", "a");
 308:             if (fp == NULL)
 309:             {
 310:                 state = ESM_PANIC;
 311:                 break;
 312:             }
 313: 
 314:             putfromline(fp, ProgMailer);
 315:             (*e->e_puthdr)(fp, ProgMailer, e);
 316:             putline("\n", fp, ProgMailer);
 317:             (*e->e_putbody)(fp, ProgMailer, e);
 318:             putline("\n", fp, ProgMailer);
 319:             (void) fflush(fp);
 320:             state = ferror(fp) ? ESM_PANIC : ESM_DONE;
 321:             (void) fclose(fp);
 322:             break;
 323: 
 324:           default:
 325:             syserr("savemail: unknown state %d", state);
 326: 
 327:             /* fall through ... */
 328: 
 329:           case ESM_PANIC:
 330:             syserr("savemail: HELP!!!!");
 331: # ifdef LOG
 332:             if (LogLevel >= 1)
 333:                 syslog(LOG_ALERT, "savemail: HELP!!!!");
 334: # endif LOG
 335: 
 336:             /* leave the locked queue & transcript files around */
 337:             exit(EX_SOFTWARE);
 338:         }
 339:     }
 340: }
 341: /*
 342: **  RETURNTOSENDER -- return a message to the sender with an error.
 343: **
 344: **	Parameters:
 345: **		msg -- the explanatory message.
 346: **		returnq -- the queue of people to send the message to.
 347: **		sendbody -- if TRUE, also send back the body of the
 348: **			message; otherwise just send the header.
 349: **
 350: **	Returns:
 351: **		zero -- if everything went ok.
 352: **		else -- some error.
 353: **
 354: **	Side Effects:
 355: **		Returns the current message to the sender via
 356: **		mail.
 357: */
 358: 
 359: static bool SendBody;
 360: 
 361: #define MAXRETURNS  6   /* max depth of returning messages */
 362: 
 363: returntosender(msg, returnq, sendbody)
 364:     char *msg;
 365:     ADDRESS *returnq;
 366:     bool sendbody;
 367: {
 368:     char buf[MAXNAME];
 369:     extern putheader(), errbody();
 370:     register ENVELOPE *ee;
 371:     extern ENVELOPE *newenvelope();
 372:     ENVELOPE errenvelope;
 373:     static int returndepth;
 374:     register ADDRESS *q;
 375: 
 376: # ifdef DEBUG
 377:     if (tTd(6, 1))
 378:     {
 379:         printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n",
 380:                msg, returndepth, CurEnv);
 381:         printf("\treturnq=");
 382:         printaddr(returnq, TRUE);
 383:     }
 384: # endif DEBUG
 385: 
 386:     if (++returndepth >= MAXRETURNS)
 387:     {
 388:         if (returndepth != MAXRETURNS)
 389:             syserr("returntosender: infinite recursion on %s", returnq->q_paddr);
 390:         /* don't "unrecurse" and fake a clean exit */
 391:         /* returndepth--; */
 392:         return (0);
 393:     }
 394: 
 395:     SendBody = sendbody;
 396:     define('g', "\001f", CurEnv);
 397:     ee = newenvelope(&errenvelope);
 398:     define('a', "\001b", ee);
 399:     ee->e_puthdr = putheader;
 400:     ee->e_putbody = errbody;
 401:     ee->e_flags |= EF_RESPONSE;
 402:     ee->e_sendqueue = returnq;
 403:     openxscript(ee);
 404:     for (q = returnq; q != NULL; q = q->q_next)
 405:     {
 406:         if (q->q_alias == NULL)
 407:             addheader("to", q->q_paddr, ee);
 408:     }
 409: 
 410:     (void) sprintf(buf, "Returned mail: %s", msg);
 411:     addheader("subject", buf, ee);
 412: 
 413:     /* fake up an address header for the from person */
 414:     expand("\001n", buf, &buf[sizeof buf - 1], CurEnv);
 415:     if (parseaddr(buf, &ee->e_from, -1, '\0') == NULL)
 416:     {
 417:         syserr("Can't parse myself!");
 418:         ExitStat = EX_SOFTWARE;
 419:         returndepth--;
 420:         return (-1);
 421:     }
 422:     loweraddr(&ee->e_from);
 423: 
 424:     /* push state into submessage */
 425:     CurEnv = ee;
 426:     define('f', "\001n", ee);
 427:     define('x', "Mail Delivery Subsystem", ee);
 428:     eatheader(ee);
 429: 
 430:     /* actually deliver the error message */
 431:     sendall(ee, SM_DEFAULT);
 432: 
 433:     /* restore state */
 434:     dropenvelope(ee);
 435:     CurEnv = CurEnv->e_parent;
 436:     returndepth--;
 437: 
 438:     /* should check for delivery errors here */
 439:     return (0);
 440: }
 441: /*
 442: **  ERRBODY -- output the body of an error message.
 443: **
 444: **	Typically this is a copy of the transcript plus a copy of the
 445: **	original offending message.
 446: **
 447: **	Parameters:
 448: **		fp -- the output file.
 449: **		m -- the mailer to output to.
 450: **		e -- the envelope we are working in.
 451: **
 452: **	Returns:
 453: **		none
 454: **
 455: **	Side Effects:
 456: **		Outputs the body of an error message.
 457: */
 458: 
 459: errbody(fp, m, e)
 460:     register FILE *fp;
 461:     register struct mailer *m;
 462:     register ENVELOPE *e;
 463: {
 464:     register FILE *xfile;
 465:     char buf[MAXLINE];
 466:     char *p;
 467: 
 468:     /*
 469: 	**  Output transcript of errors
 470: 	*/
 471: 
 472:     (void) fflush(stdout);
 473:     p = queuename(e->e_parent, 'x');
 474:     if ((xfile = fopen(p, "r")) == NULL)
 475:     {
 476:         syserr("Cannot open %s", p);
 477:         fprintf(fp, "  ----- Transcript of session is unavailable -----\n");
 478:     }
 479:     else
 480:     {
 481:         fprintf(fp, "   ----- Transcript of session follows -----\n");
 482:         if (e->e_xfp != NULL)
 483:             (void) fflush(e->e_xfp);
 484:         while (fgets(buf, sizeof buf, xfile) != NULL)
 485:             putline(buf, fp, m);
 486:         (void) fclose(xfile);
 487:     }
 488:     errno = 0;
 489: 
 490:     /*
 491: 	**  Output text of original message
 492: 	*/
 493: 
 494:     if (NoReturn)
 495:         fprintf(fp, "\n   ----- Return message suppressed -----\n\n");
 496:     else if (e->e_parent->e_dfp != NULL)
 497:     {
 498:         if (SendBody)
 499:         {
 500:             putline("\n", fp, m);
 501:             putline("   ----- Unsent message follows -----\n", fp, m);
 502:             (void) fflush(fp);
 503:             putheader(fp, m, e->e_parent);
 504:             putline("\n", fp, m);
 505:             putbody(fp, m, e->e_parent);
 506:         }
 507:         else
 508:         {
 509:             putline("\n", fp, m);
 510:             putline("  ----- Message header follows -----\n", fp, m);
 511:             (void) fflush(fp);
 512:             putheader(fp, m, e->e_parent);
 513:         }
 514:     }
 515:     else
 516:     {
 517:         putline("\n", fp, m);
 518:         putline("  ----- No message was collected -----\n", fp, m);
 519:         putline("\n", fp, m);
 520:     }
 521: 
 522:     /*
 523: 	**  Cleanup and exit
 524: 	*/
 525: 
 526:     if (errno != 0)
 527:         syserr("errbody: I/O error");
 528: }

Defined functions

errbody defined in line 459; used 2 times
returntosender defined in line 363; used 2 times
savemail defined in line 55; used 1 times

Defined variables

sccsid defined in line 18; never used

Defined macros

ESM_DEADLETTER defined in line 48; used 2 times
ESM_DONE defined in line 52; used 4 times
ESM_MAIL defined in line 46; used 9 times
ESM_PANIC defined in line 51; used 2 times
ESM_POSTMASTER defined in line 49; used 1 times
ESM_QUIET defined in line 47; used 1 times
ESM_REPORT defined in line 45; used 1 times
ESM_USRTMP defined in line 50; used 2 times
MAXRETURNS defined in line 361; used 2 times
Last modified: 1988-09-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4592
Valid CSS Valid XHTML 1.0 Strict