shithub: wired

ref: 1abb9736d43ec046c91975abedadce884ecc98a6
dir: /main.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include <acme.h>

typedef struct Session Session;
struct Session {
	AWin *cwin;
	AWin *iwin;
	
	char *mtpt;
	char *chan;
	char *usr;
	
	Channel *ctl;
	
	int fd;
};

enum { Stack = 4*1024, };

void
chatcatproc(void *aux)
{
	Session *s;
	AWin *w;
	
	w = aux;
	s = w->aux;
	
	awincat(w, s->fd);
}

void
wineventproc(void *aux)
{
	AWin *w;
	AEvent ev;
	Session *s;
	Channel *ctl;
	Channel *eventc;
	
	w = aux;
	s = w->aux;
	ctl = s->ctl;
	eventc = aeventlisten(w);
	
	while(recv(eventc, &ev)) {
		switch(ev.type) {
		case 'x':
			if(strcmp(ev.text, "Del") == 0)
				sendp(ctl, "quit");
			if(strcmp(ev.text, "Send") == 0)
				sendp(ctl, "send");
			if(strcmp(ev.text, "Action") == 0)
				sendp(ctl, "act");
				
			break;
		case 'I':
			if(strchr(ev.text, '') != 0)
				sendp(ctl, "send");

			break;
		case 'l':
		case 'L':
			aeventsend(w, &ev);
		}
	}	
}

char *
readbody(AWin *w)
{
	Biobuf *fd;
	int addr;
	char *buf;
	int i;
	
	sleep(10);
	
	addr = awinfsopen(w, "addr", OWRITE);
	fd = awinfsbopen(w, "data", OREAD);

	fprint(addr, ",");
	buf = Brdstr(fd, '\0', 0);
	
	if(!buf)
		return nil;
	
	for(i = strlen(buf)-1; i >= 0; i--) {
		if(buf[i] == '' || buf[i] == '\n')
			buf[i] = '\0';
		else
			break;
	}
	
	if(buf[0] == '\0') {
		awinclear(w);
		return nil;
	}
	
	awinclear(w);
	Bterm(fd);
	close(addr);
	return buf;
}

void
domessage(Session *s, char *msg)
{
	char *buf;
	
	if(!msg)
		return;
	
	buf = smprint("%s • %s\n", s->usr, msg);
	write(s->fd, buf, strlen(buf));
	
	free(buf);
	free(msg);
}

void
doaction(Session *s, char *msg)
{
	char *buf;
	
	if(!msg)
		return;
	
	buf = smprint("* %s %s\n", s->usr, msg);
	write(s->fd, buf, strlen(buf));
	
	free(buf);
	free(msg);
}

void
dochat(char *mtpt, char *chan, char *usr)
{
	Session *s;
	char buf[128];
	char *ctl;
	
	s = mallocz(sizeof(Session), 1);

	s->mtpt = strdup(mtpt);
	s->chan = strdup(chan);
	s->usr = strdup(usr);
	
	snprint(buf, sizeof(buf), "%s/%s", s->mtpt, s->chan);
	s->fd = open(buf, ORDWR);
	if(s->fd < 0) {
		free(s->mtpt);
		free(s->chan);
		free(s->usr);
		free(s);
		
		sysfatal("couldn't read channel: %r");
	};
		
	s->cwin = awincreate();
	awinctl(s->cwin, "name /wired/chat\n");
	awinctl(s->cwin, "scratch\n");
	awinctl(s->cwin, "nomenu\n");
	s->cwin->aux = s;
	
	s->iwin = awincreate();
	awinctl(s->iwin, "name /wired/input\n");
	awinctl(s->iwin, "scratch\n");
	awinctl(s->iwin, "nomenu\n");
	awinsettag(s->iwin, " Send Action ");
	s->iwin->aux = s;
	
	s->ctl = chancreate(sizeof(char*), 0);
	
	proccreate(chatcatproc, s->cwin, Stack);
	proccreate(wineventproc, s->cwin, Stack);
	proccreate(wineventproc, s->iwin, Stack);
	
	while(ctl = recvp(s->ctl)) {
		if(strcmp(ctl, "send") == 0)
			domessage(s, readbody(s->iwin));
		if(strcmp(ctl, "act") == 0)
			doaction(s, readbody(s->iwin));
		if(strcmp(ctl, "quit") == 0)
			break;
	}
}

void
dialchat(char *srv, char *mtpt)
{
	int fd;
	
	if((fd = dial(srv, nil, nil, nil)) < 0)
		sysfatal("couldn't dial chat server: %r");
	if(mount(fd, -1, mtpt, MREPL, "") == -1)
		sysfatal("couldn't mount chat server: %r");
}

void
usage(void)
{
	fprint(2, "usage: %s [-s srv] [-c chan] [-u user]\n", argv0);
	exits(nil);
}

void
threadmain(int argc, char *argv[])
{
	char *srv, *mtpt, *user, *chan;
	
	srv = "tcp!chat.9p.zone!9990";
	mtpt = "/n/chat";
	chan = "chat";
	user = getuser();
	
	ARGBEGIN {
	case 's':
		srv = EARGF(usage());
		break;
	case 'm':
		mtpt = EARGF(usage());
		break;
	case 'c':
		chan = EARGF(usage());
		break;
	case 'u':
		user = EARGF(usage());
		break;
	default:
		usage();
	} ARGEND
	
	dialchat(srv, mtpt);
	dochat(mtpt, chan, user);
	
	awincloseall();
	threadexitsall(nil);
}