about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2016-07-29 15:15:57 +0200
committerChristian Neukirchen <chneukirchen@gmail.com>2016-07-29 15:15:57 +0200
commitbe2ca1ba42029b80cffff78afee77abf9831131a (patch)
treebaa0e210bac2a1fbc863bf8ee2c45b70eb0e6c93
parent5d1266b38f35916d3ce48cc07052c459c802a7d3 (diff)
downloadmblaze-be2ca1ba42029b80cffff78afee77abf9831131a.tar.gz
mblaze-be2ca1ba42029b80cffff78afee77abf9831131a.tar.xz
mblaze-be2ca1ba42029b80cffff78afee77abf9831131a.zip
mshow: actually filter the parts
-rw-r--r--Makefile2
-rw-r--r--blaze822.h4
-rw-r--r--filter.c124
-rw-r--r--mshow.c34
4 files changed, 152 insertions, 12 deletions
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 <poll.h>            
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+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: