xref: /plan9/sys/src/cmd/upas/send/rewrite.c (revision c6569576083e48cef148efbb162a33bacec4ce98)
13e12c5d1SDavid du Colombier #include "common.h"
23e12c5d1SDavid du Colombier #include "send.h"
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier extern int debug;
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier /*
73e12c5d1SDavid du Colombier  *	Routines for dealing with the rewrite rules.
83e12c5d1SDavid du Colombier  */
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier /* globals */
113e12c5d1SDavid du Colombier typedef struct rule rule;
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier #define NSUBEXP 10
143e12c5d1SDavid du Colombier struct rule {
153e12c5d1SDavid du Colombier 	String *matchre;	/* address match */
163e12c5d1SDavid du Colombier 	String *repl1;		/* first replacement String */
173e12c5d1SDavid du Colombier 	String *repl2;		/* second replacement String */
183e12c5d1SDavid du Colombier 	d_status type;		/* type of rule */
193e12c5d1SDavid du Colombier 	Reprog *program;
203e12c5d1SDavid du Colombier 	Resub subexp[NSUBEXP];
213e12c5d1SDavid du Colombier 	rule *next;
223e12c5d1SDavid du Colombier };
233e12c5d1SDavid du Colombier static rule *rulep;
24219b2ee8SDavid du Colombier static rule *rlastp;
253e12c5d1SDavid du Colombier 
263e12c5d1SDavid du Colombier /* predeclared */
277dd7cddfSDavid du Colombier static String *substitute(String *, Resub *, message *);
283e12c5d1SDavid du Colombier static rule *findrule(String *, int);
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier /*
323e12c5d1SDavid du Colombier  *  Get the next token from `line'.  The symbol `\l' is replaced by
333e12c5d1SDavid du Colombier  *  the name of the local system.
343e12c5d1SDavid du Colombier  */
353e12c5d1SDavid du Colombier extern String *
rule_parse(String * line,char * system,int * backl)36219b2ee8SDavid du Colombier rule_parse(String *line, char *system, int *backl)
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 	String *token;
393e12c5d1SDavid du Colombier 	String *expanded;
403e12c5d1SDavid du Colombier 	char *cp;
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier 	token = s_parse(line, 0);
433e12c5d1SDavid du Colombier 	if(token == 0)
443e12c5d1SDavid du Colombier 		return(token);
453e12c5d1SDavid du Colombier 	if(strchr(s_to_c(token), '\\')==0)
463e12c5d1SDavid du Colombier 		return(token);
473e12c5d1SDavid du Colombier 	expanded = s_new();
483e12c5d1SDavid du Colombier 	for(cp = s_to_c(token); *cp; cp++) {
493e12c5d1SDavid du Colombier 		if(*cp == '\\') switch(*++cp) {
503e12c5d1SDavid du Colombier 		case 'l':
51219b2ee8SDavid du Colombier 			s_append(expanded, system);
52219b2ee8SDavid du Colombier 			*backl = 1;
533e12c5d1SDavid du Colombier 			break;
543e12c5d1SDavid du Colombier 		case '\\':
553e12c5d1SDavid du Colombier 			s_putc(expanded, '\\');
563e12c5d1SDavid du Colombier 			break;
573e12c5d1SDavid du Colombier 		default:
583e12c5d1SDavid du Colombier 			s_putc(expanded, '\\');
593e12c5d1SDavid du Colombier 			s_putc(expanded, *cp);
603e12c5d1SDavid du Colombier 			break;
613e12c5d1SDavid du Colombier 		} else
623e12c5d1SDavid du Colombier 			s_putc(expanded, *cp);
633e12c5d1SDavid du Colombier 	}
643e12c5d1SDavid du Colombier 	s_free(token);
653e12c5d1SDavid du Colombier 	s_terminate(expanded);
663e12c5d1SDavid du Colombier 	return(expanded);
673e12c5d1SDavid du Colombier }
683e12c5d1SDavid du Colombier 
69219b2ee8SDavid du Colombier static int
getrule(String * line,String * type,char * system)70219b2ee8SDavid du Colombier getrule(String *line, String *type, char *system)
713e12c5d1SDavid du Colombier {
72219b2ee8SDavid du Colombier 	rule	*rp;
733e12c5d1SDavid du Colombier 	String	*re;
74219b2ee8SDavid du Colombier 	int	backl;
753e12c5d1SDavid du Colombier 
76219b2ee8SDavid du Colombier 	backl = 0;
77219b2ee8SDavid du Colombier 
783e12c5d1SDavid du Colombier 	/* get a rule */
79219b2ee8SDavid du Colombier 	re = rule_parse(s_restart(line), system, &backl);
80219b2ee8SDavid du Colombier 	if(re == 0)
81219b2ee8SDavid du Colombier 		return 0;
823e12c5d1SDavid du Colombier 	rp = (rule *)malloc(sizeof(rule));
833e12c5d1SDavid du Colombier 	if(rp == 0) {
843e12c5d1SDavid du Colombier 		perror("getrules:");
853e12c5d1SDavid du Colombier 		exit(1);
863e12c5d1SDavid du Colombier 	}
873e12c5d1SDavid du Colombier 	rp->next = 0;
883e12c5d1SDavid du Colombier 	s_tolower(re);
893e12c5d1SDavid du Colombier 	rp->matchre = s_new();
903e12c5d1SDavid du Colombier 	s_append(rp->matchre, s_to_c(re));
919a747e4fSDavid du Colombier 	s_restart(rp->matchre);
923e12c5d1SDavid du Colombier 	s_free(re);
933e12c5d1SDavid du Colombier 	s_parse(line, s_restart(type));
94219b2ee8SDavid du Colombier 	rp->repl1 = rule_parse(line, system, &backl);
95219b2ee8SDavid du Colombier 	rp->repl2 = rule_parse(line, system, &backl);
963e12c5d1SDavid du Colombier 	rp->program = 0;
973e12c5d1SDavid du Colombier 	if(strcmp(s_to_c(type), "|") == 0)
983e12c5d1SDavid du Colombier 		rp->type = d_pipe;
993e12c5d1SDavid du Colombier 	else if(strcmp(s_to_c(type), ">>") == 0)
1003e12c5d1SDavid du Colombier 		rp->type = d_cat;
1013e12c5d1SDavid du Colombier 	else if(strcmp(s_to_c(type), "alias") == 0)
1023e12c5d1SDavid du Colombier 		rp->type = d_alias;
1033e12c5d1SDavid du Colombier 	else if(strcmp(s_to_c(type), "translate") == 0)
1043e12c5d1SDavid du Colombier 		rp->type = d_translate;
1053e12c5d1SDavid du Colombier 	else if(strcmp(s_to_c(type), "auth") == 0)
1063e12c5d1SDavid du Colombier 		rp->type = d_auth;
1073e12c5d1SDavid du Colombier 	else {
1083e12c5d1SDavid du Colombier 		s_free(rp->matchre);
1093e12c5d1SDavid du Colombier 		s_free(rp->repl1);
1103e12c5d1SDavid du Colombier 		s_free(rp->repl2);
1113e12c5d1SDavid du Colombier 		free((char *)rp);
1123e12c5d1SDavid du Colombier 		fprint(2,"illegal rewrite rule: %s\n", s_to_c(line));
113219b2ee8SDavid du Colombier 		return 0;
1143e12c5d1SDavid du Colombier 	}
1153e12c5d1SDavid du Colombier 	if(rulep == 0)
1163e12c5d1SDavid du Colombier 		rulep = rlastp = rp;
1173e12c5d1SDavid du Colombier 	else
1183e12c5d1SDavid du Colombier 		rlastp = rlastp->next = rp;
119219b2ee8SDavid du Colombier 	return backl;
1203e12c5d1SDavid du Colombier }
121219b2ee8SDavid du Colombier 
122219b2ee8SDavid du Colombier /*
123219b2ee8SDavid du Colombier  *  rules are of the form:
124219b2ee8SDavid du Colombier  *	<reg exp> <String> <repl exp> [<repl exp>]
125219b2ee8SDavid du Colombier  */
126219b2ee8SDavid du Colombier extern int
getrules(void)127219b2ee8SDavid du Colombier getrules(void)
128219b2ee8SDavid du Colombier {
129219b2ee8SDavid du Colombier 	Biobuf	*rfp;
130219b2ee8SDavid du Colombier 	String	*line;
131219b2ee8SDavid du Colombier 	String	*type;
132219b2ee8SDavid du Colombier 	String	*file;
133219b2ee8SDavid du Colombier 
1347dd7cddfSDavid du Colombier 	file = abspath("rewrite", UPASLIB, (String *)0);
135219b2ee8SDavid du Colombier 	rfp = sysopen(s_to_c(file), "r", 0);
136219b2ee8SDavid du Colombier 	if(rfp == 0) {
137219b2ee8SDavid du Colombier 		rulep = 0;
138219b2ee8SDavid du Colombier 		return -1;
139219b2ee8SDavid du Colombier 	}
140219b2ee8SDavid du Colombier 	rlastp = 0;
141219b2ee8SDavid du Colombier 	line = s_new();
142219b2ee8SDavid du Colombier 	type = s_new();
143219b2ee8SDavid du Colombier 	while(s_getline(rfp, s_restart(line)))
144219b2ee8SDavid du Colombier 		if(getrule(line, type, thissys) && altthissys)
145219b2ee8SDavid du Colombier 			getrule(s_restart(line), type, altthissys);
1463e12c5d1SDavid du Colombier 	s_free(type);
1473e12c5d1SDavid du Colombier 	s_free(line);
1483e12c5d1SDavid du Colombier 	s_free(file);
1493e12c5d1SDavid du Colombier 	sysclose(rfp);
1503e12c5d1SDavid du Colombier 	return 0;
1513e12c5d1SDavid du Colombier }
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier /* look up a matching rule */
1543e12c5d1SDavid du Colombier static rule *
findrule(String * addrp,int authorized)1553e12c5d1SDavid du Colombier findrule(String *addrp, int authorized)
1563e12c5d1SDavid du Colombier {
1573e12c5d1SDavid du Colombier 	rule *rp;
1583e12c5d1SDavid du Colombier 	static rule defaultrule;
1593e12c5d1SDavid du Colombier 
1603e12c5d1SDavid du Colombier 	if(rulep == 0)
1613e12c5d1SDavid du Colombier 		return &defaultrule;
1623e12c5d1SDavid du Colombier 	for (rp = rulep; rp != 0; rp = rp->next) {
1633e12c5d1SDavid du Colombier 		if(rp->type==d_auth && authorized)
1643e12c5d1SDavid du Colombier 			continue;
1653e12c5d1SDavid du Colombier 		if(rp->program == 0)
1663e12c5d1SDavid du Colombier 			rp->program = regcomp(rp->matchre->base);
1673e12c5d1SDavid du Colombier 		if(rp->program == 0)
1683e12c5d1SDavid du Colombier 			continue;
1693e12c5d1SDavid du Colombier 		memset(rp->subexp, 0, sizeof(rp->subexp));
1703e12c5d1SDavid du Colombier 		if(debug)
171*c6569576SDavid du Colombier 			fprint(2, "matching %s against %s\n", s_to_c(addrp),
172c4cb05bbSDavid du Colombier 				rp->matchre->base);
1733e12c5d1SDavid du Colombier 		if(regexec(rp->program, s_to_c(addrp), rp->subexp, NSUBEXP))
1747dd7cddfSDavid du Colombier 		if(s_to_c(addrp) == rp->subexp[0].sp)
1757dd7cddfSDavid du Colombier 		if((s_to_c(addrp) + strlen(s_to_c(addrp))) == rp->subexp[0].ep)
1763e12c5d1SDavid du Colombier 			return rp;
1773e12c5d1SDavid du Colombier 	}
1783e12c5d1SDavid du Colombier 	return 0;
1793e12c5d1SDavid du Colombier }
1803e12c5d1SDavid du Colombier 
1813e12c5d1SDavid du Colombier /*  Transforms the address into a command.
1823e12c5d1SDavid du Colombier  *  Returns:	-1 ifaddress not matched by reules
1833e12c5d1SDavid du Colombier  *		 0 ifaddress matched and ok to forward
1843e12c5d1SDavid du Colombier  *		 1 ifaddress matched and not ok to forward
1853e12c5d1SDavid du Colombier  */
1863e12c5d1SDavid du Colombier extern int
rewrite(dest * dp,message * mp)1877dd7cddfSDavid du Colombier rewrite(dest *dp, message *mp)
1883e12c5d1SDavid du Colombier {
1893e12c5d1SDavid du Colombier 	rule *rp;		/* rewriting rule */
1903e12c5d1SDavid du Colombier 	String *lower;		/* lower case version of destination */
1913e12c5d1SDavid du Colombier 
1923e12c5d1SDavid du Colombier 	/*
1933e12c5d1SDavid du Colombier 	 *  Rewrite the address.  Matching is case insensitive.
1943e12c5d1SDavid du Colombier 	 */
1957dd7cddfSDavid du Colombier 	lower = s_clone(dp->addr);
1963e12c5d1SDavid du Colombier 	s_tolower(s_restart(lower));
1973e12c5d1SDavid du Colombier 	rp = findrule(lower, dp->authorized);
1987dd7cddfSDavid du Colombier 	if(rp == 0){
1997dd7cddfSDavid du Colombier 		s_free(lower);
2003e12c5d1SDavid du Colombier 		return -1;
2017dd7cddfSDavid du Colombier 	}
2023e12c5d1SDavid du Colombier 	strcpy(s_to_c(lower), s_to_c(dp->addr));
2037dd7cddfSDavid du Colombier 	dp->repl1 = substitute(rp->repl1, rp->subexp, mp);
2047dd7cddfSDavid du Colombier 	dp->repl2 = substitute(rp->repl2, rp->subexp, mp);
2053e12c5d1SDavid du Colombier 	dp->status = rp->type;
2063e12c5d1SDavid du Colombier 	if(debug){
207*c6569576SDavid du Colombier 		fprint(2, "\t->");
2083e12c5d1SDavid du Colombier 		if(dp->repl1)
209*c6569576SDavid du Colombier 			fprint(2, "%s", s_to_c(dp->repl1));
2103e12c5d1SDavid du Colombier 		if(dp->repl2)
211*c6569576SDavid du Colombier 			fprint(2, "%s", s_to_c(dp->repl2));
212*c6569576SDavid du Colombier 		fprint(2, "\n");
2133e12c5d1SDavid du Colombier 	}
2147dd7cddfSDavid du Colombier 	s_free(lower);
2153e12c5d1SDavid du Colombier 	return 0;
2163e12c5d1SDavid du Colombier }
2173e12c5d1SDavid du Colombier 
2183e12c5d1SDavid du Colombier static String *
substitute(String * source,Resub * subexp,message * mp)2197dd7cddfSDavid du Colombier substitute(String *source, Resub *subexp, message *mp)
2203e12c5d1SDavid du Colombier {
2217dd7cddfSDavid du Colombier 	int i;
2227dd7cddfSDavid du Colombier 	char *s;
2237dd7cddfSDavid du Colombier 	char *sp;
2247dd7cddfSDavid du Colombier 	String *stp;
2253e12c5d1SDavid du Colombier 
2263e12c5d1SDavid du Colombier 	if(source == 0)
2273e12c5d1SDavid du Colombier 		return 0;
2283e12c5d1SDavid du Colombier 	sp = s_to_c(source);
2293e12c5d1SDavid du Colombier 
2303e12c5d1SDavid du Colombier 	/* someplace to put it */
2313e12c5d1SDavid du Colombier 	stp = s_new();
2323e12c5d1SDavid du Colombier 
2333e12c5d1SDavid du Colombier 	/* do the substitution */
2343e12c5d1SDavid du Colombier 	while (*sp != '\0') {
2353e12c5d1SDavid du Colombier 		if(*sp == '\\') {
2363e12c5d1SDavid du Colombier 			switch (*++sp) {
2373e12c5d1SDavid du Colombier 			case '0': case '1': case '2': case '3': case '4':
2383e12c5d1SDavid du Colombier 			case '5': case '6': case '7': case '8': case '9':
2393e12c5d1SDavid du Colombier 				i = *sp-'0';
2403e12c5d1SDavid du Colombier 				if(subexp[i].sp != 0)
2417dd7cddfSDavid du Colombier 					for (s = subexp[i].sp;
2427dd7cddfSDavid du Colombier 					     s < subexp[i].ep;
2437dd7cddfSDavid du Colombier 					     s++)
2447dd7cddfSDavid du Colombier 						s_putc(stp, *s);
2453e12c5d1SDavid du Colombier 				break;
2463e12c5d1SDavid du Colombier 			case '\\':
2473e12c5d1SDavid du Colombier 				s_putc(stp, '\\');
2483e12c5d1SDavid du Colombier 				break;
2493e12c5d1SDavid du Colombier 			case '\0':
2503e12c5d1SDavid du Colombier 				sp--;
2513e12c5d1SDavid du Colombier 				break;
2523e12c5d1SDavid du Colombier 			case 's':
2537dd7cddfSDavid du Colombier 				for(s = s_to_c(mp->replyaddr); *s; s++)
2547dd7cddfSDavid du Colombier 					s_putc(stp, *s);
2557dd7cddfSDavid du Colombier 				break;
2567dd7cddfSDavid du Colombier 			case 'p':
2577dd7cddfSDavid du Colombier 				if(mp->bulk)
2587dd7cddfSDavid du Colombier 					s = "bulk";
2597dd7cddfSDavid du Colombier 				else
2607dd7cddfSDavid du Colombier 					s = "normal";
2617dd7cddfSDavid du Colombier 				for(;*s; s++)
2627dd7cddfSDavid du Colombier 					s_putc(stp, *s);
2633e12c5d1SDavid du Colombier 				break;
2643e12c5d1SDavid du Colombier 			default:
2653e12c5d1SDavid du Colombier 				s_putc(stp, *sp);
2663e12c5d1SDavid du Colombier 				break;
2673e12c5d1SDavid du Colombier 			}
2683e12c5d1SDavid du Colombier 		} else if(*sp == '&') {
2693e12c5d1SDavid du Colombier 			if(subexp[0].sp != 0)
2707dd7cddfSDavid du Colombier 				for (s = subexp[0].sp;
2717dd7cddfSDavid du Colombier 				     s < subexp[0].ep; s++)
2727dd7cddfSDavid du Colombier 					s_putc(stp, *s);
2733e12c5d1SDavid du Colombier 		} else
2743e12c5d1SDavid du Colombier 			s_putc(stp, *sp);
2753e12c5d1SDavid du Colombier 		sp++;
2763e12c5d1SDavid du Colombier 	}
2773e12c5d1SDavid du Colombier 	s_terminate(stp);
2783e12c5d1SDavid du Colombier 
2793e12c5d1SDavid du Colombier 	return s_restart(stp);
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier 
2823e12c5d1SDavid du Colombier extern void
regerror(char * s)2833e12c5d1SDavid du Colombier regerror(char* s)
2843e12c5d1SDavid du Colombier {
2853e12c5d1SDavid du Colombier 	fprint(2, "rewrite: %s\n", s);
286be704722SDavid du Colombier 	/* make sure the message is seen locally */
2877ee8ce7cSDavid du Colombier 	syslog(0, "mail", "regexp error in rewrite: %s", s);
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier extern void
dumprules(void)2913e12c5d1SDavid du Colombier dumprules(void)
2923e12c5d1SDavid du Colombier {
2933e12c5d1SDavid du Colombier 	rule *rp;
2943e12c5d1SDavid du Colombier 
2953e12c5d1SDavid du Colombier 	for (rp = rulep; rp != 0; rp = rp->next) {
2963e12c5d1SDavid du Colombier 		fprint(2, "'%s'", rp->matchre->base);
2973e12c5d1SDavid du Colombier 		switch (rp->type) {
2983e12c5d1SDavid du Colombier 		case d_pipe:
2993e12c5d1SDavid du Colombier 			fprint(2, " |");
3003e12c5d1SDavid du Colombier 			break;
3013e12c5d1SDavid du Colombier 		case d_cat:
3023e12c5d1SDavid du Colombier 			fprint(2, " >>");
3033e12c5d1SDavid du Colombier 			break;
3043e12c5d1SDavid du Colombier 		case d_alias:
3053e12c5d1SDavid du Colombier 			fprint(2, " alias");
3063e12c5d1SDavid du Colombier 			break;
3073e12c5d1SDavid du Colombier 		case d_translate:
3083e12c5d1SDavid du Colombier 			fprint(2, " translate");
3093e12c5d1SDavid du Colombier 			break;
3103e12c5d1SDavid du Colombier 		default:
3113e12c5d1SDavid du Colombier 			fprint(2, " UNKNOWN");
3123e12c5d1SDavid du Colombier 			break;
3133e12c5d1SDavid du Colombier 		}
3143e12c5d1SDavid du Colombier 		fprint(2, " '%s'", rp->repl1 ? rp->repl1->base:"...");
3153e12c5d1SDavid du Colombier 		fprint(2, " '%s'\n", rp->repl2 ? rp->repl2->base:"...");
3163e12c5d1SDavid du Colombier 	}
3173e12c5d1SDavid du Colombier }
3183e12c5d1SDavid du Colombier 
319