BSD 4_4_Lite1 release
[unix-history] / usr / src / usr.sbin / sendmail / src / parseaddr.c
index 040d075..00621c2 100644 (file)
@@ -3,26 +3,40 @@
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * 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
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)parseaddr.c        8.30 (Berkeley) %G%";
+static char sccsid[] = "@(#)parseaddr.c        8.31 (Berkeley) 4/15/94";
 #endif /* not lint */
 
 #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
 
 /*
 **  PARSEADDR -- Parse an address
@@ -75,6 +89,8 @@ parseaddr(addr, a, flags, delim, delimptr, e)
        auto char *delimptrbuf;
        bool queueup;
        char pvpbuf[PSBUFSIZE];
        auto char *delimptrbuf;
        bool queueup;
        char pvpbuf[PSBUFSIZE];
+       extern ADDRESS *buildaddr();
+       extern bool invalidaddr();
 
        /*
        **  Initialize and prescan address.
 
        /*
        **  Initialize and prescan address.
@@ -84,22 +100,6 @@ parseaddr(addr, a, flags, delim, delimptr, e)
        if (tTd(20, 1))
                printf("\n--parseaddr(%s)\n", addr);
 
        if (tTd(20, 1))
                printf("\n--parseaddr(%s)\n", addr);
 
-       {
-               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 (delimptr == NULL)
                delimptr = &delimptrbuf;
 
        if (delimptr == NULL)
                delimptr = &delimptrbuf;
 
@@ -132,7 +132,7 @@ parseaddr(addr, a, flags, delim, delimptr, e)
 
                if (savec != '\0')
                        **delimptr = '\0';
 
                if (savec != '\0')
                        **delimptr = '\0';
-               addr = newstr(addr);
+               e->e_to = addr = newstr(addr);
                if (savec != '\0')
                        **delimptr = savec;
        }
                if (savec != '\0')
                        **delimptr = savec;
        }
@@ -286,45 +286,6 @@ allocaddr(a, flags, paddr)
                a->q_paddr = a->q_user;
 }
 \f/*
                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
 **  PRESCAN -- Prescan name and make it canonical
 **
 **     Scans a name and turns it into a set of tokens.  This process
@@ -427,6 +388,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr)
        char *saveto = CurEnv->e_to;
        static char *av[MAXATOM+1];
        static char firsttime = TRUE;
        char *saveto = CurEnv->e_to;
        static char *av[MAXATOM+1];
        static char firsttime = TRUE;
+       extern int errno;
 
        if (firsttime)
        {
 
        if (firsttime)
        {
@@ -541,7 +503,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr)
                        {
                                bslashmode = TRUE;
                        }
                        {
                                bslashmode = TRUE;
                        }
-                       if (state == QST)
+                       else if (state == QST)
                        {
                                /* do nothing, just avoid next clauses */
                        }
                        {
                                /* do nothing, just avoid next clauses */
                        }
@@ -576,20 +538,6 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr)
                        }
                        else if (delim == ' ' && isascii(c) && isspace(c))
                                c = ' ';
                        }
                        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 == NOCHAR)
                                continue;
@@ -685,58 +633,26 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr)
 **             pvp is modified.
 */
 
 **             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 */
 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 MAXMATCH      9       /* max params per rewrite */
-# define MAX_CONTROL ' '
 
 # ifndef MAXRULERECURSION
 #  define MAXRULERECURSION     50      /* max recursion depth */
 # endif
 
 # ifndef MAXRULERECURSION
 #  define MAXRULERECURSION     50      /* max recursion depth */
 # endif
-static char control_opts[MAX_CONTROL];
 
 
 int
 
 
 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, reclevel, e)
        char **pvp;
        int ruleset;
        int reclevel;
        register ENVELOPE *e;
 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 char *ap;              /* address pointer */
        register char *rp;              /* rewrite pointer */
@@ -747,20 +663,13 @@ _rewrite(pvp, ruleset)
        int ruleno;                     /* current rule number */
        int rstat = EX_OK;              /* return status */
        int loopcount;
        int ruleno;                     /* current rule number */
        int rstat = EX_OK;              /* return status */
        int loopcount;
-       int subr;                       /* subroutine number if >= 0 */
-       bool dolookup;                  /* do host aliasing */
+       struct match mlist[MAXMATCH];   /* stores match on LHS */
        char *npvp[MAXATOM+1];          /* temporary space for rebuild */
        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))
        {
                printf("rewrite: ruleset %2d   input:", ruleset);
 
        if (OpMode == MD_TEST || tTd(21, 2))
        {
                printf("rewrite: ruleset %2d   input:", ruleset);
-               printcav(pvp);
+               printav(pvp);
        }
        if (ruleset < 0 || ruleset >= MAXRWSETS)
        {
        }
        if (ruleset < 0 || ruleset >= MAXRWSETS)
        {
@@ -775,22 +684,9 @@ _rewrite(pvp, ruleset)
        if (pvp == NULL)
                return EX_USAGE;
 
        if (pvp == NULL)
                return EX_USAGE;
 
-       if (++nrw > 100)
-       {
-               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;
-       }
-
-       /* Be sure to recognize first rule as new */
-       prev_rwr = NULL;
-
        /*
        /*
-       **  Run through the list of rewrite rules, applying any that match.
+       **  Run through the list of rewrite rules, applying
+       **      any that match.
        */
 
        ruleno = 1;
        */
 
        ruleno = 1;
@@ -800,57 +696,15 @@ _rewrite(pvp, ruleset)
                if (tTd(21, 12))
                {
                        printf("-----trying rule:");
                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;
                }
 
                /* try to match on this rule */
                mlp = mlist;
-
                rvp = rwr->r_lhs;
                avp = pvp;
                rvp = rwr->r_lhs;
                avp = pvp;
-               nloops = 0;
-               extend_match = FALSE;
-
                if (++loopcount > 100)
                {
                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))
                        syserr("554 Infinite loop in ruleset %d, rule %d",
                                ruleset, ruleno);
                        if (tTd(21, 1))
@@ -864,7 +718,6 @@ _rewrite(pvp, ruleset)
                while ((ap = *avp) != NULL || *rvp != NULL)
                {
                        rp = *rvp;
                while ((ap = *avp) != NULL || *rvp != NULL)
                {
                        rp = *rvp;
-
                        if (tTd(21, 35))
                        {
                                printf("ADVANCE rp=");
                        if (tTd(21, 35))
                        {
                                printf("ADVANCE rp=");
@@ -873,90 +726,79 @@ _rewrite(pvp, ruleset)
                                xputs(ap);
                                printf("\n");
                        }
                                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)
                        if (rp == NULL)
+                       {
                                /* end-of-pattern before end-of-address */
                                goto backup;
                                /* 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);
+                               register STAB *s;
+                               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');
+                               s = stab(buf, ST_CLASS, ST_FIND);
+                               if (s == NULL || !bitnset(rp[1], s->s_class))
+                               {
+                                       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++;
                                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 */
+                               s = stab(ap, ST_CLASS, ST_FIND);
+                               if (s != NULL && bitnset(rp[1], s->s_class))
+                                       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 */
                                mlp++;
                                break;
 
                          case MATCHZERO:
                                /* match zero tokens */
-                               continue;
-                       }
+                               break;
 
                          case MACRODEXPAND:
                                /*
 
                          case MACRODEXPAND:
                                /*
@@ -991,210 +833,76 @@ _rewrite(pvp, ruleset)
                                /* match */
                                break;
 
                                /* 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;
                                        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++;
                                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++;
                        rvp++;
-                       mlp++;
                        continue;
 
                        continue;
 
-backup:
-                       /* We failed to match.  mlp marks point of failure */
-
-                       /*
-                       **  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 (*avp == NULL)
+         backup:
+                       /* match failed -- back up */
+                       while (--mlp >= mlist)
                        {
                                rvp = mlp->pattern;
                        {
                                rvp = mlp->pattern;
-                               while (--mlp > mlist)
+                               rp = *rvp;
+                               avp = mlp->last + 1;
+                               ap = *avp;
+
+                               if (tTd(21, 36))
                                {
                                {
-                                       if ((mlp->flags & OP_CLASS) &&
-                                           mlp->last > 2 + mlp->first)
-                                               break;
+                                       printf("BACKUP  rp=");
+                                       xputs(rp);
+                                       printf(", ap=");
+                                       xputs(ap);
+                                       printf("\n");
                                }
                                }
-                       }
 
 
-                       /*
-                       **  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--;
+                               if (ap == NULL)
+                               {
+                                       /* 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;
+                               }
+                       }
 
 
-                       /* Total failure to match */
                        if (mlp < mlist)
                        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++;
                        loopcount = 0;
                {
                        if (tTd(21, 10))
                                printf("----- rule fails\n");
                        rwr = rwr->r_next;
                        ruleno++;
                        loopcount = 0;
-                       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;
                        continue;
                }
 
                        continue;
                }
 
@@ -1202,7 +910,7 @@ backup:
                if (tTd(21, 12))
                {
                        printf("-----rule matches:");
                if (tTd(21, 12))
                {
                        printf("-----rule matches:");
-                       printcav(rvp);
+                       printav(rvp);
                }
 
                rp = *rvp;
                }
 
                rp = *rvp;
@@ -1212,7 +920,6 @@ backup:
                        rwr = rwr->r_next;
                        ruleno++;
                        loopcount = 0;
                        rwr = rwr->r_next;
                        ruleno++;
                        loopcount = 0;
-                       nmatches = 0;
                }
                else if ((*rp & 0377) == CANONHOST)
                {
                }
                else if ((*rp & 0377) == CANONHOST)
                {
@@ -1223,27 +930,19 @@ backup:
                        rwr = NULL;
 
                /* substitute */
                        rwr = NULL;
 
                /* substitute */
-               dolookup = FALSE;
                for (avp = npvp; *rvp != NULL; rvp++)
                {
                        register struct match *m;
                        register char **pp;
 
                        rp = *rvp;
                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)
                                {
                        {
                                /* 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;
                                }
                                                ruleset, rp[1]);
                                        return EX_CONFIG;
                                }
@@ -1251,7 +950,7 @@ backup:
                                {
                                        printf("$%c:", rp[1]);
                                        pp = m->first;
                                {
                                        printf("$%c:", rp[1]);
                                        pp = m->first;
-                                       while (pp < m->last)
+                                       while (pp <= m->last)
                                        {
                                                printf(" %x=\"", *pp);
                                                (void) fflush(stdout);
                                        {
                                                printf(" %x=\"", *pp);
                                                (void) fflush(stdout);
@@ -1260,10 +959,13 @@ backup:
                                        printf("\n");
                                }
                                pp = m->first;
                                        printf("\n");
                                }
                                pp = m->first;
-                               while (pp < m->last)
+                               while (pp <= m->last)
                                {
                                        if (avp >= &npvp[MAXATOM])
                                {
                                        if (avp >= &npvp[MAXATOM])
-                                               goto toolong;
+                                       {
+                                               syserr("554 rewrite: expansion too long");
+                                               return EX_DATAERR;
+                                       }
                                        *avp++ = *pp++;
                                }
                        }
                                        *avp++ = *pp++;
                                }
                        }
@@ -1271,21 +973,23 @@ backup:
                        {
                                /* vanilla replacement */
                                if (avp >= &npvp[MAXATOM])
                        {
                                /* 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;
                                        *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;
                        }
                }
                *avp++ = NULL;
@@ -1296,7 +1000,7 @@ backup:
 
                for (rvp = npvp; *rvp != NULL; rvp++)
                {
 
                for (rvp = npvp; *rvp != NULL; rvp++)
                {
-                       char **hbrvp, **ubrvp;
+                       char **hbrvp;
                        char **xpvp;
                        int trsize;
                        char *replac;
                        char **xpvp;
                        int trsize;
                        char *replac;
@@ -1306,14 +1010,11 @@ backup:
                        char **key_rvp;
                        char **arg_rvp;
                        char **default_rvp;
                        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];
                        char *nullpvp[1];
                        char *pvpb1[MAXATOM + 1];
                        char *argvect[10];
                        char pvpbuf[PSBUFSIZE];
                        char *nullpvp[1];
-                       bool match, defaultpart;
-                       char begintype;
-                       char db = '\0';
 
                        if ((**rvp & 0377) != HOSTBEGIN &&
                            (**rvp & 0377) != LOOKUPBEGIN)
 
                        if ((**rvp & 0377) != HOSTBEGIN &&
                            (**rvp & 0377) != LOOKUPBEGIN)
@@ -1325,9 +1026,7 @@ backup:
                        **      This could be optimized fairly easily.
                        */
 
                        **      This could be optimized fairly easily.
                        */
 
-                       begintype = **rvp;
                        hbrvp = rvp;
                        hbrvp = rvp;
-                       ubrvp = NULL;
                        if ((**rvp & 0377) == HOSTBEGIN)
                        {
                                endtoken = HOSTEND;
                        if ((**rvp & 0377) == HOSTBEGIN)
                        {
                                endtoken = HOSTEND;
@@ -1395,139 +1094,126 @@ backup:
                        trsize = (int) (avp - rvp + 1) * sizeof *rvp;
                        bcopy((char *) rvp, (char *) pvpb1, trsize);
 
                        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++)
-                               {
-                               *avp++ = newstr(*xpvp);
-                               if (avp >= &npvp[MAXATOM])
-                                       goto toolong;
-                               }
+                       /* 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;
+
+                               /* 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)
+                                       rstat = stat;
                        }
                        else
                        }
                        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);
+                               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;
                        }
                                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.
                }
 
                /*
                **  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
+                       {
+                               bcopy((char *) &npvp[2], (char *) pvp,
+                                       (int) (avp - npvp - 2) * sizeof *avp);
+                               if (tTd(21, 3))
+                                       printf("-----callsubr %s\n", npvp[1]);
+                               stat = rewrite(pvp, atoi(npvp[1]), reclevel, e);
+                               if (rstat == EX_OK || stat == EX_TEMPFAIL)
+                                       rstat = stat;
+                               if (*pvp != NULL && (**pvp & 0377) == CANONNET)
+                               rwr = NULL;
+                       }
+               }
                else
                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:");
                if (tTd(21, 4))
                {
                        printf("rewritten as:");
-                       printcav(pvp);
+                       printav(pvp);
                }
        }
 
        if (OpMode == MD_TEST || tTd(21, 2))
        {
                printf("rewrite: ruleset %2d returns:", ruleset);
                }
        }
 
        if (OpMode == MD_TEST || tTd(21, 2))
        {
                printf("rewrite: ruleset %2d returns:", ruleset);
-               printcav(pvp);
+               printav(pvp);
        }
 
        return rstat;
 }
 \f/*
        }
 
        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:
 **  BUILDADDR -- build address from token vector.
 **
 **     Parameters:
@@ -1565,7 +1251,7 @@ struct errcodes
        NULL,           EX_UNAVAILABLE,
 };
 
        NULL,           EX_UNAVAILABLE,
 };
 
-static ADDRESS *
+ADDRESS *
 buildaddr(tv, a, flags, e)
        register char **tv;
        register ADDRESS *a;
 buildaddr(tv, a, flags, e)
        register char **tv;
        register ADDRESS *a;
@@ -1588,10 +1274,10 @@ buildaddr(tv, a, flags, e)
 
        if (a == NULL)
                a = (ADDRESS *) xalloc(sizeof *a);
 
        if (a == NULL)
                a = (ADDRESS *) xalloc(sizeof *a);
-       clear((char *) a, sizeof *a);
+       bzero((char *) a, sizeof *a);
 
        /* figure out what net/mailer to use */
 
        /* figure out what net/mailer to use */
-       if (*tv == NULL || **tv != CANONNET)
+       if (*tv == NULL || (**tv & 0377) != CANONNET)
        {
                syserr("554 buildaddr: no net");
 badaddr:
        {
                syserr("554 buildaddr: no net");
 badaddr:
@@ -1628,22 +1314,10 @@ badaddr:
                }
                else
                        setstat(EX_UNAVAILABLE);
                }
                else
                        setstat(EX_UNAVAILABLE);
-               buf[0] = '\0';
-               for (; (*tv != NULL) && (**tv != CANONUSER); tv++)
-               {
-                       if (buf[0] != '\0')
-                               (void) strcat(buf, " ");
-                       (void) strcat(buf, *tv);
-               }
                if ((**tv & 0377) != CANONUSER)
                        syserr("554 buildaddr: error: no user");
                cataddr(++tv, NULL, buf, sizeof buf, ' ');
                stripquotes(buf);
                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 */
                if (isascii(buf[0]) && isdigit(buf[0]) &&
                    isascii(buf[1]) && isdigit(buf[1]) &&
                    isascii(buf[2]) && isdigit(buf[2]) &&
                if (isascii(buf[0]) && isdigit(buf[0]) &&
                    isascii(buf[1]) && isdigit(buf[1]) &&
                    isascii(buf[2]) && isdigit(buf[2]) &&
@@ -1675,20 +1349,41 @@ badaddr:
        a->q_mailer = m;
 
        /* figure out what host (if any) */
        a->q_mailer = m;
 
        /* figure out what host (if any) */
-       if (**++tv != CANONHOST)
-       {
-               a->q_host = NULL;
-       }
-       else
+       tv++;
+       if ((**tv & 0377) == CANONHOST)
        {
        {
-               else
-                       a->q_host = NULL;
+               bp = buf;
+               spaceleft = sizeof buf - 1;
+               while (*++tv != NULL && (**tv & 0377) != CANONUSER)
+               {
+                       int i = strlen(*tv);
+
+                       if (i > spaceleft)
+                       {
+                               /* out of space for this address */
+                               if (spaceleft >= 0)
+                                       syserr("554 buildaddr: host too long (%.40s...)",
+                                               buf);
+                               i = spaceleft;
+                               spaceleft = 0;
+                       }
+                       if (i <= 0)
+                               continue;
+                       bcopy(*tv, bp, i);
+                       bp += i;
+                       spaceleft -= i;
+               }
+               *bp = '\0';
+               a->q_host = newstr(buf);
        }
        else
        {
        }
        else
        {
-               while (*++tv != NULL && **tv != CANONUSER)
-                       (void) strcat(buf, *tv);
-               a->q_host = newstr(buf);
+               if (!bitnset(M_LOCALMAILER, m->m_flags))
+               {
+                       syserr("554 buildaddr: no host");
+                       goto badaddr;
+               }
+               a->q_host = NULL;
        }
 
        /* figure out the user */
        }
 
        /* figure out the user */
@@ -1731,8 +1426,15 @@ badaddr:
                a->q_flags |= QNOTREMOTE;
        }
 
                a->q_flags |= QNOTREMOTE;
        }
 
-       if (m->m_r_rwset > 0)
-               rewrite(tv, m->m_r_rwset);
+       /* rewrite according recipient mailer rewriting rules */
+       define('h', a->q_host, e);
+       if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
+       {
+               /* 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);
+       }
        (void) rewrite(tv, 4, 0, e);
 
        /* save the result for the command line/RCPT argument */
        (void) rewrite(tv, 4, 0, e);
 
        /* save the result for the command line/RCPT argument */
@@ -1769,7 +1471,6 @@ badaddr:
 **             Destroys buf.
 */
 
 **             Destroys buf.
 */
 
-void
 cataddr(pvp, evp, buf, sz, spacesub)
        char **pvp;
        char **evp;
 cataddr(pvp, evp, buf, sz, spacesub)
        char **pvp;
        char **evp;
@@ -1778,7 +1479,7 @@ cataddr(pvp, evp, buf, sz, spacesub)
        char spacesub;
 {
        bool oatomtok = FALSE;
        char spacesub;
 {
        bool oatomtok = FALSE;
-       bool natomtok;
+       bool natomtok = FALSE;
        register int i;
        register char *p;
 
        register int i;
        register char *p;
 
@@ -1835,7 +1536,7 @@ sameaddr(a, b)
                return (FALSE);
 
        /* if the user isn't the same, we can drop out */
                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 they differ, these are different */
                return (FALSE);
 
        /* if we have good uids for both but they differ, these are different */
@@ -1860,7 +1561,7 @@ sameaddr(a, b)
                /* only one is a null pointer */
                return (FALSE);
        }
                /* 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);
                return (FALSE);
 
        return (TRUE);
@@ -1879,7 +1580,6 @@ sameaddr(a, b)
 **             none.
 */
 
 **             none.
 */
 
-void
 printaddr(a, follow)
        register ADDRESS *a;
        bool follow;
 printaddr(a, follow)
        register ADDRESS *a;
        bool follow;
@@ -1888,14 +1588,9 @@ printaddr(a, follow)
        register MAILER *m;
        MAILER pseudomailer;
 
        register MAILER *m;
        MAILER pseudomailer;
 
-       static int indent;
-       register int i;
-
        while (a != NULL)
        {
                first = FALSE;
        while (a != NULL)
        {
                first = FALSE;
-               for (i = indent; i > 0; i--)
-                       printf("\t");
                printf("%x=", a);
                (void) fflush(stdout);
 
                printf("%x=", a);
                (void) fflush(stdout);
 
@@ -1908,20 +1603,20 @@ printaddr(a, follow)
                        m->m_name = "NULL";
                }
 
                        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', user `%s', ruser `%s'\n",
+                      a->q_paddr, m->m_mno, m->m_name,
+                      a->q_host, a->q_user,
+                      a->q_ruser ? a->q_ruser : "<null>");
+               printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n",
+                      a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid);
+               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);
+
                if (!follow)
                        return;
                if (!follow)
                        return;
-               
-               indent++;
-               printaddr(a->q_child, TRUE);
-               indent--;
-               a = a->q_sibling;
+               a = a->q_next;
        }
        if (first)
                printf("[NULL]\n");
        }
        if (first)
                printf("[NULL]\n");
@@ -1953,7 +1648,7 @@ printaddr(a, follow)
 char *
 remotename(name, m, flags, pstat, e)
        char *name;
 char *
 remotename(name, m, flags, pstat, e)
        char *name;
-       MAILER *m;
+       struct mailer *m;
        int flags;
        int *pstat;
        register ENVELOPE *e;
        int flags;
        int *pstat;
        register ENVELOPE *e;
@@ -1965,12 +1660,19 @@ remotename(name, m, flags, pstat, e)
        static char buf[MAXNAME];
        char lbuf[MAXNAME];
        char pvpbuf[PSBUFSIZE];
        static char buf[MAXNAME];
        char lbuf[MAXNAME];
        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 (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);
 
        /*
                return (name);
 
        /*
@@ -2018,14 +1720,21 @@ remotename(name, m, flags, pstat, e)
 
        /*
        **  Do more specific rewriting.
 
        /*
        **  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.
        */
 
        **      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
        {
        else
        {
+               if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
+                       *pstat = EX_TEMPFAIL;
+       }
        if (rwset > 0)
        {
                if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
        if (rwset > 0)
        {
                if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
@@ -2062,76 +1771,6 @@ remotename(name, m, flags, pstat, e)
        return (buf);
 }
 \f/*
        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:
 **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
 **
 **     Parameters: