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