# 2.11BSD#431 - /usr/src/usr.sbin/sendmail/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: **  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: #if !defined(lint) && !defined(NOSCCS)
      12: static char SccsId[] = "@(#)parseaddr.c	5.6 (Berkeley) 4/2/86";
      13: #endif
      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., user@host.LOCAL) 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: }

#### Defined functions

buildaddr defined in line 845; used 2 times

- in line 69, 108

cataddr defined in line 948; used 4 times

- in line 766, 928, 1188
- in /usr/src/usr.sbin/sendmail/src/envelope.c line 550

loweraddr defined in line 177; used 4 times

- in /usr/src/usr.sbin/sendmail/src/alias.c line 431
- in /usr/src/usr.sbin/sendmail/src/envelope.c line 484
- in /usr/src/usr.sbin/sendmail/src/recipient.c line 196
- in /usr/src/usr.sbin/sendmail/src/savemail.c line 416

parseaddr defined in line 58; used 11 times

- in /usr/src/usr.sbin/sendmail/src/alias.c line 426, 455
- in /usr/src/usr.sbin/sendmail/src/envelope.c line 463, 475-476(2)
- in /usr/src/usr.sbin/sendmail/src/recipient.c line 94
- in /usr/src/usr.sbin/sendmail/src/savemail.c line 84, 227, 409
- in /usr/src/usr.sbin/sendmail/src/sendmail.h line 577
- in /usr/src/usr.sbin/sendmail/src/srvrsmtp.c line 269

prescan defined in line 246; used 14 times

- in line 68, 81, 771, 1102, 1132
- in /usr/src/usr.sbin/sendmail/src/envelope.c line 419, 541
- in /usr/src/usr.sbin/sendmail/src/headers.c line 750-752(2)
- in /usr/src/usr.sbin/sendmail/src/main.c line 574-577(2)
- in /usr/src/usr.sbin/sendmail/src/readcf.c line 64, 132, 144

printaddr defined in line 1036; used 10 times

- in line 158
- in /usr/src/usr.sbin/sendmail/src/deliver.c line 212, 1302, 1410
- in /usr/src/usr.sbin/sendmail/src/queue.c line 149
- in /usr/src/usr.sbin/sendmail/src/recipient.c line 61, 176, 236
- in /usr/src/usr.sbin/sendmail/src/savemail.c line 376
- in /usr/src/usr.sbin/sendmail/src/srvrsmtp.c line 438

remotename defined in line 1088; used 6 times

- in /usr/src/usr.sbin/sendmail/src/deliver.c line 64, 119
- in /usr/src/usr.sbin/sendmail/src/headers.c line 730, 780
- in /usr/src/usr.sbin/sendmail/src/usersmtp.c line 240-242(2)

rewrite defined in line 498; used 18 times

- in line 90-91(2), 807, 922-925(3), 1135, 1151, 1164-1172(4), 1182
- in /usr/src/usr.sbin/sendmail/src/envelope.c line 547-549(3)
- in /usr/src/usr.sbin/sendmail/src/main.c line 580-584(2)

sameaddr defined in line 995; used 3 times

- in /usr/src/usr.sbin/sendmail/src/recipient.c line 107, 230
- in /usr/src/usr.sbin/sendmail/src/sendmail.h line 579

toktype defined in line 433; used 2 times

- in line 375, 967

#### Defined variables

DelimChar defined in line 244; used 12 times

- in line 120-125(4), 298, 345, 360, 402, 409, 742, 770-772(2)

SccsId defined in line 12; never used
StateTab defined in line 232; used 1 times

- in line 375

#### Defined struct's

match defined in line 489; used 6 times

- in line 506-508(4), 677(2)

#### Defined macros

ATM defined in line 219; used 6 times

- in line 235-238(3), 450-455(2), 967

B defined in line 229; used 9 times

- in line 230-236(8), 383

DELIMCHARS defined in line 56; used 1 times

- in line 443

M defined in line 228; used 3 times

- in line 230, 238, 381

MAXMATCH defined in line 495; used 1 times

- in line 508

MB defined in line 230; used 2 times

- in line 235-236(2)

NOCHAR defined in line 242; used 7 times

- in line 274, 292, 329, 338, 352, 368, 382

NSTATES defined in line 224; used 2 times

- in line 232(2)

ONE defined in line 222; used 4 times

- in line 235-238(3), 446

OPR defined in line 218; used 11 times

- in line 235-239(9), 273, 454

QST defined in line 220; used 11 times

- in line 235-238(7), 331, 372, 414, 448

SPC defined in line 221; used 4 times

- in line 235-238(3), 452

TYPE defined in line 225; used 1 times

- in line 380

Last modified: 1988-02-11 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3771 |