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
cataddr defined in line 952; used 4 times
rewrite defined in line 504; used 18 times
toktype defined in line 439; used 2 times

Defined variables

DelimChar defined in line 250; used 12 times
StateTab defined in line 238; used 1 times
sccsid defined in line 18; never used

Defined struct's

match defined in line 495; used 6 times

Defined macros

ATM defined in line 225; used 6 times
B defined in line 235; used 9 times
DELIMCHARS defined in line 62; used 1 times
M defined in line 234; used 3 times
MAXMATCH defined in line 501; used 1 times
MB defined in line 236; used 2 times
NOCHAR defined in line 248; used 7 times
NSTATES defined in line 230; used 2 times
  • in line 238(2)
ONE defined in line 228; used 4 times
OPR defined in line 224; used 11 times
QST defined in line 226; used 11 times
SPC defined in line 227; used 4 times
TYPE defined in line 231; used 1 times
Last modified: 1988-09-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6734
Valid CSS Valid XHTML 1.0 Strict