xref: /plan9-contrib/sys/src/cmd/upas/send/rewrite.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "common.h"
2 #include "send.h"
3 
4 extern int debug;
5 
6 /* configuration */
7 #define RULEBiobuf "lib/rewrite"
8 
9 /*
10  *	Routines for dealing with the rewrite rules.
11  */
12 
13 /* globals */
14 typedef struct rule rule;
15 
16 #define NSUBEXP 10
17 struct rule {
18 	String *matchre;	/* address match */
19 	String *repl1;		/* first replacement String */
20 	String *repl2;		/* second replacement String */
21 	d_status type;		/* type of rule */
22 	Reprog *program;
23 	Resub subexp[NSUBEXP];
24 	rule *next;
25 };
26 static rule *rulep;
27 static rule *rlastp;
28 
29 /* predeclared */
30 static String *substitute(String *, Resub *, char *);
31 static rule *findrule(String *, int);
32 
33 
34 /*
35  *  Get the next token from `line'.  The symbol `\l' is replaced by
36  *  the name of the local system.
37  */
38 extern String *
39 rule_parse(String *line, char *system, int *backl)
40 {
41 	String *token;
42 	String *expanded;
43 	char *cp;
44 
45 	token = s_parse(line, 0);
46 	if(token == 0)
47 		return(token);
48 	if (strchr(s_to_c(token), '\\')==0)
49 		return(token);
50 	expanded = s_new();
51 	for(cp = s_to_c(token); *cp; cp++) {
52 		if(*cp == '\\') switch(*++cp) {
53 		case 'l':
54 			s_append(expanded, system);
55 			*backl = 1;
56 			break;
57 		case '\\':
58 			s_putc(expanded, '\\');
59 			break;
60 		default:
61 			s_putc(expanded, '\\');
62 			s_putc(expanded, *cp);
63 			break;
64 		} else
65 			s_putc(expanded, *cp);
66 	}
67 	s_free(token);
68 	s_terminate(expanded);
69 	return(expanded);
70 }
71 
72 static int
73 getrule(String *line, String *type, char *system)
74 {
75 	rule	*rp;
76 	String	*re;
77 	int	backl;
78 
79 	backl = 0;
80 
81 	/* get a rule */
82 	re = rule_parse(s_restart(line), system, &backl);
83 	if(re == 0)
84 		return 0;
85 	rp = (rule *)malloc(sizeof(rule));
86 	if (rp == 0) {
87 		perror("getrules:");
88 		exit(1);
89 	}
90 	rp->next = 0;
91 	s_tolower(re);
92 	rp->matchre = s_new();
93 	if(*s_to_c(re)!='^')
94 		s_append(rp->matchre, "^");
95 	s_append(rp->matchre, s_to_c(re));
96 	s_append(rp->matchre, "$");
97 	USE(s_restart(rp->matchre));
98 	s_free(re);
99 	s_parse(line, s_restart(type));
100 	rp->repl1 = rule_parse(line, system, &backl);
101 	rp->repl2 = rule_parse(line, system, &backl);
102 	rp->program = 0;
103 	if (strcmp(s_to_c(type), "|") == 0)
104 		rp->type = d_pipe;
105 	else if (strcmp(s_to_c(type), ">>") == 0)
106 		rp->type = d_cat;
107 	else if (strcmp(s_to_c(type), "alias") == 0)
108 		rp->type = d_alias;
109 	else if (strcmp(s_to_c(type), "translate") == 0)
110 		rp->type = d_translate;
111 	else if (strcmp(s_to_c(type), "auth") == 0)
112 		rp->type = d_auth;
113 	else {
114 		s_free(rp->matchre);
115 		s_free(rp->repl1);
116 		s_free(rp->repl2);
117 		free((char *)rp);
118 		fprint(2,"illegal rewrite rule: %s\n", s_to_c(line));
119 		return 0;
120 	}
121 	if (rulep == 0)
122 		rulep = rlastp = rp;
123 	else
124 		rlastp = rlastp->next = rp;
125 	return backl;
126 }
127 
128 /*
129  *  rules are of the form:
130  *	<reg exp> <String> <repl exp> [<repl exp>]
131  */
132 extern int
133 getrules(void)
134 {
135 	Biobuf	*rfp;
136 	String	*line;
137 	String	*type;
138 	String	*file;
139 
140 	file = abspath(RULEBiobuf, MAILROOT, (String *)0);
141 	rfp = sysopen(s_to_c(file), "r", 0);
142 	if (rfp == 0) {
143 		rulep = 0;
144 		return -1;
145 	}
146 	rlastp = 0;
147 	line = s_new();
148 	type = s_new();
149 	while(s_getline(rfp, s_restart(line)))
150 		if(getrule(line, type, thissys) && altthissys)
151 			getrule(s_restart(line), type, altthissys);
152 	s_free(type);
153 	s_free(line);
154 	s_free(file);
155 	sysclose(rfp);
156 	return 0;
157 }
158 
159 /* look up a matching rule */
160 static rule *
161 findrule(String *addrp, int authorized)
162 {
163 	rule *rp;
164 	static rule defaultrule;
165 
166 	if (rulep == 0)
167 		return &defaultrule;
168 	for (rp = rulep; rp != 0; rp = rp->next) {
169 		if (rp->type==d_auth && authorized)
170 			continue;
171 		if (rp->program == 0)
172 			rp->program = regcomp(rp->matchre->base);
173 		if (rp->program == 0)
174 			continue;
175 		memset(rp->subexp, 0, sizeof(rp->subexp));
176 		if(debug)
177 			print("trying %s\n", rp->matchre->base);
178 		if (regexec(rp->program, s_to_c(addrp), rp->subexp, NSUBEXP))
179 			return rp;
180 	}
181 	return 0;
182 }
183 
184 /*  Transforms the address into a command.
185  *  Returns:	-1 if address not matched by reules
186  *		 0 if address matched and ok to forward
187  *		 1 if address matched and not ok to forward
188  */
189 extern int
190 rewrite(dest *dp, char *s)
191 {
192 	rule *rp;		/* rewriting rule */
193 	String *lower;		/* lower case version of destination */
194 
195 	/*
196 	 *  Rewrite the address.  Matching is case insensitive.
197 	 */
198 	lower = s_clone(s_restart(dp->addr));
199 	s_tolower(s_restart(lower));
200 	rp = findrule(lower, dp->authorized);
201 	if (rp == 0)
202 		return -1;
203 	strcpy(s_to_c(lower), s_to_c(dp->addr));
204 	dp->repl1 = substitute(rp->repl1, rp->subexp, s);
205 	dp->repl2 = substitute(rp->repl2, rp->subexp, s);
206 	dp->status = rp->type;
207 	if(debug){
208 		print("\t->");
209 		if(dp->repl1)
210 			print("%s", s_to_c(dp->repl1));
211 		if(dp->repl2)
212 			print("%s", s_to_c(dp->repl2));
213 		print("\n");
214 	}
215 	return 0;
216 }
217 
218 static String *
219 substitute(String *source, Resub *subexp, char *s)
220 {
221 	register char *sp;
222 	register char *ssp;
223 	register String *stp;
224 	register int i;
225 
226 	if (source == 0)
227 		return 0;
228 	sp = s_to_c(source);
229 
230 	/* someplace to put it */
231 	stp = s_new();
232 
233 	/* do the substitution */
234 	while (*sp != '\0') {
235 		if (*sp == '\\') {
236 			switch (*++sp) {
237 			case '0': case '1': case '2': case '3': case '4':
238 			case '5': case '6': case '7': case '8': case '9':
239 				i = *sp-'0';
240 				if (subexp[i].sp != 0)
241 					for (ssp = subexp[i].sp;
242 					     ssp < subexp[i].ep;
243 					     ssp++)
244 						s_putc(stp, *ssp);
245 				break;
246 			case '\\':
247 				s_putc(stp, '\\');
248 				break;
249 			case '\0':
250 				sp--;
251 				break;
252 			case 's':
253 				for(ssp = s; *ssp; ssp++)
254 					s_putc(stp, *ssp);
255 				break;
256 			default:
257 				s_putc(stp, *sp);
258 				break;
259 			}
260 		} else if (*sp == '&') {
261 			if (subexp[0].sp != 0)
262 				for (ssp = subexp[0].sp;
263 				     ssp < subexp[0].ep; ssp++)
264 					s_putc(stp, *ssp);
265 		} else
266 			s_putc(stp, *sp);
267 		sp++;
268 	}
269 	s_terminate(stp);
270 
271 	return s_restart(stp);
272 }
273 
274 extern void
275 regerror(char* s)
276 {
277 	fprint(2, "rewrite: %s\n", s);
278 }
279 
280 extern void
281 dumprules(void)
282 {
283 	rule *rp;
284 
285 	for (rp = rulep; rp != 0; rp = rp->next) {
286 		fprint(2, "'%s'", rp->matchre->base);
287 		switch (rp->type) {
288 		case d_pipe:
289 			fprint(2, " |");
290 			break;
291 		case d_cat:
292 			fprint(2, " >>");
293 			break;
294 		case d_alias:
295 			fprint(2, " alias");
296 			break;
297 		case d_translate:
298 			fprint(2, " translate");
299 			break;
300 		default:
301 			fprint(2, " UNKNOWN");
302 			break;
303 		}
304 		fprint(2, " '%s'", rp->repl1 ? rp->repl1->base:"...");
305 		fprint(2, " '%s'\n", rp->repl2 ? rp->repl2->base:"...");
306 	}
307 }
308 
309