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

Defined functions

errbody defined in line 453; used 2 times
returntosender defined in line 357; used 2 times
savemail defined in line 49; used 1 times

Defined variables

SccsId defined in line 12; never used

Defined macros

ESM_DEADLETTER defined in line 42; used 2 times
ESM_DONE defined in line 46; used 4 times
ESM_MAIL defined in line 40; used 9 times
ESM_PANIC defined in line 45; used 2 times
ESM_POSTMASTER defined in line 43; used 1 times
ESM_QUIET defined in line 41; used 1 times
ESM_REPORT defined in line 39; used 1 times
ESM_USRTMP defined in line 44; used 2 times
MAXRETURNS defined in line 355; used 2 times
Last modified: 1995-03-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4203
Valid CSS Valid XHTML 1.0 Strict