#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;