📄 deliver.c
字号:
bitnset(M_ROPT, m->m_flags)))
{
if (bitnset(M_FOPT, m->m_flags))
*pvp++ = "-f";
else
*pvp++ = "-r";
*pvp++ = newstr(rpathbuf);
}
/*
** Append the other fixed parts of the argv. These run
** up to the first entry containing "$u". There can only
** be one of these, and there are only a few more slots
** in the pv after it.
*/
for (mvp = m->m_argv; (p = *++mvp) != NULL; )
{
/* can't use strchr here because of sign extension problems */
while (*p != '\0')
{
if ((*p++ & 0377) == MACROEXPAND)
{
if (*p == 'u')
break;
}
}
if (*p != '\0')
break;
/* this entry is safe -- go ahead and process it */
expand(*mvp, buf, sizeof buf, e);
*pvp++ = newstr(buf);
if (pvp >= &pv[MAXPV - 3])
{
syserr("554 5.3.5 Too many parameters to %s before $u",
pv[0]);
return -1;
}
}
/*
** If we have no substitution for the user name in the argument
** list, we know that we must supply the names otherwise -- and
** SMTP is the answer!!
*/
if (*mvp == NULL)
{
/* running SMTP */
#if SMTP
clever = TRUE;
*pvp = NULL;
#else /* SMTP */
/* oops! we don't implement SMTP */
syserr("554 5.3.5 SMTP style mailer not implemented");
return EX_SOFTWARE;
#endif /* SMTP */
}
/*
** At this point *mvp points to the argument with $u. We
** run through our address list and append all the addresses
** we can. If we run out of space, do not fret! We can
** always send another copy later.
*/
#if _FFR_DYNAMIC_TOBUF
e->e_to = NULL;
strsize = 2;
rcptcount = 0;
#else /* _FFR_DYNAMIC_TOBUF */
tobuf[0] = '\0';
e->e_to = tobuf;
#endif /* _FFR_DYNAMIC_TOBUF */
ctladdr = NULL;
firstsig = hostsignature(firstto->q_mailer, firstto->q_host);
for (; to != NULL; to = to->q_next)
{
/* avoid sending multiple recipients to dumb mailers */
#if _FFR_DYNAMIC_TOBUF
if (tochain != NULL && !bitnset(M_MUSER, m->m_flags))
break;
#else /* _FFR_DYNAMIC_TOBUF */
if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
break;
#endif /* _FFR_DYNAMIC_TOBUF */
/* if already sent or not for this host, don't send */
if (!QS_IS_OK(to->q_state) ||
to->q_mailer != firstto->q_mailer ||
strcmp(hostsignature(to->q_mailer, to->q_host),
firstsig) != 0)
continue;
/* avoid overflowing tobuf */
#if _FFR_DYNAMIC_TOBUF
strsize += strlen(to->q_paddr) + 1;
if (!clever && strsize > TOBUFSIZE)
break;
if (++rcptcount > to->q_mailer->m_maxrcpt)
break;
#else /* _FFR_DYNAMIC_TOBUF */
if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
break;
#endif /* _FFR_DYNAMIC_TOBUF */
if (tTd(10, 1))
{
dprintf("\nsend to ");
printaddr(to, FALSE);
}
/* compute effective uid/gid when sending */
if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
contextaddr = ctladdr = getctladdr(to);
if (tTd(10, 2))
{
dprintf("ctladdr=");
printaddr(ctladdr, FALSE);
}
user = to->q_user;
e->e_to = to->q_paddr;
/*
** Check to see that these people are allowed to
** talk to each other.
** Check also for overflow of e_msgsize.
*/
if (m->m_maxsize != 0 &&
(e->e_msgsize > m->m_maxsize || e->e_msgsize < 0))
{
e->e_flags |= EF_NO_BODY_RETN;
if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags))
to->q_status = "5.2.3";
else
to->q_status = "5.3.4";
/* set to->q_rstatus = NULL; or to the following? */
usrerrenh(to->q_status,
"552 Message is too large; %ld bytes max",
m->m_maxsize);
markfailure(e, to, NULL, EX_UNAVAILABLE, FALSE);
giveresponse(EX_UNAVAILABLE, to->q_status, m,
NULL, ctladdr, xstart, e);
continue;
}
#if NAMED_BIND
h_errno = 0;
#endif /* NAMED_BIND */
ovr = TRUE;
/* do config file checking of compatibility */
rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr,
e, TRUE, TRUE, 4);
if (rcode == EX_OK)
{
/* do in-code checking if not discarding */
if (!bitset(EF_DISCARD, e->e_flags))
{
rcode = checkcompat(to, e);
ovr = FALSE;
}
}
if (rcode != EX_OK)
{
markfailure(e, to, NULL, rcode, ovr);
giveresponse(rcode, to->q_status, m,
NULL, ctladdr, xstart, e);
continue;
}
if (bitset(EF_DISCARD, e->e_flags))
{
if (tTd(10, 5))
{
dprintf("deliver: discarding recipient ");
printaddr(to, FALSE);
}
/* pretend the message was sent */
/* XXX should we log something here? */
to->q_state = QS_DISCARDED;
/*
** Remove discard bit to prevent discard of
** future recipients. This is safe because the
** true "global discard" has been handled before
** we get here.
*/
e->e_flags &= ~EF_DISCARD;
continue;
}
/*
** Strip quote bits from names if the mailer is dumb
** about them.
*/
if (bitnset(M_STRIPQ, m->m_flags))
{
stripquotes(user);
stripquotes(host);
}
/* hack attack -- delivermail compatibility */
if (m == ProgMailer && *user == '|')
user++;
/*
** If an error message has already been given, don't
** bother to send to this address.
**
** >>>>>>>>>> This clause assumes that the local mailer
** >> NOTE >> cannot do any further aliasing; that
** >>>>>>>>>> function is subsumed by sendmail.
*/
if (!QS_IS_OK(to->q_state))
continue;
/*
** See if this user name is "special".
** If the user name has a slash in it, assume that this
** is a file -- send it off without further ado. Note
** that this type of addresses is not processed along
** with the others, so we fudge on the To person.
*/
if (strcmp(m->m_mailer, "[FILE]") == 0)
{
define('u', user, e); /* to user */
p = to->q_home;
if (p == NULL && ctladdr != NULL)
p = ctladdr->q_home;
define('z', p, e); /* user's home */
expand(m->m_argv[1], buf, sizeof buf, e);
if (strlen(buf) > 0)
rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
else
{
syserr("empty filename specification for mailer %s",
m->m_name);
rcode = EX_CONFIG;
}
giveresponse(rcode, to->q_status, m, NULL,
ctladdr, xstart, e);
markfailure(e, to, NULL, rcode, TRUE);
e->e_nsent++;
if (rcode == EX_OK)
{
to->q_state = QS_SENT;
if (bitnset(M_LOCALMAILER, m->m_flags) &&
bitset(QPINGONSUCCESS, to->q_flags))
{
to->q_flags |= QDELIVERED;
to->q_status = "2.1.5";
fprintf(e->e_xfp, "%s... Successfully delivered\n",
to->q_paddr);
}
}
to->q_statdate = curtime();
markstats(e, to, FALSE);
continue;
}
/*
** Address is verified -- add this user to mailer
** argv, and add it to the print list of recipients.
*/
/* link together the chain of recipients */
to->q_tchain = tochain;
tochain = to;
#if _FFR_DYNAMIC_TOBUF
e->e_to = "[CHAIN]";
#else /* _FFR_DYNAMIC_TOBUF */
/* create list of users for error messages */
(void) strlcat(tobuf, ",", sizeof tobuf);
(void) strlcat(tobuf, to->q_paddr, sizeof tobuf);
#endif /* _FFR_DYNAMIC_TOBUF */
define('u', user, e); /* to user */
p = to->q_home;
if (p == NULL && ctladdr != NULL)
p = ctladdr->q_home;
define('z', p, e); /* user's home */
/* set the ${dsn_notify} macro if applicable */
if (bitset(QHASNOTIFY, to->q_flags))
{
char notify[MAXLINE];
notify[0] = '\0';
if (bitset(QPINGONSUCCESS, to->q_flags))
(void) strlcat(notify, "SUCCESS,",
sizeof notify);
if (bitset(QPINGONFAILURE, to->q_flags))
(void) strlcat(notify, "FAILURE,",
sizeof notify);
if (bitset(QPINGONDELAY, to->q_flags))
(void) strlcat(notify, "DELAY,", sizeof notify);
/* Set to NEVER or drop trailing comma */
if (notify[0] == '\0')
(void) strlcat(notify, "NEVER", sizeof notify);
else
notify[strlen(notify) - 1] = '\0';
define(macid("{dsn_notify}", NULL), newstr(notify), e);
}
else
define(macid("{dsn_notify}", NULL), NULL, e);
/*
** Expand out this user into argument list.
*/
if (!clever)
{
expand(*mvp, buf, sizeof buf, e);
*pvp++ = newstr(buf);
if (pvp >= &pv[MAXPV - 2])
{
/* allow some space for trailing parms */
break;
}
}
}
/* see if any addresses still exist */
#if _FFR_DYNAMIC_TOBUF
if (tochain == NULL)
#else /* _FFR_DYNAMIC_TOBUF */
if (tobuf[0] == '\0')
#endif /* _FFR_DYNAMIC_TOBUF */
{
define('g', (char *) NULL, e);
e->e_to = NULL;
return 0;
}
/* print out messages as full list */
#if _FFR_DYNAMIC_TOBUF
{
int l = 1;
char *tobufptr;
for (to = tochain; to != NULL; to = to->q_tchain)
l += strlen(to->q_paddr) + 1;
if (l < TOBUFSIZE)
l = TOBUFSIZE;
if (l > tobufsize)
{
if (tobuf != NULL)
free(tobuf);
tobufsize = l;
tobuf = xalloc(tobufsize);
}
tobufptr = tobuf;
*tobufptr = '\0';
for (to = tochain; to != NULL; to = to->q_tchain)
{
snprintf(tobufptr, tobufsize - (tobufptr - tobuf),
",%s", to->q_paddr);
tobufptr += strlen(tobufptr);
}
}
#endif /* _FFR_DYNAMIC_TOBUF */
e->e_to = tobuf + 1;
/*
** Fill out any parameters after the $u parameter.
*/
while (!clever && *++mvp != NULL)
{
expand(*mvp, buf, sizeof buf, e);
*pvp++ = newstr(buf);
if (pvp >= &pv[MAXPV])
syserr("554 5.3.0 deliver: pv overflow after $u for %s",
pv[0]);
}
*pvp++ = NULL;
/*
** Call the mailer.
** The argument vector gets built, pipes
** are created as necessary, and we fork & exec as
** appropriate.
** If we are running SMTP, we just need to clean up.
*/
/* XXX this seems a bit wierd */
if (ctladdr == NULL && m != ProgMailer && m != FileMailer &&
bitset(QGOODUID, e->e_from.q_flags))
ctladdr = &e->e_from;
#if NAMED_BIND
if (ConfigLevel < 2)
_res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
#endif /* NAMED_BIND */
if (tTd(11, 1))
{
dprintf("openmailer:");
printav(pv);
}
errno = 0;
#if NAMED_BIND
h_errno = 0;
#endif /* NAMED_BIND */
CurHostName = NULL;
/*
** Deal with the special case of mail handled through an IPC
** connection.
** In this case we don't actually fork. We must be
** running SMTP for this to work. We will return a
** zero pid to indicate that we are running IPC.
** We also handle a debug version that just talks to stdin/out.
*/
curhost = NULL;
SmtpPhase = NULL;
mci = NULL;
#if XDEBUG
{
char wbuf[MAXLINE];
/* make absolutely certain 0, 1, and 2 are in use */
snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
checkfd012(wbuf);
}
#endif /* XDEBUG */
/* check for 8-bit available */
if (bitset(EF_HAS8BIT, e->e_flags) &&
bitnset(M_7BITS, m->m_flags) &&
(bitset(EF_DONT_MIME, e->e_flags) ||
!(bitset(MM_MIME8BIT, MimeMode) ||
(bitset(EF_IS_MIME, e->e_flags) &&
bitset(MM_CVTMIME, MimeMode)))))
{
e->e_status = "5.6.3";
usrerrenh(e->e_status,
"554 Cannot send 8-bit data to 7-bit destination");
rcode = EX_DATAERR;
goto give_up;
}
if (tTd(62, 8))
checkfds("before delivery");
/* check for Local Person Communication -- not for mortals!!! */
if (strcmp(m->m_mailer, "[LPC]") == 0)
{
mci = (MCI *) xalloc(sizeof *mci);
memset((char *) mci, '\0', sizeof *mci);
mci->mci_in = stdin;
mci->mci_out = stdout;
mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
mci->mci_mailer = m;
}
else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
strcmp(m->m_mailer, "[TCP]") == 0)
{
#if DAEMON
register int i;
if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
{
syserr("null destination for %s mailer", m->m_mailer);
rcode = EX_CONFIG;
goto give_up;
}
# if NETUNIX
if (strcmp(pv[0], "FILE") == 0)
{
curhost = CurHostName = "localhost";
mux_path = pv[1];
}
else
# endif /* NETUNIX */
{
CurHostName = pv[1];
curhost = hostsignature(m, pv[1]);
}
if (curhost == NULL || curhost[0] == '\0')
{
syserr("null host signature for %s", pv[1]);
rcode = EX_CONFIG;
goto give_up;
}
if (!clever)
{
syserr("554 5.3.5 non-clever IPC");
rcode = EX_CONFIG;
goto give_up;
}
if (pv[2] != NULL
# if NETUNIX
&& mux_path == NULL
# endif /* NETUNIX */
)
{
port = htons((u_short)atoi(pv[2]));
if (port == 0)
{
# ifdef NO_GETSERVBYNAME
syserr("Invalid port number: %s", pv[2]);
# else /* NO_GETSERVBYNAME */
struct servent *sp = getservbyname(pv[2], "tcp");
if (sp == NULL)
syserr("Service %s unknown", pv[2]);
else
port = sp->s_port;
# endif /* NO_GETSERVBYNAME */
}
}
nummxhosts = parse_hostsignature(curhost, mxhosts, m);
tryhost:
while (hostnum < nummxhosts)
{
char sep = ':';
char *endp;
static char hostbuf[MAXNAME + 1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -