# 2.11BSD#431 - /usr/src/usr.sbin/sendmail.MX/src/parseaddr.c

##### Functions

    buildaddr         X
    cataddr           X
    loweraddr         X
    parseaddr         X
    prescan           X
    printaddr         X
    remotename        X
    rewrite           X
    sameaddr          X
    toktype           X

##### Variables

    DelimChar         X

##### Macros

    ATM               X
    B                 X
    DELIMCHARS        X
    M                 X
    MAXMATCH          X
    MB                X
    NOCHAR            X
    NSTATES           X
    ONE               X
    OPR               X
    QST               X
    SPC               X
    TYPE              X

##### struct's

    match             X

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

#### Defined functions

buildaddr defined in line 850; used 2 times

- in line 75, 114

cataddr defined in line 952; used 4 times

- in line 771, 932, 1192
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 554

loweraddr defined in line 183; used 4 times

- in /usr/src/usr.sbin/sendmail.MX/src/alias.c line 431
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 490
- in /usr/src/usr.sbin/sendmail.MX/src/recipient.c line 189
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 422

parseaddr defined in line 64; used 11 times

- in /usr/src/usr.sbin/sendmail.MX/src/alias.c line 426, 455
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 469, 481-482(2)
- in /usr/src/usr.sbin/sendmail.MX/src/recipient.c line 89
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 90, 233, 415
- in /usr/src/usr.sbin/sendmail.MX/src/sendmail.h line 579
- in /usr/src/usr.sbin/sendmail.MX/src/srvrsmtp.c line 279

prescan defined in line 252; used 14 times

- in line 74, 87, 776, 1106, 1136
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 425, 545
- in /usr/src/usr.sbin/sendmail.MX/src/headers.c line 755-757(2)
- in /usr/src/usr.sbin/sendmail.MX/src/main.c line 570-573(2)
- in /usr/src/usr.sbin/sendmail.MX/src/readcf.c line 70, 138, 150

printaddr defined in line 1040; used 10 times

- in line 164
- in /usr/src/usr.sbin/sendmail.MX/src/deliver.c line 232, 1357, 1459
- in /usr/src/usr.sbin/sendmail.MX/src/queue.c line 160
- in /usr/src/usr.sbin/sendmail.MX/src/recipient.c line 64, 169, 229
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 382
- in /usr/src/usr.sbin/sendmail.MX/src/srvrsmtp.c line 448

remotename defined in line 1092; used 6 times

- in /usr/src/usr.sbin/sendmail.MX/src/deliver.c line 78, 139
- in /usr/src/usr.sbin/sendmail.MX/src/headers.c line 735, 785
- in /usr/src/usr.sbin/sendmail.MX/src/usersmtp.c line 245-247(2)

rewrite defined in line 504; used 18 times

- in line 96-97(2), 812, 926-929(3), 1139, 1155, 1168-1176(4), 1186
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 551-553(3)
- in /usr/src/usr.sbin/sendmail.MX/src/main.c line 576-580(2)

sameaddr defined in line 999; used 3 times

- in /usr/src/usr.sbin/sendmail.MX/src/recipient.c line 102, 223
- in /usr/src/usr.sbin/sendmail.MX/src/sendmail.h line 581

toktype defined in line 439; used 2 times

- in line 381, 971

#### Defined variables

DelimChar defined in line 250; used 12 times

- in line 126-131(4), 304, 351, 366, 408, 415, 747, 775-777(2)

StateTab defined in line 238; used 1 times

- in line 381

sccsid defined in line 18; never used

#### Defined struct's

match defined in line 495; used 6 times

- in line 512-514(4), 682(2)

#### Defined macros

ATM defined in line 225; used 6 times

- in line 241-244(3), 456-461(2), 971

B defined in line 235; used 9 times

- in line 236-242(8), 389

DELIMCHARS defined in line 62; used 1 times

- in line 449

M defined in line 234; used 3 times

- in line 236, 244, 387

MAXMATCH defined in line 501; used 1 times

- in line 514

MB defined in line 236; used 2 times

- in line 241-242(2)

NOCHAR defined in line 248; used 7 times

- in line 280, 298, 335, 344, 358, 374, 388

NSTATES defined in line 230; used 2 times

- in line 238(2)

ONE defined in line 228; used 4 times

- in line 241-244(3), 452

OPR defined in line 224; used 11 times

- in line 241-245(9), 279, 460

QST defined in line 226; used 11 times

- in line 241-244(7), 337, 378, 420, 454

SPC defined in line 227; used 4 times

- in line 241-244(3), 458

TYPE defined in line 231; used 1 times

- in line 386

Last modified: 1988-09-14 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3362 |