📄 recipient.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: recipient.c,v 8.231.14.8 2000/09/14 23:32:27 gshapiro Exp $";
#endif /* ! lint */
#include <sendmail.h>
static void includetimeout __P((void));
static ADDRESS *self_reference __P((ADDRESS *));
/*
** SENDTOLIST -- Designate a send list.
**
** The parameter is a comma-separated list of people to send to.
** This routine arranges to send to all of them.
**
** Parameters:
** list -- the send list.
** ctladdr -- the address template for the person to
** send to -- effective uid/gid are important.
** This is typically the alias that caused this
** expansion.
** sendq -- a pointer to the head of a queue to put
** these people into.
** aliaslevel -- the current alias nesting depth -- to
** diagnose loops.
** e -- the envelope in which to add these recipients.
**
** Returns:
** The number of addresses actually on the list.
**
** Side Effects:
** none.
*/
/* q_flags bits inherited from ctladdr */
#define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY)
int
sendtolist(list, ctladdr, sendq, aliaslevel, e)
char *list;
ADDRESS *ctladdr;
ADDRESS **sendq;
int aliaslevel;
register ENVELOPE *e;
{
register char *p;
register ADDRESS *al; /* list of addresses to send to */
char delimiter; /* the address delimiter */
int naddrs;
int i;
char *oldto = e->e_to;
char *bufp;
char buf[MAXNAME + 1];
if (list == NULL)
{
syserr("sendtolist: null list");
return 0;
}
if (tTd(25, 1))
{
dprintf("sendto: %s\n ctladdr=", list);
printaddr(ctladdr, FALSE);
}
/* heuristic to determine old versus new style addresses */
if (ctladdr == NULL &&
(strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
strchr(list, '<') != NULL || strchr(list, '(') != NULL))
e->e_flags &= ~EF_OLDSTYLE;
delimiter = ' ';
if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
delimiter = ',';
al = NULL;
naddrs = 0;
/* make sure we have enough space to copy the string */
i = strlen(list) + 1;
if (i <= sizeof buf)
{
bufp = buf;
i = sizeof buf;
}
else
bufp = xalloc(i);
(void) strlcpy(bufp, denlstring(list, FALSE, TRUE), i);
#if _FFR_ADDR_TYPE
define(macid("{addr_type}", NULL), "e r", e);
#endif /* _FFR_ADDR_TYPE */
for (p = bufp; *p != '\0'; )
{
auto char *delimptr;
register ADDRESS *a;
/* parse the address */
while ((isascii(*p) && isspace(*p)) || *p == ',')
p++;
a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
p = delimptr;
if (a == NULL)
continue;
a->q_next = al;
a->q_alias = ctladdr;
/* arrange to inherit attributes from parent */
if (ctladdr != NULL)
{
ADDRESS *b;
/* self reference test */
if (sameaddr(ctladdr, a))
{
if (tTd(27, 5))
{
dprintf("sendtolist: QSELFREF ");
printaddr(ctladdr, FALSE);
}
ctladdr->q_flags |= QSELFREF;
}
/* check for address loops */
b = self_reference(a);
if (b != NULL)
{
b->q_flags |= QSELFREF;
if (tTd(27, 5))
{
dprintf("sendtolist: QSELFREF ");
printaddr(b, FALSE);
}
if (a != b)
{
if (tTd(27, 5))
{
dprintf("sendtolist: QS_DONTSEND ");
printaddr(a, FALSE);
}
a->q_state = QS_DONTSEND;
b->q_flags |= a->q_flags & QNOTREMOTE;
continue;
}
}
/* full name */
if (a->q_fullname == NULL)
a->q_fullname = ctladdr->q_fullname;
/* various flag bits */
a->q_flags &= ~QINHERITEDBITS;
a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
/* original recipient information */
a->q_orcpt = ctladdr->q_orcpt;
}
al = a;
}
/* arrange to send to everyone on the local send list */
while (al != NULL)
{
register ADDRESS *a = al;
al = a->q_next;
a = recipient(a, sendq, aliaslevel, e);
naddrs++;
}
e->e_to = oldto;
if (bufp != buf)
free(bufp);
#if _FFR_ADDR_TYPE
define(macid("{addr_type}", NULL), NULL, e);
#endif /* _FFR_ADDR_TYPE */
return naddrs;
}
/*
** REMOVEFROMLIST -- Remove addresses from a send list.
**
** The parameter is a comma-separated list of recipients to remove.
** Note that it only deletes matching addresses. If those addresses
** have been expended already in the sendq, it won't mark the
** expanded recipients as QS_REMOVED.
**
** Parameters:
** list -- the list to remove.
** sendq -- a pointer to the head of a queue to remove
** these addresses from.
** e -- the envelope in which to remove these recipients.
**
** Returns:
** The number of addresses removed from the list.
**
*/
int
removefromlist(list, sendq, e)
char *list;
ADDRESS **sendq;
ENVELOPE *e;
{
char delimiter; /* the address delimiter */
int naddrs;
int i;
char *p;
char *oldto = e->e_to;
char *bufp;
char buf[MAXNAME + 1];
if (list == NULL)
{
syserr("removefromlist: null list");
return 0;
}
if (tTd(25, 1))
dprintf("removefromlist: %s\n", list);
/* heuristic to determine old versus new style addresses */
if (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
strchr(list, '<') != NULL || strchr(list, '(') != NULL)
e->e_flags &= ~EF_OLDSTYLE;
delimiter = ' ';
if (!bitset(EF_OLDSTYLE, e->e_flags))
delimiter = ',';
naddrs = 0;
/* make sure we have enough space to copy the string */
i = strlen(list) + 1;
if (i <= sizeof buf)
{
bufp = buf;
i = sizeof buf;
}
else
bufp = xalloc(i);
(void) strlcpy(bufp, denlstring(list, FALSE, TRUE), i);
#if _FFR_ADDR_TYPE
define(macid("{addr_type}", NULL), "e r", e);
#endif /* _FFR_ADDR_TYPE */
for (p = bufp; *p != '\0'; )
{
ADDRESS a; /* parsed address to be removed */
ADDRESS *q;
ADDRESS **pq;
char *delimptr;
/* parse the address */
while ((isascii(*p) && isspace(*p)) || *p == ',')
p++;
if (parseaddr(p, &a, RF_COPYALL,
delimiter, &delimptr, e) == NULL)
{
p = delimptr;
continue;
}
p = delimptr;
for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
{
if (!QS_IS_DEAD(q->q_state) &&
sameaddr(q, &a))
{
if (tTd(25, 5))
{
dprintf("removefromlist: QS_REMOVED ");
printaddr(&a, FALSE);
}
q->q_state = QS_REMOVED;
naddrs++;
break;
}
}
}
e->e_to = oldto;
if (bufp != buf)
free(bufp);
#if _FFR_ADDR_TYPE
define(macid("{addr_type}", NULL), NULL, e);
#endif /* _FFR_ADDR_TYPE */
return naddrs;
}
/*
** RECIPIENT -- Designate a message recipient
**
** Saves the named person for future mailing.
**
** Parameters:
** a -- the (preparsed) address header for the recipient.
** sendq -- a pointer to the head of a queue to put the
** recipient in. Duplicate suppression is done
** in this queue.
** aliaslevel -- the current alias nesting depth.
** e -- the current envelope.
**
** Returns:
** The actual address in the queue. This will be "a" if
** the address is not a duplicate, else the original address.
**
** Side Effects:
** none.
*/
ADDRESS *
recipient(a, sendq, aliaslevel, e)
register ADDRESS *a;
register ADDRESS **sendq;
int aliaslevel;
register ENVELOPE *e;
{
register ADDRESS *q;
ADDRESS **pq;
register struct mailer *m;
register char *p = NULL;
bool quoted = FALSE; /* set if the addr has a quote bit */
int findusercount = 0;
bool initialdontsend = QS_IS_DEAD(a->q_state);
int i, buflen;
char *buf;
char buf0[MAXNAME + 1]; /* unquoted image of the user name */
e->e_to = a->q_paddr;
m = a->q_mailer;
errno = 0;
if (aliaslevel == 0)
a->q_flags |= QPRIMARY;
if (tTd(26, 1))
{
dprintf("\nrecipient (%d): ", aliaslevel);
printaddr(a, FALSE);
}
/* if this is primary, add it to the original recipient list */
if (a->q_alias == NULL)
{
if (e->e_origrcpt == NULL)
e->e_origrcpt = a->q_paddr;
else if (e->e_origrcpt != a->q_paddr)
e->e_origrcpt = "";
}
#if _FFR_GEN_ORCPT
/* set ORCPT DSN arg if not already set */
if (a->q_orcpt == NULL)
{
for (q = a; q->q_alias != NULL; q = q->q_alias)
continue;
/* check for an existing ORCPT */
if (q->q_orcpt != NULL)
a->q_orcpt = q->q_orcpt;
else
{
/* make our own */
bool b = FALSE;
char *qp;
char obuf[MAXLINE];
if (e->e_from.q_mailer != NULL)
p = e->e_from.q_mailer->m_addrtype;
if (p == NULL)
p = "rfc822";
(void) strlcpy(obuf, p, sizeof obuf);
(void) strlcat(obuf, ";", sizeof obuf);
qp = q->q_paddr;
/* FFR: Needs to strip comments from stdin addrs */
/* strip brackets from address */
if (*qp == '<')
{
b = qp[strlen(qp) - 1] == '>';
if (b)
qp[strlen(qp) - 1] = '\0';
qp++;
}
p = xtextify(denlstring(qp, TRUE, FALSE), NULL);
if (strlcat(obuf, p, sizeof obuf) >= sizeof obuf)
{
/* if too big, don't use it */
obuf[0] = '\0';
}
/* undo damage */
if (b)
qp[strlen(qp)] = '>';
if (obuf[0] != '\0')
a->q_orcpt = newstr(obuf);
}
}
#endif /* _FFR_GEN_ORCPT */
/* break aliasing loops */
if (aliaslevel > MaxAliasRecursion)
{
a->q_state = QS_BADADDR;
a->q_status = "5.4.6";
usrerrenh(a->q_status,
"554 aliasing/forwarding loop broken (%d aliases deep; %d max)",
aliaslevel, MaxAliasRecursion);
return a;
}
/*
** Finish setting up address structure.
*/
/* get unquoted user for file, program or user.name check */
i = strlen(a->q_user);
if (i >= sizeof buf0)
{
buflen = i + 1;
buf = xalloc(buflen);
}
else
{
buf = buf0;
buflen = sizeof buf0;
}
(void) strlcpy(buf, a->q_user, buflen);
for (p = buf; *p != '\0' && !quoted; p++)
{
if (*p == '\\')
quoted = TRUE;
}
stripquotes(buf);
/* check for direct mailing to restricted mailers */
if (m == ProgMailer)
{
if (a->q_alias == NULL)
{
a->q_state = QS_BADADDR;
a->q_status = "5.7.1";
usrerrenh(a->q_status,
"550 Cannot mail directly to programs");
}
else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
{
a->q_state = QS_BADADDR;
a->q_status = "5.7.1";
if (a->q_alias->q_ruser == NULL)
usrerrenh(a->q_status,
"550 UID %d is an unknown user: cannot mail to programs",
a->q_alias->q_uid);
else
usrerrenh(a->q_status,
"550 User %s@%s doesn't have a valid shell for mailing to programs",
a->q_alias->q_ruser, MyHostName);
}
else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
{
a->q_state = QS_BADADDR;
a->q_status = "5.7.1";
a->q_rstatus = newstr("550 Unsafe for mailing to programs");
usrerrenh(a->q_status,
"550 Address %s is unsafe for mailing to programs",
a->q_alias->q_paddr);
}
}
/*
** Look up this person in the recipient list.
** If they are there already, return, otherwise continue.
** If the list is empty, just add it. Notice the cute
** hack to make from addresses suppress things correctly:
** the QS_DUPLICATE state will be set in the send list.
** [Please note: the emphasis is on "hack."]
*/
for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
{
if (sameaddr(q, a) &&
(bitset(QRCPTOK, q->q_flags) ||
!bitset(QPRIMARY, q->q_flags)))
{
if (tTd(26, 1))
{
dprintf("%s in sendq: ", a->q_paddr);
printaddr(q, FALSE);
}
if (!bitset(QPRIMARY, q->q_flags))
{
if (!QS_IS_DEAD(a->q_state))
message("duplicate suppressed");
else
q->q_state = QS_DUPLICATE;
q->q_flags |= a->q_flags;
}
else if (bitset(QSELFREF, q->q_flags)
#if _FFR_MILTER
|| q->q_state == QS_REMOVED
#endif /* _FFR_MILTER */
)
{
#if _FFR_MILTER
/*
** If an earlier milter removed the address,
** a later one can still add it back.
*/
#endif /* _FFR_MILTER */
q->q_state = a->q_state;
q->q_flags |= a->q_flags;
}
a = q;
goto done;
}
}
/* add address on list */
if (pq != NULL)
{
*pq = a;
a->q_next = NULL;
}
/*
** Alias the name and handle special mailer types.
*/
trylocaluser:
if (tTd(29, 7))
{
dprintf("at trylocaluser: ");
printaddr(a, FALSE);
}
if (!QS_IS_OK(a->q_state))
goto testselfdestruct;
if (m == InclMailer)
{
a->q_state = QS_INCLUDED;
if (a->q_alias == NULL)
{
a->q_state = QS_BADADDR;
a->q_status = "5.7.1";
usrerrenh(a->q_status,
"550 Cannot mail directly to :include:s");
}
else
{
int ret;
message("including file %s", a->q_user);
ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e);
if (transienterror(ret))
{
if (LogLevel > 2)
sm_syslog(LOG_ERR, e->e_id,
"include %s: transient error: %s",
shortenstring(a->q_user, MAXSHORTSTR),
errstring(ret));
a->q_state = QS_QUEUEUP;
usrerr("451 4.2.4 Cannot open %s: %s",
shortenstring(a->q_user, MAXSHORTSTR),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -