shithub: gemnine

ref: d15bc694dff1248ac67740c75c299c80e0779e8a
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"

char *
readall(int fd)
{
	char *s;
	int n, sz, bufsz;

	bufsz = 1023;
	s = nil;
	for(sz = 0;; sz += n){
		if(bufsz-sz < 1024){
			bufsz *= 2;
			s = realloc(s, bufsz);
		}
		if((n = read(fd, s+sz, bufsz-sz-1)) < 1)
			break;
	}
	s[sz] = 0;
	if(sz > 1 && s[sz-1] == '\n')
		s[sz-1] = 0;

	return s;
}

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

void
play(Response *r)
{
	int wfd;
	char *wsys, tmp[64];

	if(rfork(RFPROC|RFFDG|RFNOTEG|RFNOWAIT) == 0){
		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)) < 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);
		execl("/bin/play", "play", nil);
	}
}

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

	wait = 0;
	ARGBEGIN{
	case 'w':
		wait = 1;
		break;
	}ARGEND;

	if(!wait && argc < 1){
		fprint(2, "usage: gemnine [-w] [URL]\n");
		exits("usage");
	}

	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(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));
			if((fd = open("/dev/consctl", OWRITE)) >= 0){
				write(fd, "holdon", 6);
				print("%s\n", r->prompt);
				s = readall(0);
				free(url);
				t = smprint("%s?%E", r->url->full, (Str2){s, "/:@ \n"});
				free(s);
				url = urlparse(nil, t);
				free(t);
				freeresponse(r);
				close(fd);
				goto nextreq;
			}else{
				fprint(2, "%r\n");
			}
		}else{
			if(wait)
				close(open("/dev/text", OWRITE|OTRUNC));
			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);
					Bprint(&out, "→ %U %s\n", x, t);
					freeurl(x);
				}else{
					Bprint(&out, "%s\n", s);
				}
				free(s);
			}
		}
		freeresponse(r);
	}else{
		fprint(2, "%r\n");
		if(!wait)
			exits("failed");
	}

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

	exits(nil);
}