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);
67 set_cur_mail_length_var(int len, struct list* hash)
72 pv = get_var_struct(INT_VAR_MAIL_LEN, VAR_INTERN, hash);
74 if (! pv) /* user is not interested */
77 buf = xmalloc(INT_TO_STRING_LEN);
78 sscanf(buf,"%d", &len);
79 set_var(pv->varcode, buf);
84 set_exit_code_var(int code, struct list* hash)
89 pv = get_var_struct(INT_VAR_LAST_EXIT, VAR_INTERN, hash);
91 if (! pv) /* user is not interested */
94 buf = xmalloc(INT_TO_STRING_LEN);
95 sscanf(buf,"%d", &code);
96 set_var(pv->varcode, buf);
101 set_last_pipe_var(char* buf, struct list* hash)
105 pv = get_var_struct(INT_VAR_LAST_EXIT, VAR_INTERN, hash);
107 if (! pv) /* user is not interested */
109 set_var(pv->varcode, buf);
116 return xstrdup(const_tab[-var]);
117 return xstrdup(var_tab[var]);
121 regex_cmp(char* s, char* r)
126 int ovector[OVECCOUNT];
128 brum = pcre_compile(r,0,&error,&erroroffset,NULL);
132 int res = pcre_exec(brum,NULL,s,strlen(s),0,0,ovector,OVECCOUNT);
138 #define UPPER(a) ((a) >> 8)
139 #define LOWER(a) ((a) & 0xFF)
142 xcat(char* left, char* right)
144 char* res = xmalloc(strlen(left) + strlen(right) + 1);
156 fold(const char* value, int taken)
160 int len = strlen(value);
161 int newlines[len / 78 + 5];
167 if (len + taken <= 78)
168 return xstrdup(value);
169 for(i = 0; i < len; i++) {
170 if (value[i] == ' ' || value[i]=='\t')
175 newlines[newl++] = curr_ws;
177 while(value[i] && (value[i] == '\t'
185 ret = xmalloc(2*newl + len + 1);
186 for (i = 0; i < len; i++) {
187 if (newl_done == newl) {
188 strcpy(ret + pos, value + i);
191 if(i != newlines[newl_done])
192 ret[pos++] = value[i];
203 unfold(const char* u)
209 new = xmalloc(strlen(u)+1);
212 #define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
214 while (IS_WHITE(*pu))
219 while (IS_WHITE(*pu))
232 modify_headers(struct list* headers, struct list* hash)
240 LIST_FOREACH(p, headers){
241 pv = get_var_struct(p->name, VAR_HEADER, hash);
244 u = unfold(p->value);
245 value = get_var(pv->varcode);
246 if (strcmp(u, value)){
248 free_string(p->value);
249 p->value = fold(value,
250 strlen(p->name) + 2);
257 for (i = 0; i < HASHSIZE; i++){
258 LIST_FOREACH(pv, hash + i){
259 if (pv->type == VAR_HEADER && pv->modified){
262 p = xmalloc(sizeof(struct hlist));
263 p->name = xstrdup(pv->name);
264 p->value = get_var(pv->varcode);
266 list_add_last(headers, &p->car);
273 copy_headers(struct list* orig)
275 struct list* new = xmalloc(sizeof(struct list));
276 struct hlist* po, *pn;
280 LIST_FOREACH(po, orig){
281 pn = xmalloc(sizeof(struct hlist));
282 pn->name = xstrdup(po->name);
283 pn->value = xstrdup(po->value);
286 list_add_last(new, &pn->car);
293 prepare_email(struct list* hash)
297 modify_headers(current_headers, hash);
298 em.headers = copy_headers(current_headers);
299 em.body_len = current_body->body_len;
300 em.fd = current_body->fd;
301 if (current_body->body) {
302 em.body = xmalloc(em.body_len);
303 memcpy(em.body, current_body->body, em.body_len);
306 em.tmpfile = xstrdup(current_body->tmpfile);
314 destroy_headers(struct list* h)
318 while ((p = list_del_last(h))) {
327 destroy_body(struct email* b)
338 destroy_email(struct email em)
340 destroy_headers(em.headers);
345 do_string_ternary_op(struct code* p)
347 char* l = get_var(p->u.tpop.l);
348 char* r = get_var(p->u.tpop.r);
353 result = xmalloc(INT_TO_STRING_LEN);
354 sprintf(result, "%d", regex_cmp(l, r));
357 result = xmalloc(INT_TO_STRING_LEN);
358 sprintf(result, "%d", !regex_cmp(l, r));
367 set_var(p->u.tpop.res, result);
371 do_num_ternary_op(struct code* p)
374 char* result = xmalloc(INT_TO_STRING_LEN);
376 sscanf(get_var(p->u.tpop.l),"%d", &l);
377 sscanf(get_var(p->u.tpop.r),"%d", &r);
405 res = ((l || r) && !(l && r));
423 sprintf(result, "%d", res);
424 set_var(p->u.tpop.res, result);
430 char* val = get_var(var);
437 sscanf(val, "%d", &v);
443 deliver(char* where, int copy, struct list* hash)
446 struct email em = prepare_email(hash);
448 res = deliver_local_email(where, &em);
454 bye(EX_TEMPFAIL, "Cannot save mail to mailbox %s: %m", where);
461 send_mail(char* where, int copy, struct list* hash)
466 struct email em = prepare_email(hash);
472 if ((pid = fork()) < 0)
479 res = execl("/usr/lib/sendmail", "sendmail", where, NULL);
482 write_email_to_fd(pd[1], &em);
489 bye(EX_TEMPFAIL, "Cannot forward e-mail: %m");
495 static struct procstat*
496 pipe_to(char* program, struct email* em)
501 struct pollfd pfd[2];
502 char* name = xstrdup("/tmp/umpf.XXXXXX");
507 int fd = mkstemp(name);
508 struct procstat* tmp = xmalloc(sizeof(struct procstat));
516 int res = pipe(pd_in);
523 if ((pid = fork()) < 0)
536 res = execl("/bin/sh", "sh", "-c", program, NULL);
541 pfd[1].fd = pd_in[1];
542 pfd[0].fd = pd_out[0];
543 pfd[1].events = POLLOUT;
544 pfd[0].events = POLLIN;
548 if (poll(pfd, nfds, -1) < 0)
550 if ((pfd[0].revents & POLLERR) || (pfd[1].revents & POLLERR))
553 if (pfd[0].revents & POLLIN) {
554 r = read(pfd[0].fd, buf, BUFSIZE);
559 if (pfd[0].revents & POLLHUP)
565 if (pfd[1].revents & POLLOUT) {
566 if (!chars_written) {
569 if (!chars_written) {
575 if (data_pos < chars_written) {
576 r = write(pfd[1].fd, e + data_pos,
577 chars_written - data_pos);
590 tmp->exit = WEXITSTATUS(status);
599 fix_content_length(struct list* h, int len)
603 char* clheader = "Content-Length: ";
605 LIST_FOREACH(ph, h) {
606 if (!strcasecmp("Content-Length", ph->name)) {
608 free_string(ph->value);
609 ph->value = xmalloc(INT_TO_STRING_LEN);
610 sscanf(ph->value, "%d", &len);
616 buf = xmalloc(INT_TO_STRING_LEN + strlen(clheader));
617 tmpbuf = xmalloc(INT_TO_STRING_LEN);
618 sscanf(tmpbuf, "%d", &len);
627 do_filter(char* program, struct list* hash)
629 struct email em = prepare_email(hash);
633 f = pipe_to(program, &em);
638 lseek(f->fd, 0, SEEK_SET);
640 destroy_headers(current_headers);
641 destroy_body(current_body);
642 current_headers = make_hlist(f->fd);
643 current_body = get_body(f->fd);
644 fix_content_length(current_headers, current_body->body_len);
645 save_current_headers(hash);
646 set_cur_mail_length_var(curr_email_len, hash);
647 set_exit_code_var(f->exit, hash);
652 //FIXME: what to do with exit code when pipe failed?
657 do_pipe(char* program, struct list* hash)
659 struct email em = prepare_email(hash);
665 f = pipe_to(program, &em);
670 pos = lseek(f->fd, 0, SEEK_END);
671 lseek(f->fd, 0, SEEK_SET);
674 read(f->fd, buf, pos);
675 set_exit_code_var(f->exit, hash);
676 set_last_pipe_var(buf, hash);
686 interp(struct list* ins, struct list* hash)
692 LIST_FOREACH(p, ins) {
695 set_var(p->u.set.l, get_var(p->u.set.r));
698 p = p->u.jump.target;
702 if (eval_cond(p->u.jump_if.cond))
703 p = p->u.jump_if.target;
706 case OPC_JUMP_UNLESS:
707 if (!eval_cond(p->u.jump_unless.cond))
708 p = p->u.jump_unless.target;
727 do_num_ternary_op(p);
730 result = xmalloc(INT_TO_STRING_LEN);
731 sscanf(get_var(p->u.tpop.l),"%d", &v);
732 sprintf(result, "%d", !v);
733 set_var(p->u.tpop.res, result);
737 do_string_ternary_op(p);
740 do_pipe(get_var(p->u.arrow.what), hash);
743 do_filter(get_var(p->u.arrow.what), hash);
746 send_mail(get_var(p->u.arrow.what),
747 p->u.arrow.copy, hash);
750 deliver(get_var(p->u.arrow.what),
751 p->u.arrow.copy, hash);
757 deliver(default_mailbox, 0, hash);
761 print_vars(struct list* hash)
766 for (i=0; i<HASHSIZE; i++){
767 LIST_FOREACH(p, hash + i)
768 printf("%s=%s\n",p->name, get_var(p->varcode));
773 save_current_headers(struct list* hash)
779 LIST_FOREACH(p, current_headers){
780 pv = get_var_struct(p->name, VAR_HEADER, hash);
783 u = unfold(p->value);
784 set_var(pv->varcode, u);