diff --git a/src/gmnlm.c b/src/gmnlm.c

index d5cb2dc29f9ceb448622d5c36b7b73f0ca985bcb..5d7892b83f7914da46b08100014db6211e36173a 100644

--- a/src/gmnlm.c

+++ b/src/gmnlm.c

@@ -11,6 +11,7 @@ #include <stdio.h>

#include <string.h>

#include <sys/ioctl.h>

#include <sys/stat.h>

+#include <sys/wait.h>

#include <termios.h>

#include <unistd.h>

#include "gmni.h"

@@ -79,6 +80,7 @@ "m\tSave bookmark\n"

"M\tBrowse bookmarks\n"

"r\tReload the page\n"

"d <path>\tDownload page to <path>\n"

+ "|<prog>\tPipe page into program\n"

"\n"

"Other commands include:\n\n"

"<Enter>\tread more lines\n"

@@ -309,6 +311,55 @@ }

return strcmp(&str[strl - suffl], suff) == 0;

}

+static void

+pipe_resp(FILE *out, struct gemini_response resp, char *cmd) {

+ char buf[BUFSIZ];

+ int pfd[2];

+ if (pipe(pfd) == -1) {

+ perror("pipe");

+ return;

+ }

+ pid_t pid;

+ switch ((pid = fork())) {

+ case -1:

+ perror("fork");

+ return;

+ case 0:

+ close(pfd[1]);

+ dup2(pfd[0], STDIN_FILENO);

+ close(pfd[0]);

+ execlp("sh", "sh", "-c", cmd);

+ perror("exec");

+ _exit(1);

+ }

+ close(pfd[0]);

+ FILE *f = fdopen(pfd[1], "w");

+ // XXX: may affect history, do we care?

+ for (int n = 1; n > 0;) {

+ n = BIO_read(resp.bio, buf, BUFSIZ);

+ if (n == -1) {

+ fprintf(stderr, "Error: read\n");

+ return;

+ }

+ ssize_t w = 0;

+ while (w < (ssize_t)n) {

+ ssize_t x = fwrite(&buf[w], 1, n - w, f);

+ if (ferror(f)) {

+ fprintf(stderr, "Error: write: %s\n",

+ strerror(errno));

+ return;

+ }

+ w += x;

+ }

+ }

+ fclose(f);

+ int status;

+ waitpid(pid, &status, 0);

+ if (status != 0) {

+ fprintf(out, "Command exited %d\n", status);

+ }

+}

+

static enum gemini_result

do_requests(struct browser *browser, struct gemini_response *resp)

{

@@ -570,6 +621,19 @@ }

set_url(browser, url, NULL);

download_resp(browser->tty, resp, trim_ws(&in[1]), url);

gemini_response_finish(&resp);

+ result = PROMPT_AGAIN;

+ goto exit;

+ case '|':

+ strncpy(&url[0], browser->plain_url, sizeof(url));

+ res = do_requests(browser, &resp);

+ if (res != GEMINI_OK) {

+ fprintf(stderr, "Error: %s\n",

+ gemini_strerr(res, &resp));

+ goto exit;

+ }

+ pipe_resp(browser->tty, resp, &in[1]);

+ gemini_response_finish(&resp);

+ set_url(browser, url, NULL);

result = PROMPT_AGAIN;

goto exit;

case '?':