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 '?':