]> mj.ucw.cz Git - umpf.git/blobdiff - int.c
started with filtering mail
[umpf.git] / int.c
diff --git a/int.c b/int.c
index e1c906f058342ada6c8d264876d5f4fcc48bed35..265003ee82568b9efd58683089aae82a9793b15e 100644 (file)
--- a/int.c
+++ b/int.c
@@ -8,6 +8,7 @@
 #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, ...)
 {
@@ -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;