20 #define INT_TO_STRING_LEN ((sizeof(int)*4*CHAR_BIT)/10 + 6)
28 void __attribute__ ((noreturn))
29 bye(int code, char* msg, ...)
33 if (current_body->tmpfile)
34 unlink(current_body->tmpfile);
38 vfprintf(stderr, msg, args);
55 if ((var_tab[var] != NULL))
56 free_string(var_tab[var]);
60 set_var(int var, char* value)
63 var_tab[var] = xstrdup(value);
70 return xstrdup(const_tab[-var]);
71 return xstrdup(var_tab[var]);
74 /* return var struct or NULL if not found */
75 static struct variable*
76 get_var_struct(char* name, struct list* hash)
81 n = get_bucket_number(name);
82 int nocase = isupper(*name);
83 LIST_FOREACH(p, hash + n)
84 if (!(nocase ? strcasecmp : strcmp)(p->name,name))
91 regex_cmp(char* s, char* r)
96 int ovector[OVECCOUNT];
98 brum = pcre_compile(r,0,&error,&erroroffset,NULL);
102 int res = pcre_exec(brum,NULL,s,strlen(s),0,0,ovector,OVECCOUNT);
108 #define UPPER(a) ((a) >> 8)
109 #define LOWER(a) ((a) & 0xFF)
112 xcat(char* left, char* right)
114 char* res = xmalloc(strlen(left) + strlen(right) + 1);
126 fold(const char* value, int taken)
130 int len = strlen(value);
131 int newlines[len / 78 + 5];
137 if (len + taken <= 78)
138 return xstrdup(value);
139 for(i = 0; i < len; i++) {
140 if (value[i] == ' ' || value[i]=='\t')
145 newlines[newl++] = curr_ws;
147 while(value[i] && (value[i] == '\t'
155 ret = xmalloc(2*newl + len + 1);
156 for (i = 0; i < len; i++) {
157 if (newl_done == newl) {
158 strcpy(ret + pos, value + i);
161 if(i != newlines[newl_done])
162 ret[pos++] = value[i];
173 unfold(const char* u)
179 new = xmalloc(strlen(u)+1);
182 #define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
184 while (IS_WHITE(*pu))
189 while (IS_WHITE(*pu))
202 modify_headers(struct list* headers, struct list* hash)
210 LIST_FOREACH(p, headers){
211 pv = get_var_struct(p->name, hash);
214 u = unfold(p->value);
215 value = get_var(pv->varcode);
216 if (strcmp(u, value)){
218 free_string(p->value);
219 p->value = fold(value,
220 strlen(p->name) + 2);
227 for (i = 0; i < HASHSIZE; i++){
228 LIST_FOREACH(pv, hash + i){
229 if (isupper(pv->name[0]) && pv->modified){
232 p = xmalloc(sizeof(struct hlist));
233 p->name = xstrdup(pv->name);
234 p->value = get_var(pv->varcode);
236 list_add_last(headers,&p->car);
243 copy_headers(struct list* orig)
245 struct list* new = xmalloc(sizeof(struct list));
246 struct hlist* po, *pn;
250 LIST_FOREACH(po, orig){
251 pn = xmalloc(sizeof(struct hlist));
252 pn->name = xstrdup(po->name);
253 pn->value = xstrdup(po->value);
256 list_add_last(new, &pn->car);
263 prepare_email(struct list* hash)
267 modify_headers(current_headers, hash);
268 em.headers = copy_headers(current_headers);
269 em.body_len = current_body->body_len;
270 em.fd = current_body->fd;
271 if (current_body->body) {
272 em.body = xmalloc(em.body_len);
273 memcpy(em.body, current_body->body, em.body_len);
276 em.tmpfile = xstrdup(current_body->tmpfile);
284 destroy_headers(struct list* h)
288 while ((p = list_del_last(h))) {
297 destroy_body(struct email* b)
308 destroy_email(struct email em)
310 destroy_headers(em.headers);
315 do_string_ternary_op(struct code* p)
317 char* l = get_var(p->u.tpop.l);
318 char* r = get_var(p->u.tpop.r);
323 result = xmalloc(INT_TO_STRING_LEN);
324 sprintf(result, "%d", regex_cmp(l, r));
327 result = xmalloc(INT_TO_STRING_LEN);
328 sprintf(result, "%d", !regex_cmp(l, r));
337 set_var(p->u.tpop.res, result);
341 do_num_ternary_op(struct code* p)
344 char* result = xmalloc(INT_TO_STRING_LEN);
346 sscanf(get_var(p->u.tpop.l),"%d", &l);
347 sscanf(get_var(p->u.tpop.r),"%d", &r);
375 res = ((l || r) && !(l && r));
393 sprintf(result, "%d", res);
394 set_var(p->u.tpop.res, result);
400 char* val = get_var(var);
407 sscanf(val, "%d", &v);
413 deliver(char* where, int copy, struct list* hash)
416 struct email em = prepare_email(hash);
418 res = deliver_local_email(where, &em);
424 bye(EX_TEMPFAIL, "%m");
431 send_mail(char* where, int copy, struct list* hash)
436 struct email em = prepare_email(hash);
442 if ((pid = fork()) < 0)
449 res = execl("/usr/lib/sendmail", "sendmail", where, NULL);
452 write_email_to_fd(pd[1], &em);
459 bye(EX_TEMPFAIL, "%m");
465 static struct procstat*
466 pipe_to(char* program, struct email* em)
471 struct pollfd pfd[2];
472 char* name = xstrdup("/tmp/umpf.XXXXXX");
477 int fd = mkstemp(name);
478 struct procstat* tmp = xmalloc(sizeof(struct procstat));
486 int res = pipe(pd_in);
493 if ((pid = fork()) < 0)
506 res = execl("/bin/sh", "sh", "-c", program, NULL);
511 pfd[1].fd = pd_in[1];
512 pfd[0].fd = pd_out[0];
513 pfd[1].events = POLLOUT;
514 pfd[0].events = POLLIN;
518 if (poll(pfd, nfds, -1) < 0)
520 if ((pfd[0].revents & POLLERR) || (pfd[1].revents & POLLERR))
523 if (pfd[0].revents & POLLIN) {
524 r = read(pfd[0].fd, buf, BUFSIZE);
529 if (pfd[0].revents & POLLHUP)
535 if (pfd[1].revents & POLLOUT) {
536 if (!chars_written) {
539 if (!chars_written) {
545 if (data_pos < chars_written) {
546 r = write(pfd[1].fd, e + data_pos,
547 chars_written - data_pos);
560 tmp->exit = WEXITSTATUS(status);
569 do_filter(char* program, struct list* hash)
571 struct email em = prepare_email(hash);
575 f = pipe_to(program, &em);
580 lseek(f->fd, 0, SEEK_SET);
582 destroy_headers(current_headers);
583 destroy_body(current_body);
584 current_headers = make_hlist(f->fd);
585 current_body = get_body(f->fd);
586 // set_cur_mail_length_var(current_email_len);
587 // set_exit_code_var(f->exit);
596 interp(struct list* ins, struct list* hash)
602 LIST_FOREACH(p, ins) {
605 set_var(p->u.set.l, get_var(p->u.set.r));
608 p = p->u.jump.target;
612 if (eval_cond(p->u.jump_if.cond))
613 p = p->u.jump_if.target;
616 case OPC_JUMP_UNLESS:
617 if (!eval_cond(p->u.jump_unless.cond))
618 p = p->u.jump_unless.target;
637 do_num_ternary_op(p);
640 result = xmalloc(INT_TO_STRING_LEN);
641 sscanf(get_var(p->u.tpop.l),"%d", &v);
642 sprintf(result, "%d", !v);
643 set_var(p->u.tpop.res, result);
647 do_string_ternary_op(p);
652 do_filter(get_var(p->u.arrow.what), hash);
655 send_mail(get_var(p->u.arrow.what),
656 p->u.arrow.copy, hash);
659 deliver(get_var(p->u.arrow.what),
660 p->u.arrow.copy, hash);
666 deliver(default_mailbox, 0, hash);
670 print_vars(struct list* hash)
675 for (i=0; i<HASHSIZE; i++){
676 LIST_FOREACH(p, hash + i)
677 printf("%s=%s\n",p->name, get_var(p->varcode));
682 save_current_headers(struct list* hash)
688 LIST_FOREACH(p, current_headers){
689 pv = get_var_struct(p->name, hash);
692 u = unfold(p->value);
693 set_var(pv->varcode, u);