Annotation of 40BSD/cmd/delivermail/parse.c, revision 1.1.1.1

1.1       root        1: # include <stdio.h>
                      2: # include <ctype.h>
                      3: # include "dlvrmail.h"
                      4: 
                      5: static char    SccsId[] = "@(#)parse.c 1.7     10/21/80";
                      6: 
                      7: /*
                      8: **  PARSE -- Parse an address
                      9: **
                     10: **     Parses an address and breaks it up into three parts: a
                     11: **     net to transmit the message on, the host to transmit it
                     12: **     to, and a user on that host.  These are loaded into an
                     13: **     addrq header with the values squirreled away if necessary.
                     14: **     The "user" part may not be a real user; the process may
                     15: **     just reoccur on that machine.  For example, on a machine
                     16: **     with an arpanet connection, the address
                     17: **             csvax.bill@berkeley
                     18: **     will break up to a "user" of 'csvax.bill' and a host
                     19: **     of 'berkeley' -- to be transmitted over the arpanet.
                     20: **
                     21: **     Parameters:
                     22: **             addr -- the address to parse.
                     23: **             a -- a pointer to the address descriptor buffer.
                     24: **                     If NULL, a header will be created.
                     25: **             copyf -- determines what shall be copied:
                     26: **                     -1 -- don't copy anything.  The printname
                     27: **                             (q_paddr) is just addr, and the
                     28: **                             user & host are allocated internally
                     29: **                             to parse.
                     30: **                     0 -- copy out the parsed user & host, but
                     31: **                             don't copy the printname.
                     32: **                     +1 -- copy everything.
                     33: **
                     34: **     Returns:
                     35: **             A pointer to the address descriptor header (`a' if
                     36: **                     `a' is non-NULL).
                     37: **             NULL on error.
                     38: **
                     39: **     Side Effects:
                     40: **             none
                     41: **
                     42: **     Called By:
                     43: **             main
                     44: **             sendto
                     45: **             alias
                     46: **             savemail
                     47: */
                     48: 
                     49: addrq *
                     50: parse(addr, a, copyf)
                     51:        char *addr;
                     52:        register addrq *a;
                     53:        int copyf;
                     54: {
                     55:        register char *p;
                     56:        register struct parsetab *t;
                     57:        extern struct parsetab ParseTab[];
                     58:        static char buf[MAXNAME];
                     59:        register char c;
                     60:        register char *q;
                     61:        bool got_one;
                     62:        extern char *prescan();
                     63:        extern char *xalloc();
                     64:        char **pvp;
                     65: 
                     66:        /*
                     67:        **  Initialize and prescan address.
                     68:        */
                     69: 
                     70:        To = addr;
                     71:        if (prescan(addr, buf, &buf[sizeof buf], '\0') == NULL)
                     72:                return (NULL);
                     73: 
                     74:        /*
                     75:        **  Scan parse table.
                     76:        **      Look for the first entry designating a character
                     77:        **              that is contained in the address.
                     78:        **      Arrange for q to point to that character.
                     79:        **      Check to see that there is only one of the char
                     80:        **              if it must be unique.
                     81:        **      Find the last one if the host is on the RHS.
                     82:        **      Insist that the host name is atomic.
                     83:        **      If just doing a map, do the map and then start all
                     84:        **              over.
                     85:        */
                     86: 
                     87:  rescan:
                     88:        got_one = FALSE;
                     89:        for (t = ParseTab; t->p_char != '\0'; t++)
                     90:        {
                     91:                q = NULL;
                     92:                for (p = buf; (c = *p) != '\0'; p++)
                     93:                {
                     94:                        /* find the end of this token */
                     95:                        while (isalnum(c) || c == '-' || c == '_')
                     96:                                c = *++p;
                     97:                        if (c == '\0')
                     98:                                break;
                     99: 
                    100:                        if (c == t->p_char)
                    101:                        {
                    102:                                got_one = TRUE;
                    103: 
                    104:                                /* do mapping as appropriate */
                    105:                                if (flagset(P_MAP, t->p_flags))
                    106:                                {
                    107:                                        *p = t->p_arg[0];
                    108:                                        if (flagset(P_ONE, t->p_flags))
                    109:                                                goto rescan;
                    110:                                        else
                    111:                                                continue;
                    112:                                }
                    113: 
                    114:                                /* arrange for q to point to it */
                    115:                                if (q != NULL && flagset(P_ONE, t->p_flags))
                    116:                                {
                    117:                                        usrerr("multichar error");
                    118:                                        ExitStat = EX_USAGE;
                    119:                                        return (NULL);
                    120:                                }
                    121:                                if (q == NULL || flagset(P_HLAST, t->p_flags))
                    122:                                        q = p;
                    123:                        }
                    124:                        else
                    125:                        {
                    126:                                /* insist that host name is atomic */
                    127:                                if (flagset(P_HLAST, t->p_flags))
                    128:                                        q = NULL;
                    129:                                else
                    130:                                        break;
                    131:                        }
                    132:                }
                    133: 
                    134:                if (q != NULL)
                    135:                        break;
                    136:        }
                    137: 
                    138:        /*
                    139:        **  If we matched nothing cleanly, but we did match something
                    140:        **  somewhere in the process of scanning, then we have a
                    141:        **  syntax error.  This can happen on things like a@b:c where
                    142:        **  @ has a right host and : has a left host.
                    143:        **
                    144:        **  We also set `q' to the null string, in case someone forgets
                    145:        **  to put the P_MOVE bit in the local mailer entry of the
                    146:        **  configuration table.
                    147:        */
                    148: 
                    149:        if (q == NULL)
                    150:        {
                    151:                q = "";
                    152:                if (got_one)
                    153:                {
                    154:                        usrerr("syntax error");
                    155:                        ExitStat = EX_USAGE;
                    156:                        return (NULL);
                    157:                }
                    158:        }
                    159: 
                    160:        /*
                    161:        **  Interpret entry.
                    162:        **      t points to the entry for the mailer we will use.
                    163:        **      q points to the significant character.
                    164:        */
                    165: 
                    166:        if (a == NULL)
                    167:                a = (addrq *) xalloc(sizeof *a);
                    168:        if (copyf > 0)
                    169:        {
                    170:                p = xalloc((unsigned) strlen(addr) + 1);
                    171:                strcpy(p, addr);
                    172:                a->q_paddr = p;
                    173:        }
                    174:        else
                    175:                a->q_paddr = addr;
                    176:        a->q_mailer = &Mailer[t->p_mailer];
                    177: 
                    178:        if (flagset(P_MOVE, t->p_flags))
                    179:        {
                    180:                /* send the message to another host & retry */
                    181:                a->q_host = t->p_arg;
                    182:                if (copyf >= 0)
                    183:                {
                    184:                        p = xalloc((unsigned) strlen(buf) + 1);
                    185:                        strcpy(p, buf);
                    186:                        a->q_user = p;
                    187:                }
                    188:                else
                    189:                        a->q_user = buf;
                    190:        }
                    191:        else
                    192:        {
                    193:                /*
                    194:                **  Make local copies of the host & user and then
                    195:                **  transport them out.
                    196:                */
                    197: 
                    198:                *q++ = '\0';
                    199:                if (flagset(P_HLAST, t->p_flags))
                    200:                {
                    201:                        a->q_host = q;
                    202:                        a->q_user = buf;
                    203:                }
                    204:                else
                    205:                {
                    206:                        a->q_host = buf;
                    207:                        a->q_user = q;
                    208:                }
                    209: 
                    210:                /*
                    211:                **  Don't go to the net if already on the target host.
                    212:                **      This is important on the berkeley network, since
                    213:                **      it get confused if we ask to send to ourselves.
                    214:                **      For nets like the ARPANET, we probably will have
                    215:                **      the local list set to NULL to simplify testing.
                    216:                **      The canonical representation of the name is also set
                    217:                **      to be just the local name so the duplicate letter
                    218:                **      suppression algorithm will work.
                    219:                */
                    220: 
                    221:                if ((pvp = a->q_mailer->m_local) != NULL)
                    222:                {
                    223:                        while (*pvp != NULL)
                    224:                        {
                    225:                                auto char buf2[MAXNAME];
                    226: 
                    227:                                strcpy(buf2, a->q_host);
                    228:                                if (!flagset(P_HST_UPPER, t->p_flags))
                    229:                                        makelower(buf2);
                    230:                                if (strcmp(*pvp++, buf2) == 0)
                    231:                                {
                    232:                                        strcpy(buf2, a->q_user);
                    233:                                        p = a->q_paddr;
                    234:                                        if (parse(buf2, a, -1) == NULL)
                    235:                                        {
                    236:                                                To = addr;
                    237:                                                return (NULL);
                    238:                                        }
                    239:                                        To = a->q_paddr = p;
                    240:                                        break;
                    241:                                }
                    242:                        }
                    243:                }
                    244: 
                    245:                /* make copies if specified */
                    246:                if (copyf >= 0)
                    247:                {
                    248:                        p = xalloc((unsigned) strlen(a->q_host) + 1);
                    249:                        strcpy(p, a->q_host);
                    250:                        a->q_host = p;
                    251:                        p = xalloc((unsigned) strlen(a->q_user) + 1);
                    252:                        strcpy(p, a->q_user);
                    253:                        a->q_user = p;
                    254:                }
                    255:        }
                    256: 
                    257:        /*
                    258:        **  Do UPPER->lower case mapping unless inhibited.
                    259:        */
                    260: 
                    261:        if (!flagset(P_HST_UPPER, t->p_flags))
                    262:                makelower(a->q_host);
                    263:        if (!flagset(P_USR_UPPER, t->p_flags))
                    264:                makelower(a->q_user);
                    265: 
                    266:        /*
                    267:        **  Compute return value.
                    268:        */
                    269: 
                    270: # ifdef DEBUG
                    271:        if (Debug)
                    272:                printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n",
                    273:                    addr, a->q_host, a->q_user, t->p_mailer);
                    274: # endif DEBUG
                    275: 
                    276:        return (a);
                    277: }
                    278: /*
                    279: **  MAKELOWER -- Translate a line into lower case
                    280: **
                    281: **     Parameters:
                    282: **             p -- the string to translate.  If NULL, return is
                    283: **                     immediate.
                    284: **
                    285: **     Returns:
                    286: **             none.
                    287: **
                    288: **     Side Effects:
                    289: **             String pointed to by p is translated to lower case.
                    290: **
                    291: **     Called By:
                    292: **             parse
                    293: */
                    294: 
                    295: makelower(p)
                    296:        register char *p;
                    297: {
                    298:        register char c;
                    299: 
                    300:        if (p == NULL)
                    301:                return;
                    302:        for (; (c = *p) != '\0'; p++)
                    303:                if ((c & 0200) == 0 && isupper(c))
                    304:                        *p = c - 'A' + 'a';
                    305: }
                    306: /*
                    307: **  PRESCAN -- Prescan name and make it canonical
                    308: **
                    309: **     Scans a name and turns it into canonical form.  This involves
                    310: **     deleting blanks, comments (in parentheses), and turning the
                    311: **     word "at" into an at-sign ("@").  The name is copied as this
                    312: **     is done; it is legal to copy a name onto itself, since this
                    313: **     process can only make things smaller.
                    314: **
                    315: **     This routine knows about quoted strings and angle brackets.
                    316: **
                    317: **     There are certain subtleties to this routine.  The one that
                    318: **     comes to mind now is that backslashes on the ends of names
                    319: **     are silently stripped off; this is intentional.  The problem
                    320: **     is that some versions of sndmsg (like at LBL) set the kill
                    321: **     character to something other than @ when reading addresses;
                    322: **     so people type "csvax.eric\@berkeley" -- which screws up the
                    323: **     berknet mailer.
                    324: **
                    325: **     Parameters:
                    326: **             addr -- the name to chomp.
                    327: **             buf -- the buffer to copy it into.
                    328: **             buflim -- the last usable address in the buffer
                    329: **                     (which will old a null byte).  Normally
                    330: **                     &buf[sizeof buf - 1].
                    331: **             delim -- the delimiter for the address, normally
                    332: **                     '\0' or ','; \0 is accepted in any case.
                    333: **                     are moving in place; set buflim to high core.
                    334: **
                    335: **     Returns:
                    336: **             A pointer to the terminator of buf.
                    337: **             NULL on error.
                    338: **
                    339: **     Side Effects:
                    340: **             buf gets clobbered.
                    341: **
                    342: **     Called By:
                    343: **             parse
                    344: **             maketemp
                    345: */
                    346: 
                    347: char *
                    348: prescan(addr, buf, buflim, delim)
                    349:        char *addr;
                    350:        char *buf;
                    351:        char *buflim;
                    352:        char delim;
                    353: {
                    354:        register char *p;
                    355:        bool space;
                    356:        bool quotemode;
                    357:        bool bslashmode;
                    358:        int cmntcnt;
                    359:        int brccnt;
                    360:        register char c;
                    361:        register char *q;
                    362:        extern bool any();
                    363: 
                    364:        space = TRUE;
                    365:        q = buf;
                    366:        bslashmode = quotemode = FALSE;
                    367:        cmntcnt = brccnt = 0;
                    368:        for (p = addr; (c = *p++) != '\0'; )
                    369:        {
                    370:                /* chew up special characters */
                    371:                *q = '\0';
                    372:                if (bslashmode)
                    373:                {
                    374:                        c |= 0200;
                    375:                        bslashmode = FALSE;
                    376:                }
                    377:                else if (c == '"')
                    378:                        quotemode = !quotemode;
                    379:                else if (c == '\\')
                    380:                {
                    381:                        bslashmode++;
                    382:                        continue;
                    383:                }
                    384:                else if (quotemode)
                    385:                        c |= 0200;
                    386:                else if (c == delim)
                    387:                        break;
                    388:                else if (c == '(')
                    389:                {
                    390:                        cmntcnt++;
                    391:                        continue;
                    392:                }
                    393:                else if (c == ')')
                    394:                {
                    395:                        if (cmntcnt <= 0)
                    396:                        {
                    397:                                usrerr("Unbalanced ')'");
                    398:                                return (NULL);
                    399:                        }
                    400:                        else
                    401:                        {
                    402:                                cmntcnt--;
                    403:                                continue;
                    404:                        }
                    405:                }
                    406:                else if (c == '<')
                    407:                {
                    408:                        brccnt++;
                    409:                        if (brccnt == 1)
                    410:                        {
                    411:                                /* we prefer using machine readable name */
                    412:                                q = buf;
                    413:                                *q = '\0';
                    414:                                continue;
                    415:                        }
                    416:                }
                    417:                else if (c == '>')
                    418:                {
                    419:                        if (brccnt <= 0)
                    420:                        {
                    421:                                usrerr("Unbalanced `>'");
                    422:                                return (NULL);
                    423:                        }
                    424:                        else
                    425:                                brccnt--;
                    426:                        if (brccnt <= 0)
                    427:                                continue;
                    428:                }
                    429: 
                    430:                /*
                    431:                **  Turn "at" into "@",
                    432:                **      but only if "at" is a word.
                    433:                **      By the way, I violate the ARPANET RFC-733
                    434:                **      standard here, by assuming that 'space' delimits
                    435:                **      atoms.  I assume that is just a mistake, since
                    436:                **      it violates the spirit of the semantics
                    437:                **      of the document.....
                    438:                */
                    439: 
                    440:                if (space && (c == 'a' || c == 'A') &&
                    441:                    (p[0] == 't' || p[0] == 'T') &&
                    442:                    (any(p[1], "()<>@,;:\\\"") || p[1] <= 040))
                    443:                {
                    444:                        c = '@';
                    445:                        p++;
                    446:                }
                    447: 
                    448:                /* skip blanks */
                    449:                if (((c & 0200) != 0 || !isspace(c)) && cmntcnt <= 0)
                    450:                {
                    451:                        if (q >= buflim)
                    452:                        {
                    453:                                usrerr("Address too long");
                    454:                                return (NULL);
                    455:                        }
                    456:                        *q++ = c;
                    457:                }
                    458:                space = isspace(c);
                    459:        }
                    460:        *q = '\0';
                    461:        if (c == '\0')
                    462:                p--;
                    463:        if (cmntcnt > 0)
                    464:                usrerr("Unbalanced '('");
                    465:        else if (quotemode)
                    466:                usrerr("Unbalanced '\"'");
                    467:        else if (brccnt > 0)
                    468:                usrerr("Unbalanced '<'");
                    469:        else if (buf[0] != '\0')
                    470:                return (p);
                    471:        return (NULL);
                    472: }

unix.superglobalmegacorp.com

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