diff options
author | rsc <devnull@localhost> | 2005-10-29 16:26:44 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-10-29 16:26:44 +0000 |
commit | 5cdb17983ae6e6367ad7a940cb219eab247a9304 (patch) | |
tree | 8ca1ef49af2a96e7daebe624d91fdf679814a057 /src/cmd/upas/send/rewrite.c | |
parent | cd3745196389579fb78b9b01ef1daefb5a57aa71 (diff) | |
download | plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.tar.gz plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.tar.bz2 plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.zip |
Thanks to John Cummings.
Diffstat (limited to 'src/cmd/upas/send/rewrite.c')
-rw-r--r-- | src/cmd/upas/send/rewrite.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/src/cmd/upas/send/rewrite.c b/src/cmd/upas/send/rewrite.c new file mode 100644 index 00000000..4f40b293 --- /dev/null +++ b/src/cmd/upas/send/rewrite.c @@ -0,0 +1,315 @@ +#include "common.h" +#include "send.h" + +extern int debug; + +/* + * Routines for dealing with the rewrite rules. + */ + +/* globals */ +typedef struct rule rule; + +#define NSUBEXP 10 +struct rule { + String *matchre; /* address match */ + String *repl1; /* first replacement String */ + String *repl2; /* second replacement String */ + d_status type; /* type of rule */ + Reprog *program; + Resub subexp[NSUBEXP]; + rule *next; +}; +static rule *rulep; +static rule *rlastp; + +/* predeclared */ +static String *substitute(String *, Resub *, message *); +static rule *findrule(String *, int); + + +/* + * Get the next token from `line'. The symbol `\l' is replaced by + * the name of the local system. + */ +extern String * +rule_parse(String *line, char *system, int *backl) +{ + String *token; + String *expanded; + char *cp; + + token = s_parse(line, 0); + if(token == 0) + return(token); + if(strchr(s_to_c(token), '\\')==0) + return(token); + expanded = s_new(); + for(cp = s_to_c(token); *cp; cp++) { + if(*cp == '\\') switch(*++cp) { + case 'l': + s_append(expanded, system); + *backl = 1; + break; + case '\\': + s_putc(expanded, '\\'); + break; + default: + s_putc(expanded, '\\'); + s_putc(expanded, *cp); + break; + } else + s_putc(expanded, *cp); + } + s_free(token); + s_terminate(expanded); + return(expanded); +} + +static int +getrule(String *line, String *type, char *system) +{ + rule *rp; + String *re; + int backl; + + backl = 0; + + /* get a rule */ + re = rule_parse(s_restart(line), system, &backl); + if(re == 0) + return 0; + rp = (rule *)malloc(sizeof(rule)); + if(rp == 0) { + perror("getrules:"); + exit(1); + } + rp->next = 0; + s_tolower(re); + rp->matchre = s_new(); + s_append(rp->matchre, s_to_c(re)); + s_restart(rp->matchre); + s_free(re); + s_parse(line, s_restart(type)); + rp->repl1 = rule_parse(line, system, &backl); + rp->repl2 = rule_parse(line, system, &backl); + rp->program = 0; + if(strcmp(s_to_c(type), "|") == 0) + rp->type = d_pipe; + else if(strcmp(s_to_c(type), ">>") == 0) + rp->type = d_cat; + else if(strcmp(s_to_c(type), "alias") == 0) + rp->type = d_alias; + else if(strcmp(s_to_c(type), "translate") == 0) + rp->type = d_translate; + else if(strcmp(s_to_c(type), "auth") == 0) + rp->type = d_auth; + else { + s_free(rp->matchre); + s_free(rp->repl1); + s_free(rp->repl2); + free((char *)rp); + fprint(2,"illegal rewrite rule: %s\n", s_to_c(line)); + return 0; + } + if(rulep == 0) + rulep = rlastp = rp; + else + rlastp = rlastp->next = rp; + return backl; +} + +/* + * rules are of the form: + * <reg exp> <String> <repl exp> [<repl exp>] + */ +extern int +getrules(void) +{ + Biobuf *rfp; + String *line; + String *type; + String *file; + + file = abspath("rewrite", unsharp(UPASLIB), (String *)0); + rfp = sysopen(s_to_c(file), "r", 0); + if(rfp == 0) { + rulep = 0; + return -1; + } + rlastp = 0; + line = s_new(); + type = s_new(); + while(s_getline(rfp, s_restart(line))) + if(getrule(line, type, thissys) && altthissys) + getrule(s_restart(line), type, altthissys); + s_free(type); + s_free(line); + s_free(file); + sysclose(rfp); + return 0; +} + +/* look up a matching rule */ +static rule * +findrule(String *addrp, int authorized) +{ + rule *rp; + static rule defaultrule; + + if(rulep == 0) + return &defaultrule; + for (rp = rulep; rp != 0; rp = rp->next) { + if(rp->type==d_auth && authorized) + continue; + if(rp->program == 0) + rp->program = regcomp(rp->matchre->base); + if(rp->program == 0) + continue; + memset(rp->subexp, 0, sizeof(rp->subexp)); + if(debug) + print("matching %s aginst %s\n", s_to_c(addrp), rp->matchre->base); + if(regexec(rp->program, s_to_c(addrp), rp->subexp, NSUBEXP)) + if(s_to_c(addrp) == rp->subexp[0].s.sp) + if((s_to_c(addrp) + strlen(s_to_c(addrp))) == rp->subexp[0].e.ep) + return rp; + } + return 0; +} + +/* Transforms the address into a command. + * Returns: -1 ifaddress not matched by reules + * 0 ifaddress matched and ok to forward + * 1 ifaddress matched and not ok to forward + */ +extern int +rewrite(dest *dp, message *mp) +{ + rule *rp; /* rewriting rule */ + String *lower; /* lower case version of destination */ + + /* + * Rewrite the address. Matching is case insensitive. + */ + lower = s_clone(dp->addr); + s_tolower(s_restart(lower)); + rp = findrule(lower, dp->authorized); + if(rp == 0){ + s_free(lower); + return -1; + } + strcpy(s_to_c(lower), s_to_c(dp->addr)); + dp->repl1 = substitute(rp->repl1, rp->subexp, mp); + dp->repl2 = substitute(rp->repl2, rp->subexp, mp); + dp->status = rp->type; + if(debug){ + print("\t->"); + if(dp->repl1) + print("%s", s_to_c(dp->repl1)); + if(dp->repl2) + print("%s", s_to_c(dp->repl2)); + print("\n"); + } + s_free(lower); + return 0; +} + +static String * +substitute(String *source, Resub *subexp, message *mp) +{ + int i; + char *s; + char *sp; + String *stp; + + if(source == 0) + return 0; + sp = s_to_c(source); + + /* someplace to put it */ + stp = s_new(); + + /* do the substitution */ + while (*sp != '\0') { + if(*sp == '\\') { + switch (*++sp) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + i = *sp-'0'; + if(subexp[i].s.sp != 0) + for (s = subexp[i].s.sp; + s < subexp[i].e.ep; + s++) + s_putc(stp, *s); + break; + case '\\': + s_putc(stp, '\\'); + break; + case '\0': + sp--; + break; + case 's': + for(s = s_to_c(mp->replyaddr); *s; s++) + s_putc(stp, *s); + break; + case 'p': + if(mp->bulk) + s = "bulk"; + else + s = "normal"; + for(;*s; s++) + s_putc(stp, *s); + break; + default: + s_putc(stp, *sp); + break; + } + } else if(*sp == '&') { + if(subexp[0].s.sp != 0) + for (s = subexp[0].s.sp; + s < subexp[0].e.ep; s++) + s_putc(stp, *s); + } else + s_putc(stp, *sp); + sp++; + } + s_terminate(stp); + + return s_restart(stp); +} + +extern void +regerror(char* s) +{ + fprint(2, "rewrite: %s\n", s); +} + +extern void +dumprules(void) +{ + rule *rp; + + for (rp = rulep; rp != 0; rp = rp->next) { + fprint(2, "'%s'", rp->matchre->base); + switch (rp->type) { + case d_pipe: + fprint(2, " |"); + break; + case d_cat: + fprint(2, " >>"); + break; + case d_alias: + fprint(2, " alias"); + break; + case d_translate: + fprint(2, " translate"); + break; + default: + fprint(2, " UNKNOWN"); + break; + } + fprint(2, " '%s'", rp->repl1 ? rp->repl1->base:"..."); + fprint(2, " '%s'\n", rp->repl2 ? rp->repl2->base:"..."); + } +} + |