]> mj.ucw.cz Git - umpf.git/blob - int.c
436181b748b13d9b92574b25e8e6f9b4c7d50069
[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 int 
257 last_rescue(void)
258 {
259         //FIXME: add some magic
260         return 1;
261 }
262
263 static void
264 deliver(char* where, int copy, int last_try, struct list* hash)
265 {
266         int ok = 0;
267         int fd, len, written;
268         off_t off;
269         struct email em = prepare_email(hash);
270         struct hlist* p;
271
272         fd = open_mailbox(where, last_try);
273         if (fd < 0)
274                 goto end;
275         off = lseek(fd, 0, SEEK_END);
276         if (off < 0)
277                 goto end;
278         LIST_FOREACH(p, em.headers) {
279                 len = strlen(p->name);
280                 written = write(fd, p->name, len);
281                 if (written < len) {
282                         ftruncate(fd, off);
283                         goto end;
284                 }
285
286                 written = write(fd, ": ", 2);
287                 if (written < 2) {
288                         ftruncate(fd, off);
289                         goto end;
290                 }
291
292                 len = strlen(p->value);
293                 written = write(fd, p->value, len);
294                 if (written < len) {
295                         ftruncate(fd, off);
296                         goto end;
297                 }
298
299                 written = write(fd, "\n", 1);
300                 if (written < len) {
301                         ftruncate(fd, off);
302                         goto end;
303                 }
304         }
305         written = write(fd, "\n", 1);
306         if (written < 1) {
307                 ftruncate(fd, off);
308                 goto end;
309         }
310
311         written = write(fd, em.body, em.body_len);
312         if (written < em.body_len) {
313                 ftruncate(fd, off);
314                 goto end;
315         }
316
317         ok = 1;
318         close_mailbox(fd, where, last_try);
319
320         
321 end:
322         if (ok) {
323                 if (!copy || last_try)
324                         exit(0);
325         } else {
326                 if (!copy || last_try)
327                         ok = last_rescue();
328                         exit(ok);       
329         }
330 }
331
332 void
333 interp(struct list* ins, struct list* hash)
334 {
335         struct code* p;
336         char* result;
337         int v;
338         
339         LIST_FOREACH(p, ins) {
340         switch (p->opcode) {
341                 case OPC_SET:
342                         set_var(p->u.set.l, get_var(p->u.set.r));
343                         break;  
344                 case OPC_JUMP:
345                         p = p->u.jump.target;
346                         continue;
347                         break;
348                 case OPC_JUMP_IF:
349                         if (eval_cond(p->u.jump_if.cond))
350                                 p = p->u.jump_if.target;
351                         continue;
352                         break;
353                 case OPC_JUMP_UNLESS:
354                         if (!eval_cond(p->u.jump_unless.cond))
355                                 p = p->u.jump_unless.target;
356                         continue;
357                         break;
358                 case OPC_NOP:
359                         continue;
360                         break;
361                 case OPC_GT:
362                 case OPC_LT:
363                 case OPC_LE:
364                 case OPC_GE:
365                 case OPC_EQ:
366                 case OPC_NEQ:
367                 case OPC_AND:
368                 case OPC_OR:
369                 case OPC_XOR:
370                 case OPC_PLUS:
371                 case OPC_MINUS:
372                 case OPC_MUL:
373                 case OPC_DIV:
374                         do_num_ternary_op(p);
375                         break;
376                 case OPC_NOT:
377                         result = xmalloc(INT_TO_STRING_LEN);
378                         sscanf(get_var(p->u.tpop.l),"%d", &v);
379                         sprintf(result, "%d", !v);
380                         set_var(p->u.tpop.res, result);
381                 case OPC_CAT:
382                 case OPC_RE:
383                 case OPC_NRE:
384                         do_string_ternary_op(p);
385                         break;
386                 case OPC_PIPE:
387                         break;
388                 case OPC_MAIL:
389                         break;
390                 case OPC_DELIVER:
391                         deliver(get_var(p->u.arrow.what), 
392                                 p->u.arrow.copy, 0, hash);
393                         break;
394                 case OPC_CALL_EXT:
395                         break;
396                 case OPC_DISCARD:
397                         exit(0);
398                         break;
399         }}
400         deliver(default_mailbox, 0, 1, hash);
401 }
402
403 void
404 print_vars(struct list* hash)
405 {
406         int i;
407         struct variable* p;
408
409         for (i=0; i<HASHSIZE; i++){
410                 LIST_FOREACH(p, hash + i)
411                         printf("%s=%s\n",p->name, get_var(p->varcode));
412         }
413 }
414
415 static char*
416 unfold(char* u)
417 {
418         char* new;
419         char* pu = u; 
420         char* pn;
421
422         new = xmalloc(strlen(u)+1);
423         pn = new;
424
425 #define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
426
427         while (IS_WHITE(*pu))
428                 pu++;
429
430         while (*pu != 0){
431                 if (IS_WHITE(*pu)){
432                         while (IS_WHITE(*pu))
433                                 pu++;
434                         if (*pu != 0)
435                                 *pn++ = ' ';
436                 } else
437                         *pn++ = *pu++;          
438         }
439         *pn = 0;
440
441         return new;
442 }
443
444 void
445 save_current_headers(struct list* hash)
446 {
447         struct hlist* p;
448         char* u;
449         struct variable* pv;
450
451         LIST_FOREACH(p, current_headers){
452                 pv = get_var_struct(p->name, hash);
453                 if (!pv)
454                         continue;
455                 u = unfold(p->value);
456                 set_var(pv->varcode, u);
457                 pv->modified = 0;
458                 p->have_var = 1;
459         }
460
461 }