ref: 5a9e919a0872f18fd39b62ab3c74216f0666e2e6
parent: 1abb9736d43ec046c91975abedadce884ecc98a6
author: james palmer <james@biobuf.link>
date: Tue Jun 15 08:33:48 EDT 2021
rewired. toggleable grep window soon™
--- a/main.c
+++ b/main.c
@@ -1,202 +1,291 @@
#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;
-
+typedef struct Server Server;
+typedef struct Chan Chan;
+typedef struct Ctl Ctl;
+
+struct Server {
+ char *addr;
char *mtpt;
- char *chan;
- char *usr;
+ 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;
+
int fd;
+
+ Server *srv;
};
-enum { Stack = 4*1024, };
+struct Ctl {
+ int type;
+ void *aux;
+};
-void
-chatcatproc(void *aux)
+enum {
+ MExit,
+ MMessage,
+ MSend,
+ MAct,
+
+ Stack = 4*1024,
+ Buf = 8*1024,
+};
+
+int
+sendctl(Channel *chan, int type, void *aux)
{
- Session *s;
- AWin *w;
+ Ctl ctl;
- w = aux;
- s = w->aux;
+ ctl.type = type;
+ ctl.aux = aux;
- awincat(w, s->fd);
+ return send(chan, &ctl);
}
void
-wineventproc(void *aux)
+handleevent(Chan *chan, AWin *win, AEvent *ev)
{
- AWin *w;
+ 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;
+ }
+}
+
+void
+eventproc(void *aux)
+{
+ AWin *win;
AEvent ev;
- Session *s;
- Channel *ctl;
- Channel *eventc;
+
+ threadsetname("event");
+
+ win = aux;
+ win->eventfd = awinfsopen(win, "event", ORDWR);
- 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");
+ while(aeventnext(win, &ev) > 0)
+ handleevent(win->aux, win, &ev);
- break;
- case 'l':
- case 'L':
- aeventsend(w, &ev);
- }
- }
+ threadexits(nil);
}
-char *
-readbody(AWin *w)
+void
+logproc(void *aux)
{
- Biobuf *fd;
- int addr;
- char *buf;
- int i;
-
- sleep(10);
-
- addr = awinfsopen(w, "addr", OWRITE);
- fd = awinfsbopen(w, "data", OREAD);
+ Chan *chan;
+ Ctl ctl;
+ AWin *win;
- fprint(addr, ",");
- buf = Brdstr(fd, '\0', 0);
+ threadsetname("log");
- if(!buf)
- return nil;
+ chan = aux;
+ win = awincreate();
+ fprint(win->ctlfd, "name /wired/%s/log\n"
+ "scratch\n" "nomenu\n", chan->name);
+ win->aux = chan;
- for(i = strlen(buf)-1; i >= 0; i--) {
- if(buf[i] == '' || buf[i] == '\n')
- buf[i] = '\0';
- else
+ proccreate(eventproc, win, Stack);
+
+ while(recv(chan->logc, &ctl)) {
+ switch(ctl.type) {
+ case MMessage:
+ fprint(win->bodyfd, "%s", ctl.aux);
+ free(ctl.aux);
break;
+ case MExit:
+ goto exit;
+ }
}
+
+exit:
+ close(win->eventfd);
+ chanfree(chan->logc);
+ awinclose(win);
+ threadexits(nil);
+}
+
+void
+sendmessage(AWin *win, char *fmt, ...)
+{
+ Chan *chan;
+ char *prefix;
+ char *message;
+ va_list args;
- if(buf[0] == '\0') {
- awinclear(w);
- return nil;
- }
+ chan = win->aux;
+
+ va_start(args, fmt);
+ prefix = vsmprint(fmt, args);
+ va_end(args);
- awinclear(w);
- Bterm(fd);
- close(addr);
- return buf;
+ 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
-domessage(Session *s, char *msg)
+inputproc(void *aux)
{
- char *buf;
+ Server *srv;
+ Chan *chan;
+ Ctl ctl;
+ AWin *win;
+
+ threadsetname("input");
- if(!msg)
- return;
+ 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;
- buf = smprint("%s • %s\n", s->usr, msg);
- write(s->fd, buf, strlen(buf));
+ proccreate(eventproc, win, Stack);
- free(buf);
- free(msg);
+ while(recv(chan->inputc, &ctl)) {
+ switch(ctl.type) {
+ case MSend:
+ sendmessage(win, "%s %s", srv->user, srv->sep);
+ break;
+ case MAct:
+ sendmessage(win, "%s %s", srv->actsep, srv->user);
+ break;
+ case MExit:
+ goto exit;
+ }
+ }
+
+exit:
+ close(win->eventfd);
+ chanfree(chan->inputc);
+ awinclose(win);
+ threadexits(nil);
}
void
-doaction(Session *s, char *msg)
+readproc(void *aux)
{
+ Chan *chan;
char *buf;
+ long n;
+ Ctl ctl;
+
+ threadsetname("read");
- if(!msg)
- return;
+ chan = aux;
+ buf = mallocz(Buf, 1);
- buf = smprint("* %s %s\n", s->usr, msg);
- write(s->fd, buf, strlen(buf));
+ 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;
+ }
free(buf);
- free(msg);
+ chanfree(chan->readc);
+ threadexits(nil);
}
void
-dochat(char *mtpt, char *chan, char *usr)
+connectchan(Server *srv, char *name)
{
- Session *s;
- char buf[128];
- char *ctl;
+ Chan *chan;
+ char *buf;
+ Ctl ctl;
- s = mallocz(sizeof(Session), 1);
-
- s->mtpt = strdup(mtpt);
- s->chan = strdup(chan);
- s->usr = strdup(usr);
+ chan = mallocz(sizeof(Chan), 1);
+ chan->name = name;
+ chan->srv = srv;
- 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;
+ 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;
+ }
- 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;
+ chan->logc = chancreate(sizeof(Ctl), 0);
+ chan->inputc = chancreate(sizeof(Ctl), 0);
+ chan->readc = chancreate(sizeof(Ctl), 0);
- s->ctl = chancreate(sizeof(char*), 0);
+ chan->ctl = chancreate(sizeof(Ctl), 0);
- proccreate(chatcatproc, s->cwin, Stack);
- proccreate(wineventproc, s->cwin, Stack);
- proccreate(wineventproc, s->iwin, Stack);
+ chan->logproc = proccreate(logproc, chan, Stack);
+ chan->inputproc = proccreate(inputproc, chan, Stack);
+ chan->readproc = proccreate(readproc, chan, 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)
+ 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;
+ }
}
+
+
+ chanfree(chan->ctl);
+ free(chan);
+ free(buf);
+ return;
}
void
-dialchat(char *srv, char *mtpt)
+connectsrv(Server *srv)
{
int fd;
- if((fd = dial(srv, nil, nil, nil)) < 0)
+ if((fd = dial(srv->addr, nil, nil, nil)) < 0)
sysfatal("couldn't dial chat server: %r");
- if(mount(fd, -1, mtpt, MREPL, "") == -1)
+ if(mount(fd, -1, srv->mtpt, MREPL, "") < 0)
sysfatal("couldn't mount chat server: %r");
}
@@ -203,40 +292,53 @@
void
usage(void)
{
- fprint(2, "usage: %s [-s srv] [-c chan] [-u user]\n", argv0);
- exits(nil);
+ fprint(2, "usage: %s [-s srv] [-m mtpt] [-u user] "
+ "[-S sep] [-A actsep]\n", argv0);
+ threadexitsall("usage");
}
void
threadmain(int argc, char *argv[])
{
- char *srv, *mtpt, *user, *chan;
+ Server *srv;
+ char *channel;
- srv = "tcp!chat.9p.zone!9990";
- mtpt = "/n/chat";
- chan = "chat";
- user = getuser();
+ srv = mallocz(sizeof(Server), 1);
+ srv->addr = "tcp!9p.zone!9990";
+ srv->mtpt = "/n/wired";
+ srv->sep = "•";
+ srv->actsep = "*";
+ srv->user = getuser();
+
+ channel = "chat";
ARGBEGIN {
case 's':
- srv = EARGF(usage());
+ srv->addr = EARGF(usage());
break;
case 'm':
- mtpt = EARGF(usage());
+ srv->mtpt = EARGF(usage());
break;
- case 'c':
- chan = EARGF(usage());
- break;
case 'u':
- user = EARGF(usage());
+ srv->user = EARGF(usage());
break;
+ case 'S':
+ srv->sep = EARGF(usage());
+ break;
+ case 'A':
+ srv->actsep = EARGF(usage());
+ break;
+ case 'c':
+ channel = EARGF(usage());
+ break;
default:
usage();
} ARGEND
- dialchat(srv, mtpt);
- dochat(mtpt, chan, user);
-
- awincloseall();
- threadexitsall(nil);
+ connectsrv(srv);
+ connectchan(srv, channel);
+ unmount(nil, srv->mtpt);
+
+ free(srv);
+ threadexits(nil);
}