home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / parseaddr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  24.6 KB  |  1,188 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34.  
  35. #ifndef lint
  36. static char sccsid[] = "@(#)parseaddr.c    5.13 (Berkeley) 6/1/90";
  37. #endif /* not lint */
  38.  
  39. # include "sendmail.h"
  40.  
  41. /*
  42. **  PARSEADDR -- Parse an address
  43. **
  44. **    Parses an address and breaks it up into three parts: a
  45. **    net to transmit the message on, the host to transmit it
  46. **    to, and a user on that host.  These are loaded into an
  47. **    ADDRESS header with the values squirreled away if necessary.
  48. **    The "user" part may not be a real user; the process may
  49. **    just reoccur on that machine.  For example, on a machine
  50. **    with an arpanet connection, the address
  51. **        csvax.bill@berkeley
  52. **    will break up to a "user" of 'csvax.bill' and a host
  53. **    of 'berkeley' -- to be transmitted over the arpanet.
  54. **
  55. **    Parameters:
  56. **        addr -- the address to parse.
  57. **        a -- a pointer to the address descriptor buffer.
  58. **            If NULL, a header will be created.
  59. **        copyf -- determines what shall be copied:
  60. **            -1 -- don't copy anything.  The printname
  61. **                (q_paddr) is just addr, and the
  62. **                user & host are allocated internally
  63. **                to parse.
  64. **            0 -- copy out the parsed user & host, but
  65. **                don't copy the printname.
  66. **            +1 -- copy everything.
  67. **        delim -- the character to terminate the address, passed
  68. **            to prescan.
  69. **
  70. **    Returns:
  71. **        A pointer to the address descriptor header (`a' if
  72. **            `a' is non-NULL).
  73. **        NULL on error.
  74. **
  75. **    Side Effects:
  76. **        none
  77. */
  78.  
  79. /* following delimiters are inherent to the internal algorithms */
  80. # define DELIMCHARS    "\001()<>,;\\\"\r\n"    /* word delimiters */
  81.  
  82. ADDRESS *
  83. parseaddr(addr, a, copyf, delim)
  84.     char *addr;
  85.     register ADDRESS *a;
  86.     int copyf;
  87.     char delim;
  88. {
  89.     register char **pvp;
  90.     register struct mailer *m;
  91.     char pvpbuf[PSBUFSIZE];
  92.     extern char **prescan();
  93.     extern ADDRESS *buildaddr();
  94.  
  95.     /*
  96.     **  Initialize and prescan address.
  97.     */
  98.  
  99.     CurEnv->e_to = addr;
  100.     if (tTd(20, 1))
  101.         printf("\n--parseaddr(%s)\n", addr);
  102.  
  103.     pvp = prescan(addr, delim, pvpbuf);
  104.     if (pvp == NULL)
  105.         return (NULL);
  106.  
  107.     /*
  108.     **  Apply rewriting rules.
  109.     **    Ruleset 0 does basic parsing.  It must resolve.
  110.     */
  111.  
  112.     rewrite(pvp, 3);
  113.     rewrite(pvp, 0);
  114.  
  115.     /*
  116.     **  See if we resolved to a real mailer.
  117.     */
  118.  
  119.     if (pvp[0][0] != CANONNET)
  120.     {
  121.         setstat(EX_USAGE);
  122.         usrerr("cannot resolve name");
  123.         return (NULL);
  124.     }
  125.  
  126.     /*
  127.     **  Build canonical address from pvp.
  128.     */
  129.  
  130.     a = buildaddr(pvp, a);
  131.     if (a == NULL)
  132.         return (NULL);
  133.     m = a->q_mailer;
  134.  
  135.     /*
  136.     **  Make local copies of the host & user and then
  137.     **  transport them out.
  138.     */
  139.  
  140.     if (copyf > 0)
  141.     {
  142.         extern char *DelimChar;
  143.         char savec = *DelimChar;
  144.  
  145.         *DelimChar = '\0';
  146.         a->q_paddr = newstr(addr);
  147.         *DelimChar = savec;
  148.     }
  149.     else
  150.         a->q_paddr = addr;
  151.  
  152.     if (a->q_user == NULL)
  153.         a->q_user = "";
  154.     if (a->q_host == NULL)
  155.         a->q_host = "";
  156.  
  157.     if (copyf >= 0)
  158.     {
  159.         a->q_host = newstr(a->q_host);
  160.         if (a->q_user != a->q_paddr)
  161.             a->q_user = newstr(a->q_user);
  162.     }
  163.  
  164.     /*
  165.     **  Convert host name to lower case if requested.
  166.     **    User name will be done later.
  167.     */
  168.  
  169.     if (!bitnset(M_HST_UPPER, m->m_flags))
  170.         makelower(a->q_host);
  171.  
  172.     /*
  173.     **  Compute return value.
  174.     */
  175.  
  176.     if (tTd(20, 1))
  177.     {
  178.         printf("parseaddr-->");
  179.         printaddr(a, FALSE);
  180.     }
  181.  
  182.     return (a);
  183. }
  184. /*
  185. **  LOWERADDR -- map UPPER->lower case on addresses as requested.
  186. **
  187. **    Parameters:
  188. **        a -- address to be mapped.
  189. **
  190. **    Returns:
  191. **        none.
  192. **
  193. **    Side Effects:
  194. **        none.
  195. */
  196.  
  197. loweraddr(a)
  198.     register ADDRESS *a;
  199. {
  200.     register MAILER *m = a->q_mailer;
  201.  
  202.     if (!bitnset(M_USR_UPPER, m->m_flags))
  203.         makelower(a->q_user);
  204. }
  205. /*
  206. **  PRESCAN -- Prescan name and make it canonical
  207. **
  208. **    Scans a name and turns it into a set of tokens.  This process
  209. **    deletes blanks and comments (in parentheses).
  210. **
  211. **    This routine knows about quoted strings and angle brackets.
  212. **
  213. **    There are certain subtleties to this routine.  The one that
  214. **    comes to mind now is that backslashes on the ends of names
  215. **    are silently stripped off; this is intentional.  The problem
  216. **    is that some versions of sndmsg (like at LBL) set the kill
  217. **    character to something other than @ when reading addresses;
  218. **    so people type "csvax.eric\@berkeley" -- which screws up the
  219. **    berknet mailer.
  220. **
  221. **    Parameters:
  222. **        addr -- the name to chomp.
  223. **        delim -- the delimiter for the address, normally
  224. **            '\0' or ','; \0 is accepted in any case.
  225. **            If '\t' then we are reading the .cf file.
  226. **        pvpbuf -- place to put the saved text -- note that
  227. **            the pointers are static.
  228. **
  229. **    Returns:
  230. **        A pointer to a vector of tokens.
  231. **        NULL on error.
  232. **
  233. **    Side Effects:
  234. **        sets DelimChar to point to the character matching 'delim'.
  235. */
  236.  
  237. /* states and character types */
  238. # define OPR        0    /* operator */
  239. # define ATM        1    /* atom */
  240. # define QST        2    /* in quoted string */
  241. # define SPC        3    /* chewing up spaces */
  242. # define ONE        4    /* pick up one character */
  243.  
  244. # define NSTATES    5    /* number of states */
  245. # define TYPE        017    /* mask to select state type */
  246.  
  247. /* meta bits for table */
  248. # define M        020    /* meta character; don't pass through */
  249. # define B        040    /* cause a break */
  250. # define MB        M|B    /* meta-break */
  251.  
  252. static short StateTab[NSTATES][NSTATES] =
  253. {
  254.    /*    oldst    chtype>    OPR    ATM    QST    SPC    ONE    */
  255.     /*OPR*/        OPR|B,    ATM|B,    QST|B,    SPC|MB,    ONE|B,
  256.     /*ATM*/        OPR|B,    ATM,    QST|B,    SPC|MB,    ONE|B,
  257.     /*QST*/        QST,    QST,    OPR,    QST,    QST,
  258.     /*SPC*/        OPR,    ATM,    QST,    SPC|M,    ONE,
  259.     /*ONE*/        OPR,    OPR,    OPR,    OPR,    OPR,
  260. };
  261.  
  262. # define NOCHAR        -1    /* signal nothing in lookahead token */
  263.  
  264. char    *DelimChar;        /* set to point to the delimiter */
  265.  
  266. char **
  267. prescan(addr, delim, pvpbuf)
  268.     char *addr;
  269.     char delim;
  270.     char pvpbuf[];
  271. {
  272.     register char *p;
  273.     register char *q;
  274.     register int c;
  275.     char **avp;
  276.     bool bslashmode;
  277.     int cmntcnt;
  278.     int anglecnt;
  279.     char *tok;
  280.     int state;
  281.     int newstate;
  282.     static char *av[MAXATOM+1];
  283.     extern int errno;
  284.  
  285.     /* make sure error messages don't have garbage on them */
  286.     errno = 0;
  287.  
  288.     q = pvpbuf;
  289.     bslashmode = FALSE;
  290.     cmntcnt = 0;
  291.     anglecnt = 0;
  292.     avp = av;
  293.     state = OPR;
  294.     c = NOCHAR;
  295.     p = addr;
  296.     if (tTd(22, 45))
  297.     {
  298.         printf("prescan: ");
  299.         xputs(p);
  300.         (void) putchar('\n');
  301.     }
  302.  
  303.     do
  304.     {
  305.         /* read a token */
  306.         tok = q;
  307.         for (;;)
  308.         {
  309.             /* store away any old lookahead character */
  310.             if (c != NOCHAR)
  311.             {
  312.                 /* see if there is room */
  313.                 if (q >= &pvpbuf[PSBUFSIZE - 5])
  314.                 {
  315.                     usrerr("Address too long");
  316.                     DelimChar = p;
  317.                     return (NULL);
  318.                 }
  319.  
  320.                 /* squirrel it away */
  321.                 *q++ = c;
  322.             }
  323.  
  324.             /* read a new input character */
  325.             c = *p++;
  326.             if (c == '\0')
  327.                 break;
  328.             c &= ~0200;
  329.  
  330.             if (tTd(22, 101))
  331.                 printf("c=%c, s=%d; ", c, state);
  332.  
  333.             /* chew up special characters */
  334.             *q = '\0';
  335.             if (bslashmode)
  336.             {
  337.                 /* kludge \! for naive users */
  338.                 if (c != '!')
  339.                     c |= 0200;
  340.                 bslashmode = FALSE;
  341.             }
  342.             else if (c == '\\')
  343.             {
  344.                 bslashmode = TRUE;
  345.                 c = NOCHAR;
  346.             }
  347.             else if (state == QST)
  348.             {
  349.                 /* do nothing, just avoid next clauses */
  350.             }
  351.             else if (c == '(')
  352.             {
  353.                 cmntcnt++;
  354.                 c = NOCHAR;
  355.             }
  356.             else if (c == ')')
  357.             {
  358.                 if (cmntcnt <= 0)
  359.                 {
  360.                     usrerr("Unbalanced ')'");
  361.                     DelimChar = p;
  362.                     return (NULL);
  363.                 }
  364.                 else
  365.                     cmntcnt--;
  366.             }
  367.             else if (cmntcnt > 0)
  368.                 c = NOCHAR;
  369.             else if (c == '<')
  370.                 anglecnt++;
  371.             else if (c == '>')
  372.             {
  373.                 if (anglecnt <= 0)
  374.                 {
  375.                     usrerr("Unbalanced '>'");
  376.                     DelimChar = p;
  377.                     return (NULL);
  378.                 }
  379.                 anglecnt--;
  380.             }
  381.             else if (delim == ' ' && isspace(c))
  382.                 c = ' ';
  383.  
  384.             if (c == NOCHAR)
  385.                 continue;
  386.  
  387.             /* see if this is end of input */
  388.             if (c == delim && anglecnt <= 0 && state != QST)
  389.                 break;
  390.  
  391.             newstate = StateTab[state][toktype(c)];
  392.             if (tTd(22, 101))
  393.                 printf("ns=%02o\n", newstate);
  394.             state = newstate & TYPE;
  395.             if (bitset(M, newstate))
  396.                 c = NOCHAR;
  397.             if (bitset(B, newstate))
  398.                 break;
  399.         }
  400.  
  401.         /* new token */
  402.         if (tok != q)
  403.         {
  404.             *q++ = '\0';
  405.             if (tTd(22, 36))
  406.             {
  407.                 printf("tok=");
  408.                 xputs(tok);
  409.                 (void) putchar('\n');
  410.             }
  411.             if (avp >= &av[MAXATOM])
  412.             {
  413.                 syserr("prescan: too many tokens");
  414.                 DelimChar = p;
  415.                 return (NULL);
  416.             }
  417.             *avp++ = tok;
  418.         }
  419.     } while (c != '\0' && (c != delim || anglecnt > 0));
  420.     *avp = NULL;
  421.     DelimChar = --p;
  422.     if (cmntcnt > 0)
  423.         usrerr("Unbalanced '('");
  424.     else if (anglecnt > 0)
  425.         usrerr("Unbalanced '<'");
  426.     else if (state == QST)
  427.         usrerr("Unbalanced '\"'");
  428.     else if (av[0] != NULL)
  429.         return (av);
  430.     return (NULL);
  431. }
  432. /*
  433. **  TOKTYPE -- return token type
  434. **
  435. **    Parameters:
  436. **        c -- the character in question.
  437. **
  438. **    Returns:
  439. **        Its type.
  440. **
  441. **    Side Effects:
  442. **        none.
  443. */
  444.  
  445. toktype(c)
  446.     register char c;
  447. {
  448.     static char buf[50];
  449.     static bool firstime = TRUE;
  450.  
  451.     if (firstime)
  452.     {
  453.         firstime = FALSE;
  454.         expand("\001o", buf, &buf[sizeof buf - 1], CurEnv);
  455.         (void) strcat(buf, DELIMCHARS);
  456.     }
  457.     if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
  458.         return (ONE);
  459.     if (c == '"')
  460.         return (QST);
  461.     if (!isascii(c))
  462.         return (ATM);
  463.     if (isspace(c) || c == ')')
  464.         return (SPC);
  465.     if (iscntrl(c) || index(buf, c) != NULL)
  466.         return (OPR);
  467.     return (ATM);
  468. }
  469. /*
  470. **  REWRITE -- apply rewrite rules to token vector.
  471. **
  472. **    This routine is an ordered production system.  Each rewrite
  473. **    rule has a LHS (called the pattern) and a RHS (called the
  474. **    rewrite); 'rwr' points the the current rewrite rule.
  475. **
  476. **    For each rewrite rule, 'avp' points the address vector we
  477. **    are trying to match against, and 'pvp' points to the pattern.
  478. **    If pvp points to a special match value (MATCHZANY, MATCHANY,
  479. **    MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
  480. **    matched is saved away in the match vector (pointed to by 'mvp').
  481. **
  482. **    When a match between avp & pvp does not match, we try to
  483. **    back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
  484. **    we must also back out the match in mvp.  If we reach a
  485. **    MATCHANY or MATCHZANY we just extend the match and start
  486. **    over again.
  487. **
  488. **    When we finally match, we rewrite the address vector
  489. **    and try over again.
  490. **
  491. **    Parameters:
  492. **        pvp -- pointer to token vector.
  493. **
  494. **    Returns:
  495. **        none.
  496. **
  497. **    Side Effects:
  498. **        pvp is modified.
  499. */
  500.  
  501. struct match
  502. {
  503.     char    **first;    /* first token matched */
  504.     char    **last;        /* last token matched */
  505. };
  506.  
  507. # define MAXMATCH    9    /* max params per rewrite */
  508.  
  509.  
  510. rewrite(pvp, ruleset)
  511.     char **pvp;
  512.     int ruleset;
  513. {
  514.     register char *ap;        /* address pointer */
  515.     register char *rp;        /* rewrite pointer */
  516.     register char **avp;        /* address vector pointer */
  517.     register char **rvp;        /* rewrite vector pointer */
  518.     register struct match *mlp;    /* cur ptr into mlist */
  519.     register struct rewrite *rwr;    /* pointer to current rewrite rule */
  520.     struct match mlist[MAXMATCH];    /* stores match on LHS */
  521.     char *npvp[MAXATOM+1];        /* temporary space for rebuild */
  522.  
  523.     if (OpMode == MD_TEST || tTd(21, 2))
  524.     {
  525.         printf("rewrite: ruleset %2d   input:", ruleset);
  526.         printav(pvp);
  527.     }
  528.     if (pvp == NULL)
  529.         return;
  530.  
  531.     /*
  532.     **  Run through the list of rewrite rules, applying
  533.     **    any that match.
  534.     */
  535.  
  536.     for (rwr = RewriteRules[ruleset]; rwr != NULL; )
  537.     {
  538.         if (tTd(21, 12))
  539.         {
  540.             printf("-----trying rule:");
  541.             printav(rwr->r_lhs);
  542.         }
  543.  
  544.         /* try to match on this rule */
  545.         mlp = mlist;
  546.         rvp = rwr->r_lhs;
  547.         avp = pvp;
  548.         while ((ap = *avp) != NULL || *rvp != NULL)
  549.         {
  550.             rp = *rvp;
  551.             if (tTd(21, 35))
  552.             {
  553.                 printf("ap=");
  554.                 xputs(ap);
  555.                 printf(", rp=");
  556.                 xputs(rp);
  557.                 printf("\n");
  558.             }
  559.             if (rp == NULL)
  560.             {
  561.                 /* end-of-pattern before end-of-address */
  562.                 goto backup;
  563.             }
  564.             if (ap == NULL && *rp != MATCHZANY)
  565.             {
  566.                 /* end-of-input */
  567.                 break;
  568.             }
  569.  
  570.             switch (*rp)
  571.             {
  572.                 register STAB *s;
  573.  
  574.               case MATCHCLASS:
  575.               case MATCHNCLASS:
  576.                 /* match any token in (not in) a class */
  577.                 s = stab(ap, ST_CLASS, ST_FIND);
  578.                 if (s == NULL || !bitnset(rp[1], s->s_class))
  579.                 {
  580.                     if (*rp == MATCHCLASS)
  581.                         goto backup;
  582.                 }
  583.                 else if (*rp == MATCHNCLASS)
  584.                     goto backup;
  585.  
  586.                 /* explicit fall-through */
  587.  
  588.               case MATCHONE:
  589.               case MATCHANY:
  590.                 /* match exactly one token */
  591.                 mlp->first = avp;
  592.                 mlp->last = avp++;
  593.                 mlp++;
  594.                 break;
  595.  
  596.               case MATCHZANY:
  597.                 /* match zero or more tokens */
  598.                 mlp->first = avp;
  599.                 mlp->last = avp - 1;
  600.                 mlp++;
  601.                 break;
  602.  
  603.               default:
  604.                 /* must have exact match */
  605.                 if (strcasecmp(rp, ap))
  606.                     goto backup;
  607.                 avp++;
  608.                 break;
  609.             }
  610.  
  611.             /* successful match on this token */
  612.             rvp++;
  613.             continue;
  614.  
  615.           backup:
  616.             /* match failed -- back up */
  617.             while (--rvp >= rwr->r_lhs)
  618.             {
  619.                 rp = *rvp;
  620.                 if (*rp == MATCHANY || *rp == MATCHZANY)
  621.                 {
  622.                     /* extend binding and continue */
  623.                     avp = ++mlp[-1].last;
  624.                     avp++;
  625.                     rvp++;
  626.                     break;
  627.                 }
  628.                 avp--;
  629.                 if (*rp == MATCHONE || *rp == MATCHCLASS ||
  630.                     *rp == MATCHNCLASS)
  631.                 {
  632.                     /* back out binding */
  633.                     mlp--;
  634.                 }
  635.             }
  636.  
  637.             if (rvp < rwr->r_lhs)
  638.             {
  639.                 /* total failure to match */
  640.                 break;
  641.             }
  642.         }
  643.  
  644.         /*
  645.         **  See if we successfully matched
  646.         */
  647.  
  648.         if (rvp < rwr->r_lhs || *rvp != NULL)
  649.         {
  650.             if (tTd(21, 10))
  651.                 printf("----- rule fails\n");
  652.             rwr = rwr->r_next;
  653.             continue;
  654.         }
  655.  
  656.         rvp = rwr->r_rhs;
  657.         if (tTd(21, 12))
  658.         {
  659.             printf("-----rule matches:");
  660.             printav(rvp);
  661.         }
  662.  
  663.         rp = *rvp;
  664.         if (*rp == CANONUSER)
  665.         {
  666.             rvp++;
  667.             rwr = rwr->r_next;
  668.         }
  669.         else if (*rp == CANONHOST)
  670.         {
  671.             rvp++;
  672.             rwr = NULL;
  673.         }
  674.         else if (*rp == CANONNET)
  675.             rwr = NULL;
  676.  
  677.         /* substitute */
  678.         for (avp = npvp; *rvp != NULL; rvp++)
  679.         {
  680.             register struct match *m;
  681.             register char **pp;
  682.  
  683.             rp = *rvp;
  684.             if (*rp == MATCHREPL)
  685.             {
  686.                 /* substitute from LHS */
  687.                 m = &mlist[rp[1] - '1'];
  688.                 if (m >= mlp)
  689.                 {
  690.                     syserr("rewrite: ruleset %d: replacement out of bounds", ruleset);
  691.                     return;
  692.                 }
  693.                 if (tTd(21, 15))
  694.                 {
  695.                     printf("$%c:", rp[1]);
  696.                     pp = m->first;
  697.                     while (pp <= m->last)
  698.                     {
  699.                         printf(" %x=\"", *pp);
  700.                         (void) fflush(stdout);
  701.                         printf("%s\"", *pp++);
  702.                     }
  703.                     printf("\n");
  704.                 }
  705.                 pp = m->first;
  706.                 while (pp <= m->last)
  707.                 {
  708.                     if (avp >= &npvp[MAXATOM])
  709.                     {
  710.                         syserr("rewrite: expansion too long");
  711.                         return;
  712.                     }
  713.                     *avp++ = *pp++;
  714.                 }
  715.             }
  716.             else
  717.             {
  718.                 /* vanilla replacement */
  719.                 if (avp >= &npvp[MAXATOM])
  720.                 {
  721.     toolong:
  722.                     syserr("rewrite: expansion too long");
  723.                     return;
  724.                 }
  725.                 *avp++ = rp;
  726.             }
  727.         }
  728.         *avp++ = NULL;
  729.  
  730.         /*
  731.         **  Check for any hostname lookups.
  732.         */
  733.  
  734.         for (rvp = npvp; *rvp != NULL; rvp++)
  735.         {
  736.             char **hbrvp;
  737.             char **xpvp;
  738.             int trsize;
  739.             char *olddelimchar;
  740.             char buf[MAXNAME + 1];
  741.             char *pvpb1[MAXATOM + 1];
  742.             char pvpbuf[PSBUFSIZE];
  743.             extern char *DelimChar;
  744.  
  745.             if (**rvp != HOSTBEGIN)
  746.                 continue;
  747.  
  748.             /*
  749.             **  Got a hostname lookup.
  750.             **
  751.             **    This could be optimized fairly easily.
  752.             */
  753.  
  754.             hbrvp = rvp;
  755.  
  756.             /* extract the match part */
  757.             while (*++rvp != NULL && **rvp != HOSTEND)
  758.                 continue;
  759.             if (*rvp != NULL)
  760.                 *rvp++ = NULL;
  761.  
  762.             /* save the remainder of the input string */
  763.             trsize = (int) (avp - rvp + 1) * sizeof *rvp;
  764.             bcopy((char *) rvp, (char *) pvpb1, trsize);
  765.  
  766.             /* look it up */
  767.             cataddr(++hbrvp, buf, sizeof buf);
  768.             maphostname(buf, sizeof buf);
  769.  
  770.             /* scan the new host name */
  771.             olddelimchar = DelimChar;
  772.             xpvp = prescan(buf, '\0', pvpbuf);
  773.             DelimChar = olddelimchar;
  774.             if (xpvp == NULL)
  775.             {
  776.                 syserr("rewrite: cannot prescan canonical hostname: %s", buf);
  777.                 return;
  778.             }
  779.  
  780.             /* append it to the token list */
  781.             for (avp = --hbrvp; *xpvp != NULL; xpvp++)
  782.             {
  783.                 *avp++ = newstr(*xpvp);
  784.                 if (avp >= &npvp[MAXATOM])
  785.                     goto toolong;
  786.             }
  787.  
  788.             /* restore the old trailing information */
  789.             for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
  790.                 if (avp >= &npvp[MAXATOM])
  791.                     goto toolong;
  792.  
  793.             break;
  794.         }
  795.  
  796.         /*
  797.         **  Check for subroutine calls.
  798.         */
  799.  
  800.         if (*npvp != NULL && **npvp == CALLSUBR)
  801.         {
  802.             bcopy((char *) &npvp[2], (char *) pvp,
  803.                 (int) (avp - npvp - 2) * sizeof *avp);
  804.             if (tTd(21, 3))
  805.                 printf("-----callsubr %s\n", npvp[1]);
  806.             rewrite(pvp, atoi(npvp[1]));
  807.         }
  808.         else
  809.         {
  810.             bcopy((char *) npvp, (char *) pvp,
  811.                 (int) (avp - npvp) * sizeof *avp);
  812.         }
  813.         if (tTd(21, 4))
  814.         {
  815.             printf("rewritten as:");
  816.             printav(pvp);
  817.         }
  818.     }
  819.  
  820.     if (OpMode == MD_TEST || tTd(21, 2))
  821.     {
  822.         printf("rewrite: ruleset %2d returns:", ruleset);
  823.         printav(pvp);
  824.     }
  825. }
  826. /*
  827. **  BUILDADDR -- build address from token vector.
  828. **
  829. **    Parameters:
  830. **        tv -- token vector.
  831. **        a -- pointer to address descriptor to fill.
  832. **            If NULL, one will be allocated.
  833. **
  834. **    Returns:
  835. **        NULL if there was an error.
  836. **        'a' otherwise.
  837. **
  838. **    Side Effects:
  839. **        fills in 'a'
  840. */
  841.  
  842. ADDRESS *
  843. buildaddr(tv, a)
  844.     register char **tv;
  845.     register ADDRESS *a;
  846. {
  847.     static char buf[MAXNAME];
  848.     struct mailer **mp;
  849.     register struct mailer *m;
  850.  
  851.     if (a == NULL)
  852.         a = (ADDRESS *) xalloc(sizeof *a);
  853.     bzero((char *) a, sizeof *a);
  854.  
  855.     /* figure out what net/mailer to use */
  856.     if (**tv != CANONNET)
  857.     {
  858.         syserr("buildaddr: no net");
  859.         return (NULL);
  860.     }
  861.     tv++;
  862.     if (!strcasecmp(*tv, "error"))
  863.     {
  864.         if (**++tv == CANONHOST)
  865.         {
  866.             setstat(atoi(*++tv));
  867.             tv++;
  868.         }
  869.         if (**tv != CANONUSER)
  870.             syserr("buildaddr: error: no user");
  871.         buf[0] = '\0';
  872.         while (*++tv != NULL)
  873.         {
  874.             if (buf[0] != '\0')
  875.                 (void) strcat(buf, " ");
  876.             (void) strcat(buf, *tv);
  877.         }
  878.         usrerr(buf);
  879.         return (NULL);
  880.     }
  881.     for (mp = Mailer; (m = *mp++) != NULL; )
  882.     {
  883.         if (!strcasecmp(m->m_name, *tv))
  884.             break;
  885.     }
  886.     if (m == NULL)
  887.     {
  888.         syserr("buildaddr: unknown mailer %s", *tv);
  889.         return (NULL);
  890.     }
  891.     a->q_mailer = m;
  892.  
  893.     /* figure out what host (if any) */
  894.     tv++;
  895.     if (!bitnset(M_LOCAL, m->m_flags))
  896.     {
  897.         if (**tv++ != CANONHOST)
  898.         {
  899.             syserr("buildaddr: no host");
  900.             return (NULL);
  901.         }
  902.         buf[0] = '\0';
  903.         while (*tv != NULL && **tv != CANONUSER)
  904.             (void) strcat(buf, *tv++);
  905.         a->q_host = newstr(buf);
  906.     }
  907.     else
  908.         a->q_host = NULL;
  909.  
  910.     /* figure out the user */
  911.     if (*tv == NULL || **tv != CANONUSER)
  912.     {
  913.         syserr("buildaddr: no user");
  914.         return (NULL);
  915.     }
  916.  
  917.     /* rewrite according recipient mailer rewriting rules */
  918.     rewrite(++tv, 2);
  919.     if (m->m_r_rwset > 0)
  920.         rewrite(tv, m->m_r_rwset);
  921.     rewrite(tv, 4);
  922.  
  923.     /* save the result for the command line/RCPT argument */
  924.     cataddr(tv, buf, sizeof buf);
  925.     a->q_user = buf;
  926.  
  927.     return (a);
  928. }
  929. /*
  930. **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
  931. **
  932. **    Parameters:
  933. **        pvp -- parameter vector to rebuild.
  934. **        buf -- buffer to build the string into.
  935. **        sz -- size of buf.
  936. **
  937. **    Returns:
  938. **        none.
  939. **
  940. **    Side Effects:
  941. **        Destroys buf.
  942. */
  943.  
  944. cataddr(pvp, buf, sz)
  945.     char **pvp;
  946.     char *buf;
  947.     register int sz;
  948. {
  949.     bool oatomtok = FALSE;
  950.     bool natomtok = FALSE;
  951.     register int i;
  952.     register char *p;
  953.  
  954.     if (pvp == NULL)
  955.     {
  956.         (void) strcpy(buf, "");
  957.         return;
  958.     }
  959.     p = buf;
  960.     sz -= 2;
  961.     while (*pvp != NULL && (i = strlen(*pvp)) < sz)
  962.     {
  963.         natomtok = (toktype(**pvp) == ATM);
  964.         if (oatomtok && natomtok)
  965.             *p++ = SpaceSub;
  966.         (void) strcpy(p, *pvp);
  967.         oatomtok = natomtok;
  968.         p += i;
  969.         sz -= i + 1;
  970.         pvp++;
  971.     }
  972.     *p = '\0';
  973. }
  974. /*
  975. **  SAMEADDR -- Determine if two addresses are the same
  976. **
  977. **    This is not just a straight comparison -- if the mailer doesn't
  978. **    care about the host we just ignore it, etc.
  979. **
  980. **    Parameters:
  981. **        a, b -- pointers to the internal forms to compare.
  982. **
  983. **    Returns:
  984. **        TRUE -- they represent the same mailbox.
  985. **        FALSE -- they don't.
  986. **
  987. **    Side Effects:
  988. **        none.
  989. */
  990.  
  991. bool
  992. sameaddr(a, b)
  993.     register ADDRESS *a;
  994.     register ADDRESS *b;
  995. {
  996.     /* if they don't have the same mailer, forget it */
  997.     if (a->q_mailer != b->q_mailer)
  998.         return (FALSE);
  999.  
  1000.     /* if the user isn't the same, we can drop out */
  1001.     if (strcmp(a->q_user, b->q_user) != 0)
  1002.         return (FALSE);
  1003.  
  1004.     /* if the mailer ignores hosts, we have succeeded! */
  1005.     if (bitnset(M_LOCAL, a->q_mailer->m_flags))
  1006.         return (TRUE);
  1007.  
  1008.     /* otherwise compare hosts (but be careful for NULL ptrs) */
  1009.     if (a->q_host == NULL || b->q_host == NULL)
  1010.         return (FALSE);
  1011.     if (strcmp(a->q_host, b->q_host) != 0)
  1012.         return (FALSE);
  1013.  
  1014.     return (TRUE);
  1015. }
  1016. /*
  1017. **  PRINTADDR -- print address (for debugging)
  1018. **
  1019. **    Parameters:
  1020. **        a -- the address to print
  1021. **        follow -- follow the q_next chain.
  1022. **
  1023. **    Returns:
  1024. **        none.
  1025. **
  1026. **    Side Effects:
  1027. **        none.
  1028. */
  1029.  
  1030. printaddr(a, follow)
  1031.     register ADDRESS *a;
  1032.     bool follow;
  1033. {
  1034.     bool first = TRUE;
  1035.  
  1036.     while (a != NULL)
  1037.     {
  1038.         first = FALSE;
  1039.         printf("%x=", a);
  1040.         (void) fflush(stdout);
  1041.         printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n",
  1042.                a->q_paddr, a->q_mailer->m_mno, a->q_mailer->m_name,
  1043.                a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>");
  1044.         printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags,
  1045.                a->q_alias);
  1046.         printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home,
  1047.                a->q_fullname);
  1048.  
  1049.         if (!follow)
  1050.             return;
  1051.         a = a->q_next;
  1052.     }
  1053.     if (first)
  1054.         printf("[NULL]\n");
  1055. }
  1056.  
  1057. /*
  1058. **  REMOTENAME -- return the name relative to the current mailer
  1059. **
  1060. **    Parameters:
  1061. **        name -- the name to translate.
  1062. **        m -- the mailer that we want to do rewriting relative
  1063. **            to.
  1064. **        senderaddress -- if set, uses the sender rewriting rules
  1065. **            rather than the recipient rewriting rules.
  1066. **        canonical -- if set, strip out any comment information,
  1067. **            etc.
  1068. **
  1069. **    Returns:
  1070. **        the text string representing this address relative to
  1071. **            the receiving mailer.
  1072. **
  1073. **    Side Effects:
  1074. **        none.
  1075. **
  1076. **    Warnings:
  1077. **        The text string returned is tucked away locally;
  1078. **            copy it if you intend to save it.
  1079. */
  1080.  
  1081. char *
  1082. remotename(name, m, senderaddress, canonical)
  1083.     char *name;
  1084.     struct mailer *m;
  1085.     bool senderaddress;
  1086.     bool canonical;
  1087. {
  1088.     register char **pvp;
  1089.     char *fancy;
  1090.     extern char *macvalue();
  1091.     char *oldg = macvalue('g', CurEnv);
  1092.     static char buf[MAXNAME];
  1093.     char lbuf[MAXNAME];
  1094.     char pvpbuf[PSBUFSIZE];
  1095.     extern char **prescan();
  1096.     extern char *crackaddr();
  1097.  
  1098.     if (tTd(12, 1))
  1099.         printf("remotename(%s)\n", name);
  1100.  
  1101.     /* don't do anything if we are tagging it as special */
  1102.     if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0)
  1103.         return (name);
  1104.  
  1105.     /*
  1106.     **  Do a heuristic crack of this name to extract any comment info.
  1107.     **    This will leave the name as a comment and a $g macro.
  1108.     */
  1109.  
  1110.     if (canonical)
  1111.         fancy = "\001g";
  1112.     else
  1113.         fancy = crackaddr(name);
  1114.  
  1115.     /*
  1116.     **  Turn the name into canonical form.
  1117.     **    Normally this will be RFC 822 style, i.e., "user@domain".
  1118.     **    If this only resolves to "user", and the "C" flag is
  1119.     **    specified in the sending mailer, then the sender's
  1120.     **    domain will be appended.
  1121.     */
  1122.  
  1123.     pvp = prescan(name, '\0', pvpbuf);
  1124.     if (pvp == NULL)
  1125.         return (name);
  1126.     rewrite(pvp, 3);
  1127.     if (CurEnv->e_fromdomain != NULL)
  1128.     {
  1129.         /* append from domain to this address */
  1130.         register char **pxp = pvp;
  1131.  
  1132.         /* see if there is an "@domain" in the current name */
  1133.         while (*pxp != NULL && strcmp(*pxp, "@") != 0)
  1134.             pxp++;
  1135.         if (*pxp == NULL)
  1136.         {
  1137.             /* no.... append the "@domain" from the sender */
  1138.             register char **qxq = CurEnv->e_fromdomain;
  1139.  
  1140.             while ((*pxp++ = *qxq++) != NULL)
  1141.                 continue;
  1142.             rewrite(pvp, 3);
  1143.         }
  1144.     }
  1145.  
  1146.     /*
  1147.     **  Do more specific rewriting.
  1148.     **    Rewrite using ruleset 1 or 2 depending on whether this is
  1149.     **        a sender address or not.
  1150.     **    Then run it through any receiving-mailer-specific rulesets.
  1151.     */
  1152.  
  1153.     if (senderaddress)
  1154.     {
  1155.         rewrite(pvp, 1);
  1156.         if (m->m_s_rwset > 0)
  1157.             rewrite(pvp, m->m_s_rwset);
  1158.     }
  1159.     else
  1160.     {
  1161.         rewrite(pvp, 2);
  1162.         if (m->m_r_rwset > 0)
  1163.             rewrite(pvp, m->m_r_rwset);
  1164.     }
  1165.  
  1166.     /*
  1167.     **  Do any final sanitation the address may require.
  1168.     **    This will normally be used to turn internal forms
  1169.     **    (e.g., user@host.LOCAL) into external form.  This
  1170.     **    may be used as a default to the above rules.
  1171.     */
  1172.  
  1173.     rewrite(pvp, 4);
  1174.  
  1175.     /*
  1176.     **  Now restore the comment information we had at the beginning.
  1177.     */
  1178.  
  1179.     cataddr(pvp, lbuf, sizeof lbuf);
  1180.     define('g', lbuf, CurEnv);
  1181.     expand(fancy, buf, &buf[sizeof buf - 1], CurEnv);
  1182.     define('g', oldg, CurEnv);
  1183.  
  1184.     if (tTd(12, 1))
  1185.         printf("remotename => `%s'\n", buf);
  1186.     return (buf);
  1187. }
  1188.