📄 parseaddr.c
字号:
{ register char *ap; /* address pointer */ register char *rp; /* rewrite pointer */ register char **avp; /* address vector pointer */ register char **rvp; /* rewrite vector pointer */ register struct match *mlp; /* cur ptr into mlist */ register struct rewrite *rwr; /* pointer to current rewrite rule */ int ruleno; /* current rule number */ int rstat = EX_OK; /* return status */ int loopcount; struct match mlist[MAXMATCH]; /* stores match on LHS */ char *npvp[MAXATOM+1]; /* temporary space for rebuild */ if (OpMode == MD_TEST || tTd(21, 2)) { printf("rewrite: ruleset %2d input:", ruleset); printav(pvp); } if (ruleset < 0 || ruleset >= MAXRWSETS) { syserr("554 rewrite: illegal ruleset number %d", ruleset); return EX_CONFIG; } if (reclevel++ > MAXRULERECURSION) { syserr("rewrite: infinite recursion, ruleset %d", ruleset); return EX_CONFIG; } if (pvp == NULL) return EX_USAGE; /* ** Run through the list of rewrite rules, applying ** any that match. */ ruleno = 1; loopcount = 0; for (rwr = RewriteRules[ruleset]; rwr != NULL; ) { if (tTd(21, 12)) { printf("-----trying rule:"); printav(rwr->r_lhs); } /* try to match on this rule */ mlp = mlist; rvp = rwr->r_lhs; avp = pvp; if (++loopcount > 100) { syserr("554 Infinite loop in ruleset %d, rule %d", ruleset, ruleno); if (tTd(21, 1)) { printf("workspace: "); printav(pvp); } break; } while ((ap = *avp) != NULL || *rvp != NULL) { rp = *rvp; if (tTd(21, 35)) { printf("ADVANCE rp="); xputs(rp); printf(", ap="); xputs(ap); printf("\n"); } if (rp == NULL) { /* end-of-pattern before end-of-address */ goto backup; } if (ap == NULL && (*rp & 0377) != MATCHZANY && (*rp & 0377) != MATCHZERO) { /* end-of-input with patterns left */ goto backup; } switch (*rp & 0377) { register STAB *s; char buf[MAXLINE]; case MATCHCLASS: /* match any phrase in a class */ mlp->pattern = rvp; mlp->first = avp; extendclass: ap = *avp; if (ap == NULL) goto backup; mlp->last = avp++; cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); s = stab(buf, ST_CLASS, ST_FIND); if (s == NULL || !bitnset(rp[1], s->s_class)) { if (tTd(21, 36)) { printf("EXTEND rp="); xputs(rp); printf(", ap="); xputs(ap); printf("\n"); } goto extendclass; } if (tTd(21, 36)) printf("CLMATCH\n"); mlp++; break; case MATCHNCLASS: /* match any token not in a class */ s = stab(ap, ST_CLASS, ST_FIND); if (s != NULL && bitnset(rp[1], s->s_class)) goto backup; /* fall through */ case MATCHONE: case MATCHANY: /* match exactly one token */ mlp->pattern = rvp; mlp->first = avp; mlp->last = avp++; mlp++; break; case MATCHZANY: /* match zero or more tokens */ mlp->pattern = rvp; mlp->first = avp; mlp->last = avp - 1; mlp++; break; case MATCHZERO: /* match zero tokens */ break; case MACRODEXPAND: /* ** Match against run-time macro. ** This algorithm is broken for the ** general case (no recursive macros, ** improper tokenization) but should ** work for the usual cases. */ ap = macvalue(rp[1], e); mlp->first = avp; if (tTd(21, 2)) printf("rewrite: LHS $&%c => \"%s\"\n", rp[1], ap == NULL ? "(NULL)" : ap); if (ap == NULL) break; while (*ap != '\0') { if (*avp == NULL || strncasecmp(ap, *avp, strlen(*avp)) != 0) { /* no match */ avp = mlp->first; goto backup; } ap += strlen(*avp++); } /* match */ break; default: /* must have exact match */ if (strcasecmp(rp, ap)) goto backup; avp++; break; } /* successful match on this token */ rvp++; continue; backup: /* match failed -- back up */ while (--mlp >= mlist) { rvp = mlp->pattern; rp = *rvp; avp = mlp->last + 1; ap = *avp; if (tTd(21, 36)) { printf("BACKUP rp="); xputs(rp); printf(", ap="); xputs(ap); printf("\n"); } if (ap == NULL) { /* run off the end -- back up again */ continue; } if ((*rp & 0377) == MATCHANY || (*rp & 0377) == MATCHZANY) { /* extend binding and continue */ mlp->last = avp++; rvp++; mlp++; break; } if ((*rp & 0377) == MATCHCLASS) { /* extend binding and try again */ mlp->last = avp; goto extendclass; } } if (mlp < mlist) { /* total failure to match */ break; } } /* ** See if we successfully matched */ if (mlp < mlist || *rvp != NULL) { if (tTd(21, 10)) printf("----- rule fails\n"); rwr = rwr->r_next; ruleno++; loopcount = 0; continue; } rvp = rwr->r_rhs; if (tTd(21, 12)) { printf("-----rule matches:"); printav(rvp); } rp = *rvp; if ((*rp & 0377) == CANONUSER) { rvp++; rwr = rwr->r_next; ruleno++; loopcount = 0; } else if ((*rp & 0377) == CANONHOST) { rvp++; rwr = NULL; } else if ((*rp & 0377) == CANONNET) rwr = NULL; /* substitute */ for (avp = npvp; *rvp != NULL; rvp++) { register struct match *m; register char **pp; rp = *rvp; if ((*rp & 0377) == MATCHREPL) { /* substitute from LHS */ m = &mlist[rp[1] - '1']; if (m < mlist || m >= mlp) { syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", ruleset, rp[1]); return EX_CONFIG; } if (tTd(21, 15)) { printf("$%c:", rp[1]); pp = m->first; while (pp <= m->last) { printf(" %x=\"", *pp); (void) fflush(stdout); printf("%s\"", *pp++); } printf("\n"); } pp = m->first; while (pp <= m->last) { if (avp >= &npvp[MAXATOM]) { syserr("554 rewrite: expansion too long"); return EX_DATAERR; } *avp++ = *pp++; } } else { /* vanilla replacement */ if (avp >= &npvp[MAXATOM]) { toolong: syserr("554 rewrite: expansion too long"); return EX_DATAERR; } if ((*rp & 0377) != MACRODEXPAND) *avp++ = rp; else { *avp = macvalue(rp[1], e); if (tTd(21, 2)) printf("rewrite: RHS $&%c => \"%s\"\n", rp[1], *avp == NULL ? "(NULL)" : *avp); if (*avp != NULL) avp++; } } } *avp++ = NULL; /* ** Check for any hostname/keyword lookups. */ for (rvp = npvp; *rvp != NULL; rvp++) { char **hbrvp; char **xpvp; int trsize; char *replac; int endtoken; STAB *map; char *mapname; char **key_rvp; char **arg_rvp; char **default_rvp; char buf[MAXNAME + 1]; char *pvpb1[MAXATOM + 1]; char *argvect[10]; char pvpbuf[PSBUFSIZE]; char *nullpvp[1]; if ((**rvp & 0377) != HOSTBEGIN && (**rvp & 0377) != LOOKUPBEGIN) continue; /* ** Got a hostname/keyword lookup. ** ** This could be optimized fairly easily. */ hbrvp = rvp; if ((**rvp & 0377) == HOSTBEGIN) { endtoken = HOSTEND; mapname = "host"; } else { endtoken = LOOKUPEND; mapname = *++rvp; } map = stab(mapname, ST_MAP, ST_FIND); if (map == NULL) syserr("554 rewrite: map %s not found", mapname); /* extract the match part */ key_rvp = ++rvp; default_rvp = NULL; arg_rvp = argvect; xpvp = NULL; replac = pvpbuf; while (*rvp != NULL && (**rvp & 0377) != endtoken) { int nodetype = **rvp & 0377; if (nodetype != CANONHOST && nodetype != CANONUSER) { rvp++; continue; } *rvp++ = NULL; if (xpvp != NULL) { cataddr(xpvp, NULL, replac, &pvpbuf[sizeof pvpbuf] - replac, '\0'); *++arg_rvp = replac; replac += strlen(replac) + 1; xpvp = NULL; } switch (nodetype) { case CANONHOST: xpvp = rvp; break; case CANONUSER: default_rvp = rvp; break; } } if (*rvp != NULL) *rvp++ = NULL; if (xpvp != NULL) { cataddr(xpvp, NULL, replac, &pvpbuf[sizeof pvpbuf] - replac, '\0'); *++arg_rvp = replac; } *++arg_rvp = NULL; /* save the remainder of the input string */ trsize = (int) (avp - rvp + 1) * sizeof *rvp; bcopy((char *) rvp, (char *) pvpb1, trsize); /* look it up */ cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); argvect[0] = buf; if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) { auto int stat = EX_OK; /* XXX should try to auto-open the map here */ if (tTd(60, 1)) printf("map_lookup(%s, %s) => ", mapname, buf); replac = (*map->s_map.map_class->map_lookup)(&map->s_map, buf, argvect, &stat); if (tTd(60, 1)) printf("%s (%d)\n", replac ? replac : "NOT FOUND", stat); /* should recover if stat == EX_TEMPFAIL */ if (stat == EX_TEMPFAIL) rstat = stat; } else replac = NULL; /* if no replacement, use default */ if (replac == NULL && default_rvp != NULL) { /* create the default */ cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); replac = buf; } if (replac == NULL) { xpvp = key_rvp; } else if (*replac == '\0') { /* null replacement */ nullpvp[0] = NULL; xpvp = nullpvp; } else { /* scan the new replacement */ xpvp = prescan(replac, '\0', pvpbuf, sizeof pvpbuf, NULL); if (xpvp == NULL) { /* prescan already printed error */ return EX_DATAERR; } } /* append it to the token list */ for (avp = hbrvp; *xpvp != NULL; xpvp++) { *avp++ = newstr(*xpvp); if (avp >= &npvp[MAXATOM]) goto toolong; } /* restore the old trailing information */ for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) if (avp >= &npvp[MAXATOM]) goto toolong; break; } /* ** Check for subroutine calls. */ if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) { int stat; if (npvp[1] == NULL) { syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", ruleset, ruleno); *pvp = NULL; } else { bcopy((char *) &npvp[2], (char *) pvp, (int) (avp - npvp - 2) * sizeof *avp); if (tTd(21, 3)) printf("-----callsubr %s\n", npvp[1]); stat = rewrite(pvp, atoi(npvp[1]), reclevel, e); if (rstat == EX_OK || stat == EX_TEMPFAIL) rstat = stat; if (*pvp != NULL && (**pvp & 0377) == CANONNET) rwr = NULL; } } else { bcopy((char *) npvp, (char *) pvp, (int) (avp - npvp) * sizeof *avp); } if (tTd(21, 4)) { printf("rewritten as:"); printav(pvp); } } if (OpMode == MD_TEST || tTd(21, 2)) { printf("rewrite: ruleset %2d returns:", ruleset); printav(pvp); } return rstat;}/*** BUILDADDR -- build address from token vector.**** Parameters:** tv -- token vector.** a -- pointer to address descriptor to fill.** If NULL, one will be allocated.** flags -- info regarding whether this is a sender or** a recipient.** e -- the current envelope.**** Returns:** NULL if there was an error.** 'a' otherwise.**** Side Effects:** fills in 'a'*/struct errcodes{ char *ec_name; /* name of error code */ int ec_code; /* numeric code */} ErrorCodes[] ={ "usage", EX_USAGE, "nouser", EX_NOUSER, "nohost", EX_NOHOST, "unavailable", EX_UNAVAILABLE, "software", EX_SOFTWARE, "tempfail", EX_TEMPFAIL, "protocol", EX_PROTOCOL,#ifdef EX_CONFIG "config", EX_CONFIG,#endif NULL, EX_UNAVAILABLE,};ADDRESS *buildaddr(tv, a, flags, e) register char **tv; register ADDRESS *a; int flags; register ENVELOPE *e;{ struct mailer **mp; register struct mailer *m; char *bp; int spaceleft; static MAILER errormailer; static char *errorargv[] = { "ERROR", NULL }; static char buf[MAXNAME]; if (tTd(24, 5)) { printf("buildaddr, flags=%o, tv=", flags); printav(tv); } if (a == NULL) a = (ADDRESS *) xalloc(sizeof *a); bzero((char *) a, sizeof *a); /* figure out what net/mailer to use */ if (*tv == NULL || (**tv & 0377) != CANONNET) { syserr("554 buildaddr: no net");badaddr: a->q_flags |= QBADADDR; a->q_mailer = &errormailer; if (errormailer.m_name == NULL) { /* initialize the bogus mailer */ errormailer.m_name = "*error*"; errormailer.m_mailer = "ERROR"; errormailer.m_argv = errorargv; } return a; } tv++; if (strcasecmp(*tv, "error") == 0) { if ((**++tv & 0377) == CANONHOST) { register struct errcodes *ep; if (isascii(**++tv) && isdigit(**tv)) { setstat(atoi(*tv)); } else { for (ep = ErrorCodes; ep->ec_name != NULL; ep++) if (strcasecmp(ep->ec_name, *tv) == 0) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -