📄 envelope.c
字号:
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char id[] = "@(#)$Id: envelope.c,v 8.180.14.4 2000/08/22 18:22:39 gshapiro Exp $";
#endif /* ! lint */
#include <sendmail.h>
/*
** NEWENVELOPE -- allocate a new envelope
**
** Supports inheritance.
**
** Parameters:
** e -- the new envelope to fill in.
** parent -- the envelope to be the parent of e.
**
** Returns:
** e.
**
** Side Effects:
** none.
*/
ENVELOPE *
newenvelope(e, parent)
register ENVELOPE *e;
register ENVELOPE *parent;
{
if (e == parent && e->e_parent != NULL)
parent = e->e_parent;
clearenvelope(e, TRUE);
if (e == CurEnv)
memmove((char *) &e->e_from,
(char *) &NullAddress,
sizeof e->e_from);
else
memmove((char *) &e->e_from,
(char *) &CurEnv->e_from,
sizeof e->e_from);
e->e_parent = parent;
assign_queueid(e);
e->e_ctime = curtime();
if (parent != NULL)
e->e_msgpriority = parent->e_msgsize;
e->e_puthdr = putheader;
e->e_putbody = putbody;
if (CurEnv->e_xfp != NULL)
(void) fflush(CurEnv->e_xfp);
return e;
}
/*
** DROPENVELOPE -- deallocate an envelope.
**
** Parameters:
** e -- the envelope to deallocate.
** fulldrop -- if set, do return receipts.
**
** Returns:
** none.
**
** Side Effects:
** housekeeping necessary to dispose of an envelope.
** Unlocks this queue file.
*/
void
dropenvelope(e, fulldrop)
register ENVELOPE *e;
bool fulldrop;
{
bool queueit = FALSE;
bool message_timeout = FALSE;
bool failure_return = FALSE;
bool delay_return = FALSE;
bool success_return = FALSE;
bool pmnotify = bitset(EF_PM_NOTIFY, e->e_flags);
bool done = FALSE;
register ADDRESS *q;
char *id = e->e_id;
char buf[MAXLINE];
if (tTd(50, 1))
{
dprintf("dropenvelope %lx: id=", (u_long) e);
xputs(e->e_id);
dprintf(", flags=");
printenvflags(e);
if (tTd(50, 10))
{
dprintf("sendq=");
printaddr(e->e_sendqueue, TRUE);
}
}
if (LogLevel > 84)
sm_syslog(LOG_DEBUG, id,
"dropenvelope, e_flags=0x%lx, OpMode=%c, pid=%d",
e->e_flags, OpMode, getpid());
/* we must have an id to remove disk files */
if (id == NULL)
return;
/* if verify-only mode, we can skip most of this */
if (OpMode == MD_VERIFY)
goto simpledrop;
if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
logsender(e, NULL);
e->e_flags &= ~EF_LOGSENDER;
/* post statistics */
poststats(StatFile);
/*
** Extract state information from dregs of send list.
*/
if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
message_timeout = TRUE;
if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
!bitset(EF_RESPONSE, e->e_flags))
{
message_timeout = TRUE;
e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
}
e->e_flags &= ~EF_QUEUERUN;
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_UNDELIVERED(q->q_state))
queueit = TRUE;
/* see if a notification is needed */
if (bitset(QPINGONFAILURE, q->q_flags) &&
((message_timeout && QS_IS_QUEUEUP(q->q_state)) ||
QS_IS_BADADDR(q->q_state) ||
(TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
!bitset(EF_RESPONSE, e->e_flags))))
{
failure_return = TRUE;
if (!done && q->q_owner == NULL &&
!emptyaddr(&e->e_from))
{
(void) sendtolist(e->e_from.q_paddr, NULLADDR,
&e->e_errorqueue, 0, e);
done = TRUE;
}
}
else if (bitset(QPINGONSUCCESS, q->q_flags) &&
((QS_IS_SENT(q->q_state) &&
bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags)))
{
success_return = TRUE;
}
}
if (e->e_class < 0)
e->e_flags |= EF_NO_BODY_RETN;
/*
** See if the message timed out.
*/
if (!queueit)
/* EMPTY */
/* nothing to do */ ;
else if (message_timeout)
{
if (failure_return)
{
(void) snprintf(buf, sizeof buf,
"Cannot send message for %s",
pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
if (e->e_message != NULL)
free(e->e_message);
e->e_message = newstr(buf);
message(buf);
e->e_flags |= EF_CLRQUEUE;
}
fprintf(e->e_xfp, "Message could not be delivered for %s\n",
pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
fprintf(e->e_xfp, "Message will be deleted from queue\n");
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_UNDELIVERED(q->q_state))
{
q->q_state = QS_BADADDR;
q->q_status = "4.4.7";
}
}
}
else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
{
if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
e->e_class >= 0 &&
e->e_from.q_paddr != NULL &&
strcmp(e->e_from.q_paddr, "<>") != 0 &&
strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
(strlen(e->e_from.q_paddr) <= (SIZE_T) 8 ||
strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
{
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_QUEUEUP(q->q_state) &&
#if _FFR_NODELAYDSN_ON_HOLD
!bitnset(M_HOLD, q->q_mailer->m_flags) &&
#endif /* _FFR_NODELAYDSN_ON_HOLD */
bitset(QPINGONDELAY, q->q_flags))
{
q->q_flags |= QDELAYED;
delay_return = TRUE;
}
}
}
if (delay_return)
{
(void) snprintf(buf, sizeof buf,
"Warning: could not send message for past %s",
pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
if (e->e_message != NULL)
free(e->e_message);
e->e_message = newstr(buf);
message(buf);
e->e_flags |= EF_WARNING;
}
fprintf(e->e_xfp,
"Warning: message still undelivered after %s\n",
pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
}
if (tTd(50, 2))
dprintf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
failure_return, delay_return, success_return, queueit);
/*
** If we had some fatal error, but no addresses are marked as
** bad, mark them _all_ as bad.
*/
if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
{
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if ((QS_IS_OK(q->q_state) ||
QS_IS_VERIFIED(q->q_state)) &&
bitset(QPINGONFAILURE, q->q_flags))
{
failure_return = TRUE;
q->q_state = QS_BADADDR;
}
}
}
/*
** Send back return receipts as requested.
*/
if (success_return && !failure_return && !delay_return && fulldrop &&
!bitset(PRIV_NORECEIPTS, PrivacyFlags) &&
strcmp(e->e_from.q_paddr, "<>") != 0)
{
auto ADDRESS *rlist = NULL;
if (tTd(50, 8))
dprintf("dropenvelope(%s): sending return receipt\n",
id);
e->e_flags |= EF_SENDRECEIPT;
(void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e);
(void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e);
}
e->e_flags &= ~EF_SENDRECEIPT;
/*
** Arrange to send error messages if there are fatal errors.
*/
if ((failure_return || delay_return) && e->e_errormode != EM_QUIET)
{
if (tTd(50, 8))
dprintf("dropenvelope(%s): saving mail\n", id);
savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
}
/*
** Arrange to send warning messages to postmaster as requested.
*/
if ((failure_return || pmnotify) &&
PostMasterCopy != NULL &&
!bitset(EF_RESPONSE, e->e_flags) &&
e->e_class >= 0)
{
auto ADDRESS *rlist = NULL;
char pcopy[MAXNAME];
if (failure_return)
{
expand(PostMasterCopy, pcopy, sizeof pcopy, e);
if (tTd(50, 8))
dprintf("dropenvelope(%s): sending postmaster copy to %s\n",
id, pcopy);
(void) sendtolist(pcopy, NULLADDR, &rlist, 0, e);
}
if (pmnotify)
(void) sendtolist("postmaster", NULLADDR,
&rlist, 0, e);
(void) returntosender(e->e_message, rlist,
RTSF_PM_BOUNCE|RTSF_NO_BODY, e);
}
/*
** Instantiate or deinstantiate the queue.
*/
simpledrop:
if (tTd(50, 8))
dprintf("dropenvelope(%s): at simpledrop, queueit=%d\n",
id, queueit);
if (!queueit || bitset(EF_CLRQUEUE, e->e_flags))
{
if (tTd(50, 1))
{
dprintf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=",
e->e_id, queueit);
printenvflags(e);
}
xunlink(queuename(e, 'd'));
xunlink(queuename(e, 'q'));
if (e->e_ntries > 0 && LogLevel > 9)
sm_syslog(LOG_INFO, id, "done; delay=%s, ntries=%d",
pintvl(curtime() - e->e_ctime, TRUE),
e->e_ntries);
}
else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
{
#if QUEUE
queueup(e, FALSE);
#else /* QUEUE */
syserr("554 5.3.0 dropenvelope: queueup");
#endif /* QUEUE */
}
/* now unlock the job */
if (tTd(50, 8))
dprintf("dropenvelope(%s): unlocking job\n", id);
closexscript(e);
unlockqueue(e);
/* make sure that this envelope is marked unused */
if (e->e_dfp != NULL)
(void) bfclose(e->e_dfp);
e->e_dfp = NULL;
e->e_id = NULL;
e->e_flags &= ~EF_HAS_DF;
}
/*
** CLEARENVELOPE -- clear an envelope without unlocking
**
** This is normally used by a child process to get a clean
** envelope without disturbing the parent.
**
** Parameters:
** e -- the envelope to clear.
** fullclear - if set, the current envelope is total
** garbage and should be ignored; otherwise,
** release any resources it may indicate.
**
** Returns:
** none.
**
** Side Effects:
** Closes files associated with the envelope.
** Marks the envelope as unallocated.
*/
void
clearenvelope(e, fullclear)
register ENVELOPE *e;
bool fullclear;
{
register HDR *bh;
register HDR **nhp;
extern ENVELOPE BlankEnvelope;
if (!fullclear)
{
/* clear out any file information */
if (e->e_xfp != NULL)
(void) bfclose(e->e_xfp);
if (e->e_dfp != NULL)
(void) bfclose(e->e_dfp);
e->e_xfp = e->e_dfp = NULL;
}
/* now clear out the data */
STRUCTCOPY(BlankEnvelope, *e);
e->e_message = NULL;
if (Verbose)
set_delivery_mode(SM_DELIVER, e);
bh = BlankEnvelope.e_header;
nhp = &e->e_header;
while (bh != NULL)
{
*nhp = (HDR *) xalloc(sizeof *bh);
memmove((char *) *nhp, (char *) bh, sizeof *bh);
bh = bh->h_link;
nhp = &(*nhp)->h_link;
}
}
/*
** INITSYS -- initialize instantiation of system
**
** In Daemon mode, this is done in the child.
**
** Parameters:
** e -- the envelope to use.
**
** Returns:
** none.
**
** Side Effects:
** Initializes the system macros, some global variables,
** etc. In particular, the current time in various
** forms is set.
*/
void
initsys(e)
register ENVELOPE *e;
{
char cbuf[5]; /* holds hop count */
char pbuf[10]; /* holds pid */
#ifdef TTYNAME
static char ybuf[60]; /* holds tty id */
register char *p;
extern char *ttyname();
#endif /* TTYNAME */
/*
** Give this envelope a reality.
** I.e., an id, a transcript, and a creation time.
*/
setnewqueue(e);
openxscript(e);
e->e_ctime = curtime();
#if _FFR_QUEUEDELAY
e->e_queuealg = QueueAlg;
e->e_queuedelay = QueueInitDelay;
#endif /* _FFR_QUEUEDELAY */
/*
** Set OutChannel to something useful if stdout isn't it.
** This arranges that any extra stuff the mailer produces
** gets sent back to the user on error (because it is
** tucked away in the transcript).
*/
if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
e->e_xfp != NULL)
OutChannel = e->e_xfp;
/*
** Set up some basic system macros.
*/
/* process id */
(void) snprintf(pbuf, sizeof pbuf, "%d", (int) getpid());
define('p', newstr(pbuf), e);
/* hop count */
(void) snprintf(cbuf, sizeof cbuf, "%d", e->e_hopcount);
define('c', newstr(cbuf), e);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -