From be2ca1ba42029b80cffff78afee77abf9831131a Mon Sep 17 00:00:00 2001 From: Christian Neukirchen Date: Fri, 29 Jul 2016 15:15:57 +0200 Subject: [PATCH] mshow: actually filter the parts --- Makefile | 2 +- blaze822.h | 4 ++ filter.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++ mshow.c | 34 ++++++++++----- 4 files changed, 152 insertions(+), 12 deletions(-) create mode 100644 filter.c diff --git a/Makefile b/Makefile index 864de84..c627112 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ mmime: mmime.o mpick: mpick.o blaze822.o seq.o rfc2047.c mymemmem.o mscan: mscan.o blaze822.o seq.o rfc2047.o mymemmem.o mseq: mseq.o seq.o -mshow: mshow.o blaze822.o seq.o rfc2045.o rfc2047.c mymemmem.o +mshow: mshow.o blaze822.o seq.o rfc2045.o rfc2047.c mymemmem.o filter.o msort: msort.o blaze822.o seq.o mystrverscmp.o mymemmem.o mthread: mthread.o blaze822.o seq.o mymemmem.o diff --git a/blaze822.h b/blaze822.h index c43df3e..450da28 100644 --- a/blaze822.h +++ b/blaze822.h @@ -61,3 +61,7 @@ char *blaze822_seq_next(char *map, char *range, struct blaze822_seq_iter *iter); int blaze822_loop(int, char **, void (*)(char *)); int blaze822_loop1(char *arg, void (*cb)(char *)); char *blaze822_home_file(char *basename); + +// filter.c + +int filter(char *input, size_t inlen, char *cmd, char **outputo, size_t *outleno); diff --git a/filter.c b/filter.c new file mode 100644 index 0000000..3996dfd --- /dev/null +++ b/filter.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include + +int +filter(char *input, size_t inlen, char *cmd, char **outputo, size_t *outleno) +{ + char *output; + size_t outlen; + ssize_t outalloc = 4096; + pid_t pid; + + output = malloc(outalloc); + outlen = 0; + + int pipe0[2]; + int pipe1[2]; + + if (pipe(pipe0) != 0 || pipe(pipe1) != 0) + goto fail; + + char *argv[] = { "/bin/sh", "-c", cmd, (char *)0 }; + + if (!(pid = fork())) { + dup2(pipe0[0], 0); + close(pipe0[1]); + close(pipe0[0]); + + dup2(pipe1[1], 1); + close(pipe1[0]); + close(pipe1[1]); + + execvp(argv[0], argv); + exit(-1); + } + close(pipe0[0]); + close(pipe1[1]); + + if (pid < 0) { + close(pipe0[1]); + close(pipe1[0]); + goto fail; + } + + struct pollfd fds[2]; + + fds[0].fd = pipe1[0]; + fds[0].events = POLLIN; + fds[1].fd = pipe0[1]; + fds[1].events = POLLOUT; + + while ((fds[0].fd >= 0 || fds[1].fd >= 0) && + poll(fds, sizeof fds / sizeof fds[0], -1) >= 0) { + if (fds[0].revents & POLLIN) { + if (outlen + 512 > outalloc) { + outalloc *= 2; + if (outalloc < 0) + exit(-1); + output = realloc(output, outalloc); + if (!output) + exit(-1); + } + ssize_t ret = read(fds[0].fd, output + outlen, 512); + if (ret > 0) + outlen += ret; + else if (ret < 0) + close(fds[0].fd); + } else if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { + fds[0].fd = -1; + } + + if (fds[1].revents & POLLOUT) { + ssize_t ret = write(fds[1].fd, input, inlen); + if (ret > 0) { + input += ret; + inlen -= ret; + } + if (ret <= 0 || inlen == 0) + close(fds[1].fd); + } else if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) { + fds[1].fd = -1; + } + } + + // ok to fail when closed already + close(pipe0[1]); + close(pipe1[0]); + + int status; + waitpid(pid, &status, 0); + + *outputo = output; + *outleno = outlen; + + return WEXITSTATUS(status); + +fail: + *outputo = 0; + *outleno = 0; + + return -1; +} + +#ifdef TEST +int +main() +{ + char *input = "foo\nbar\nbaz"; + int e; + + char *output; + size_t outlen; + + e = filter(input, strlen(input), "rev;exit 2", &output, &outlen); + + fwrite(output, 1, outlen, stdout); + printf("%ld -> %d\n", outlen, e); + + return 0; +} +#endif diff --git a/mshow.c b/mshow.c index 9c1be33..4d4e217 100644 --- a/mshow.c +++ b/mshow.c @@ -149,6 +149,8 @@ typedef enum { typedef mime_action (*mime_callback)(int, struct message *, char *, size_t); +mime_action walk_mime(struct message *msg, int depth, mime_callback visit); + char * mime_filename(struct message *msg) { @@ -199,19 +201,29 @@ render_mime(int depth, struct message *msg, char *body, size_t bodylen) setenv("PIPE_CHARSET", charset, 1); free(charset); } - printf(" filter=\"%s\" ---\n", cmd); - FILE *p; - fflush(stdout); - p = popen(cmd, "w"); - if (!p) { - perror("popen"); - goto nofilter; - } - fwrite(body, 1, bodylen, p); - if (pclose(p) != 0) { - perror("pclose"); + setenv("PIPE_CONTENTTYPE", ct, 1); + + char *output; + size_t outlen; + int e = filter(body, bodylen, cmd, &output, &outlen); + + if (e == 0) { + printf(" render=\"%s\" ---\n", cmd); + print_ascii(output, outlen); + } else if (e == 64) { // decode output again + printf(" filter=\"%s\" ---\n", cmd); + struct message *imsg = blaze822_mem(output, outlen); + if (imsg) + walk_mime(imsg, depth+1, render_mime); + blaze822_free(imsg); + } else { + printf(" filter=\"%s\" FAILED status=%d", cmd, e); + free(output); goto nofilter; } + + free(output); + r = MIME_PRUNE; } else { nofilter: