Annotation of 43BSD/usr.lib/sendmail/src/parseaddr.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.