📄 parseaddr.c
字号:
** name -- the name to translate.
** m -- the mailer that we want to do rewriting relative
** to.
** flags -- fine tune operations.
** pstat -- pointer to status word.
** e -- the current envelope.
**
** Returns:
** the text string representing this address relative to
** the receiving mailer.
**
** Side Effects:
** none.
**
** Warnings:
** The text string returned is tucked away locally;
** copy it if you intend to save it.
*/
char *
remotename(name, m, flags, pstat, e)
char *name;
struct mailer *m;
int flags;
int *pstat;
register ENVELOPE *e;
{
register char **pvp;
char *fancy;
char *oldg = macvalue('g', e);
int rwset;
static char buf[MAXNAME + 1];
char lbuf[MAXNAME + 1];
char pvpbuf[PSBUFSIZE];
#if _FFR_ADDR_TYPE
char addrtype[4];
#endif /* _FFR_ADDR_TYPE */
if (tTd(12, 1))
dprintf("remotename(%s)\n", name);
/* don't do anything if we are tagging it as special */
if (bitset(RF_SENDERADDR, flags))
{
rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
: m->m_se_rwset;
#if _FFR_ADDR_TYPE
addrtype[2] = 's';
#endif /* _FFR_ADDR_TYPE */
}
else
{
rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
: m->m_re_rwset;
#if _FFR_ADDR_TYPE
addrtype[2] = 'r';
#endif /* _FFR_ADDR_TYPE */
}
if (rwset < 0)
return name;
#if _FFR_ADDR_TYPE
addrtype[1] = ' ';
addrtype[3] = '\0';
addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e';
define(macid("{addr_type}", NULL), addrtype, e);
#endif /* _FFR_ADDR_TYPE */
/*
** Do a heuristic crack of this name to extract any comment info.
** This will leave the name as a comment and a $g macro.
*/
if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
fancy = "\201g";
else
fancy = crackaddr(name);
/*
** Turn the name into canonical form.
** Normally this will be RFC 822 style, i.e., "user@domain".
** If this only resolves to "user", and the "C" flag is
** specified in the sending mailer, then the sender's
** domain will be appended.
*/
pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
if (pvp == NULL)
return name;
if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
{
/* append from domain to this address */
register char **pxp = pvp;
int l = MAXATOM; /* size of buffer for pvp */
/* see if there is an "@domain" in the current name */
while (*pxp != NULL && strcmp(*pxp, "@") != 0)
{
pxp++;
--l;
}
if (*pxp == NULL)
{
/* no.... append the "@domain" from the sender */
register char **qxq = e->e_fromdomain;
while ((*pxp++ = *qxq++) != NULL)
{
if (--l <= 0)
{
*--pxp = NULL;
usrerr("553 5.1.0 remotename: too many tokens");
*pstat = EX_UNAVAILABLE;
break;
}
}
if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
}
/*
** Do more specific rewriting.
** Rewrite using ruleset 1 or 2 depending on whether this is
** a sender address or not.
** Then run it through any receiving-mailer-specific rulesets.
*/
if (bitset(RF_SENDERADDR, flags))
{
if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
else
{
if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
if (rwset > 0)
{
if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
/*
** Do any final sanitation the address may require.
** This will normally be used to turn internal forms
** (e.g., user@host.LOCAL) into external form. This
** may be used as a default to the above rules.
*/
if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
/*
** Now restore the comment information we had at the beginning.
*/
cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
define('g', lbuf, e);
/* need to make sure route-addrs have <angle brackets> */
if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
expand("<\201g>", buf, sizeof buf, e);
else
expand(fancy, buf, sizeof buf, e);
define('g', oldg, e);
if (tTd(12, 1))
dprintf("remotename => `%s'\n", buf);
return buf;
}
/*
** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
**
** Parameters:
** a -- the address to map (but just the user name part).
** sendq -- the sendq in which to install any replacement
** addresses.
** aliaslevel -- the alias nesting depth.
** e -- the envelope.
**
** Returns:
** none.
*/
#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
Q_PINGFLAGS|QHASNOTIFY|\
QRELAYED|QEXPANDED|QDELIVERED|QDELAYED)
void
maplocaluser(a, sendq, aliaslevel, e)
register ADDRESS *a;
ADDRESS **sendq;
int aliaslevel;
ENVELOPE *e;
{
register char **pvp;
register ADDRESS *a1 = NULL;
auto char *delimptr;
char pvpbuf[PSBUFSIZE];
if (tTd(29, 1))
{
dprintf("maplocaluser: ");
printaddr(a, FALSE);
}
pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
if (pvp == NULL)
{
if (tTd(29, 9))
dprintf("maplocaluser: cannot prescan %s\n",
a->q_user);
return;
}
define('h', a->q_host, e);
define('u', a->q_user, e);
define('z', a->q_home, e);
#if _FFR_ADDR_TYPE
define(macid("{addr_type}", NULL), "e r", e);
#endif /* _FFR_ADDR_TYPE */
if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL)
{
if (tTd(29, 9))
dprintf("maplocaluser: rewrite tempfail\n");
a->q_state = QS_QUEUEUP;
a->q_status = "4.4.3";
return;
}
if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
{
if (tTd(29, 9))
dprintf("maplocaluser: doesn't resolve\n");
return;
}
/* if non-null, mailer destination specified -- has it changed? */
a1 = buildaddr(pvp, NULL, 0, e);
if (a1 == NULL || sameaddr(a, a1))
{
if (tTd(29, 9))
dprintf("maplocaluser: address unchanged\n");
if (a1 != NULL)
free(a1);
return;
}
/* make new address take on flags and print attributes of old */
a1->q_flags &= ~Q_COPYFLAGS;
a1->q_flags |= a->q_flags & Q_COPYFLAGS;
a1->q_paddr = newstr(a->q_paddr);
a1->q_orcpt = a->q_orcpt;
/* mark old address as dead; insert new address */
a->q_state = QS_REPLACED;
if (tTd(29, 5))
{
dprintf("maplocaluser: QS_REPLACED ");
printaddr(a, FALSE);
}
a1->q_alias = a;
allocaddr(a1, RF_COPYALL, newstr(a->q_paddr));
(void) recipient(a1, sendq, aliaslevel, e);
}
/*
** DEQUOTE_INIT -- initialize dequote map
**
** This is a no-op.
**
** Parameters:
** map -- the internal map structure.
** args -- arguments.
**
** Returns:
** TRUE.
*/
bool
dequote_init(map, args)
MAP *map;
char *args;
{
register char *p = args;
/* there is no check whether there is really an argument */
map->map_mflags |= MF_KEEPQUOTES;
for (;;)
{
while (isascii(*p) && isspace(*p))
p++;
if (*p != '-')
break;
switch (*++p)
{
case 'a':
map->map_app = ++p;
break;
case 'D':
map->map_mflags |= MF_DEFER;
break;
case 'S':
case 's':
map->map_spacesub = *++p;
break;
}
while (*p != '\0' && !(isascii(*p) && isspace(*p)))
p++;
if (*p != '\0')
*p = '\0';
}
if (map->map_app != NULL)
map->map_app = newstr(map->map_app);
return TRUE;
}
/*
** DEQUOTE_MAP -- unquote an address
**
** Parameters:
** map -- the internal map structure (ignored).
** name -- the name to dequote.
** av -- arguments (ignored).
** statp -- pointer to status out-parameter.
**
** Returns:
** NULL -- if there were no quotes, or if the resulting
** unquoted buffer would not be acceptable to prescan.
** else -- The dequoted buffer.
*/
/* ARGSUSED2 */
char *
dequote_map(map, name, av, statp)
MAP *map;
char *name;
char **av;
int *statp;
{
register char *p;
register char *q;
register char c;
int anglecnt = 0;
int cmntcnt = 0;
int quotecnt = 0;
int spacecnt = 0;
bool quotemode = FALSE;
bool bslashmode = FALSE;
char spacesub = map->map_spacesub;
for (p = q = name; (c = *p++) != '\0'; )
{
if (bslashmode)
{
bslashmode = FALSE;
*q++ = c;
continue;
}
if (c == ' ' && spacesub != '\0')
c = spacesub;
switch (c)
{
case '\\':
bslashmode = TRUE;
break;
case '(':
cmntcnt++;
break;
case ')':
if (cmntcnt-- <= 0)
return NULL;
break;
case ' ':
case '\t':
spacecnt++;
break;
}
if (cmntcnt > 0)
{
*q++ = c;
continue;
}
switch (c)
{
case '"':
quotemode = !quotemode;
quotecnt++;
continue;
case '<':
anglecnt++;
break;
case '>':
if (anglecnt-- <= 0)
return NULL;
break;
}
*q++ = c;
}
if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
quotemode || quotecnt <= 0 || spacecnt != 0)
return NULL;
*q++ = '\0';
return map_rewrite(map, name, strlen(name), NULL);
}
/*
** RSCHECK -- check string(s) for validity using rewriting sets
**
** Parameters:
** rwset -- the rewriting set to use.
** p1 -- the first string to check.
** p2 -- the second string to check -- may be null.
** e -- the current envelope.
** rmcomm -- remove comments?
** cnt -- count rejections (statistics)?
** logl -- logging level
**
** Returns:
** EX_OK -- if the rwset doesn't resolve to $#error
** else -- the failure status (message printed)
*/
int
rscheck(rwset, p1, p2, e, rmcomm, cnt, logl)
char *rwset;
char *p1;
char *p2;
ENVELOPE *e;
bool rmcomm, cnt;
int logl;
{
char *buf;
int bufsize;
int saveexitstat;
int rstat = EX_OK;
char **pvp;
int rsno;
bool discard = FALSE;
auto ADDRESS a1;
bool saveQuickAbort = QuickAbort;
bool saveSuprErrs = SuprErrs;
char buf0[MAXLINE];
char pvpbuf[PSBUFSIZE];
extern char MsgBuf[];
if (tTd(48, 2))
dprintf("rscheck(%s, %s, %s)\n", rwset, p1,
p2 == NULL ? "(NULL)" : p2);
rsno = strtorwset(rwset, NULL, ST_FIND);
if (rsno < 0)
return EX_OK;
if (p2 != NULL)
{
bufsize = strlen(p1) + strlen(p2) + 2;
if (bufsize > sizeof buf0)
buf = xalloc(bufsize);
else
{
buf = buf0;
bufsize = sizeof buf0;
}
(void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
}
else
{
bufsize = strlen(p1) + 1;
if (bufsize > sizeof buf0)
buf = xalloc(bufsize);
else
{
buf = buf0;
bufsize = sizeof buf0;
}
(void) snprintf(buf, bufsize, "%s", p1);
}
SuprErrs = TRUE;
QuickAbort = FALSE;
pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL,
rmcomm ? NULL : TokTypeNoC);
SuprErrs = saveSuprErrs;
if (pvp == NULL)
{
if (tTd(48, 2))
dprintf("rscheck: cannot prescan input\n");
/*
syserr("rscheck: cannot prescan input: \"%s\"",
shortenstring(buf, MAXSHORTSTR));
rstat = EX_DATAERR;
*/
goto finis;
}
MapOpenErr = FALSE;
(void) rewrite(pvp, rsno, 0, e);
if (MapOpenErr)
usrerrenh("4.3.0", "451 Temporary failure");
if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
strcmp(pvp[1], "discard") != 0))
{
goto finis;
}
if (strcmp(pvp[1], "discard") == 0)
{
if (tTd(48, 2))
dprintf("rscheck: discard mailer selected\n");
e->e_flags |= EF_DISCARD;
discard = TRUE;
}
else
{
int savelogusrerrs = LogUsrErrs;
static bool logged = FALSE;
/* got an error -- process it */
saveexitstat = ExitStat;
LogUsrErrs = FALSE;
(void) buildaddr(pvp, &a1, 0, e);
LogUsrErrs = savelogusrerrs;
rstat = ExitStat;
ExitStat = saveexitstat;
if (!logged)
{
if (cnt)
markstats(e, &a1, TRUE);
logged = TRUE;
}
}
if (LogLevel >= logl)
{
char *relay;
char *p;
char lbuf[MAXLINE];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -