case K_DISCARD:
ins.opcode = OPC_DISCARD;
break;
+ case K_FILTER:
+ ins.opcode = OPC_FILTER;
+ break;
default:
die("do_arrow: This cannot happen ;-)");
}
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;
%token <n> NUM
%token <str> VAR
%token <n> KW_DISCARD
-%token <n> KW_PIPE KW_MAIL KW_COPY
+%token <n> KW_PIPE KW_MAIL KW_COPY KW_FILTER
%token '(' ')' '{' '}' ';'
%nonassoc KW_IF
%nonassoc KW_ELSE
right: /* empty */ { $$ = K_EMPTY; }
| KW_PIPE { $$ = K_PIPE; }
| KW_MAIL { $$ = K_MAIL; }
+ | KW_FILTER { $$ = K_FILTER; }
;
ass_right_p: '(' ass_right ')' {$$ = $2; }
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)
{
#include <stdarg.h>
#include <sys/wait.h>
#include <sysexits.h>
+#include <poll.h>
#include "cond.tab.h"
#include "umpf.h"
#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, ...)
{
}
}
+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)
{
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);
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;
{"if", KW_IF},
{"mail", KW_MAIL},
{"pipe", KW_PIPE},
- {"discard", KW_DISCARD}
+ {"discard", KW_DISCARD},
+ {"filter", KW_FILTER}
};
void
K_COPY,
K_MAIL,
K_PIPE,
- K_EMPTY
+ K_EMPTY,
+ K_FILTER
};
struct tree {
OPC_JUMP_IF,
OPC_JUMP_UNLESS,
OPC_DELIVER,
- OPC_CALL_EXT,
OPC_NOP,
OPC_CAT,
OPC_GT,
OPC_DIV,
OPC_PIPE,
OPC_MAIL,
+ OPC_FILTER,
OPC_DISCARD
} opcode;
/* ham.c */
char* default_mailbox;
+int chars_written;
struct list* current_headers;
struct email* current_body;
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);