Commit Diff


commit - f5ccf7ae3254e2e1ae090253ae13e21b16f8d50b
commit + 35e1f40abf408663d468038e22af2c6f2ec34659
blob - 731893b48ab311b07be28cc9781bb004cec09e22
blob + e16501d2dcee4bd502a2a607fd995a5c7310903f
--- Makefile.am
+++ Makefile.am
@@ -2,6 +2,7 @@ bin_PROGRAMS =		telescope
 
 telescope_SOURCES =	compat.h	\
 			compat/*.[ch]	\
+			fs.c		\
 			gemini.c	\
 			gemtext.c	\
 			hist.c		\
blob - cab5f282060ec52b8f8eb22f0e0ad9a48f0a7523
blob + bd119ecb712192bbcc512815692a08ebb2db55fe
--- gemini.c
+++ gemini.c
@@ -40,6 +40,7 @@
 #include <tls.h>
 #include <unistd.h>
 
+static struct event		 imsgev;
 static struct tls_config	*tlsconf;
 static struct imsgbuf		*ibuf;
 
blob - /dev/null
blob + a5847c463c7f75320b500f978acd57640cbf2ba4 (mode 644)
--- /dev/null
+++ fs.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "telescope.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void		 die(void) __attribute__((__noreturn__));
+static void		 serve_bookmarks(uint32_t);
+static void		 handle_get(struct imsg*, size_t);
+static void		 handle_quit(struct imsg*, size_t);
+static void		 dispatch_imsg(int, short, void*);
+
+static struct event		 imsgev;
+static struct imsgbuf		*ibuf;
+
+static imsg_handlerfn *handlers[] = {
+	[IMSG_GET] = handle_get,
+	[IMSG_QUIT] = handle_quit,
+};
+
+static void __attribute__((__noreturn__))
+die(void)
+{
+	abort(); 		/* TODO */
+}
+
+static void
+serve_bookmarks(uint32_t peerid)
+{
+	const char	*t;
+	char		 path[PATH_MAX], buf[BUFSIZ];
+	size_t		 r;
+	FILE		*f;
+
+	strlcpy(path, getenv("HOME"), sizeof(path));
+	strlcat(path, "/.telescope/bookmarks.gmi", sizeof(path));
+
+	if ((f = fopen(path, "r")) == NULL) {
+		t = "# error\n\nCan't open ~/.telescope/bookmarks.gmi";
+		imsg_compose(ibuf, IMSG_BUF, peerid, 0, -1, t, strlen(t));
+		imsg_compose(ibuf, IMSG_EOF, peerid, 0, -1, NULL, 0);
+		imsg_flush(ibuf);
+		return;
+	}
+
+	for (;;) {
+		r = fread(buf, 1, sizeof(buf), f);
+		imsg_compose(ibuf, IMSG_BUF, peerid, 0, -1, buf, r);
+		imsg_flush(ibuf);
+		if (r != sizeof(buf))
+			break;
+	}
+
+	imsg_compose(ibuf, IMSG_EOF, peerid, 0, -1, NULL, 0);
+	imsg_flush(ibuf);
+
+	fclose(f);
+}
+
+static void
+handle_get(struct imsg *imsg, size_t datalen)
+{
+	char		*data;
+	const char	*p;
+
+	data = imsg->data;
+
+	if (data[datalen-1] != '\0')
+		die();
+
+	if (!strcmp(data, "about:new")) {
+		imsg_compose(ibuf, IMSG_BUF, imsg->hdr.peerid, 0, -1,
+		    about_new, strlen(about_new));
+		imsg_compose(ibuf, IMSG_EOF, imsg->hdr.peerid, 0, -1, NULL, 0);
+		imsg_flush(ibuf);
+	} else if (!strcmp(data, "about:bookmarks")) {
+		serve_bookmarks(imsg->hdr.peerid);
+	} else {
+		p = "# not found!\n";
+		imsg_compose(ibuf, IMSG_BUF, imsg->hdr.peerid, 0, -1, p, strlen(p));
+		imsg_compose(ibuf, IMSG_EOF, imsg->hdr.peerid, 0, -1, NULL, 0);
+		imsg_flush(ibuf);
+	}
+}
+
+static void
+handle_quit(struct imsg *imsg, size_t datalen)
+{
+	event_loopbreak();
+}
+
+static void
+dispatch_imsg(int fd, short ev, void *d)
+{
+	struct imsgbuf	*ibuf = d;
+	struct imsg	 imsg;
+	ssize_t		 n;
+	size_t		 datalen;
+
+	if ((n = imsg_read(ibuf)) == -1) {
+		if (errno == EAGAIN || errno == EWOULDBLOCK)
+			return;
+		_exit(1);
+	}
+
+	if (n == 0)
+		_exit(1);
+
+	for (;;) {
+		if ((n = imsg_get(ibuf, &imsg)) == -1)
+			_exit(1);
+		if (n == 0)
+			return;
+		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+		handlers[imsg.hdr.type](&imsg, datalen);
+		imsg_free(&imsg);
+	}
+}
+
+int
+fs_main(struct imsgbuf *b)
+{
+	ibuf = b;
+
+	event_init();
+
+	event_set(&imsgev, ibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, ibuf);
+	event_add(&imsgev, NULL);
+
+	sandbox_fs_process();
+
+	event_dispatch();
+	return 0;
+}
blob - 550c6d1f6a2c846270a261c5c863b4f119ca6fcf
blob + ce229f46156efda7fbd24c38fa125849669a5fd5
--- sandbox.c
+++ sandbox.c
@@ -19,7 +19,9 @@
 #ifdef __OpenBSD__
 
 # include <err.h>
-# include <stddef.h>
+# include <limits.h>
+# include <stdlib.h>
+# include <string.h>
 # include <unistd.h>
 
 void
@@ -32,10 +34,32 @@ sandbox_network_process(void)
 void
 sandbox_ui_process(void)
 {
-	if (pledge("stdio tty", NULL))
+	if (pledge("stdio tty", NULL) == -1)
 		err(1, "pledge");
 }
 
+void
+sandbox_fs_process(void)
+{
+	char path[PATH_MAX];
+
+        if (unveil("/tmp", "r") == -1)
+		err(1, "unveil");
+
+	strlcpy(path, getenv("HOME"), sizeof(path));
+	strlcat(path, "/Downloads", sizeof(path));
+	if (unveil(path, "r") == -1)
+		err(1, "unveil");
+
+	strlcpy(path, getenv("HOME"), sizeof(path));
+	strlcat(path, "/.telescope", sizeof(path));
+	if (unveil(path, "r") == -1)
+		err(1, "unveil");
+
+	if (pledge("stdio rpath", NULL) == -1)
+		err(1, "pledge");
+}
+
 #else
 
 #warning "No sandbox for this OS"
@@ -46,4 +70,16 @@ sandbox_network_process(void)
 	return;
 }
 
+void
+sandbox_ui_process(void)
+{
+	return;
+}
+
+void
+sandbox_fs_process(void)
+{
+	return;
+}
+
 #endif
blob - 9044a5f66221c0e8dafa303ace681e87d1de1a89
blob + 6d3c77320242a17abb3375bb5be608c085a67389
--- telescope.c
+++ telescope.c
@@ -10,7 +10,7 @@
 #include <string.h>
 #include <unistd.h>
 
-struct event		 imsgev;
+struct event		 netev, fsev;
 struct tabshead		 tabshead;
 
 /* the first is also the fallback one */
@@ -20,7 +20,7 @@ static struct proto protos[] = {
 	{ NULL, NULL },
 };
 
-static struct imsgbuf	*netibuf;
+static struct imsgbuf	*netibuf, *fsibuf;
 
 static void		 die(void) __attribute__((__noreturn__));
 static struct tab	*tab_by_id(uint32_t);
@@ -201,23 +201,22 @@ handle_imsg_eof(struct imsg *imsg, size_t datalen)
 static void
 dispatch_imsg(int fd, short ev, void *d)
 {
-	struct imsg	imsg;
-	size_t		datalen;
-	ssize_t		n;
+	struct imsgbuf	*ibuf = d;
+	struct imsg	 imsg;
+	size_t		 datalen;
+	ssize_t		 n;
 
-	if ((n = imsg_read(netibuf)) == -1) {
+	if ((n = imsg_read(ibuf)) == -1) {
 		if (errno == EAGAIN || errno == EWOULDBLOCK)
 			return;
 		die();
 	}
 
-	if (n == 0) {
-		fprintf(stderr, "other side is dead\n");
-		exit(0);
-	}
+	if (n == 0)
+		_exit(1);
 
 	for (;;) {
-		if ((n = imsg_get(netibuf, &imsg)) == -1)
+		if ((n = imsg_get(ibuf, &imsg)) == -1)
 			die();
 		if (n == 0)
 			return;
@@ -255,10 +254,11 @@ load_about_url(struct tab *tab, const char *url)
 	len = sizeof(tab->hist_cur->h)-1;
 	strlcpy(tab->hist_cur->h, url, len);
 
-	if (!strcmp(url, "about:new"))
-		load_page_from_str(tab, about_new);
-	else
-		load_page_from_str(tab, "# not found\n");
+	gemtext_initparser(&tab->page);
+
+	imsg_compose(fsibuf, IMSG_GET, tab->id, 0, -1,
+	    tab->hist_cur->h, len+1);
+	imsg_flush(fsibuf);
 }
 
 void
@@ -355,12 +355,15 @@ stop_tab(struct tab *tab)
 int
 main(void)
 {
-	struct imsgbuf	main_ibuf, network_ibuf;
-	int		imsg_fds[2];
+	struct imsgbuf	network_ibuf, fs_ibuf;
+	int		net_fds[2], fs_fds[2];
+	pid_t		pid;
 
+	pid = getpid();
+
 	signal(SIGCHLD, SIG_IGN);
 
-	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
+	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fs_fds) == -1)
 		err(1, "socketpair");
 
 	switch (fork()) {
@@ -368,25 +371,47 @@ main(void)
 		err(1, "fork");
 	case 0:
 		/* child */
-		setproctitle("client");
-		close(imsg_fds[0]);
-		imsg_init(&network_ibuf, imsg_fds[1]);
-		exit(client_main(&network_ibuf));
+		setproctitle("(%d) fs", pid);
+		close(fs_fds[0]);
+		imsg_init(&fs_ibuf, fs_fds[1]);
+		exit(fs_main(&fs_ibuf));
+	default:
+		close(fs_fds[1]);
+		imsg_init(&fs_ibuf, fs_fds[0]);
+		fsibuf = &fs_ibuf;
 	}
 
-	setproctitle("ui");
+	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, net_fds) == -1)
+		err(1, "socketpair");
 
-	close(imsg_fds[1]);
-	imsg_init(&main_ibuf, imsg_fds[0]);
-	netibuf = &main_ibuf;
+	switch (fork()) {
+	case -1:
+		err(1, "fork");
+	case 0:
+		/* child */
+		setproctitle("(%d) client", pid);
+		close(net_fds[0]);
+		close(fs_fds[0]);
+		imsg_init(&network_ibuf, net_fds[1]);
+		exit(client_main(&network_ibuf));
+	default:
+		close(net_fds[1]);
+		imsg_init(&network_ibuf, net_fds[0]);
+		netibuf = &network_ibuf;
+	}
 
+	setproctitle("(%d) ui", pid);
+
 	TAILQ_INIT(&tabshead);
 
 	event_init();
 
-	event_set(&imsgev, netibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, netibuf);
-	event_add(&imsgev, NULL);
+	event_set(&netev, netibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, netibuf);
+	event_add(&netev, NULL);
 
+	event_set(&fsev, fsibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, fsibuf);
+	event_add(&fsev, NULL);
+
 	ui_init();
 
 	sandbox_ui_process();
@@ -396,6 +421,9 @@ main(void)
 	imsg_compose(netibuf, IMSG_QUIT, 0, 0, -1, NULL, 0);
 	imsg_flush(netibuf);
 
+	imsg_compose(fsibuf, IMSG_QUIT, 0, 0, -1, NULL, 0);
+	imsg_flush(fsibuf);
+
 	ui_end();
 
 	return 0;
blob - 382a95116c89beb11b4d9a2975dbe37d594463e4
blob + dbbcaa9440b78c25e03f3b714416d3349db6abcb
--- telescope.h
+++ telescope.h
@@ -29,6 +29,7 @@
 #define GEMINI_URL_LEN 1024
 
 enum imsg_type {
+	/* ui <-> client */
 	IMSG_GET,		/* data is URL, peerid the tab id */
 	IMSG_ERR,
 	IMSG_CHECK_CERT,
@@ -158,10 +159,11 @@ struct keymap {
 	TAILQ_ENTRY(keymap)	 keymaps;
 };
 
-extern struct event		 imsgev;
+/* fs.c */
+int		 fs_main(struct imsgbuf*);
 
 /* gemini.c */
-int		 client_main(struct imsgbuf *b);
+int		 client_main(struct imsgbuf*);
 
 /* gemtext.c */
 void		 gemtext_initparser(struct parser*);
@@ -194,6 +196,7 @@ int		 parser_set_buf(struct parser*, const char*, size
 /* sandbox.c */
 void		 sandbox_network_process(void);
 void		 sandbox_ui_process(void);
+void		 sandbox_fs_process(void);
 
 /* telescope.c */
 void		 load_about_url(struct tab*, const char*);