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);
46 set_modif_flag(int var, int flag)
48 var_tab[var].modif = flag;
52 get_modif_flag(int var)
54 return var_tab[var].modif;
67 if ((var_tab[var].value != NULL))
68 free_string(var_tab[var].value);
69 var_tab[var].modif = 0;
73 set_var(int var, char* value)
76 var_tab[var].modif = 1;
77 var_tab[var].value = xstrdup(value);
81 set_cur_mail_length_var(int len, struct list* hash)
84 char buf[INT_TO_STRING_LEN];
86 pv = get_var_struct(INT_VAR_MAIL_LEN, VAR_INTERN, hash);
88 if (! pv) /* user is not interested */
91 sprintf(buf,"%d", len);
92 set_var(pv->varcode, buf);
96 set_exit_code_var(int code, struct list* hash)
99 char buf[INT_TO_STRING_LEN];
101 pv = get_var_struct(INT_VAR_LAST_EXIT, VAR_INTERN, hash);
103 if (! pv) /* user is not interested */
106 sprintf(buf,"%d", code);
107 set_var(pv->varcode, buf);
111 set_last_pipe_var(char* buf, struct list* hash)
115 pv = get_var_struct(INT_VAR_LAST_EXIT, VAR_INTERN, hash);
117 if (! pv) /* user is not interested */
119 set_var(pv->varcode, buf);
126 return xstrdup(const_tab[-var]);
127 return xstrdup(var_tab[var].value);
134 return const_tab[-var];
135 return var_tab[var].value;
139 regex_cmp(char* s, char* r)
144 int ovector[OVECCOUNT];
146 brum = pcre_compile(r,0,&error,&erroroffset,NULL);
150 int res = pcre_exec(brum,NULL,s,strlen(s),0,0,ovector,OVECCOUNT);
156 #define UPPER(a) ((a) >> 8)
157 #define LOWER(a) ((a) & 0xFF)
160 xcat(char* left, char* right)
162 char* res = xmalloc(strlen(left) + strlen(right) + 1);
174 fold(const char* value, int taken)
178 int len = strlen(value);
179 int newlines[len / 40 + 5];
185 if (len + taken <= 78)
186 return xstrdup(value);
187 for(i = 0; i < len; i++) {
188 if (value[i] == ' ' || value[i]=='\t')
193 newlines[newl++] = curr_ws;
195 while(value[i] && (value[i] == '\t'
203 ret = xmalloc(2*newl + len + 1);
204 for (i = 0; i < len; i++) {
205 if (newl_done == newl) {
206 strcpy(ret + pos, value + i);
209 if(i != newlines[newl_done])
210 ret[pos++] = value[i];
221 unfold(const char* u)
227 new = xmalloc(strlen(u)+1);
230 #define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
232 while (IS_WHITE(*pu))
237 while (IS_WHITE(*pu))
250 modify_headers(struct list* headers, struct list* hash)
258 LIST_FOREACH(p, headers){
259 pv = get_var_struct(p->name, VAR_HEADER, hash);
262 u = unfold(p->value);
263 value = get_var_nc(pv->varcode);
264 if (strcmp(u, value)){
265 set_modif_flag(pv->varcode, 0);
266 free_string(p->value);
267 p->value = fold(value,
268 strlen(p->name) + 2);
274 for (i = 0; i < HASHSIZE; i++){
275 LIST_FOREACH(pv, hash + i){
276 if (pv->type == VAR_HEADER &&
277 get_modif_flag(pv->varcode)){
279 set_modif_flag(pv->varcode, 0);
280 p = xmalloc(sizeof(struct hlist));
281 p->name = xstrdup(pv->name);
282 p->value = get_var(pv->varcode);
284 list_add_last(headers, &p->car);
291 copy_headers(struct list* orig)
293 struct list* new = xmalloc(sizeof(struct list));
294 struct hlist* po, *pn;
298 LIST_FOREACH(po, orig){
299 pn = xmalloc(sizeof(struct hlist));
300 pn->name = xstrdup(po->name);
301 pn->value = xstrdup(po->value);
304 list_add_last(new, &pn->car);
311 prepare_email(struct list* hash)
315 modify_headers(current_headers, hash);
316 em.headers = copy_headers(current_headers);
317 em.body_len = current_body->body_len;
318 em.fd = current_body->fd;
319 if (current_body->body) {
320 em.body = xmalloc(em.body_len);
321 memcpy(em.body, current_body->body, em.body_len);
324 em.tmpfile = xstrdup(current_body->tmpfile);
332 destroy_headers(struct list* h)
336 while ((p = list_del_last(h))) {
345 destroy_body(struct email* b)
356 destroy_email(struct email em)
358 destroy_headers(em.headers);
363 do_string_ternary_op(struct code* p)
365 char* l = get_var_nc(p->u.tpop.l);
366 char* r = get_var_nc(p->u.tpop.r);
371 result = xmalloc(INT_TO_STRING_LEN);
372 sprintf(result, "%d", regex_cmp(l, r));
375 result = xmalloc(INT_TO_STRING_LEN);
376 sprintf(result, "%d", !regex_cmp(l, r));
385 set_var(p->u.tpop.res, result);
389 do_num_ternary_op(struct code* p)
391 int l = 0, r = 0, res;
392 char* result = xmalloc(INT_TO_STRING_LEN);
394 sscanf(get_var_nc(p->u.tpop.l),"%d", &l);
395 sscanf(get_var_nc(p->u.tpop.r),"%d", &r);
423 res = ((l || r) && !(l && r));
441 sprintf(result, "%d", res);
443 set_var(p->u.tpop.res, result);
449 char* val = get_var_nc(var);
456 sscanf(val, "%d", &v);
462 deliver(char* where, int copy, struct list* hash)
465 struct email em = prepare_email(hash);
467 res = deliver_local_email(where, &em);
473 bye(EX_TEMPFAIL, "Cannot save mail to mailbox %s: %m", where);
480 send_mail(char* where, int copy, struct list* hash)
485 struct email em = prepare_email(hash);
491 if ((pid = fork()) < 0)
498 execl("/usr/lib/sendmail", "sendmail", where, NULL);
502 write_email_to_fd(pd[1], &em);
509 bye(EX_TEMPFAIL, "Cannot forward e-mail: %m");
515 static struct procstat*
516 pipe_to(char* program, struct email* em)
521 struct pollfd pfd[2];
522 char* name = xstrdup("/tmp/umpf.XXXXXX");
527 int fd = mkstemp(name);
528 struct procstat* tmp = xmalloc(sizeof(struct procstat));
536 int res = pipe(pd_in);
543 if ((pid = fork()) < 0)
556 execl("/bin/sh", "sh", "-c", program, NULL);
562 pfd[1].fd = pd_in[1];
563 pfd[0].fd = pd_out[0];
564 pfd[1].events = POLLOUT;
565 pfd[0].events = POLLIN;
569 if (poll(pfd, nfds, -1) < 0)
571 if ((pfd[0].revents & POLLERR) || (pfd[1].revents & POLLERR))
574 if (pfd[0].revents & POLLIN) {
575 r = read(pfd[0].fd, buf, BUFSIZE);
580 if (pfd[0].revents & POLLHUP) {
589 if (pfd[1].revents & POLLOUT) {
590 if (!chars_written) {
593 if (!chars_written) {
599 if (data_pos < chars_written) {
600 r = write(pfd[1].fd, e + data_pos,
601 chars_written - data_pos);
614 tmp->exit = WEXITSTATUS(status);
623 fix_content_length(struct list* h, int len)
627 char* clheader = "Content-Length: ";
629 LIST_FOREACH(ph, h) {
630 if (!strcasecmp("Content-Length", ph->name)) {
632 free_string(ph->value);
633 ph->value = xmalloc(INT_TO_STRING_LEN);
634 sprintf(ph->value, "%d", len);
640 buf = xmalloc(INT_TO_STRING_LEN + strlen(clheader));
641 tmpbuf = xmalloc(INT_TO_STRING_LEN);
642 sprintf(tmpbuf, "%d", len);
643 strcpy(buf, clheader);
652 do_filter(char* program, struct list* hash)
654 struct email em = prepare_email(hash);
658 f = pipe_to(program, &em);
663 lseek(f->fd, 0, SEEK_SET);
665 destroy_headers(current_headers);
666 destroy_body(current_body);
667 current_headers = make_hlist(f->fd);
668 current_body = get_body(f->fd);
669 fix_content_length(current_headers, current_body->body_len);
670 save_current_headers(hash);
671 set_cur_mail_length_var(curr_email_len, hash);
672 set_exit_code_var(f->exit, hash);
677 //FIXME: what to do with exit code when pipe failed?
682 do_pipe(char* program, struct list* hash)
684 struct email em = prepare_email(hash);
690 f = pipe_to(program, &em);
695 pos = lseek(f->fd, 0, SEEK_END);
696 lseek(f->fd, 0, SEEK_SET);
699 read(f->fd, buf, pos);
700 set_exit_code_var(f->exit, hash);
701 set_last_pipe_var(buf, hash);
711 interp(struct list* ins, struct list* hash)
717 p = (void*) ins->head.next;
718 while ((struct node*) p != &ins->head) {
721 result = get_var_nc(p->u.set.r);
722 set_var(p->u.set.l, result);
725 p = p->u.jump.target;
728 if (eval_cond(p->u.jump_if.cond)) {
729 p = p->u.jump_if.target;
733 case OPC_JUMP_UNLESS:
734 if (!eval_cond(p->u.jump_unless.cond)) {
735 p = p->u.jump_unless.target;
754 do_num_ternary_op(p);
757 result = xmalloc(INT_TO_STRING_LEN);
758 sscanf(get_var_nc(p->u.dpop.par),"%d", &v);
759 sprintf(result, "%d", !v);
760 set_var(p->u.dpop.res, result);
766 do_string_ternary_op(p);
769 do_pipe(get_var_nc(p->u.arrow.what), hash);
772 do_filter(get_var_nc(p->u.arrow.what), hash);
775 send_mail(get_var_nc(p->u.arrow.what),
776 p->u.arrow.copy, hash);
779 deliver(get_var_nc(p->u.arrow.what),
780 p->u.arrow.copy, hash);
786 p = (void*) ((struct node*) p)->next;
788 deliver(default_mailbox, 0, hash);
792 print_vars(struct list* hash)
797 for (i=0; i<HASHSIZE; i++){
798 LIST_FOREACH(p, hash + i)
799 printf("%s=%s\n",p->name, get_var_nc(p->varcode));
804 save_current_headers(struct list* hash)
810 LIST_FOREACH(p, current_headers){
811 pv = get_var_struct(p->name, VAR_HEADER, hash);
814 u = unfold(p->value);
815 set_var(pv->varcode, u);
817 set_modif_flag(pv->varcode, 0);