📄 savemail.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)savemail.c 8.28 (Berkeley) 3/11/94";#endif /* not lint */# include "sendmail.h"# include <pwd.h>/*** SAVEMAIL -- Save mail on error**** If mailing back errors, mail it back to the originator** together with an error message; otherwise, just put it in** dead.letter in the user's home directory (if he exists on** this machine).**** Parameters:** e -- the envelope containing the message in error.**** Returns:** none**** Side Effects:** Saves the letter, by writing or mailing it back to the** sender, or by putting it in dead.letter in her home** directory.*//* defines for state machine */# define ESM_REPORT 0 /* report to sender's terminal */# define ESM_MAIL 1 /* mail back to sender */# define ESM_QUIET 2 /* messages have already been returned */# define ESM_DEADLETTER 3 /* save in ~/dead.letter */# define ESM_POSTMASTER 4 /* return to postmaster */# define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */# define ESM_PANIC 6 /* leave the locked queue/transcript files */# define ESM_DONE 7 /* the message is successfully delivered */# ifndef _PATH_VARTMP# define _PATH_VARTMP "/usr/tmp/"# endifsavemail(e) register ENVELOPE *e;{ register struct passwd *pw; register FILE *fp; int state; auto ADDRESS *q = NULL; register char *p; MCI mcibuf; char buf[MAXLINE+1]; extern struct passwd *getpwnam(); extern char *ttypath(); typedef int (*fnptr)(); extern bool writable(); if (tTd(6, 1)) { printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=", e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id, ExitStat); printaddr(&e->e_from, FALSE); } if (e->e_id == NULL) { /* can't return a message with no id */ return; } /* ** In the unhappy event we don't know who to return the mail ** to, make someone up. */ if (e->e_from.q_paddr == NULL) { e->e_sender = "Postmaster"; if (parseaddr(e->e_sender, &e->e_from, RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL) { syserr("553 Cannot parse Postmaster!"); ExitStat = EX_SOFTWARE; finis(); } } e->e_to = NULL; /* ** Basic state machine. ** ** This machine runs through the following states: ** ** ESM_QUIET Errors have already been printed iff the ** sender is local. ** ESM_REPORT Report directly to the sender's terminal. ** ESM_MAIL Mail response to the sender. ** ESM_DEADLETTER Save response in ~/dead.letter. ** ESM_POSTMASTER Mail response to the postmaster. ** ESM_PANIC Save response anywhere possible. */ /* determine starting state */ switch (e->e_errormode) { case EM_WRITE: state = ESM_REPORT; break; case EM_BERKNET: /* mail back, but return o.k. exit status */ ExitStat = EX_OK; /* fall through.... */ case EM_MAIL: state = ESM_MAIL; break; case EM_PRINT: case '\0': state = ESM_QUIET; break; case EM_QUIET: /* no need to return anything at all */ return; default: syserr("554 savemail: bogus errormode x%x\n", e->e_errormode); state = ESM_MAIL; break; } /* if this is already an error response, send to postmaster */ if (bitset(EF_RESPONSE, e->e_flags)) { if (e->e_parent != NULL && bitset(EF_RESPONSE, e->e_parent->e_flags)) { /* got an error sending a response -- can it */ return; } state = ESM_POSTMASTER; } while (state != ESM_DONE) { if (tTd(6, 5)) printf(" state %d\n", state); switch (state) { case ESM_QUIET: if (e->e_from.q_mailer == LocalMailer) state = ESM_DEADLETTER; else state = ESM_MAIL; break; case ESM_REPORT: /* ** If the user is still logged in on the same terminal, ** then write the error messages back to hir (sic). */ p = ttypath(); if (p == NULL || freopen(p, "w", stdout) == NULL) { state = ESM_MAIL; break; } expand("\201n", buf, &buf[sizeof buf - 1], e); printf("\r\nMessage from %s...\r\n", buf); printf("Errors occurred while sending mail.\r\n"); if (e->e_xfp != NULL) { (void) fflush(e->e_xfp); fp = fopen(queuename(e, 'x'), "r"); } else fp = NULL; if (fp == NULL) { syserr("Cannot open %s", queuename(e, 'x')); printf("Transcript of session is unavailable.\r\n"); } else { printf("Transcript follows:\r\n"); while (fgets(buf, sizeof buf, fp) != NULL && !ferror(stdout)) fputs(buf, stdout); (void) xfclose(fp, "savemail transcript", e->e_id); } printf("Original message will be saved in dead.letter.\r\n"); state = ESM_DEADLETTER; break; case ESM_MAIL: /* ** If mailing back, do it. ** Throw away all further output. Don't alias, ** since this could cause loops, e.g., if joe ** mails to joe@x, and for some reason the network ** for @x is down, then the response gets sent to ** joe@x, which gives a response, etc. Also force ** the mail to be delivered even if a version of ** it has already been sent to the sender. ** ** If this is a configuration or local software ** error, send to the local postmaster as well, ** since the originator can't do anything ** about it anyway. Note that this is a full ** copy of the message (intentionally) so that ** the Postmaster can forward things along. */ if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE) { (void) sendtolist("postmaster", NULLADDR, &e->e_errorqueue, e); } if (strcmp(e->e_from.q_paddr, "<>") != 0) { (void) sendtolist(e->e_from.q_paddr, NULLADDR, &e->e_errorqueue, e); } /* ** Deliver a non-delivery report to the ** Postmaster-designate (not necessarily ** Postmaster). This does not include the ** body of the message, for privacy reasons. ** You really shouldn't need this. */ e->e_flags |= EF_PM_NOTIFY; /* check to see if there are any good addresses */ for (q = e->e_errorqueue; q != NULL; q = q->q_next) if (!bitset(QBADADDR|QDONTSEND, q->q_flags)) break; if (q == NULL) { /* this is an error-error */ state = ESM_POSTMASTER; break; } if (returntosender(e->e_message, e->e_errorqueue, (e->e_class >= 0), e) == 0) { state = ESM_DONE; break; } /* didn't work -- return to postmaster */ state = ESM_POSTMASTER; break; case ESM_POSTMASTER: /* ** Similar to previous case, but to system postmaster. */ q = NULL; if (sendtolist("postmaster", NULL, &q, e) <= 0) { syserr("553 cannot parse postmaster!"); ExitStat = EX_SOFTWARE; state = ESM_USRTMP; break; } if (returntosender(e->e_message, q, (e->e_class >= 0), e) == 0) { state = ESM_DONE; break; } /* didn't work -- last resort */ state = ESM_USRTMP; break; case ESM_DEADLETTER: /* ** Save the message in dead.letter. ** If we weren't mailing back, and the user is ** local, we should save the message in ** ~/dead.letter so that the poor person doesn't ** have to type it over again -- and we all know ** what poor typists UNIX users are. */ p = NULL; if (e->e_from.q_mailer == LocalMailer) { if (e->e_from.q_home != NULL) p = e->e_from.q_home; else if ((pw = getpwnam(e->e_from.q_user)) != NULL) p = pw->pw_dir; } if (p == NULL) { /* no local directory */ state = ESM_MAIL; break; } if (e->e_dfp != NULL) { bool oldverb = Verbose; /* we have a home directory; open dead.letter */ define('z', p, e); expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e); Verbose = TRUE; message("Saving message in %s", buf); Verbose = oldverb; e->e_to = buf; q = NULL; (void) sendtolist(buf, &e->e_from, &q, e); if (q != NULL && !bitset(QBADADDR, q->q_flags) && deliver(e, q) == 0) state = ESM_DONE; else state = ESM_MAIL; } else { /* no data file -- try mailing back */ state = ESM_MAIL; } break; case ESM_USRTMP: /* ** Log the mail in /usr/tmp/dead.letter. */ if (e->e_class < 0) { state = ESM_DONE; break; } strcpy(buf, _PATH_VARTMP); strcat(buf, "dead.letter"); if (!writable(buf, NULLADDR, SFF_NOSLINK)) { state = ESM_PANIC; break; } fp = dfopen(buf, O_WRONLY|O_CREAT|O_APPEND, FileMode); if (fp == NULL) { state = ESM_PANIC; break; } bzero(&mcibuf, sizeof mcibuf); mcibuf.mci_out = fp; mcibuf.mci_mailer = FileMailer; if (bitnset(M_7BITS, FileMailer->m_flags)) mcibuf.mci_flags |= MCIF_7BIT; putfromline(&mcibuf, e); (*e->e_puthdr)(&mcibuf, e); putline("\n", &mcibuf); (*e->e_putbody)(&mcibuf, e, NULL); putline("\n", &mcibuf); (void) fflush(fp); state = ferror(fp) ? ESM_PANIC : ESM_DONE; (void) xfclose(fp, "savemail", "/usr/tmp/dead.letter"); break; default: syserr("554 savemail: unknown state %d", state); /* fall through ... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -