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);
}