From: Anicka Bernathova Date: Sun, 19 Jul 2009 21:48:41 +0000 (+0200) Subject: started with filtering mail X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=43367dfb74d85a732b8973140a7b87a888b11902;p=umpf.git started with filtering mail --- diff --git a/code.c b/code.c index 18fde4f..59742fc 100644 --- a/code.c +++ b/code.c @@ -297,6 +297,9 @@ do_arrow(struct tree* t, struct list* where) case K_DISCARD: ins.opcode = OPC_DISCARD; break; + case K_FILTER: + ins.opcode = OPC_FILTER; + break; default: die("do_arrow: This cannot happen ;-)"); } @@ -428,6 +431,9 @@ print_code(void) case OPC_PIPE: printf("PIPE %d %d\n", p->u.arrow.what, p->u.arrow.copy); break; + case OPC_FILTER: + printf("FILTER %d %d\n", p->u.arrow.what, p->u.arrow.copy); + break; case OPC_DELIVER: printf("DELIVER %d %d\n", p->u.arrow.what, p->u.arrow.copy); break; diff --git a/cond.y b/cond.y index 5410156..38ec08c 100644 --- a/cond.y +++ b/cond.y @@ -21,7 +21,7 @@ static struct tree* tree_malloc(int type); %token NUM %token VAR %token KW_DISCARD -%token KW_PIPE KW_MAIL KW_COPY +%token KW_PIPE KW_MAIL KW_COPY KW_FILTER %token '(' ')' '{' '}' ';' %nonassoc KW_IF %nonassoc KW_ELSE @@ -194,6 +194,7 @@ left: /* empty */ { $$ = K_EMPTY;} right: /* empty */ { $$ = K_EMPTY; } | KW_PIPE { $$ = K_PIPE; } | KW_MAIL { $$ = K_MAIL; } + | KW_FILTER { $$ = K_FILTER; } ; ass_right_p: '(' ass_right ')' {$$ = $2; } diff --git a/ham.c b/ham.c index f8f96bd..93e461c 100644 --- a/ham.c +++ b/ham.c @@ -297,6 +297,73 @@ write_email_to_fd(int fd, struct email* email) return 0; } +int email_pos; +int headers_sent; +int email_opened; + +void +open_email(void) +{ + email_pos = 0; + headers_sent = 0; + email_opened = 1; +} + +char* +read_email(struct email* em) +{ + char* buf; + int r, pos; + + if (! email_opened) { + chars_written = 0; + return NULL; + } + + if (! headers_sent) { + struct hlist* ph; + int curbufsize = BUFSIZE; + buf = xmalloc(BUFSIZE); + pos = 0; + + LIST_FOREACH(ph, em->headers){ + int needed = strlen(ph->name) + strlen(ph->value) + 3; + if (curbufsize < pos + needed) + buf = xrealloc(buf, curbufsize*=2); + strcpy(buf + pos, ph->name); + pos += strlen(ph->name); + buf[pos++] = ':'; + strcpy(buf + pos, ph->value); + pos += strlen(ph->value); + buf[pos++] = '\n'; + + } + buf[pos] = '\n'; + headers_sent = 1; + chars_written = pos; + return buf; + } + + if (em->body) { + buf = xstrdup(em->body); + chars_written = em->body_len; + //printf("%d: %s\n", em->body_len, em->body); + email_opened = 0; + return buf; + } + + if (! email_pos) + lseek(em->fd, 0, SEEK_SET); + + buf = xmalloc(MAIL_LEN + 1); + r = read(em->fd, buf, MAIL_LEN); + if (r < MAIL_LEN) + email_opened = 0; + chars_written = r; + + return buf; +} + int deliver_local_email(char* folder, struct email* email) { diff --git a/int.c b/int.c index e1c906f..265003e 100644 --- a/int.c +++ b/int.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "cond.tab.h" #include "umpf.h" @@ -18,6 +19,11 @@ #define INT_TO_STRING_LEN ((sizeof(int)*4*CHAR_BIT)/10 + 6) +struct tmpfile { + int fd; + char* name; +}; + void __attribute__ ((noreturn)) bye(int code, char* msg, ...) { @@ -433,6 +439,149 @@ end: } } +static struct tmpfile* +pipe_to(char* program, struct email* em) +{ + int pd_in[2]; + int pd_out[2]; + int pid, status; + struct pollfd pfd[2]; + char* name = xstrdup("/tmp/umpf.XXXXXX"); + char buf[BUFSIZE]; + int r; + int nfds = 2; + int data_pos = 0; + int fd = mkstemp(name); + struct tmpfile* tmp = xmalloc(sizeof(struct tmpfile)); + char* e = NULL; + if (fd < 0) + return NULL; + + tmp->name = name; + tmp->fd = fd; + + int res = pipe(pd_in); + if (res < 0) + goto bad; + res = pipe(pd_out); + if (res < 0) + goto bad; + + if ((pid = fork()) < 0) + goto bad; + else if (pid == 0) { + close(0); + dup(pd_in[0]); + + close(1); + dup(pd_out[1]); + + close(pd_in[0]); + close(pd_out[1]); + close(pd_in[1]); + close(pd_out[0]); + res = execl("/bin/sh", "sh", "-c", program, NULL); + } + close(pd_in[0]); + close(pd_out[1]); + + pfd[1].fd = pd_in[1]; + pfd[0].fd = pd_out[0]; + pfd[1].events = POLLOUT; + pfd[0].events = POLLIN; + + open_email(); + for (;;) { + if (poll(pfd, nfds, -1) < 0) + goto bad; + if ((pfd[0].revents & POLLERR) || (pfd[1].revents & POLLERR)) + goto bad; + + if (pfd[0].revents & POLLIN) { + r = read(pfd[0].fd, buf, BUFSIZE); + if (r <= 0) + break; + write(fd, buf, r); + } + if (pfd[0].revents & POLLHUP) + break; + + if (nfds < 2) + continue; + + if (pfd[1].revents & POLLOUT) { + if (!chars_written) { + e = read_email(em); + data_pos = 0; + if (!chars_written) { + close(pfd[1].fd); + nfds = 1; + continue; + } + } + if (data_pos < chars_written) { + r = write(pfd[1].fd, e + data_pos, + chars_written - data_pos); + data_pos += r; + } else { + free_string(e); + data_pos = 0; + e = read_email(em); + } + } + } + + close(pd_out[0]); + wait(&status); + + return tmp; +bad: + close(fd); + unlink(name); + return NULL; +} + +static void +do_filter(char* program, int copy, struct list* hash) +{ + struct email em = prepare_email(hash); + struct tmpfile* f; + int res = 0; + off_t pos; + + f = pipe_to(program, &em); + if (!f) { + res++; + goto end; + } + pos = lseek(f->fd, 0, SEEK_END); + lseek(f->fd, 0, SEEK_SET); + +/* + FIXME: do some real work ;) + + printf("Tmp filename %s, file is long %d\n", f->name, (int) pos); + + int i; + char c; + for (i = 0; i < pos; i++) { + read(f->fd, &c, 1); + write(1, &c, 1); + } + +*/ + unlink(f->name); + free(f); +end: + destroy_email(em); + if (!copy) { + if (!res) + bye(EX_TEMPFAIL, "%m"); + else + bye(0, NULL); + } +} + void interp(struct list* ins, struct list* hash) { @@ -489,6 +638,10 @@ interp(struct list* ins, struct list* hash) break; case OPC_PIPE: break; + case OPC_FILTER: + do_filter(get_var(p->u.arrow.what), + p->u.arrow.copy, hash); + break; case OPC_MAIL: send_mail(get_var(p->u.arrow.what), p->u.arrow.copy, hash); @@ -497,8 +650,6 @@ interp(struct list* ins, struct list* hash) deliver(get_var(p->u.arrow.what), p->u.arrow.copy, hash); break; - case OPC_CALL_EXT: - break; case OPC_DISCARD: bye(0, NULL); break; diff --git a/lex.c b/lex.c index 9f02013..4e4a103 100644 --- a/lex.c +++ b/lex.c @@ -19,7 +19,8 @@ static struct keys kwds[] = {"if", KW_IF}, {"mail", KW_MAIL}, {"pipe", KW_PIPE}, - {"discard", KW_DISCARD} + {"discard", KW_DISCARD}, + {"filter", KW_FILTER} }; void diff --git a/umpf.h b/umpf.h index 7947ef3..32cd804 100644 --- a/umpf.h +++ b/umpf.h @@ -9,7 +9,8 @@ enum keyword { K_COPY, K_MAIL, K_PIPE, - K_EMPTY + K_EMPTY, + K_FILTER }; struct tree { @@ -100,7 +101,6 @@ struct code { OPC_JUMP_IF, OPC_JUMP_UNLESS, OPC_DELIVER, - OPC_CALL_EXT, OPC_NOP, OPC_CAT, OPC_GT, @@ -121,6 +121,7 @@ struct code { OPC_DIV, OPC_PIPE, OPC_MAIL, + OPC_FILTER, OPC_DISCARD } opcode; @@ -208,6 +209,7 @@ void __attribute__ ((noreturn)) bye(int code, char* msg, ...); /* ham.c */ char* default_mailbox; +int chars_written; struct list* current_headers; struct email* current_body; @@ -216,6 +218,8 @@ void print_headers(struct list* l); struct email* get_body(void); int deliver_local_email(char* folder, struct email* email); int write_email_to_fd(int fd, struct email* email); +char* read_email(struct email* em); +void open_email(void); /* lock.c */ void save_gids(void);