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