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
cataddr defined in line 948; used 4 times
rewrite defined in line 498; used 18 times
toktype defined in line 433; used 2 times

Defined variables

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

Defined struct's

match defined in line 489; used 6 times

Defined macros

ATM defined in line 219; used 6 times
B defined in line 229; used 9 times
DELIMCHARS defined in line 56; used 1 times
M defined in line 228; used 3 times
MAXMATCH defined in line 495; used 1 times
MB defined in line 230; used 2 times
NOCHAR defined in line 242; used 7 times
NSTATES defined in line 224; used 2 times
  • in line 232(2)
ONE defined in line 222; used 4 times
OPR defined in line 218; used 11 times
QST defined in line 220; used 11 times
SPC defined in line 221; used 4 times
TYPE defined in line 225; used 1 times
Last modified: 1988-02-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6045
Valid CSS Valid XHTML 1.0 Strict