repair numeric codes on $#error lines (broken a few days ago)
[unix-history] / usr / src / usr.sbin / sendmail / src / parseaddr.c
index b361b54..a94c23b 100644 (file)
@@ -1,13 +1,13 @@
 /*
  * Copyright (c) 1983 Eric P. Allman
 /*
  * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 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%
  */
 
 #ifndef lint
  *
  * %sccs.include.redist.c%
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)parseaddr.c        6.33 (Berkeley) %G%";
+static char sccsid[] = "@(#)parseaddr.c        8.12 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -42,14 +42,8 @@ char *DelimChar;             /* set to point to the delimiter */
 **             addr -- the address to parse.
 **             a -- a pointer to the address descriptor buffer.
 **                     If NULL, a header will be created.
 **             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
 **             delim -- the character to terminate the address, passed
 **                     to prescan.
 **             delimptr -- if non-NULL, set to the location of the
@@ -66,19 +60,20 @@ char        *DelimChar;             /* set to point to the delimiter */
 */
 
 /* following delimiters are inherent to the internal algorithms */
 */
 
 /* following delimiters are inherent to the internal algorithms */
-# define DELIMCHARS    "\201()<>,;\\\"\r\n"    /* word delimiters */
+# define DELIMCHARS    "()<>,;\r\n"    /* default word delimiters */
 
 ADDRESS *
 
 ADDRESS *
-parseaddr(addr, a, copyf, delim, delimptr, e)
+parseaddr(addr, a, flags, delim, delimptr, e)
        char *addr;
        register ADDRESS *a;
        char *addr;
        register ADDRESS *a;
-       int copyf;
-       char delim;
+       int flags;
+       int delim;
        char **delimptr;
        register ENVELOPE *e;
 {
        register char **pvp;
        auto char *delimptrbuf;
        char **delimptr;
        register ENVELOPE *e;
 {
        register char **pvp;
        auto char *delimptrbuf;
+       bool queueup;
        char pvpbuf[PSBUFSIZE];
 
        /*
        char pvpbuf[PSBUFSIZE];
 
        /*
@@ -124,38 +119,66 @@ parseaddr(addr, a, copyf, delim, delimptr, e)
        }
 
        /*
        }
 
        /*
-       **  Apply rewriting rules.
-       **      Ruleset 0 does basic parsing.  It must resolve.
+       **  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.
        */
 
        */
 
-       rewrite(pvp, 3);
-       rewrite(pvp, 0);
+       if (bitset(RF_COPYPADDR, flags) && addr != NULL)
+       {
+               char savec = **delimptr;
+
+               if (savec != '\0')
+                       **delimptr = '\0';
+               addr = newstr(addr);
+               if (savec != '\0')
+                       **delimptr = savec;
+       }
 
        /*
 
        /*
-       **  See if we resolved to a real mailer.
+       **  Apply rewriting rules.
+       **      Ruleset 0 does basic parsing.  It must resolve.
        */
 
        */
 
-       if ((pvp[0][0] & 0377) != CANONNET)
-       {
-               setstat(EX_USAGE);
-               syserr("554 cannot resolve name");
-               return (NULL);
-       }
+       queueup = FALSE;
+       if (rewrite(pvp, 3, e) == EX_TEMPFAIL)
+               queueup = TRUE;
+       if (rewrite(pvp, 0, e) == EX_TEMPFAIL)
+               queueup = TRUE;
+
 
        /*
        **  Build canonical address from pvp.
        */
 
 
        /*
        **  Build canonical address from pvp.
        */
 
-       a = buildaddr(pvp, a);
-       if (a == NULL)
-               return (NULL);
+       a = buildaddr(pvp, a, flags, e);
 
        /*
        **  Make local copies of the host & user and then
        **  transport them out.
        */
 
 
        /*
        **  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 (queueup)
+       {
+               char *msg = "Transient parse error -- message queued for future delivery";
+
+               if (tTd(20, 1))
+                       printf("parseaddr: queuing message\n");
+               message(msg);
+               if (e->e_message == NULL)
+                       e->e_message = newstr(msg);
+               a->q_flags |= QQUEUEUP;
+       }
 
        /*
        **  Compute return value.
 
        /*
        **  Compute return value.
@@ -201,9 +224,9 @@ invalidaddr(addr)
 **
 **     Parameters:
 **             a -- the address to reallocate.
 **
 **     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.
 **             paddr -- the printname of the address.
-**             delimptr -- a pointer to the address delimiter.  Must be set.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -212,34 +235,22 @@ invalidaddr(addr)
 **             Copies portions of a into local buffers as requested.
 */
 
 **             Copies portions of a into local buffers as requested.
 */
 
-allocaddr(a, copyf, paddr, delimptr)
+allocaddr(a, flags, paddr)
        register ADDRESS *a;
        register ADDRESS *a;
-       int copyf;
+       int flags;
        char *paddr;
        char *paddr;
-       char *delimptr;
 {
 {
-       register MAILER *m = a->q_mailer;
-
        if (tTd(24, 4))
        if (tTd(24, 4))
-               printf("allocaddr(copyf=%d, paddr=%s)\n", copyf, paddr);
-
-       if (copyf > 0 && paddr != NULL)
-       {
-               char savec = *delimptr;
+               printf("allocaddr(flags=%o, paddr=%s)\n", flags, paddr);
 
 
-               *delimptr = '\0';
-               a->q_paddr = newstr(paddr);
-               *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 (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_host = newstr(a->q_host);
                if (a->q_user != a->q_paddr)
@@ -363,6 +374,7 @@ prescan(addr, delim, pvpbuf, delimptr)
        char *tok;
        int state;
        int newstate;
        char *tok;
        int state;
        int newstate;
+       char *saveto = CurEnv->e_to;
        static char *av[MAXATOM+1];
 
        /* make sure error messages don't have garbage on them */
        static char *av[MAXATOM+1];
 
        /* make sure error messages don't have garbage on them */
@@ -376,6 +388,7 @@ prescan(addr, delim, pvpbuf, delimptr)
        state = ATM;
        c = NOCHAR;
        p = addr;
        state = ATM;
        c = NOCHAR;
        p = addr;
+       CurEnv->e_to = p;
        if (tTd(22, 11))
        {
                printf("prescan: ");
        if (tTd(22, 11))
        {
                printf("prescan: ");
@@ -390,7 +403,7 @@ prescan(addr, delim, pvpbuf, delimptr)
                for (;;)
                {
                        /* store away any old lookahead character */
                for (;;)
                {
                        /* store away any old lookahead character */
-                       if (c != NOCHAR)
+                       if (c != NOCHAR && !bslashmode)
                        {
                                /* see if there is room */
                                if (q >= &pvpbuf[PSBUFSIZE - 5])
                        {
                                /* see if there is room */
                                if (q >= &pvpbuf[PSBUFSIZE - 5])
@@ -398,6 +411,7 @@ prescan(addr, delim, pvpbuf, delimptr)
                                        usrerr("553 Address too long");
                                        if (delimptr != NULL)
                                                *delimptr = p;
                                        usrerr("553 Address too long");
                                        if (delimptr != NULL)
                                                *delimptr = p;
+                                       CurEnv->e_to = saveto;
                                        return (NULL);
                                }
 
                                        return (NULL);
                                }
 
@@ -412,18 +426,18 @@ prescan(addr, delim, pvpbuf, delimptr)
                                /* diagnose and patch up bad syntax */
                                if (state == QST)
                                {
                                /* diagnose and patch up bad syntax */
                                if (state == QST)
                                {
-                                       usrerr("553 Unbalanced '\"'");
+                                       usrerr("653 Unbalanced '\"' (fixed)");
                                        c = '"';
                                }
                                else if (cmntcnt > 0)
                                {
                                        c = '"';
                                }
                                else if (cmntcnt > 0)
                                {
-                                       usrerr("553 Unbalanced '('");
+                                       usrerr("653 Unbalanced '(' (fixed)");
                                        c = ')';
                                }
                                else if (anglecnt > 0)
                                {
                                        c = '>';
                                        c = ')';
                                }
                                else if (anglecnt > 0)
                                {
                                        c = '>';
-                                       usrerr("553 Unbalanced '<'");
+                                       usrerr("653 Unbalanced '<' (fixed)");
                                }
                                else
                                        break;
                                }
                                else
                                        break;
@@ -441,22 +455,24 @@ prescan(addr, delim, pvpbuf, delimptr)
                        *q = '\0';
                        if (bslashmode)
                        {
                        *q = '\0';
                        if (bslashmode)
                        {
+                               bslashmode = FALSE;
+
                                /* kludge \! for naive users */
                                if (cmntcnt > 0)
                                /* kludge \! for naive users */
                                if (cmntcnt > 0)
+                               {
                                        c = NOCHAR;
                                        c = NOCHAR;
-                               else if (c != '!')
+                                       continue;
+                               }
+                               else if (c != '!' || state == QST)
+                               {
                                        *q++ = '\\';
                                        *q++ = '\\';
-                               bslashmode = FALSE;
-                               if (cmntcnt > 0)
-                                       c = NOCHAR;
-                               continue;
+                                       continue;
+                               }
                        }
 
                        if (c == '\\')
                        {
                                bslashmode = TRUE;
                        }
 
                        if (c == '\\')
                        {
                                bslashmode = TRUE;
-                               c = NOCHAR;
-                               continue;
                        }
                        if (state == QST)
                        {
                        }
                        if (state == QST)
                        {
@@ -471,10 +487,8 @@ prescan(addr, delim, pvpbuf, delimptr)
                        {
                                if (cmntcnt <= 0)
                                {
                        {
                                if (cmntcnt <= 0)
                                {
-                                       usrerr("553 Unbalanced ')'");
-                                       if (delimptr != NULL)
-                                               *delimptr = p;
-                                       return (NULL);
+                                       usrerr("653 Unbalanced ')' (fixed)");
+                                       c = NOCHAR;
                                }
                                else
                                        cmntcnt--;
                                }
                                else
                                        cmntcnt--;
@@ -487,12 +501,11 @@ prescan(addr, delim, pvpbuf, delimptr)
                        {
                                if (anglecnt <= 0)
                                {
                        {
                                if (anglecnt <= 0)
                                {
-                                       usrerr("553 Unbalanced '>'");
-                                       if (delimptr != NULL)
-                                               *delimptr = p;
-                                       return (NULL);
+                                       usrerr("653 Unbalanced '>' (fixed)");
+                                       c = NOCHAR;
                                }
                                }
-                               anglecnt--;
+                               else
+                                       anglecnt--;
                        }
                        else if (delim == ' ' && isascii(c) && isspace(c))
                                c = ' ';
                        }
                        else if (delim == ' ' && isascii(c) && isspace(c))
                                c = ' ';
@@ -543,6 +556,7 @@ prescan(addr, delim, pvpbuf, delimptr)
                                syserr("553 prescan: too many tokens");
                                if (delimptr != NULL)
                                        *delimptr = p;
                                syserr("553 prescan: too many tokens");
                                if (delimptr != NULL)
                                        *delimptr = p;
+                               CurEnv->e_to = saveto;
                                return (NULL);
                        }
                        *avp++ = tok;
                                return (NULL);
                        }
                        *avp++ = tok;
@@ -557,6 +571,7 @@ prescan(addr, delim, pvpbuf, delimptr)
                printf("prescan==>");
                printav(av);
        }
                printf("prescan==>");
                printav(av);
        }
+       CurEnv->e_to = saveto;
        if (av[0] == NULL)
                return (NULL);
        return (av);
        if (av[0] == NULL)
                return (NULL);
        return (av);
@@ -590,6 +605,8 @@ toktype(c)
        c &= 0377;
        if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
                return (ONE);
        c &= 0377;
        if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
                return (ONE);
+       if (c == MACRODEXPAND)
+               return (ONE);
 #ifdef MACVALUE
        if (c == MACVALUE)
                return (ONE);
 #ifdef MACVALUE
        if (c == MACVALUE)
                return (ONE);
@@ -630,9 +647,12 @@ toktype(c)
 **
 **     Parameters:
 **             pvp -- pointer to token vector.
 **
 **     Parameters:
 **             pvp -- pointer to token vector.
+**             ruleset -- the ruleset to use for rewriting.
+**             e -- the current envelope.
 **
 **     Returns:
 **
 **     Returns:
-**             none.
+**             A status code.  If EX_TEMPFAIL, higher level code should
+**                     attempt recovery.
 **
 **     Side Effects:
 **             pvp is modified.
 **
 **     Side Effects:
 **             pvp is modified.
@@ -657,6 +677,7 @@ struct match
 
 static char control_opts[MAX_CONTROL];
 
 
 static char control_opts[MAX_CONTROL];
 
+int
 static char control_init_data[] = { 
        MATCHZANY,      OP_VARLEN,
        MATCHONE,       OP_NONZLEN,
 static char control_init_data[] = { 
        MATCHZANY,      OP_VARLEN,
        MATCHONE,       OP_NONZLEN,
@@ -671,9 +692,10 @@ static char control_init_data[] = {
 static int nrw;
 
 void
 static int nrw;
 
 void
-rewrite(pvp, ruleset)
+rewrite(pvp, ruleset, e)
        char **pvp;
        int ruleset;
        char **pvp;
        int ruleset;
+       register ENVELOPE *e;
 {
        nrw = 0;
        _rewrite(pvp, ruleset);
 {
        nrw = 0;
        _rewrite(pvp, ruleset);
@@ -690,6 +712,8 @@ _rewrite(pvp, ruleset)
        register char **rvp;            /* rewrite vector pointer */
        register struct match *mlp;     /* cur ptr into mlist */
        register struct rewrite *rwr;   /* pointer to current rewrite rule */
        register char **rvp;            /* rewrite vector pointer */
        register struct match *mlp;     /* cur ptr into mlist */
        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 */
        char *npvp[MAXATOM+1];          /* temporary space for rebuild */
        int subr;                       /* subroutine number if >= 0 */
        bool dolookup;                  /* do host aliasing */
        char *npvp[MAXATOM+1];          /* temporary space for rebuild */
@@ -708,10 +732,10 @@ _rewrite(pvp, ruleset)
        if (ruleset < 0 || ruleset >= MAXRWSETS)
        {
                syserr("554 rewrite: illegal ruleset number %d", ruleset);
        if (ruleset < 0 || ruleset >= MAXRWSETS)
        {
                syserr("554 rewrite: illegal ruleset number %d", ruleset);
-               return;
+               return EX_CONFIG;
        }
        if (pvp == NULL)
        }
        if (pvp == NULL)
-               return;
+               return EX_USAGE;
 
        if (++nrw > 100)
        {
 
        if (++nrw > 100)
        {
@@ -731,6 +755,7 @@ _rewrite(pvp, ruleset)
        **  Run through the list of rewrite rules, applying any that match.
        */
 
        **  Run through the list of rewrite rules, applying any that match.
        */
 
+       ruleno = 1;
        for (rwr = RewriteRules[ruleset]; rwr != NULL; )
        {
                int loopcount = 0;
        for (rwr = RewriteRules[ruleset]; rwr != NULL; )
        {
                int loopcount = 0;
@@ -780,7 +805,7 @@ _rewrite(pvp, ruleset)
                nloops = 0;
                extend_match = FALSE;
 
                nloops = 0;
                extend_match = FALSE;
 
-               while ((ap = *avp) != NULL || *rvp != NULL)
+               if (++loopcount > 100)
                {
                        if (nloops++ > 400)
                        {
                {
                        if (nloops++ > 400)
                        {
@@ -789,13 +814,18 @@ _rewrite(pvp, ruleset)
                                mlp = mlist - 1; /* force rule failure */
                                break;
                        }
                                mlp = mlist - 1; /* force rule failure */
                                break;
                        }
-                       if (++loopcount > 100)
+                       syserr("554 Infinite loop in ruleset %d, rule %d",
+                               ruleset, ruleno);
+                       if (tTd(21, 1))
                        {
                        {
-                               syserr("554 Infinite loop in ruleset %d", ruleset);
                                printf("workspace: ");
                                printav(pvp);
                                printf("workspace: ");
                                printav(pvp);
-                               break;
                        }
                        }
+                       break;
+               }
+
+               while ((ap = *avp) != NULL || *rvp != NULL)
+               {
                        rp = *rvp;
 
                        if (tTd(21, 35))
                        rp = *rvp;
 
                        if (tTd(21, 35))
@@ -886,11 +916,44 @@ _rewrite(pvp, ruleset)
                                mlp++;
                                break;
 
                                mlp++;
                                break;
 
-                         case CANONHOST:
+                         case MATCHZERO:
                                /* match zero tokens */
                                continue;
                        }
 
                                /* match zero tokens */
                                continue;
                        }
 
+                         case MACRODEXPAND:
+                               /*
+                               **  Match against run-time macro.
+                               **  This algorithm is broken for the
+                               **  general case (no recursive macros,
+                               **  improper tokenization) but should
+                               **  work for the usual cases.
+                               */
+
+                               ap = macvalue(rp[1], e);
+                               mlp->first = avp;
+                               if (tTd(21, 2))
+                                       printf("rewrite: LHS $&%c => \"%s\"\n",
+                                               rp[1],
+                                               ap == NULL ? "(NULL)" : ap);
+
+                               if (ap == NULL)
+                                       break;
+                               while (*ap != '\0')
+                               {
+                                       if (*avp == NULL ||
+                                           strncasecmp(ap, *avp, strlen(*avp)) != 0)
+                                       {
+                                               /* no match */
+                                               avp = mlp->first;
+                                               goto backup;
+                                       }
+                                       ap += strlen(*avp++);
+                               }
+
+                               /* match */
+                               break;
+
                        /*
                        **  We now have a variable length item.  It could
                        **  be $+ or $* in which case no special checking
                        /*
                        **  We now have a variable length item.  It could
                        **  be $+ or $* in which case no special checking
@@ -1083,6 +1146,7 @@ backup:
                        if (tTd(21, 10))
                                printf("----- rule fails\n");
                        rwr = rwr->r_next;
                        if (tTd(21, 10))
                                printf("----- rule fails\n");
                        rwr = rwr->r_next;
+                       ruleno++;
                        nmatches = 0;
                        continue;
                }
                        nmatches = 0;
                        continue;
                }
@@ -1108,6 +1172,7 @@ backup:
                {
                        rvp++;
                        rwr = rwr->r_next;
                {
                        rvp++;
                        rwr = rwr->r_next;
+                       ruleno++;
                        nmatches = 0;
                }
                else if ((*rp & 0377) == CANONHOST)
                        nmatches = 0;
                }
                else if ((*rp & 0377) == CANONHOST)
@@ -1141,7 +1206,7 @@ backup:
                                  toolong:
                                        syserr("rewrite: ruleset %d: replacement #%c out of bounds",
                                                ruleset, rp[1]);
                                  toolong:
                                        syserr("rewrite: ruleset %d: replacement #%c out of bounds",
                                                ruleset, rp[1]);
-                                       return;
+                                       return EX_CONFIG;
                                }
                                if (tTd(21, 15))
                                {
                                }
                                if (tTd(21, 15))
                                {
@@ -1195,7 +1260,6 @@ backup:
                        char **hbrvp, **ubrvp;
                        char **xpvp;
                        int trsize;
                        char **hbrvp, **ubrvp;
                        char **xpvp;
                        int trsize;
-                       char *olddelimchar;
                        char *replac;
                        int endtoken;
                        STAB *map;
                        char *replac;
                        int endtoken;
                        STAB *map;
@@ -1207,6 +1271,7 @@ backup:
                        char *pvpb1[MAXATOM + 1];
                        char *argvect[10];
                        char pvpbuf[PSBUFSIZE];
                        char *pvpb1[MAXATOM + 1];
                        char *argvect[10];
                        char pvpbuf[PSBUFSIZE];
+                       char *nullpvp[1];
                        bool match, defaultpart;
                        char begintype;
                        char db = '\0';
                        bool match, defaultpart;
                        char begintype;
                        char db = '\0';
@@ -1372,6 +1437,8 @@ backup:
                printf("rewrite: ruleset %2d returns:", ruleset);
                printcav(pvp);
        }
                printf("rewrite: ruleset %2d returns:", ruleset);
                printcav(pvp);
        }
+
+       return rstat;
 }
 \f/*
 **  CALLSUBR -- call subroutines in rewrite vector
 }
 \f/*
 **  CALLSUBR -- call subroutines in rewrite vector
@@ -1428,6 +1495,9 @@ callsubr(pvp)
 **             tv -- token vector.
 **             a -- pointer to address descriptor to fill.
 **                     If NULL, one will be allocated.
 **             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 if there was an error.
 **
 **     Returns:
 **             NULL if there was an error.
@@ -1457,14 +1527,18 @@ struct errcodes
 };
 
 static ADDRESS *
 };
 
 static ADDRESS *
-buildaddr(tv, a)
+buildaddr(tv, a, flags, e)
        register char **tv;
        register ADDRESS *a;
        register char **tv;
        register ADDRESS *a;
+       int flags;
+       register ENVELOPE *e;
 {
        struct mailer **mp;
        register struct mailer *m;
        char *bp;
        int spaceleft;
 {
        struct mailer **mp;
        register struct mailer *m;
        char *bp;
        int spaceleft;
+       static MAILER errormailer;
+       static char *errorargv[] = { "ERROR", NULL };
        static char buf[MAXNAME];
 
        if (a == NULL)
        static char buf[MAXNAME];
 
        if (a == NULL)
@@ -1475,7 +1549,17 @@ buildaddr(tv, a)
        if (*tv == NULL || **tv != CANONNET)
        {
                syserr("554 buildaddr: no net");
        if (*tv == NULL || **tv != 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;
        }
        tv++;
        if (strcasecmp(*tv, "error") == 0)
        }
        tv++;
        if (strcasecmp(*tv, "error") == 0)
@@ -1513,8 +1597,22 @@ buildaddr(tv, a)
                        syslog (LOG_DEBUG, "%s: Trace: $#ERROR $: %s",
                                CurEnv->e_id, buf);
 #endif /* LOG */
                        syslog (LOG_DEBUG, "%s: Trace: $#ERROR $: %s",
                                CurEnv->e_id, buf);
 #endif /* LOG */
-               usrerr(buf);
-               return (NULL);
+               if (isascii(buf[0]) && isdigit(buf[0]) &&
+                   isascii(buf[1]) && isdigit(buf[1]) &&
+                   isascii(buf[2]) && isdigit(buf[2]) &&
+                   buf[3] == ' ')
+               {
+                       char fmt[10];
+
+                       strncpy(fmt, buf, 3);
+                       strcpy(&fmt[3], " %s");
+                       usrerr(fmt, buf + 4);
+               }
+               else
+               {
+                       usrerr("%s", buf);
+               }
+               goto badaddr;
        }
 
        for (mp = Mailer; (m = *mp++) != NULL; )
        }
 
        for (mp = Mailer; (m = *mp++) != NULL; )
@@ -1525,7 +1623,7 @@ buildaddr(tv, a)
        if (m == NULL)
        {
                syserr("554 buildaddr: unknown mailer %s", *tv);
        if (m == NULL)
        {
                syserr("554 buildaddr: unknown mailer %s", *tv);
-               return (NULL);
+               goto badaddr;
        }
        a->q_mailer = m;
 
        }
        a->q_mailer = m;
 
@@ -1550,7 +1648,7 @@ buildaddr(tv, a)
        if (*tv == NULL || (**tv & 0377) != CANONUSER)
        {
                syserr("554 buildaddr: no user");
        if (*tv == NULL || (**tv & 0377) != CANONUSER)
        {
                syserr("554 buildaddr: no user");
-               return (NULL);
+               goto badaddr;
        }
        tv++;
 
        }
        tv++;
 
@@ -1588,7 +1686,7 @@ buildaddr(tv, a)
 
        if (m->m_r_rwset > 0)
                rewrite(tv, m->m_r_rwset);
 
        if (m->m_r_rwset > 0)
                rewrite(tv, m->m_r_rwset);
-       rewrite(tv, 4);
+       (void) rewrite(tv, 4, e);
 
        /* save the result for the command line/RCPT argument */
        cataddr(tv, NULL, buf, sizeof buf, '\0');
 
        /* save the result for the command line/RCPT argument */
        cataddr(tv, NULL, buf, sizeof buf, '\0');
@@ -1780,13 +1878,8 @@ printaddr(a, follow)
 **             name -- the name to translate.
 **             m -- the mailer that we want to do rewriting relative
 **                     to.
 **             name -- the name to translate.
 **             m -- the mailer that we want to do rewriting relative
 **                     to.
-**             senderaddress -- if set, uses the sender rewriting rules
-**                     rather than the recipient rewriting rules.
-**             header -- set if this address is in the header, rather
-**                     than an envelope header.
-**             canonical -- if set, strip out any comment information,
-**                     etc.
-**             adddomain -- if set, OK to do domain extension.
+**             flags -- fine tune operations.
+**             pstat -- pointer to status word.
 **             e -- the current envelope.
 **
 **     Returns:
 **             e -- the current envelope.
 **
 **     Returns:
@@ -1802,13 +1895,11 @@ printaddr(a, follow)
 */
 
 char *
 */
 
 char *
-remotename(name, m, senderaddress, header, canonical, adddomain, e)
+remotename(name, m, flags, pstat, e)
        char *name;
        MAILER *m;
        char *name;
        MAILER *m;
-       bool senderaddress;
-       bool header;
-       bool canonical;
-       bool adddomain;
+       int flags;
+       int *pstat;
        register ENVELOPE *e;
 {
        register char **pvp;
        register ENVELOPE *e;
 {
        register char **pvp;
@@ -1831,7 +1922,7 @@ remotename(name, m, senderaddress, header, canonical, adddomain, e)
        **      This will leave the name as a comment and a $g macro.
        */
 
        **      This will leave the name as a comment and a $g macro.
        */
 
-       if (canonical || bitnset(M_NOCOMMENT, m->m_flags))
+       if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
                fancy = "\201g";
        else
                fancy = crackaddr(name);
                fancy = "\201g";
        else
                fancy = crackaddr(name);
@@ -1847,8 +1938,9 @@ remotename(name, m, senderaddress, header, canonical, adddomain, e)
        pvp = prescan(name, '\0', pvpbuf, NULL);
        if (pvp == NULL)
                return (name);
        pvp = prescan(name, '\0', pvpbuf, NULL);
        if (pvp == NULL)
                return (name);
-       rewrite(pvp, 3);
-       if (adddomain && e->e_fromdomain != NULL)
+       if (rewrite(pvp, 3, e) == EX_TEMPFAIL)
+               *pstat = EX_TEMPFAIL;
+       if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
        {
                /* append from domain to this address */
                register char **pxp = pvp;
        {
                /* append from domain to this address */
                register char **pxp = pvp;
@@ -1863,7 +1955,8 @@ remotename(name, m, senderaddress, header, canonical, adddomain, e)
 
                        while ((*pxp++ = *qxq++) != NULL)
                                continue;
 
                        while ((*pxp++ = *qxq++) != NULL)
                                continue;
-                       rewrite(pvp, 3);
+                       if (rewrite(pvp, 3, e) == EX_TEMPFAIL)
+                               *pstat = EX_TEMPFAIL;
                }
        }
 
                }
        }
 
@@ -1875,10 +1968,13 @@ remotename(name, m, senderaddress, header, canonical, adddomain, e)
        **      Then run it through any receiving-mailer-specific rulesets.
        */
 
        **      Then run it through any receiving-mailer-specific rulesets.
        */
 
-       if (senderaddress)
        else
        else
+       {
        if (rwset > 0)
        if (rwset > 0)
-               rewrite(pvp, rwset);
+       {
+               if (rewrite(pvp, rwset, e) == EX_TEMPFAIL)
+                       *pstat = EX_TEMPFAIL;
+       }
 
        /*
        **  Do any final sanitation the address may require.
 
        /*
        **  Do any final sanitation the address may require.
@@ -1887,7 +1983,8 @@ remotename(name, m, senderaddress, header, canonical, adddomain, e)
        **      may be used as a default to the above rules.
        */
 
        **      may be used as a default to the above rules.
        */
 
-       rewrite(pvp, 4);
+       if (rewrite(pvp, 4, e) == EX_TEMPFAIL)
+               *pstat = EX_TEMPFAIL;
 
        /*
        **  Now restore the comment information we had at the beginning.
 
        /*
        **  Now restore the comment information we had at the beginning.
@@ -2003,12 +2100,12 @@ maplocaluser(a, sendq, e)
        if (pvp == NULL)
                return;
 
        if (pvp == NULL)
                return;
 
-       rewrite(pvp, 5);
+       (void) rewrite(pvp, 5, e);
        if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
                return;
 
        /* if non-null, mailer destination specified -- has it changed? */
        if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
                return;
 
        /* if non-null, mailer destination specified -- has it changed? */
-       a1 = buildaddr(pvp, NULL);
+       a1 = buildaddr(pvp, NULL, 0, e);
        if (a1 == NULL || sameaddr(a, a1))
                return;
 
        if (a1 == NULL || sameaddr(a, a1))
                return;
 
@@ -2020,7 +2117,7 @@ maplocaluser(a, sendq, e)
                printaddr(a, FALSE);
        }
        a1->q_alias = a;
                printaddr(a, FALSE);
        }
        a1->q_alias = a;
-       allocaddr(a1, 1, NULL, delimptr);
+       allocaddr(a1, RF_COPYALL, NULL);
        (void) recipient(a1, sendq, e);
 }
 \f/*
        (void) recipient(a1, sendq, e);
 }
 \f/*
@@ -2030,7 +2127,6 @@ maplocaluser(a, sendq, e)
 **
 **     Parameters:
 **             map -- the internal map structure.
 **
 **     Parameters:
 **             map -- the internal map structure.
-**             mapname -- the name of the mapl.
 **             args -- arguments.
 **
 **     Returns:
 **             args -- arguments.
 **
 **     Returns:
@@ -2038,9 +2134,8 @@ maplocaluser(a, sendq, e)
 */
 
 bool
 */
 
 bool
-dequote_init(map, mapname, args)
+dequote_init(map, args)
        MAP *map;
        MAP *map;
-       char *mapname;
        char *args;
 {
        register char *p = args;
        char *args;
 {
        register char *p = args;
@@ -2072,9 +2167,9 @@ dequote_init(map, mapname, args)
 **
 **     Parameters:
 **             map -- the internal map structure (ignored).
 **
 **     Parameters:
 **             map -- the internal map structure (ignored).
-**             buf -- the buffer to dequote.
-**             bufsiz -- the size of that buffer.
+**             name -- the name to dequote.
 **             av -- arguments (ignored).
 **             av -- arguments (ignored).
+**             statp -- pointer to status out-parameter.
 **
 **     Returns:
 **             NULL -- if there were no quotes, or if the resulting
 **
 **     Returns:
 **             NULL -- if there were no quotes, or if the resulting
@@ -2083,11 +2178,11 @@ dequote_init(map, mapname, args)
 */
 
 char *
 */
 
 char *
-dequote_map(map, buf, bufsiz, av)
+dequote_map(map, name, av, statp)
        MAP *map;
        MAP *map;
-       char buf[];
-       int bufsiz;
+       char *name;
        char **av;
        char **av;
+       int *statp;
 {
        register char *p;
        register char *q;
 {
        register char *p;
        register char *q;
@@ -2095,16 +2190,18 @@ dequote_map(map, buf, bufsiz, av)
        int anglecnt;
        int cmntcnt;
        int quotecnt;
        int anglecnt;
        int cmntcnt;
        int quotecnt;
+       int spacecnt;
        bool quotemode;
        bool bslashmode;
 
        anglecnt = 0;
        cmntcnt = 0;
        quotecnt = 0;
        bool quotemode;
        bool bslashmode;
 
        anglecnt = 0;
        cmntcnt = 0;
        quotecnt = 0;
+       spacecnt = 0;
        quotemode = FALSE;
        bslashmode = FALSE;
 
        quotemode = FALSE;
        bslashmode = FALSE;
 
-       for (p = q = buf; (c = *p++) != '\0'; )
+       for (p = q = name; (c = *p++) != '\0'; )
        {
                if (bslashmode)
                {
        {
                if (bslashmode)
                {
@@ -2127,6 +2224,10 @@ dequote_map(map, buf, bufsiz, av)
                        if (cmntcnt-- <= 0)
                                return NULL;
                        break;
                        if (cmntcnt-- <= 0)
                                return NULL;
                        break;
+
+                 case ' ':
+                       spacecnt++;
+                       break;
                }
 
                if (cmntcnt > 0)
                }
 
                if (cmntcnt > 0)
@@ -2155,8 +2256,8 @@ dequote_map(map, buf, bufsiz, av)
        }
 
        if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
        }
 
        if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
-           quotemode || quotecnt <= 0)
+           quotemode || quotecnt <= 0 || spacecnt != 0)
                return NULL;
        *q++ = '\0';
                return NULL;
        *q++ = '\0';
-       return buf;
+       return name;
 }
 }