]> mj.ucw.cz Git - umpf.git/blob - int.c
really do local delivery
[umpf.git] / int.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <pcre.h>
4 #include <ctype.h>
5 #include <limits.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8
9 #include "cond.tab.h"
10 #include "umpf.h"
11
12 #define OVECCOUNT 3
13 #define HASHSIZE 103
14 #define MAGIC 19
15
16 #define INT_TO_STRING_LEN ((sizeof(int)*4*CHAR_BIT)/10 + 6)
17
18 static void
19 clear_var(int var)
20 {
21         if (var_tab[var])
22                 free(var_tab[var]);
23 }
24
25 static void
26 set_var(int var, char* value)
27 {
28         clear_var(var);
29         var_tab[var] = xstrdup(value);
30         
31 }
32
33 static char*
34 get_var(int var)
35 {
36         if (var < 0)
37                 return const_tab[-var];
38         return var_tab[var];
39 }
40
41 /* return var struct or NULL if not found */
42 static struct variable*
43 get_var_struct(char* name, struct list* hash)
44 {
45         int n;
46         struct variable *p;
47
48         n = get_bucket_number(name);
49         int nocase = isupper(*name);
50         LIST_FOREACH(p, hash + n)
51                 if (!(nocase ? strcasecmp : strcmp)(p->name,name))
52                         return p;
53
54         return NULL;
55 }
56
57 static int 
58 regex_cmp(char* s, char* r)
59 {
60         pcre *brum;
61         int erroroffset;
62         const char* error;
63         int ovector[OVECCOUNT];
64         
65         brum = pcre_compile(r,0,&error,&erroroffset,NULL);
66         if (!brum)
67                 return -1;
68         
69         int res = pcre_exec(brum,NULL,s,strlen(s),0,0,ovector,OVECCOUNT);
70         pcre_free(brum);
71
72         return res;
73 }
74
75 #define UPPER(a) ((a) >> 8)
76 #define LOWER(a) ((a) & 0xFF)
77
78 static char*
79 xcat(char* left, char* right)
80 {
81         char* res = xmalloc(strlen(left) + strlen(right) + 1);
82
83         strcpy(res,left);
84         strcat(left,right);
85
86         free(left);
87         free(right);    
88
89         return res;
90 }
91
92 static void
93 modify_headers(struct list* headers, struct list* hash)
94 {
95         struct hlist* p;
96         int i;
97         struct variable* pv;
98         
99
100         LIST_FOREACH(p, headers){
101                 pv = get_var_struct(p->name, hash);
102                 if (!pv)
103                         continue;
104                 if (pv->modified){
105                         pv->modified = 0;
106                         free(p->value);
107                         p->value = xstrdup(get_var(pv->varcode)); //FIXME: fold it
108                 }
109         }
110
111         // find new headers 
112         for (i = 0; i < HASHSIZE; i++){
113                 LIST_FOREACH(pv, hash + i){
114                         if (isupper(pv->name[0]) && pv->modified){
115                                 pv->modified = 0;
116
117                                 p = xmalloc(sizeof(struct hlist));
118                                 p->name = xstrdup(pv->name);
119                                 p->value = xstrdup(get_var(pv->varcode));
120
121                                 list_add_last(headers,&p->car);
122                         }
123                 }
124         }
125 }
126
127 static struct list*
128 copy_headers(struct list* orig)
129 {
130         struct list* new = xmalloc(sizeof(struct list));
131         struct hlist* po, *pn;
132
133         list_init(new);
134
135         LIST_FOREACH(po, orig){
136                 pn = xmalloc(sizeof(struct hlist));
137                 pn->name = xstrdup(po->name);
138                 pn->value = xstrdup(po->value);
139                 pn->have_var = 0;
140
141                 list_add_last(new, &pn->car);
142         }
143
144         return new;
145 }
146
147 static struct email 
148 prepare_email(struct list* hash)
149 {
150         struct email em;
151
152         modify_headers(current_headers, hash);
153         em.headers = copy_headers(current_headers);
154         em.body_len = current_body->body_len; 
155         em.body = xmalloc(em.body_len);
156         memcpy(em.body, current_body->body, em.body_len);
157
158         return em;
159 }
160
161 static void
162 do_string_ternary_op(struct code* p)
163 {
164         char* l = get_var(p->u.tpop.l);
165         char* r = get_var(p->u.tpop.r);
166         char* result;
167
168         switch(p->opcode) {
169                 case OPC_RE:
170                         result = xmalloc(INT_TO_STRING_LEN);
171                         sprintf(result, "%d", regex_cmp(l, r));
172                 case OPC_NRE:
173                         result = xmalloc(INT_TO_STRING_LEN);
174                         sprintf(result, "%d", !regex_cmp(l, r));
175                 case OPC_CAT:
176                         result = xcat(l, r);
177                 default:
178                         break;
179         };
180
181         set_var(p->u.tpop.res, result); 
182 }
183
184 static void
185 do_num_ternary_op(struct code* p)
186 {
187         int l, r, res;
188         char* result = xmalloc(INT_TO_STRING_LEN);
189
190         sscanf(get_var(p->u.tpop.l),"%d", &l);
191         sscanf(get_var(p->u.tpop.r),"%d", &r);
192
193         switch(p->opcode) {
194                 case OPC_GT:
195                         res = (l > r);
196                         break;
197                 case OPC_LT:
198                         res = (l < r);
199                         break;
200                 case OPC_LE:
201                         res = (l <= r);
202                         break;
203                 case OPC_GE:
204                         res = (l >= r);
205                         break;
206                 case OPC_EQ:
207                         res = (l == r);
208                         break;
209                 case OPC_NEQ:
210                         res = (l != r);
211                         break;
212                 case OPC_AND:
213                         res = (l && r);
214                         break;
215                 case OPC_OR:
216                         res = (l || r);
217                         break;
218                 case OPC_XOR:
219                         res = ((l || r) && !(l && r));
220                         break;
221                 case OPC_PLUS:
222                         res = (l + r);
223                         break;
224                 case OPC_MINUS:
225                         res = (l - r);
226                         break;
227                 case OPC_MUL:
228                         res = (l * r);
229                         break;
230                 case OPC_DIV:
231                         res = (l / r);
232                         break;
233                 default:
234                         break;
235         }
236
237         sprintf(result, "%d", res);
238         set_var(p->u.tpop.res, result);
239 }
240
241 static int
242 eval_cond(int var)
243 {
244         char* val = get_var(var);
245         int v;
246
247         if (! val)
248                 return 0;
249         if (! *val)
250                 return 0;
251         sscanf(val, "%d", &v);
252
253         return !!v;
254 }
255
256 static void
257 deliver(char* where, int copy, struct list* hash)
258 {
259         int res = 0;
260         struct email em = prepare_email(hash);
261         
262         res = deliver_local_email(where, &em);
263
264         if (!copy)
265                 exit(-res);
266 }
267
268 void
269 interp(struct list* ins, struct list* hash)
270 {
271         struct code* p;
272         char* result;
273         int v;
274
275         var_tab = xmalloc(max_varcode * sizeof(char*));
276         
277         LIST_FOREACH(p, ins) {
278         switch (p->opcode) {
279                 case OPC_SET:
280                         set_var(p->u.set.l, get_var(p->u.set.r));
281                         break;  
282                 case OPC_JUMP:
283                         p = p->u.jump.target;
284                         continue;
285                         break;
286                 case OPC_JUMP_IF:
287                         if (eval_cond(p->u.jump_if.cond))
288                                 p = p->u.jump_if.target;
289                         continue;
290                         break;
291                 case OPC_JUMP_UNLESS:
292                         if (!eval_cond(p->u.jump_unless.cond))
293                                 p = p->u.jump_unless.target;
294                         continue;
295                         break;
296                 case OPC_NOP:
297                         continue;
298                         break;
299                 case OPC_GT:
300                 case OPC_LT:
301                 case OPC_LE:
302                 case OPC_GE:
303                 case OPC_EQ:
304                 case OPC_NEQ:
305                 case OPC_AND:
306                 case OPC_OR:
307                 case OPC_XOR:
308                 case OPC_PLUS:
309                 case OPC_MINUS:
310                 case OPC_MUL:
311                 case OPC_DIV:
312                         do_num_ternary_op(p);
313                         break;
314                 case OPC_NOT:
315                         result = xmalloc(INT_TO_STRING_LEN);
316                         sscanf(get_var(p->u.tpop.l),"%d", &v);
317                         sprintf(result, "%d", !v);
318                         set_var(p->u.tpop.res, result);
319                 case OPC_CAT:
320                 case OPC_RE:
321                 case OPC_NRE:
322                         do_string_ternary_op(p);
323                         break;
324                 case OPC_PIPE:
325                         break;
326                 case OPC_MAIL:
327                         break;
328                 case OPC_DELIVER:
329                         deliver(get_var(p->u.arrow.what), 
330                                 p->u.arrow.copy, hash);
331                         break;
332                 case OPC_CALL_EXT:
333                         break;
334                 case OPC_DISCARD:
335                         exit(0);
336                         break;
337         }}
338         deliver(default_mailbox, 0, hash);
339 }
340
341 void
342 print_vars(struct list* hash)
343 {
344         int i;
345         struct variable* p;
346
347         for (i=0; i<HASHSIZE; i++){
348                 LIST_FOREACH(p, hash + i)
349                         printf("%s=%s\n",p->name, get_var(p->varcode));
350         }
351 }
352
353 static char*
354 unfold(char* u)
355 {
356         char* new;
357         char* pu = u; 
358         char* pn;
359
360         new = xmalloc(strlen(u)+1);
361         pn = new;
362
363 #define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
364
365         while (IS_WHITE(*pu))
366                 pu++;
367
368         while (*pu != 0){
369                 if (IS_WHITE(*pu)){
370                         while (IS_WHITE(*pu))
371                                 pu++;
372                         if (*pu != 0)
373                                 *pn++ = ' ';
374                 } else
375                         *pn++ = *pu++;          
376         }
377         *pn = 0;
378
379         return new;
380 }
381
382 void
383 save_current_headers(struct list* hash)
384 {
385         struct hlist* p;
386         char* u;
387         struct variable* pv;
388
389         LIST_FOREACH(p, current_headers){
390                 pv = get_var_struct(p->name, hash);
391                 if (!pv)
392                         continue;
393                 u = unfold(p->value);
394                 set_var(pv->varcode, u);
395                 pv->modified = 0;
396                 p->have_var = 1;
397         }
398
399 }