shithub: wired

Download patch

ref: a61225ef49bd5e0e89e101ab3cfe0550628e500c
parent: 5a9e919a0872f18fd39b62ab3c74216f0666e2e6
author: james palmer <james@biobuf.link>
date: Fri Jun 25 09:56:13 EDT 2021

drastically simplified.

--- a/main.c
+++ b/main.c
@@ -3,91 +3,67 @@
 #include <thread.h>
 #include <acme.h>
 
-typedef struct Server Server;
-typedef struct Chan Chan;
-typedef struct Ctl Ctl;
+char *srv = "tcp!9p.zone!9990";
+char *mtpt = "/n/wired";
+char *chan = "chat";
+char *sep = "•";
+char *nick;
 
-struct Server {
-	char *addr;
-	char *mtpt;
-	char *user;
-	
-	char *sep;
-	char *actsep;
-
-	Chan *channels;
-};
-
-struct Chan {
-	char *name;
-	
-	Channel *logc;
-	Channel *inputc;
-	Channel *readc;
-	
-	Channel *ctl;
-	
-	int logproc;
-	int inputproc;
-	int readproc;
-
+void
+connectsrv(void)
+{
 	int fd;
 
-	Server *srv;
-};
+	fd = dial(srv, nil, nil, nil);
+	if(fd < 0)
+		sysfatal("dial: %r");
+	if(mount(fd, -1, mtpt, MREPL, "") < 0)
+		sysfatal("mount: %r");
+}
 
-struct Ctl {
-	int type;
-	void *aux;
-};
+AWin *
+makewin(char *name, Channel *c)
+{
+	AWin *win;
 
-enum {
-	MExit,
-	MMessage,
-	MSend,
-	MAct,
+	win = awincreate();
+	win->aux = c;
 
-	Stack = 4*1024,
-	Buf = 8*1024,
-};
+	fprint(win->ctlfd, "name /wired/%s/%s\n", chan, name);
+	fprint(win->ctlfd, "scratch\nnomenu\n");
 
-int
-sendctl(Channel *chan, int type, void *aux)
-{
-	Ctl ctl;
-	
-	ctl.type = type;
-	ctl.aux = aux;
-	
-	return send(chan, &ctl);
+	return win;
 }
 
 void
-handleevent(Chan *chan, AWin *win, AEvent *ev)
+readproc(void *aux)
 {
-	switch(ev->type) {
-	case 'x':
-	case 'X':
-		if(strcmp(ev->text, "Del") == 0)
-			sendctl(chan->ctl, MExit, nil);
-		else if(strcmp(ev->text, "Send") == 0)
-			sendctl(chan->inputc, MSend, nil);
-		else if(strcmp(ev->text, "Action") == 0)
-			sendctl(chan->inputc, MAct, nil);
-		else
-			aeventsend(win, ev);
-			
-		break;
-	case 'I':
-		if(strchr(ev->text, '') != 0)
-			sendctl(chan->ctl, MSend, nil);
-			
-		break;
-	case 'l':
-	case 'L':
-		aeventsend(win, ev);
-		break;
+	AWin *win;
+	char *file;
+	char buf[8192];
+	int fd;
+	long n;
+
+	threadsetname("read");
+
+	win = aux;
+	file = smprint("%s/%s", mtpt, chan);
+	if(!file) {
+		awincloseall();
+		sysfatal("smprint failed");
 	}
+
+	fd = open(file, OREAD);
+	if(fd < 0) {
+		awincloseall();
+		sysfatal("channel not found");
+	}
+
+	while((n = read(fd, buf, sizeof(buf))) > 0)
+		write(win->bodyfd, buf, n);
+
+	awincloseall();
+	sysfatal("failed to read channel");
 }
 
 void
@@ -94,251 +70,150 @@
 eventproc(void *aux)
 {
 	AWin *win;
+	Channel *events;
 	AEvent ev;
 
 	threadsetname("event");
-		
+
 	win = aux;
+	events = win->aux;
 	win->eventfd = awinfsopen(win, "event", ORDWR);
-	
-	while(aeventnext(win, &ev) > 0)
-		handleevent(win->aux, win, &ev);
 
-	threadexits(nil);
-}
-
-void
-logproc(void *aux)
-{
-	Chan *chan;
-	Ctl ctl;
-	AWin *win;
-
-	threadsetname("log");
-	
-	chan = aux;
-	win = awincreate();
-	fprint(win->ctlfd, "name /wired/%s/log\n"
-		"scratch\n" "nomenu\n", chan->name);
-	win->aux = chan;
-	
-	proccreate(eventproc, win, Stack);
-	
-	while(recv(chan->logc, &ctl)) {
-		switch(ctl.type) {
-		case MMessage:
-			fprint(win->bodyfd, "%s", ctl.aux);
-			free(ctl.aux);
+	while(aeventnext(win, &ev)) {
+		switch(ev.type) {
+		case 'L':
+		case 'l':
+			aeventsend(win, &ev);
 			break;
-		case MExit:
-			goto exit;
+		default:
+			send(events, &ev);
 		}
 	}
 
-exit:
-	close(win->eventfd);
-	chanfree(chan->logc);
-	awinclose(win);
 	threadexits(nil);
 }
 
 void
-sendmessage(AWin *win, char *fmt, ...)
+filter(char *s)
 {
-	Chan *chan;
-	char *prefix;
-	char *message;
-	va_list args;
-	
-	chan = win->aux;
+	int len;
+	int i, j;
 
-	va_start(args, fmt);
-	prefix = vsmprint(fmt, args);
-	va_end(args);
+	len = strlen(s);
 	
-	message = mallocz(Buf, 1);
-	fprint(win->addrfd, ",");
-	if(read(win->datafd, message, Buf-1) < 0)
-		return;
-	
-	fprint(chan->fd, "%s %s\n", prefix, message);
-	free(prefix);
-	free(message);
-}
-
-void
-inputproc(void *aux)
-{
-	Server *srv;
-	Chan *chan;
-	Ctl ctl;
-	AWin *win;
-
-	threadsetname("input");
-	
-	chan = aux;
-	srv = chan->srv;
-	win = awincreate();
-	fprint(win->ctlfd, "name /wired/%s/input\n"
-		"scratch\n" "nomenu\n", chan->name);
-	awinsettag(win, " Send Action ");
-	win->aux = chan;
-	
-	proccreate(eventproc, win, Stack);
-	
-	while(recv(chan->inputc, &ctl)) {
-		switch(ctl.type) {
-		case MSend:
-			sendmessage(win, "%s %s", srv->user, srv->sep);
+	/* strip trailing nl */
+	for(i = len-1; i > 0; i--)
+		if(s[i] == '\n')
+			s[i] = 0;
+		else
 			break;
-		case MAct:
-			sendmessage(win, "%s %s", srv->actsep, srv->user);
-			break;
-		case MExit:
-			goto exit;
+
+	/* strip eot */
+	j = 0; len = strlen(s);
+	for(i = 0; i < len; i++) {
+		if(s[i] != '') {
+			s[j] = s[i];
+			j++;
 		}
 	}
-
-exit:
-	close(win->eventfd);
-	chanfree(chan->inputc);
-	awinclose(win);
-	threadexits(nil);
+	s[j] = 0;
 }
 
 void
-readproc(void *aux)
+sendmessage(AWin *win)
 {
-	Chan *chan;
-	char *buf;
+	int fd;
+	char *file;
+	char buf[4096];
 	long n;
-	Ctl ctl;
 
-	threadsetname("read");
-	
-	chan = aux;
-	buf = mallocz(Buf, 1);
-	
-	while((n = read(chan->fd, buf, Buf-1)) > 0) {
-		buf[n] = '\0';
-		sendctl(chan->logc, MMessage, strdup(buf));
-		
-		if(nbrecv(chan->readc, &ctl))
-			if(ctl.type == MExit)
-				break;
+	file = smprint("%s/%s", mtpt, chan);
+	if(!file) {
+		awincloseall();
+		sysfatal("smprint failed");
 	}
-	
-	free(buf);
-	chanfree(chan->readc);
-	threadexits(nil);
-}
 
-void
-connectchan(Server *srv, char *name)
-{
-	Chan *chan;
-	char *buf;
-	Ctl ctl;
-	
-	chan = mallocz(sizeof(Chan), 1);
-	chan->name = name;
-	chan->srv = srv;
-	
-	buf = smprint("%s/%s", srv->mtpt, name);
-	chan->fd = open(buf, ORDWR);
-	if(chan->fd < 0) {
-		fprint(2, "channel %s not found\n", name);
-		free(chan);
-		return;
+	fd = open(file, OWRITE);
+	if(fd < 0) {
+		awincloseall();
+		sysfatal("couldn't write channel");
 	}
-	
-	chan->logc = chancreate(sizeof(Ctl), 0);
-	chan->inputc = chancreate(sizeof(Ctl), 0);
-	chan->readc = chancreate(sizeof(Ctl), 0);
-	
-	chan->ctl = chancreate(sizeof(Ctl), 0);
-	
-	chan->logproc = proccreate(logproc, chan, Stack);
-	chan->inputproc = proccreate(inputproc, chan, Stack);
-	chan->readproc = proccreate(readproc, chan, Stack);
-	
-	while(recv(chan->ctl, &ctl)) {
-		if(ctl.type == MExit) {
-			threadint(chan->readproc); /* try to interrupt the read */
-			sendctl(chan->logc, MExit, nil);
-			sendctl(chan->inputc, MExit, nil);
-			break;
-		}
-	}
 
+	/* read the input window in 4096 byte chunks.
+	 * if the message is too large it will be split awkwardly :(
+	 * hopefully nobody needs a message that large */
+	fprint(win->addrfd, ",");
+	while((n = read(win->datafd, buf, sizeof(buf)-1)) > 0) {
+		buf[n] = '\0'; filter(buf); /* null terminate and filter */
+		fprint(fd, "%s %s %s\n", nick, sep, buf);
+	};
 
-	chanfree(chan->ctl);
-	free(chan);
-	free(buf);
-	return;
-}
 
-void
-connectsrv(Server *srv)
-{
-	int fd;
-	
-	if((fd = dial(srv->addr, nil, nil, nil)) < 0)
-		sysfatal("couldn't dial chat server: %r");
-	if(mount(fd, -1, srv->mtpt, MREPL, "") < 0)
-		sysfatal("couldn't mount chat server: %r");
+	/* clear: use of buf here means nothing, the write is 0 bytes.
+	 * it is only there to prevent a crash due to a bad syscall. */
+	fprint(win->addrfd, ",");
+	write(win->datafd, buf, 0);
 }
 
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-s srv] [-m mtpt] [-u user] "
-		"[-S sep] [-A actsep]\n", argv0);
-	threadexitsall("usage");
+	fprint(2, "usage: %s [-s srv] [-n nick] [channel...]", argv0);
+	threadexitsall(nil);
 }
 
 void
 threadmain(int argc, char *argv[])
 {
-	Server *srv;
-	char *channel;
-	
-	srv = mallocz(sizeof(Server), 1);
-	srv->addr = "tcp!9p.zone!9990";
-	srv->mtpt = "/n/wired";
-	srv->sep = "•";
-	srv->actsep = "*";
-	srv->user = getuser();
+	AWin *log, *input;
+	Channel *events;
+	AEvent ev;
 
-	channel = "chat";
-	
+	nick = getuser();
+
 	ARGBEGIN {
+	case 'n':
+		nick = EARGF(usage());
+		break;
 	case 's':
-		srv->addr = EARGF(usage());
+		srv = EARGF(usage());
 		break;
-	case 'm':
-		srv->mtpt = EARGF(usage());
-		break;
-	case 'u':
-		srv->user = EARGF(usage());
-		break;
-	case 'S':
-		srv->sep = EARGF(usage());
-		break;
-	case 'A':
-		srv->actsep = EARGF(usage());
-		break;
 	case 'c':
-		channel = EARGF(usage());
+		chan = EARGF(usage());
 		break;
-	default:
-		usage();
 	} ARGEND
-	
-	connectsrv(srv);
-	connectchan(srv, channel);
-	unmount(nil, srv->mtpt);
 
-	free(srv);
-	threadexits(nil);
+	connectsrv();
+	events = chancreate(sizeof(AEvent), 0);
+
+	log = makewin("log", events);
+	input = makewin("input", events);
+
+	proccreate(readproc, log, 16*1024);
+	proccreate(eventproc, log, 8*1024);
+	proccreate(eventproc, input, 8*1024);
+
+	while(recv(events, &ev)) {
+		switch(ev.type) {
+		case 'x':
+		case 'X':
+			if(strcmp(ev.text, "Del") == 0)
+				goto quit;
+			if(strcmp(ev.text, "Send") == 0)
+				sendmessage(input);
+			if(strcmp(ev.text, "Act") == 0)
+				sendmessage(input);
+
+			break;
+		case 'I':
+			/* there is an EOT char here, it allows ctrl+d to send */
+			if(strchr(ev.text, ''))
+				sendmessage(input);
+		}
+	}
+
+quit:
+	unmount(nil, mtpt);
+	awincloseall();
+	threadexitsall(nil);
 }