shithub: gemnine

ref: 456b709807fdeb7c725731fd1469f7181b342893
dir: gemnine/main.c

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <plumb.h>
#include <ctype.h>
#include "gemnine.h"

static void
page(Response *r)
{
	if(rfork(RFPROC|RFFDG|RFNOTEG|RFNOWAIT) == 0){
		char tmp[32] = "/tmp/gem9XXXXXXXXXXX", *cmd;
		int f;
		mktemp(tmp);
		cmd = smprint("cat >%s; page %s; rm %s", tmp, tmp, tmp);
		dup(r->fd, 0); close(r->fd);
		dup((f = open("/dev/null", OWRITE)), 1);
		dup(f, 2);
		close(f);
		execl("/bin/rc", "rc", "-c", cmd, nil);
	}
}

static void
play(Response *r)
{
	if(rfork(RFPROC|RFFDG|RFNOTEG|RFNOWAIT) == 0){
		int wfd, f;
		char *wsys, tmp[64];
		snprint(tmp, sizeof(tmp), "new -pid %d -dx %d -dy %d", getpid(), 640, 480);
		if ((wsys = getenv("wsys")) == nil)
			exits("no wsys");
		if ((wfd = open(wsys, ORDWR|OCEXEC)) < 0 ||
		    mount(wfd, -1, "/mnt/wsys", MREPL, tmp) < 0 ||
		    bind("/mnt/wsys", "/dev", MBEFORE) < 0){
			exits("wsys: %r");
		}
		dup(r->fd, 0); close(r->fd);
		dup((f = open("/dev/null", OWRITE)), 1);
		dup(f, 2);
		execl("/bin/play", "play", nil);
	}
}

static void
usage(void)
{
	fprint(2, "usage: %s [-w] [URL]\n", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	Response *r;
	char *s, *t, *u, *tmp;
	Url *url, *x;
	int len, raw, wait, pl, fd;
	Plumbmsg *m;
	Biobuf out, body;
	char buf[8192];

	wait = 0;
	ARGBEGIN{
	case 'w':
		wait = 1;
		break;
	default:
		usage();
	}ARGEND;

	if(!wait && argc < 1)
		usage();

	raw = fd2path(1, buf, sizeof(buf)) == 0 && strcmp(buf, "/dev/cons") != 0;

	quotefmtinstall();
	fmtinstall('U', Ufmt);
	fmtinstall('N', Nfmt);
	fmtinstall(']', Mfmt);
	fmtinstall('E', Efmt);
	fmtinstall('[', encodefmt);
	fmtinstall('H', encodefmt);

	Binit(&out, 1, OWRITE);
	pl = -1;

nexturl:
	url = nil;
	if(wait){
		if(pl >= 0 || (pl = plumbopen("gemini", OREAD)) >= 0){
			if((m = plumbrecv(pl)) != nil){
				url = urlparse(nil, estrdup(m->data));
				plumbfree(m);
			}else{
				exits(nil);
			}
		}else{
			sysfatal("plumbopen: %r");
		}
	}else{
		url = urlparse(nil, estrdup(argv[0]));
	}

nextreq:
	if((r = request(url)) != nil){
		if(!raw && r->mime != nil && strncmp(r->mime, "text/", 5) != 0){
			if(strncmp(r->mime, "image/", 6) == 0 || strcmp(r->mime, "application/pdf") == 0)
				page(r);
			else if(strncmp(r->mime, "audio/", 6) == 0)
				play(r);
			else
				fprint(2, "unsupported MIME %q\n", r->mime);
		}else if(r->prompt != nil){
			if(wait)
				close(open("/dev/text", OWRITE|OTRUNC|OCEXEC));
			if((fd = open("/dev/consctl", OWRITE|OCEXEC)) >= 0){
				write(fd, "holdon", 6);
				print("%s\n", r->prompt);
				Binit(&body, 0, OREAD);
				t = nil;
				if((s = Brdstr(&body, 0, 1)) != nil)
					t = smprint("%s?%E", r->url->full, (Str2){s, "/:@ \n"});
				Bterm(&body);
				free(s);
				if(t != nil){
					freeresponse(r);
					freeurl(url);
					url = urlparse(nil, t);
					free(t);
				}else{
					fprint(2, "%r\n");
				}
				close(fd);
				goto nextreq;
			}else{
				fprint(2, "%r\n");
			}
		}else{
			if(wait)
				close(open("/dev/text", OWRITE|OTRUNC|OCEXEC));
			if(r->code < 20 || r->code >= 30){
				if(r->code > 0)
					fprint(2, "%U: %d %s\n", url, r->code, (r->meta && r->meta[0]) ? r->meta : r->status);
				else
					fprint(2, "%U: %r\n", url);
				if(!wait)
					exits("failed");
			}else if(raw){
				for(;;){
					if((len = read(r->fd, buf, sizeof(buf))) == 0)
						break;
					if(len < 0)
						goto err;
					if(write(1, buf, len) <= 0)
						break;
				}
			}else{
				Binit(&body, r->fd, OREAD);
				while((s = Brdstr(&body, '\n', 1)) != nil){
					if((len = Blinelen(&body)) > 0)
						s[len] = 0;
					for(len--; len >= 0 && (s[len] == '\r' || s[len] == '\n'); len--)
						s[len] = 0;
					if(s[0] == '=' && s[1] == '>'){
						u = s + 2;
						while(isspace(*u))
							u++;
						if((t = strpbrk(u, " \t")) != nil)
							*t++ = 0;
						else
							t = "";
						x = urlparse(r->url, u);
						if((tmp = smprint("%U", x)) != nil && strcmp(tmp, t) == 0)
							Bprint(&out, "→ %s\n", tmp);
						else
							Bprint(&out, "→ %s %s\n", tmp, t);
						free(tmp);
						freeurl(x);
					}else{
						Bprint(&out, "%s\n", s);
					}
					free(s);
				}
				Bterm(&body);
			}
		}
		freeresponse(r);
		freeurl(url);
	}else{
err:
		fprint(2, "%U: %r\n", url);
		if(!wait)
			exits("failed");
	}

	Bflush(&out);
	if(wait)
		goto nexturl;

	exits(nil);
}