/*
- * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1983, 1995 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
- * %sccs.include.redist.c%
+ * 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 lint
-static char sccsid[] = "@(#)parseaddr.c 8.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)parseaddr.c 8.73 (Berkeley) 6/19/95";
#endif /* not lint */
-#include "sendmail.h"
-
-#ifdef CC_WONT_PROMOTE
-static int toktype __P((char));
-#else /* !CC_WONT_PROMOTE */
-static int toktype __P((int)); /* char -> int */
-#endif /* CC_WONT_PROMOTE */
-static void _rewrite __P((char **, int));
-static void callsubr __P((char **));
-static ADDRESS * buildaddr __P((char **, ADDRESS *));
-static void uurelativize __P((const char *, const char *, char **));
-
-char *DelimChar; /* set to point to the delimiter */
+# include "sendmail.h"
/*
** PARSEADDR -- Parse an address
** addr -- the address to parse.
** a -- a pointer to the address descriptor buffer.
** If NULL, a header will be created.
-** copyf -- determines what shall be copied:
-** -1 -- don't copy anything. The printname
-** (q_paddr) is just addr, and the
-** user & host are allocated internally
-** to parse.
-** 0 -- copy out the parsed user & host, but
-** don't copy the printname.
-** +1 -- copy everything.
+** flags -- describe detail for parsing. See RF_ definitions
+** in sendmail.h.
** delim -- the character to terminate the address, passed
** to prescan.
** delimptr -- if non-NULL, set to the location of the
# define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
ADDRESS *
-parseaddr(addr, a, copyf, delim, delimptr, e)
+parseaddr(addr, a, flags, delim, delimptr, e)
char *addr;
register ADDRESS *a;
- int copyf;
+ int flags;
int delim;
char **delimptr;
register ENVELOPE *e;
auto char *delimptrbuf;
bool queueup;
char pvpbuf[PSBUFSIZE];
+ extern ADDRESS *buildaddr();
+ extern bool invalidaddr();
+ extern void allocaddr __P((ADDRESS *, int, char *));
/*
** Initialize and prescan address.
if (tTd(20, 1))
printf("\n--parseaddr(%s)\n", addr);
- if (invalidaddr(addr))
+ if (delimptr == NULL)
+ delimptr = &delimptrbuf;
+
+ pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
+ if (pvp == NULL)
{
if (tTd(20, 1))
- printf("parseaddr-->bad address\n");
- return NULL;
+ printf("parseaddr-->NULL\n");
+ return (NULL);
}
+ if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
{
- extern char *DelimChar; /* parseaddr.c */
- char savec;
- bool invalid;
- extern char *finddelim();
- extern bool invalidaddr();
-
- DelimChar = finddelim(addr, delim);
- savec = *DelimChar;
- *DelimChar = '\0';
- invalid = invalidaddr(addr);
- *DelimChar = savec;
- if (invalid)
- return (NULL);
+ if (tTd(20, 1))
+ printf("parseaddr-->bad address\n");
+ return NULL;
}
- if (delimptr == NULL)
- delimptr = &delimptrbuf;
+ /*
+ ** Save addr if we are going to have to.
+ **
+ ** We have to do this early because there is a chance that
+ ** the map lookups in the rewriting rules could clobber
+ ** static memory somewhere.
+ */
- pvp = prescan(addr, delim, pvpbuf, delimptr);
- if (pvp == NULL)
+ if (bitset(RF_COPYPADDR, flags) && addr != NULL)
{
- if (tTd(20, 1))
- printf("parseaddr-->NULL\n");
- return (NULL);
+ char savec = **delimptr;
+
+ if (savec != '\0')
+ **delimptr = '\0';
+ e->e_to = addr = newstr(addr);
+ if (savec != '\0')
+ **delimptr = savec;
}
/*
*/
queueup = FALSE;
- if (rewrite(pvp, 3, e) == EX_TEMPFAIL)
+ if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
queueup = TRUE;
- if (rewrite(pvp, 0, e) == EX_TEMPFAIL)
+ if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
queueup = TRUE;
- /*
- ** See if we resolved to a real mailer.
- */
-
- if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
- {
- setstat(EX_USAGE);
- syserr("554 cannot resolve name");
- return (NULL);
- }
/*
** Build canonical address from pvp.
*/
- a = buildaddr(pvp, a, e);
- if (a == NULL)
- return (NULL);
+ a = buildaddr(pvp, a, flags, e);
/*
** Make local copies of the host & user and then
** transport them out.
*/
- allocaddr(a, copyf, addr, *delimptr);
+ allocaddr(a, flags, addr);
+ if (bitset(QBADADDR, a->q_flags))
+ return a;
/*
** If there was a parsing failure, mark it for queueing.
if (e->e_message == NULL)
e->e_message = newstr(msg);
a->q_flags |= QQUEUEUP;
+ a->q_status = "4.4.3";
}
/*
*/
bool
-invalidaddr(addr)
+invalidaddr(addr, delimptr)
register char *addr;
+ char *delimptr;
{
+ char savedelim = '\0';
+
+ if (delimptr != NULL)
+ {
+ savedelim = *delimptr;
+ if (savedelim != '\0')
+ *delimptr = '\0';
+ }
+#if 0
+ /* for testing.... */
+ if (strcmp(addr, "INvalidADDR") == 0)
+ {
+ usrerr("553 INvalid ADDRess");
+ goto addrfailure;
+ }
+#endif
for (; *addr != '\0'; addr++)
{
- if ((*addr & 0340) != 0200)
- continue;
- setstat(EX_USAGE);
- usrerr("553 Address contained invalid control characters");
- return TRUE;
+ if ((*addr & 0340) == 0200)
+ break;
}
- return FALSE;
+ if (*addr == '\0')
+ {
+ if (delimptr != NULL && savedelim != '\0')
+ *delimptr = savedelim;
+ return FALSE;
+ }
+ setstat(EX_USAGE);
+ usrerr("553 Address contained invalid control characters");
+ addrfailure:
+ if (delimptr != NULL && savedelim != '\0')
+ *delimptr = savedelim;
+ return TRUE;
}
\f/*
** ALLOCADDR -- do local allocations of address on demand.
**
** Parameters:
** a -- the address to reallocate.
-** copyf -- the copy flag (see parseaddr for description).
+** flags -- the copy flag (see RF_ definitions in sendmail.h
+** for a description).
** paddr -- the printname of the address.
-** delimptr -- a pointer to the address delimiter. Must be set.
**
** Returns:
** none.
** Copies portions of a into local buffers as requested.
*/
-allocaddr(a, copyf, paddr, delimptr)
+void
+allocaddr(a, flags, paddr)
register ADDRESS *a;
- int copyf;
+ int flags;
char *paddr;
- char *delimptr;
{
if (tTd(24, 4))
- printf("allocaddr(copyf=%d, paddr=%s)\n", copyf, paddr);
-
- if (copyf > 0 && paddr != NULL)
- {
- char savec = *delimptr;
+ printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
- if (savec != '\0')
- *delimptr = '\0';
- a->q_paddr = newstr(paddr);
- if (savec != '\0')
- *delimptr = savec;
- }
- else
- a->q_paddr = paddr;
+ a->q_paddr = paddr;
if (a->q_user == NULL)
a->q_user = "";
if (a->q_host == NULL)
a->q_host = "";
- if (copyf >= 0)
+ if (bitset(RF_COPYPARSE, flags))
{
a->q_host = newstr(a->q_host);
if (a->q_user != a->q_paddr)
a->q_paddr = a->q_user;
}
\f/*
-** INVALIDADDR -- check an address string for invalid control characters.
-**
-** Parameters:
-** addr -- address string to be checked.
-**
-** Returns:
-** TRUE if address string could cause problems, FALSE o/w.
-**
-** Side Effects:
-** ExitStat may be changed and an error message generated.
-*/
-
-bool
-invalidaddr(addr)
- const char *addr;
-{
- register const char *cp;
-
- /* make sure error messages don't have garbage on them */
- errno = 0;
-
- /*
- ** Sendmail reserves characters 020 - 036 for rewriting rules
- ** which can cause havoc (e.g. infinite rewriting loops) if
- ** one shows up at the wrong time. If any of these characters
- ** appear in an address, the address is deemed "invalid" and
- ** an error message is generated.
- */
-
- for (cp = addr; *cp; cp++)
- if ((*cp >= MATCHZANY && *cp <= HOSTEND) || *cp == '\001')
- {
- setstat(EX_USAGE);
- usrerr("address contained invalid control char(s)");
- return (TRUE);
- }
- return (FALSE);
-}
-\f/*
** PRESCAN -- Prescan name and make it canonical
**
** Scans a name and turns it into a set of tokens. This process
** If '\t' then we are reading the .cf file.
** pvpbuf -- place to put the saved text -- note that
** the pointers are static.
+** pvpbsize -- size of pvpbuf.
** delimptr -- if non-NULL, set to the location of the
** terminating delimiter.
+** toktab -- if set, a token table to use for parsing.
+** If NULL, use the default table.
**
** Returns:
** A pointer to a vector of tokens.
# define QST 2 /* in quoted string */
# define SPC 3 /* chewing up spaces */
# define ONE 4 /* pick up one character */
+# define ILL 5 /* illegal character */
-# define NSTATES 5 /* number of states */
+# define NSTATES 6 /* number of states */
# define TYPE 017 /* mask to select state type */
/* meta bits for table */
static short StateTab[NSTATES][NSTATES] =
{
- /* oldst chtype> OPR ATM QST SPC ONE */
- /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B,
- /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B,
- /*QST*/ QST, QST, OPR, QST, QST,
- /*SPC*/ OPR, ATM, QST, SPC|M, ONE,
- /*ONE*/ OPR, OPR, OPR, OPR, OPR,
+ /* oldst chtype> OPR ATM QST SPC ONE ILL */
+ /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB,
+ /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB,
+ /*QST*/ QST, QST, OPR, QST, QST, QST,
+ /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ILL|MB,
+ /*ONE*/ OPR, OPR, OPR, OPR, OPR, ILL|MB,
+ /*ILL*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M,
+};
+
+/* token type table -- it gets modified with $o characters */
+static u_char TokTypeTab[256] =
+{
+ /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
+ /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* sp ! " # $ % & ' ( ) * + , - . / */
+ SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* @ A B C D E F G H I J K L M N O */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* P Q R S T U V W X Y Z [ \ ] ^ _ */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* ` a b c d e f g h i j k l m n o */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* p q r s t u v w x y z { | } ~ del */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+
+ /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
+ OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
+ /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
+ OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
+ /* sp ! " # $ % & ' ( ) * + , - . / */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* @ A B C D E F G H I J K L M N O */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* P Q R S T U V W X Y Z [ \ ] ^ _ */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* ` a b c d e f g h i j k l m n o */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* p q r s t u v w x y z { | } ~ del */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
};
+/* token type table for MIME parsing */
+u_char MimeTokenTab[256] =
+{
+ /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
+ /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* sp ! " # $ % & ' ( ) * + , - . / */
+ SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
+ /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
+ /* @ A B C D E F G H I J K L M N O */
+ OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* P Q R S T U V W X Y Z [ \ ] ^ _ */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
+ /* ` a b c d e f g h i j k l m n o */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+ /* p q r s t u v w x y z { | } ~ del */
+ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
+
+ /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* sp ! " # $ % & ' ( ) * + , - . / */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* @ A B C D E F G H I J K L M N O */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* P Q R S T U V W X Y Z [ \ ] ^ _ */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* ` a b c d e f g h i j k l m n o */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+ /* p q r s t u v w x y z { | } ~ del */
+ ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
+};
+
+
# define NOCHAR -1 /* signal nothing in lookahead token */
char **
-prescan(addr, delim, pvpbuf, delimptr)
+prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
char *addr;
- char delim;
+ int delim;
char pvpbuf[];
char **delimptr;
+ u_char *toktab;
{
register char *p;
register char *q;
int newstate;
char *saveto = CurEnv->e_to;
static char *av[MAXATOM+1];
+ static char firsttime = TRUE;
+ extern int errno;
+
+ if (firsttime)
+ {
+ /* initialize the token type table */
+ char obuf[50];
+
+ firsttime = FALSE;
+ expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv);
+ strcat(obuf, DELIMCHARS);
+ for (p = obuf; *p != '\0'; p++)
+ {
+ if (TokTypeTab[*p & 0xff] == ATM)
+ TokTypeTab[*p & 0xff] = OPR;
+ }
+ }
+ if (toktab == NULL)
+ toktab = TokTypeTab;
/* make sure error messages don't have garbage on them */
errno = 0;
if (c != NOCHAR && !bslashmode)
{
/* see if there is room */
- if (q >= &pvpbuf[PSBUFSIZE - 5])
+ if (q >= &pvpbuf[pvpbsize - 5])
{
usrerr("553 Address too long");
+ if (strlen(addr) > MAXNAME)
+ addr[MAXNAME] = '\0';
+ returnnull:
if (delimptr != NULL)
*delimptr = p;
CurEnv->e_to = saveto;
/* diagnose and patch up bad syntax */
if (state == QST)
{
- usrerr("553 Unbalanced '\"'");
+ usrerr("653 Unbalanced '\"'");
c = '"';
}
else if (cmntcnt > 0)
{
- usrerr("553 Unbalanced '('");
+ usrerr("653 Unbalanced '('");
c = ')';
}
else if (anglecnt > 0)
{
c = '>';
- usrerr("553 Unbalanced '<'");
+ usrerr("653 Unbalanced '<'");
}
else
break;
{
bslashmode = TRUE;
}
- if (state == QST)
+ else if (state == QST)
{
/* do nothing, just avoid next clauses */
}
{
if (cmntcnt <= 0)
{
- usrerr("553 Unbalanced ')'");
- if (delimptr != NULL)
- *delimptr = p;
- CurEnv->e_to = saveto;
- return (NULL);
+ usrerr("653 Unbalanced ')'");
+ c = NOCHAR;
}
else
cmntcnt--;
{
if (anglecnt <= 0)
{
- usrerr("553 Unbalanced '>'");
- if (delimptr != NULL)
- *delimptr = p;
- CurEnv->e_to = saveto;
- return (NULL);
+ usrerr("653 Unbalanced '>'");
+ c = NOCHAR;
}
- anglecnt--;
+ else
+ anglecnt--;
}
else if (delim == ' ' && isascii(c) && isspace(c))
c = ' ';
- else if (c == ':' && !CurEnv->e_oldstyle)
- {
- /* consume characters until a semicolon */
- while (*p != '\0' && *p != ';')
- p++;
- if (*p == '\0')
- usrerr("Unbalanced ':...;' group spec");
- else
- p++;
- c = ' ';
- }
-
- else if (c == ';') /* semicolons are not tokens */
- c = NOCHAR;
if (c == NOCHAR)
continue;
if (c == delim && anglecnt <= 0 && state != QST)
break;
- newstate = StateTab[state][toktype(c)];
+ newstate = StateTab[state][toktab[c & 0xff]];
if (tTd(22, 101))
printf("ns=%02o\n", newstate);
state = newstate & TYPE;
+ if (state == ILL)
+ {
+ if (isascii(c) && isprint(c))
+ usrerr("653 Illegal character %c", c);
+ else
+ usrerr("653 Illegal character 0x%02x", c);
+ }
if (bitset(M, newstate))
c = NOCHAR;
if (bitset(B, newstate))
if (avp >= &av[MAXATOM])
{
syserr("553 prescan: too many tokens");
- if (delimptr != NULL)
- *delimptr = p;
- CurEnv->e_to = saveto;
- return (NULL);
+ goto returnnull;
+ }
+ if (q - tok > MAXNAME)
+ {
+ syserr("553 prescan: token too long");
+ goto returnnull;
}
*avp++ = tok;
}
}
CurEnv->e_to = saveto;
if (av[0] == NULL)
- return (NULL);
- return (av);
-}
-\f/*
-** TOKTYPE -- return token type
-**
-** Parameters:
-** c -- the character in question.
-**
-** Returns:
-** Its type.
-**
-** Side Effects:
-** none.
-*/
-
-static int
-toktype(c)
- register int c;
-{
- static char buf[50];
- static bool firstime = TRUE;
-
- if (firstime)
{
- firstime = FALSE;
- expand("\201o", buf, &buf[sizeof buf - 1], CurEnv);
- (void) strcat(buf, DELIMCHARS);
+ if (tTd(22, 1))
+ printf("prescan: null leading token\n");
+ return (NULL);
}
- c &= 0377;
- if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
- return (ONE);
- if (c == MACRODEXPAND)
- return (ONE);
-#ifdef MACVALUE
- if (c == MACVALUE)
- return (ONE);
-#endif /* MACVALUE */
- if (c == '"')
- return (QST);
- if ((c & 0340) == 0200)
- return (OPR);
- if (!isascii(c))
- return (ATM);
- if (isspace(c) || c == ')')
- return (SPC);
- if (strchr(buf, c) != NULL)
- return (OPR);
- return (ATM);
+ return (av);
}
\f/*
** REWRITE -- apply rewrite rules to token vector.
** Parameters:
** pvp -- pointer to token vector.
** ruleset -- the ruleset to use for rewriting.
+** reclevel -- recursion level (to catch loops).
** e -- the current envelope.
**
** Returns:
** pvp is modified.
*/
-# define OP_NONZLEN 00001
-# define OP_VARLEN 00002
-# define OP_CLASS 00004
-# define OP_EXACT 00010
-
struct match
{
char **first; /* first token matched */
char **last; /* last token matched */
char **pattern; /* pointer to pattern */
- char **source; /* left hand source operand */
- char flags; /* attributes of this operator */
};
# define MAXMATCH 9 /* max params per rewrite */
-# define MAX_CONTROL ' '
-static char control_opts[MAX_CONTROL];
+# ifndef MAXRULERECURSION
+# define MAXRULERECURSION 50 /* max recursion depth */
+# endif
-int
-static char control_init_data[] = {
- MATCHZANY, OP_VARLEN,
- MATCHONE, OP_NONZLEN,
- MATCHANY, OP_VARLEN|OP_NONZLEN,
-#ifdef MACVALUE
- MACVALUE, OP_EXACT,
-#endif /* MACVALUE */
- MATCHNCLASS, OP_NONZLEN,
- MATCHCLASS, OP_NONZLEN|OP_VARLEN|OP_CLASS,
-};
-
-static int nrw;
-void
-rewrite(pvp, ruleset, e)
+int
+rewrite(pvp, ruleset, reclevel, e)
char **pvp;
int ruleset;
+ int reclevel;
register ENVELOPE *e;
-{
- nrw = 0;
- _rewrite(pvp, ruleset);
-}
-
-static void
-_rewrite(pvp, ruleset)
- char **pvp;
- int ruleset;
{
register char *ap; /* address pointer */
register char *rp; /* rewrite pointer */
register struct rewrite *rwr; /* pointer to current rewrite rule */
int ruleno; /* current rule number */
int rstat = EX_OK; /* return status */
- int subr; /* subroutine number if >= 0 */
- bool dolookup; /* do host aliasing */
+ int loopcount;
+ struct match mlist[MAXMATCH]; /* stores match on LHS */
char *npvp[MAXATOM+1]; /* temporary space for rebuild */
- char tokbuf[MAXNAME+1]; /* for concatenated class tokens */
- int nloops, nmatches = 0; /* for looping rule checks */
- struct rewrite *prev_rwr; /* pointer to previous rewrite rule */
- struct match mlist[MAXMATCH+1]; /* stores match on LHS */
- struct match *old_mlp; /* to save our place */
- bool extend_match; /* extend existing match during backup */
-
- if (OpMode == MD_TEST || tTd(21, 2))
+
+ if (OpMode == MD_TEST || tTd(21, 1))
{
printf("rewrite: ruleset %2d input:", ruleset);
- printcav(pvp);
+ printav(pvp);
}
if (ruleset < 0 || ruleset >= MAXRWSETS)
{
syserr("554 rewrite: illegal ruleset number %d", ruleset);
return EX_CONFIG;
}
- if (pvp == NULL)
- return EX_USAGE;
-
- if (++nrw > 100)
+ if (reclevel++ > MAXRULERECURSION)
{
- char buf[MAXLINE];
-
- buf[0] = buf[MAXLINE-1] = 0;
- while (*pvp)
- (void) strncat(buf, *pvp++, sizeof buf);
- syserr("address causes rewrite loop: <%s>", buf);
- return;
+ syserr("rewrite: infinite recursion, ruleset %d", ruleset);
+ return EX_CONFIG;
}
-
- /* Be sure to recognize first rule as new */
- prev_rwr = NULL;
+ if (pvp == NULL)
+ return EX_USAGE;
/*
- ** Run through the list of rewrite rules, applying any that match.
+ ** Run through the list of rewrite rules, applying
+ ** any that match.
*/
ruleno = 1;
+ loopcount = 0;
for (rwr = RewriteRules[ruleset]; rwr != NULL; )
{
- int loopcount = 0;
-
if (tTd(21, 12))
{
printf("-----trying rule:");
- printcav(rwr->r_lhs);
- }
-
- /*
- ** Set up the match list. This is done once for each
- ** rule. If a rule is used repeatedly, the list need not
- ** be set up the next time.
- */
-
- if (rwr != prev_rwr)
- {
- prev_rwr = rwr;
- for (rvp = rwr->r_lhs, mlp = mlist;
- *rvp && (mlp < &mlist[MAXMATCH]); rvp++)
- {
- mlp->flags = ((unsigned char) **rvp >= MAX_CONTROL) ?
- 0 : control_opts[**rvp] ;
- if (mlp->flags)
- {
- mlp->source = rvp;
- mlp++;
- }
- }
- if (*rvp)
- {
- syserr("Too many variables on LHS in ruleset %d", ruleset);
- return;
- }
- mlp->source = rvp;
-
- /* Make sure end marker is initialized */
- mlp->flags = 0;
+ printav(rwr->r_lhs);
}
/* try to match on this rule */
mlp = mlist;
-
rvp = rwr->r_lhs;
avp = pvp;
- nloops = 0;
- extend_match = FALSE;
-
if (++loopcount > 100)
{
- if (nloops++ > 400)
- {
- syserr("Looping on ruleset %d, rule %d",
- ruleset, rwr-RewriteRules[ruleset]);
- mlp = mlist - 1; /* force rule failure */
- break;
- }
syserr("554 Infinite loop in ruleset %d, rule %d",
ruleset, ruleno);
if (tTd(21, 1))
while ((ap = *avp) != NULL || *rvp != NULL)
{
rp = *rvp;
-
if (tTd(21, 35))
{
printf("ADVANCE rp=");
xputs(ap);
printf("\n");
}
-
- if (extend_match)
- extend_match = FALSE;
- else
- {
- mlp->first = avp;
- mlp->last = mlp->flags == 0 || (mlp->flags & OP_NONZLEN) ?
- avp + 1 : avp;
- }
-
if (rp == NULL)
+ {
/* end-of-pattern before end-of-address */
goto backup;
-
- /* Premature end of address */
- if (ap == NULL && avp != mlp->last)
- goto backup;
-
- /*
- ** Simplest case - exact token comparison between
- ** pattern and address. Such a match is not saved
- ** in mlp.
- */
-
- if (rvp < mlp->source)
+ }
+ if (ap == NULL && (*rp & 0377) != MATCHZANY &&
+ (*rp & 0377) != MATCHZERO)
{
- if (ap == NULL || strcasecmp(ap, rp))
- goto backup;
- rvp++;
- avp++;
- continue;
+ /* end-of-input with patterns left */
+ goto backup;
}
-#ifdef MACVALUE
- /*
- ** This is special case handled. The match is exact,
- ** but might span zero or more address tokens. The
- ** result is saved in mlp.
- */
-
- if (*rp == MACVALUE)
+ switch (*rp & 0377)
{
- int len;
- rp = macvalue(rp[1], CurEnv);
+ char buf[MAXLINE];
- if (rp)
- while (*rp)
+ case MATCHCLASS:
+ /* match any phrase in a class */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ extendclass:
+ ap = *avp;
+ if (ap == NULL)
+ goto backup;
+ mlp->last = avp++;
+ cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
+ if (!wordinclass(buf, rp[1]))
+ {
+ if (tTd(21, 36))
{
- if (*avp == NULL || strncasecmp(rp,*avp,len = strlen(*avp)))
- goto backup;
- rp += len;
- avp++;
+ printf("EXTEND rp=");
+ xputs(rp);
+ printf(", ap=");
+ xputs(ap);
+ printf("\n");
}
- mlp->last = avp;
- rvp++;
+ goto extendclass;
+ }
+ if (tTd(21, 36))
+ printf("CLMATCH\n");
mlp++;
- continue;
- }
-#endif /* MACVALUE */
+ break;
- /*
- ** All other matches are saved in mlp. Initially
- ** assume they match at the shortest possible length
- ** for this pattern. Variable patterns will be
- ** extended later as needed.
- */
+ case MATCHNCLASS:
+ /* match any token not in a class */
+ if (wordinclass(ap, rp[1]))
+ goto backup;
- /* Fixed length first */
- if (!(mlp->flags & OP_VARLEN))
- {
- switch (*rp)
- {
- break;
- }
+ /* fall through */
- avp = mlp->last;
- rvp++;
+ case MATCHONE:
+ case MATCHANY:
+ /* match exactly one token */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ mlp->last = avp++;
+ mlp++;
+ break;
+
+ case MATCHZANY:
+ /* match zero or more tokens */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ mlp->last = avp - 1;
mlp++;
break;
case MATCHZERO:
/* match zero tokens */
- continue;
- }
+ break;
case MACRODEXPAND:
/*
/* match */
break;
- /*
- ** We now have a variable length item. It could
- ** be $+ or $* in which case no special checking
- ** is needed. But a class match such as $=x must
- ** be verified.
- **
- ** As a speedup, if a variable length item is
- ** followed by a plain character token, we initially
- ** extend the match to the first such token we find.
- ** If the required character token cannot be found,
- ** we fail the match at this point.
- */
-
- avp = mlp->last;
-
- /* If next token is char token */
- if (&rvp[1] < mlp[1].source)
- {
- while (*avp && strcasecmp(*avp, rvp[1]))
- avp++;
-
- /*
- ** If we can't find the proper ending token,
- ** leave avp point to NULL. This indicates
- ** we have run out of address tokens. It is
- ** pointless to advance the beginning of this
- ** match and retry.
- */
-
- if (*avp == NULL)
+ default:
+ /* must have exact match */
+ if (strcasecmp(rp, ap))
goto backup;
- mlp->last = avp;
- }
- else if (rvp[1] == NULL)
- /* next token is end of address */
- {
- while (*avp)
- avp++;
- mlp->last = avp;
- }
-
- if (mlp->flags & OP_CLASS)
- {
- register char *cp = tokbuf;
-
- avp = mlp->first;
- strcpy(cp, *avp);
avp++;
- for (;;)
- {
- while (avp < mlp->last)
- {
- while (*cp)
- cp++;
- strcpy(cp, *avp);
- avp++;
- }
- switch (*rp)
- {
- register STAB *s;
-
- case MATCHCLASS:
- s = stab(tokbuf, ST_CLASS, ST_FIND);
- if (s != NULL && bitnset(rp[1], s->s_class))
- goto have_match;
- break;
- }
-
- /*
- ** Class match initially failed.
- ** Extend the tentative match.
- ** Again, if followed by a character
- ** token, extend all the way to that
- ** token before checking.
- */
-
- if (*avp)
- {
- (mlp->last)++;
- if (&rvp[1] < mlp[1].source)
- {
- while (*(mlp->last) && strcasecmp(*(mlp->last), rvp[1]))
- (mlp->last)++;
- if (*(mlp->last) == NULL)
- avp = mlp->last;
- }
- }
- if (*avp == NULL)
- {
- /*
- ** We could not find the
- ** ending token. But we had
- ** found ending tokens before.
- ** A match is still plausible
- ** if the start of the
- ** tentative match is advanced.
- ** Hence we must not leave avp
- ** pointing to NULL.
- */
- avp = mlp->first;
- goto backup;
- }
- }
+ break;
}
- have_match:
+ /* successful match on this token */
rvp++;
- mlp++;
continue;
-backup:
- /* We failed to match. mlp marks point of failure */
+ backup:
+ /* match failed -- back up */
+ while (--mlp >= mlist)
+ {
+ rvp = mlp->pattern;
+ rp = *rvp;
+ avp = mlp->last + 1;
+ ap = *avp;
- /*
- ** There is a special case when we have exhausted
- ** the address, but have not exhausted the pattern.
- ** Under normal circumstances we could consider the
- ** failure permanent, since extending the number of
- ** address tokens matched by a '$+' or a '$*' will
- ** only worsen the situation.
- **
- ** There is an exception, however. It is possible
- ** that we have matched a class token, say '$=x',
- ** with three or more tokens. Extending a '$+' say,
- ** which precedes the '$=x' will move the beginning
- ** of the '$=x' match to the right, but it might match
- ** a smaller number of tokens then, possibly
- ** correcting the mismatch.
- **
- ** Thus in this case we initially back up to the
- ** $=x which matches three or more tokens.
- */
+ if (tTd(21, 36))
+ {
+ printf("BACKUP rp=");
+ xputs(rp);
+ printf(", ap=");
+ xputs(ap);
+ printf("\n");
+ }
- if (*avp == NULL)
- {
- rvp = mlp->pattern;
- while (--mlp > mlist)
+ if (ap == NULL)
{
- if ((mlp->flags & OP_CLASS) &&
- mlp->last > 2 + mlp->first)
- break;
+ /* run off the end -- back up again */
+ continue;
+ }
+ if ((*rp & 0377) == MATCHANY ||
+ (*rp & 0377) == MATCHZANY)
+ {
+ /* extend binding and continue */
+ mlp->last = avp++;
+ rvp++;
+ mlp++;
+ break;
+ }
+ if ((*rp & 0377) == MATCHCLASS)
+ {
+ /* extend binding and try again */
+ mlp->last = avp;
+ goto extendclass;
}
}
- /*
- ** Now backup till we find a match with a pattern
- ** whose length is extendable, and extend that.
- */
-
- mlp--;
- while (mlp >= mlist && !(mlp->flags & OP_VARLEN))
- mlp--;
-
- /* Total failure to match */
if (mlp < mlist)
- break;
-
- avp = ++(mlp->last);
- rvp = mlp->source;
-
- /*
- ** We have found a backup point. Normally we would
- ** increase the matched amount by one token, and
- ** continue from the next item in the pattern. But
- ** there are two special cases. If this is a
- ** class-type match (OP_CLASS), we must test the
- ** validity of the extended match. If this pattern
- ** item is directly followed by a character token, it
- ** is worth going back and locating the next such
- ** character token before we continue on.
- */
- if ((mlp->flags & OP_CLASS) || (&rvp[1] < mlp[1].source))
- {
- avp = mlp->first;
- extend_match = TRUE;
- }
- else
{
- mlp++;
- rvp++;
+ /* total failure to match */
+ break;
}
}
/*
- ** See if we successfully matched.
+ ** See if we successfully matched
*/
- if (mlp < mlist)
+ if (mlp < mlist || *rvp != NULL)
{
if (tTd(21, 10))
printf("----- rule fails\n");
rwr = rwr->r_next;
ruleno++;
- nmatches = 0;
- continue;
- }
-
- if (nmatches++ > 200)
- {
- syserr("Loop in ruleset %d, rule %d (too many matches)",
- ruleset, rwr - RewriteRules[ruleset]);
- rwr = rwr->r_next;
- nmatches = 0;
+ loopcount = 0;
continue;
}
if (tTd(21, 12))
{
printf("-----rule matches:");
- printcav(rvp);
+ printav(rvp);
}
rp = *rvp;
rvp++;
rwr = rwr->r_next;
ruleno++;
- nmatches = 0;
+ loopcount = 0;
}
else if ((*rp & 0377) == CANONHOST)
{
rwr = NULL;
/* substitute */
- dolookup = FALSE;
for (avp = npvp; *rvp != NULL; rvp++)
{
register struct match *m;
register char **pp;
rp = *rvp;
-
- /* check to see if we should do a lookup */
- if (*rp == MATCHLOOKUP)
- dolookup = TRUE;
-
- /* see if there is substitution here */
- if (*rp == MATCHREPL && rp[1] >= '1' && rp[1] <= '9')
+ if ((*rp & 0377) == MATCHREPL)
{
/* substitute from LHS */
m = &mlist[rp[1] - '1'];
if (m < mlist || m >= mlp)
{
- toolong:
- syserr("rewrite: ruleset %d: replacement #%c out of bounds",
+ syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
ruleset, rp[1]);
return EX_CONFIG;
}
{
printf("$%c:", rp[1]);
pp = m->first;
- while (pp < m->last)
+ while (pp <= m->last)
{
printf(" %x=\"", *pp);
(void) fflush(stdout);
printf("\n");
}
pp = m->first;
- while (pp < m->last)
+ while (pp <= m->last)
{
if (avp >= &npvp[MAXATOM])
- goto toolong;
+ {
+ syserr("554 rewrite: expansion too long");
+ return EX_DATAERR;
+ }
*avp++ = *pp++;
}
}
{
/* vanilla replacement */
if (avp >= &npvp[MAXATOM])
- goto toolong;
-#ifdef MACVALUE
- if (*rp == MACVALUE)
{
- char *p = macvalue(rp[1], CurEnv);
-
- if (tTd(21, 2))
- printf("expanding runtime macro '%c' to \"%s\"\n",
- rp[1], p ? p : "(null)");
- if (p)
- *avp++ = p;
+ toolong:
+ syserr("554 rewrite: expansion too long");
+ return EX_DATAERR;
}
- else
-#endif /* MACVALUE */
+ if ((*rp & 0377) != MACRODEXPAND)
*avp++ = rp;
+ else
+ {
+ *avp = macvalue(rp[1], e);
+ if (tTd(21, 2))
+ printf("rewrite: RHS $&%c => \"%s\"\n",
+ rp[1],
+ *avp == NULL ? "(NULL)" : *avp);
+ if (*avp != NULL)
+ avp++;
+ }
}
}
*avp++ = NULL;
for (rvp = npvp; *rvp != NULL; rvp++)
{
- char **hbrvp, **ubrvp;
+ char **hbrvp;
char **xpvp;
int trsize;
char *replac;
char **key_rvp;
char **arg_rvp;
char **default_rvp;
- char hbuf[MAXNAME + 1], ubuf[MAXNAME + 1];
+ char buf[MAXNAME + 1];
char *pvpb1[MAXATOM + 1];
char *argvect[10];
char pvpbuf[PSBUFSIZE];
- bool match, defaultpart;
- char begintype;
- char db = '\0';
+ char *nullpvp[1];
if ((**rvp & 0377) != HOSTBEGIN &&
(**rvp & 0377) != LOOKUPBEGIN)
** This could be optimized fairly easily.
*/
- begintype = **rvp;
hbrvp = rvp;
- ubrvp = NULL;
if ((**rvp & 0377) == HOSTBEGIN)
{
endtoken = HOSTEND;
trsize = (int) (avp - rvp + 1) * sizeof *rvp;
bcopy((char *) rvp, (char *) pvpb1, trsize);
- /* append it to the token list */
- for (avp = hbrvp; *xpvp != NULL; xpvp++)
+ /* look it up */
+ cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
+ argvect[0] = buf;
+ if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
+ {
+ auto int stat = EX_OK;
+
+ if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags))
+ stripquotes(buf);
+
+ /* XXX should try to auto-open the map here */
+
+ if (tTd(60, 1))
+ printf("map_lookup(%s, %s) => ",
+ mapname, buf);
+ replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
+ buf, argvect, &stat);
+ if (tTd(60, 1))
+ printf("%s (%d)\n",
+ replac ? replac : "NOT FOUND",
+ stat);
+
+ /* should recover if stat == EX_TEMPFAIL */
+ if (stat == EX_TEMPFAIL)
{
- *avp++ = newstr(*xpvp);
- if (avp >= &npvp[MAXATOM])
- goto toolong;
+ rstat = EX_TEMPFAIL;
+ if (tTd(60, 1))
+ printf("map_lookup(%s, %s) failed (stat = %d)\n",
+ mapname, buf, stat);
+ if (e->e_message == NULL)
+ {
+ char mbuf[300];
+
+ sprintf(mbuf, "map %s: lookup (%s) failed",
+ mapname, buf);
+ e->e_message = newstr(mbuf);
+ }
}
}
else
- avp = hbrvp;
+ replac = NULL;
- /* restore the old trailing information */
- rvp = avp - 1;
- for (xpvp = pvpb1; *xpvp != NULL; xpvp++)
+ /* if no replacement, use default */
+ if (replac == NULL && default_rvp != NULL)
+ {
+ /* create the default */
+ cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
+ replac = buf;
+ }
+
+ if (replac == NULL)
+ {
+ xpvp = key_rvp;
+ }
+ else if (*replac == '\0')
{
- if (defaultpart && **xpvp == HOSTEND)
+ /* null replacement */
+ nullpvp[0] = NULL;
+ xpvp = nullpvp;
+ }
+ else
+ {
+ /* scan the new replacement */
+ xpvp = prescan(replac, '\0', pvpbuf,
+ sizeof pvpbuf, NULL, NULL);
+ if (xpvp == NULL)
{
- defaultpart = FALSE;
- rvp = avp - 1;
+ /* prescan already printed error */
+ return EX_DATAERR;
}
- else if (!defaultpart || !match)
- *avp++ = *xpvp;
+ }
+
+ /* append it to the token list */
+ for (avp = hbrvp; *xpvp != NULL; xpvp++)
+ {
+ *avp++ = newstr(*xpvp);
if (avp >= &npvp[MAXATOM])
goto toolong;
}
- *avp++ = NULL;
- /*break;*/
+ /* restore the old trailing information */
+ for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
+ if (avp >= &npvp[MAXATOM])
+ goto toolong;
+
+ break;
}
/*
** Check for subroutine calls.
- ** Then copy vector back into original space.
*/
- callsubr(npvp);
-
- for (avp = npvp; *avp++ != NULL;);
- subr = atoi(*++rvp);
- rvp++;
+ if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
+ {
+ int stat;
+ if (npvp[1] == NULL)
+ {
+ syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
+ ruleset, ruleno);
+ *pvp = NULL;
+ }
+ else
+ {
+ int ruleset;
+ STAB *s;
+
+ bcopy((char *) &npvp[2], (char *) pvp,
+ (int) (avp - npvp - 2) * sizeof *avp);
+ if (tTd(21, 3))
+ printf("-----callsubr %s\n", npvp[1]);
+ ruleset = strtorwset(npvp[1], NULL, ST_FIND);
+ stat = rewrite(pvp, ruleset, reclevel, e);
+ if (rstat == EX_OK || stat == EX_TEMPFAIL)
+ rstat = stat;
+ if (*pvp != NULL && (**pvp & 0377) == CANONNET)
+ rwr = NULL;
+ }
+ }
else
- subr = -1;
-
- /*
- ** Copy result back to original string.
- */
-
- for (avp = pvp; *rvp != NULL; rvp++)
- *avp++ = *rvp;
- *avp = NULL;
-
- /*
- ** If this specified a subroutine, call it.
- */
-
- if (subr >= 0)
{
-# ifdef DEBUG
- if (tTd(21, 3))
- printf("-----callsubr %s\n", subr);
-# endif DEBUG
- rewrite(pvp, subr);
+ bcopy((char *) npvp, (char *) pvp,
+ (int) (avp - npvp) * sizeof *avp);
}
-
- /*
- ** Done with rewriting this pass.
- */
-
if (tTd(21, 4))
{
printf("rewritten as:");
- printcav(pvp);
+ printav(pvp);
}
}
- if (OpMode == MD_TEST || tTd(21, 2))
+ if (OpMode == MD_TEST || tTd(21, 1))
{
printf("rewrite: ruleset %2d returns:", ruleset);
- printcav(pvp);
+ printav(pvp);
}
return rstat;
}
\f/*
-** CALLSUBR -- call subroutines in rewrite vector
-**
-** Parameters:
-** pvp -- pointer to token vector.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** pvp is modified.
-*/
-
-static void
-callsubr(pvp)
- char **pvp;
-{
- char **rvp;
- int subr;
-
- for (; *pvp != NULL; pvp++)
- if (**pvp == CALLSUBR && pvp[1] != NULL && isdigit(pvp[1][0]))
- {
- subr = atoi(pvp[1]);
-
- if (tTd(21, 3))
- printf("-----callsubr %d\n", subr);
-
- /*
- ** Take care of possible inner calls.
- */
- callsubr(pvp+2);
-
- /*
- ** Move vector up over calling opcode.
- */
- for (rvp = pvp+2; *rvp != NULL; rvp++)
- rvp[-2] = rvp[0];
- rvp[-2] = NULL;
-
- /*
- ** Call inferior ruleset.
- */
- _rewrite(pvp, subr);
-
- break;
- }
-}
-\f/*
** BUILDADDR -- build address from token vector.
**
** Parameters:
** tv -- token vector.
** a -- pointer to address descriptor to fill.
** If NULL, one will be allocated.
+** flags -- info regarding whether this is a sender or
+** a recipient.
** e -- the current envelope.
**
** Returns:
NULL, EX_UNAVAILABLE,
};
-static ADDRESS *
-buildaddr(tv, a, e)
+ADDRESS *
+buildaddr(tv, a, flags, e)
register char **tv;
register ADDRESS *a;
+ int flags;
register ENVELOPE *e;
{
struct mailer **mp;
register struct mailer *m;
- char *bp;
- int spaceleft;
- static char buf[MAXNAME];
+ register char *p;
+ char *mname;
+ char **hostp;
+ char hbuf[MAXNAME + 1];
+ static MAILER errormailer;
+ static char *errorargv[] = { "ERROR", NULL };
+ static char ubuf[MAXNAME + 1];
+
+ if (tTd(24, 5))
+ {
+ printf("buildaddr, flags=%x, tv=", flags);
+ printav(tv);
+ }
if (a == NULL)
a = (ADDRESS *) xalloc(sizeof *a);
- clear((char *) a, sizeof *a);
+ bzero((char *) a, sizeof *a);
+
+ /* set up default error return flags */
+ a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
/* figure out what net/mailer to use */
- if (*tv == NULL || **tv != CANONNET)
+ if (*tv == NULL || (**tv & 0377) != CANONNET)
{
syserr("554 buildaddr: no net");
- return (NULL);
+badaddr:
+ a->q_flags |= QBADADDR;
+ a->q_mailer = &errormailer;
+ if (errormailer.m_name == NULL)
+ {
+ /* initialize the bogus mailer */
+ errormailer.m_name = "*error*";
+ errormailer.m_mailer = "ERROR";
+ errormailer.m_argv = errorargv;
+ }
+ return a;
+ }
+ mname = *++tv;
+
+ /* extract host and user portions */
+ if ((**++tv & 0377) == CANONHOST)
+ hostp = ++tv;
+ else
+ hostp = NULL;
+ while (*tv != NULL && (**tv & 0377) != CANONUSER)
+ tv++;
+ if (*tv == NULL)
+ {
+ syserr("554 buildaddr: no user");
+ goto badaddr;
}
- tv++;
- if (strcasecmp(*tv, "error") == 0)
+ if (hostp != NULL)
+ cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
+ cataddr(++tv, NULL, ubuf, sizeof ubuf, '\0');
+
+ /* save away the host name */
+ if (strcasecmp(mname, "error") == 0)
{
- if ((**++tv & 0377) == CANONHOST)
+ if (hostp != NULL)
{
register struct errcodes *ep;
- if (isascii(**++tv) && isdigit(**tv))
+ if (strchr(hbuf, '.') != NULL)
{
- setstat(atoi(*tv));
+ a->q_status = newstr(hbuf);
+ setstat(dsntoexitstat(hbuf));
+ }
+ else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
+ {
+ setstat(atoi(hbuf));
}
else
{
for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
- if (strcasecmp(ep->ec_name, *tv) == 0)
+ if (strcasecmp(ep->ec_name, hbuf) == 0)
break;
setstat(ep->ec_code);
}
- tv++;
}
- buf[0] = '\0';
- for (; (*tv != NULL) && (**tv != CANONUSER); tv++)
+ else
+ setstat(EX_UNAVAILABLE);
+ stripquotes(ubuf);
+ if (isascii(ubuf[0]) && isdigit(ubuf[0]) &&
+ isascii(ubuf[1]) && isdigit(ubuf[1]) &&
+ isascii(ubuf[2]) && isdigit(ubuf[2]) &&
+ ubuf[3] == ' ')
+ {
+ char fmt[10];
+
+ strncpy(fmt, ubuf, 3);
+ strcpy(&fmt[3], " %s");
+ usrerr(fmt, ubuf + 4);
+
+ /*
+ ** If this is a 4xx code and we aren't running
+ ** SMTP on our input, bounce this message;
+ ** otherwise it disappears without a trace.
+ */
+
+ if (fmt[0] == '4' && OpMode != MD_SMTP &&
+ OpMode != MD_DAEMON)
+ {
+ e->e_flags |= EF_FATALERRS;
+ }
+ }
+ else
{
- if (buf[0] != '\0')
- (void) strcat(buf, " ");
- (void) strcat(buf, *tv);
+ usrerr("553 %s", ubuf);
}
- if ((**tv & 0377) != CANONUSER)
- syserr("554 buildaddr: error: no user");
- cataddr(++tv, NULL, buf, sizeof buf, ' ');
- stripquotes(buf);
-#ifdef LOG
- if (LogLevel > 8)
- syslog (LOG_DEBUG, "%s: Trace: $#ERROR $: %s",
- CurEnv->e_id, buf);
-#endif /* LOG */
- usrerr(buf);
- return (NULL);
+ goto badaddr;
}
for (mp = Mailer; (m = *mp++) != NULL; )
{
- if (strcasecmp(m->m_name, *tv) == 0)
+ if (strcasecmp(m->m_name, mname) == 0)
break;
}
if (m == NULL)
{
- syserr("554 buildaddr: unknown mailer %s", *tv);
- return (NULL);
+ syserr("554 buildaddr: unknown mailer %s", mname);
+ goto badaddr;
}
a->q_mailer = m;
/* figure out what host (if any) */
- if (**++tv != CANONHOST)
+ if (hostp == NULL)
{
+ if (!bitnset(M_LOCALMAILER, m->m_flags))
+ {
+ syserr("554 buildaddr: no host");
+ goto badaddr;
+ }
a->q_host = NULL;
}
else
- {
- else
- a->q_host = NULL;
- }
- else
- {
- while (*++tv != NULL && **tv != CANONUSER)
- (void) strcat(buf, *tv);
- a->q_host = newstr(buf);
- }
+ a->q_host = newstr(hbuf);
/* figure out the user */
- if (*tv == NULL || (**tv & 0377) != CANONUSER)
+ p = ubuf;
+ if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
{
- syserr("554 buildaddr: no user");
- return (NULL);
+ p++;
+ tv++;
+ a->q_flags |= QNOTREMOTE;
}
- tv++;
/* do special mapping for local mailer */
- if (m == LocalMailer && *tv != NULL)
+ if (*p == '"')
+ p++;
+ if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
+ a->q_mailer = m = ProgMailer;
+ else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
+ a->q_mailer = m = FileMailer;
+ else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
{
- register char *p = *tv;
-
- if (*p == '"')
- p++;
- if (*p == '|')
- a->q_mailer = m = ProgMailer;
- else if (*p == '/')
- a->q_mailer = m = FileMailer;
- else if (*p == ':')
+ /* may be :include: */
+ stripquotes(ubuf);
+ if (strncasecmp(ubuf, ":include:", 9) == 0)
{
- /* may be :include: */
- cataddr(tv, NULL, buf, sizeof buf, '\0');
- stripquotes(buf);
- if (strncasecmp(buf, ":include:", 9) == 0)
- {
- /* if :include:, don't need further rewriting */
- a->q_mailer = m = InclMailer;
- a->q_user = &buf[9];
- return (a);
- }
+ /* if :include:, don't need further rewriting */
+ a->q_mailer = m = InclMailer;
+ a->q_user = newstr(&ubuf[9]);
+ return a;
}
}
- if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0)
+ /* rewrite according recipient mailer rewriting rules */
+ define('h', a->q_host, e);
+ if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
{
- tv++;
- a->q_flags |= QNOTREMOTE;
+ /* sender addresses done later */
+ (void) rewrite(tv, 2, 0, e);
+ if (m->m_re_rwset > 0)
+ (void) rewrite(tv, m->m_re_rwset, 0, e);
}
-
- if (m->m_r_rwset > 0)
- rewrite(tv, m->m_r_rwset);
- (void) rewrite(tv, 4, e);
+ (void) rewrite(tv, 4, 0, e);
/* save the result for the command line/RCPT argument */
- cataddr(tv, NULL, buf, sizeof buf, '\0');
- a->q_user = buf;
+ cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
+ a->q_user = ubuf;
/*
** Do mapping to lower case as requested by mailer
if (!bitnset(M_USR_UPPER, m->m_flags))
makelower(a->q_user);
- return (a);
+ return a;
}
\f/*
** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
char **evp;
char *buf;
register int sz;
- char spacesub;
+ int spacesub;
{
bool oatomtok = FALSE;
- bool natomtok;
+ bool natomtok = FALSE;
register int i;
register char *p;
sz -= 2;
while (*pvp != NULL && (i = strlen(*pvp)) < sz)
{
- natomtok = (toktype(**pvp) == ATM);
+ natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
if (oatomtok && natomtok)
*p++ = spacesub;
(void) strcpy(p, *pvp);
register ADDRESS *a;
register ADDRESS *b;
{
+ register ADDRESS *ca, *cb;
+
/* if they don't have the same mailer, forget it */
if (a->q_mailer != b->q_mailer)
return (FALSE);
/* if the user isn't the same, we can drop out */
- if (strcasecmp(a->q_user, b->q_user))
+ if (strcmp(a->q_user, b->q_user) != 0)
return (FALSE);
- /* if we have good uids for both but the differ, these are different */
- if (bitset(QGOODUID, a->q_flags & b->q_flags) && a->q_uid != b->q_uid)
- return (FALSE);
+ /* if we have good uids for both but they differ, these are different */
+ if (a->q_mailer == ProgMailer)
+ {
+ ca = getctladdr(a);
+ cb = getctladdr(b);
+ if (ca != NULL && cb != NULL &&
+ bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
+ ca->q_uid != cb->q_uid)
+ return (FALSE);
+ }
/* otherwise compare hosts (but be careful for NULL ptrs) */
if (a->q_host == b->q_host)
/* only one is a null pointer */
return (FALSE);
}
- if (strcasecmp(a->q_host, b->q_host))
+ if (strcmp(a->q_host, b->q_host) != 0)
return (FALSE);
return (TRUE);
** none.
*/
+struct qflags
+{
+ char *qf_name;
+ u_long qf_bit;
+};
+
+struct qflags AddressFlags[] =
+{
+ "QDONTSEND", QDONTSEND,
+ "QBADADDR", QBADADDR,
+ "QGOODUID", QGOODUID,
+ "QPRIMARY", QPRIMARY,
+ "QQUEUEUP", QQUEUEUP,
+ "QSENT", QSENT,
+ "QNOTREMOTE", QNOTREMOTE,
+ "QSELFREF", QSELFREF,
+ "QVERIFIED", QVERIFIED,
+ "QBOGUSSHELL", QBOGUSSHELL,
+ "QUNSAFEADDR", QUNSAFEADDR,
+ "QPINGONSUCCESS", QPINGONSUCCESS,
+ "QPINGONFAILURE", QPINGONFAILURE,
+ "QPINGONDELAY", QPINGONDELAY,
+ "QHASNOTIFY", QHASNOTIFY,
+ "QRELAYED", QRELAYED,
+ "QEXPANDED", QEXPANDED,
+ "QDELIVERED", QDELIVERED,
+ "QDELAYED", QDELAYED,
+ "QTHISPASS", QTHISPASS,
+ NULL
+};
+
void
printaddr(a, follow)
register ADDRESS *a;
bool follow;
{
- bool first = TRUE;
register MAILER *m;
MAILER pseudomailer;
+ register struct qflags *qfp;
+ bool firstone;
- static int indent;
- register int i;
+ if (a == NULL)
+ {
+ printf("[NULL]\n");
+ return;
+ }
while (a != NULL)
{
- first = FALSE;
- for (i = indent; i > 0; i--)
- printf("\t");
printf("%x=", a);
(void) fflush(stdout);
m->m_name = "NULL";
}
- for (i = indent; i > 0; i--)
- printf("\t");
- printf("\tnext=%x, flags=%o, rmailer %d, alias=%x, sibling=%x, child=%x\n",
- a->q_next, a->q_flags, a->q_rmailer, a->q_alias,
- a->q_sibling, a->q_child);
-
- /* follow the chain if appropriate */
+ printf("%s:\n\tmailer %d (%s), host `%s'\n",
+ a->q_paddr, m->m_mno, m->m_name,
+ a->q_host == NULL ? "<null>" : a->q_host);
+ printf("\tuser `%s', ruser `%s'\n",
+ a->q_user,
+ a->q_ruser == NULL ? "<null>" : a->q_ruser);
+ printf("\tnext=%x, alias %x, uid %d, gid %d\n",
+ a->q_next, a->q_alias, a->q_uid, a->q_gid);
+ printf("\tflags=%lx<", a->q_flags);
+ firstone = TRUE;
+ for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
+ {
+ if (!bitset(qfp->qf_bit, a->q_flags))
+ continue;
+ if (!firstone)
+ printf(",");
+ firstone = FALSE;
+ printf("%s", qfp->qf_name);
+ }
+ printf(">\n");
+ printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
+ a->q_owner == NULL ? "(none)" : a->q_owner,
+ a->q_home == NULL ? "(none)" : a->q_home,
+ a->q_fullname == NULL ? "(none)" : a->q_fullname);
+ printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n",
+ a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
+ a->q_statmta == NULL ? "(none)" : a->q_statmta,
+ a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
+
if (!follow)
return;
-
- indent++;
- printaddr(a->q_child, TRUE);
- indent--;
- a = a->q_sibling;
+ a = a->q_next;
}
- if (first)
- printf("[NULL]\n");
}
+\f/*
+** EMPTYADDR -- return TRUE if this address is empty (``<>'')
+**
+** Parameters:
+** a -- pointer to the address
+**
+** Returns:
+** TRUE -- if this address is "empty" (i.e., no one should
+** ever generate replies to it.
+** FALSE -- if it is a "regular" (read: replyable) address.
+*/
+bool
+emptyaddr(a)
+ register ADDRESS *a;
+{
+ return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
+}
\f/*
** REMOTENAME -- return the name relative to the current mailer
**
char *
remotename(name, m, flags, pstat, e)
char *name;
- MAILER *m;
+ struct mailer *m;
int flags;
int *pstat;
register ENVELOPE *e;
char *fancy;
char *oldg = macvalue('g', e);
int rwset;
- static char buf[MAXNAME];
- char lbuf[MAXNAME];
+ static char buf[MAXNAME + 1];
+ char lbuf[MAXNAME + 1];
char pvpbuf[PSBUFSIZE];
+ extern char *crackaddr();
if (tTd(12, 1))
printf("remotename(%s)\n", name);
/* don't do anything if we are tagging it as special */
- if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0)
+ if (bitset(RF_SENDERADDR, flags))
+ rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
+ : m->m_se_rwset;
+ else
+ rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
+ : m->m_re_rwset;
+ if (rwset < 0)
return (name);
/*
** domain will be appended.
*/
- pvp = prescan(name, '\0', pvpbuf, NULL);
+ pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
if (pvp == NULL)
return (name);
- if (rewrite(pvp, 3, e) == EX_TEMPFAIL)
+ if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
{
while ((*pxp++ = *qxq++) != NULL)
continue;
- if (rewrite(pvp, 3, e) == EX_TEMPFAIL)
+ if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
}
/*
** Do more specific rewriting.
- ** Rewrite using ruleset 1 or 2 for envelope addresses and
- ** 5 or 6 for header addresses depending on whether this
- ** is a sender address or not.
+ ** 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, e) == EX_TEMPFAIL)
+ if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
** may be used as a default to the above rules.
*/
- if (rewrite(pvp, 4, e) == EX_TEMPFAIL)
+ if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
/*
cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
define('g', lbuf, e);
- expand(fancy, buf, &buf[sizeof buf - 1], 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))
return (buf);
}
\f/*
-** UURELATIVIZE -- Make an address !-relative to recipient/sender nodes
-**
-** Parameters:
-** from -- the sending node (usually "$k" or "$w")
-** to -- the receiving node (usually "$h")
-** pvp -- address vector
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** The pvp is rewritten to be relative the "to" node
-** wrt the "from" node. In other words, if the pvp
-** is headed by "to!" that part is stripped; otherwise
-** "from!" is prepended. Exception: "to!user" addresses
-** with no '!'s in the user part are sent as is.
-**
-** Bugs:
-** The pvp may overflow, but we don't catch it.
-*/
-
-static void
-uurelativize(from, to, pvp)
- const char *from, *to;
- char **pvp;
-{
- register char **pxp = pvp;
- char expfrom[MAXNAME], expto[MAXNAME];
-
- expand(from, expfrom, &expfrom[sizeof expfrom - 1], CurEnv);
- expand(to, expto, &expto[sizeof expto - 1], CurEnv);
-
- /*
- * supposing that we've got something, should
- * we add "from!" or remove "to!"?
- */
- if (pvp[0] != NULL)
- if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 ||
- /*strcasecmp?*/ strcmp(pvp[0], expto) != 0)
- {
- /* either local name, no UUCP address, */
- /* or not to "to!" ==> prepend address with "from!" */
-
- /* already there? */
- if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 ||
- /*strcasecmp?*/ strcmp(pvp[0], expfrom) != 0)
- {
-
- /* no, put it there */
- while (*pxp != NULL)
- pxp++;
- do
- pxp[2] = *pxp;
- while (pxp-- != pvp);
- pvp[0] = newstr(expfrom);
- pvp[1] = "!";
- }
- }
- else
- {
- /* address is to "to!" -- remove if not "to!user" */
- for (pxp = &pvp[2];
- *pxp != NULL && strcmp(*pxp, "!") != 0; pxp++)
- ;
- if (*pxp != NULL)
- for (pxp = pvp; *pxp != NULL; pxp++)
- *pxp = pxp[2];
- }
-}
-\f/*
** 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.
*/
-maplocaluser(a, sendq, e)
+void
+maplocaluser(a, sendq, aliaslevel, e)
register ADDRESS *a;
ADDRESS **sendq;
+ int aliaslevel;
ENVELOPE *e;
{
register char **pvp;
printf("maplocaluser: ");
printaddr(a, FALSE);
}
- pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr);
+ pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
if (pvp == NULL)
return;
- (void) rewrite(pvp, 5, e);
+ (void) rewrite(pvp, 5, 0, e);
if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
return;
/* if non-null, mailer destination specified -- has it changed? */
- a1 = buildaddr(pvp, NULL, e);
+ a1 = buildaddr(pvp, NULL, 0, e);
if (a1 == NULL || sameaddr(a, a1))
return;
printaddr(a, FALSE);
}
a1->q_alias = a;
- allocaddr(a1, 1, NULL, delimptr);
- (void) recipient(a1, sendq, e);
+ allocaddr(a1, RF_COPYALL, NULL);
+ (void) recipient(a1, sendq, aliaslevel, e);
}
\f/*
** DEQUOTE_INIT -- initialize dequote map
{
register char *p = args;
+ map->map_mflags |= MF_KEEPQUOTES;
for (;;)
{
while (isascii(*p) && isspace(*p))
case 'a':
map->map_app = ++p;
break;
+
+ case 's':
+ map->map_coldelim = *++p;
+ break;
}
while (*p != '\0' && !(isascii(*p) && isspace(*p)))
p++;
register char *p;
register char *q;
register char c;
- int anglecnt;
- int cmntcnt;
- int quotecnt;
- int spacecnt;
- bool quotemode;
- bool bslashmode;
-
- anglecnt = 0;
- cmntcnt = 0;
- quotecnt = 0;
- spacecnt = 0;
- quotemode = FALSE;
- bslashmode = FALSE;
+ int anglecnt = 0;
+ int cmntcnt = 0;
+ int quotecnt = 0;
+ int spacecnt = 0;
+ bool quotemode = FALSE;
+ bool bslashmode = FALSE;
+ char spacesub = map->map_coldelim;
for (p = q = name; (c = *p++) != '\0'; )
{
continue;
}
+ if (c == ' ' && spacesub != '\0')
+ c = spacesub;
+
switch (c)
{
case '\\':