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

Defined functions

buildaddr defined in line 718; never used
cataddr defined in line 814; used 3 times
rewrite defined in line 450; used 16 times
toktype defined in line 385; used 2 times

Defined variables

DelimChar defined in line 205; used 9 times
StateTab defined in line 193; used 1 times

Defined struct's

match defined in line 441; used 6 times

Defined macros

ATM defined in line 180; used 6 times
B defined in line 190; used 9 times
DELIMCHARS defined in line 44; used 1 times
M defined in line 189; used 3 times
MAXMATCH defined in line 447; used 1 times
MB defined in line 191; used 2 times
NOCHAR defined in line 203; used 7 times
NSTATES defined in line 185; used 2 times
  • in line 193(2)
ONE defined in line 183; used 4 times
OPR defined in line 179; used 11 times
QST defined in line 181; used 11 times
SPC defined in line 182; used 4 times
TYPE defined in line 186; used 1 times
Last modified: 1983-12-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2429
Valid CSS Valid XHTML 1.0 Strict