diff --git a/pkgs/irc b/pkgs/irc deleted file mode 100644 index 8c396cb..0000000 --- a/pkgs/irc +++ /dev/null @@ -1,13 +0,0 @@ -fetch() { - cp $top/stuff/irc.c src -} - -build() { - pushd src - x86_64-linux-musl-gcc -o irc irc.c -static -I$libcroot/include/ncurses -lncurses || return 1 - popd -} - -install() { - cp src/irc $root/bin -} diff --git a/stuff/irc.c b/stuff/irc.c deleted file mode 100644 index e1a2fa1..0000000 --- a/stuff/irc.c +++ /dev/null @@ -1,624 +0,0 @@ -/*% cc -g -Wall -lncurses -o # % - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CTRL(c) ((c) & 037) - -#define SCROLL 15 -#define DATEFMT "%H:%M" -#define PFMT "%-12s < %s" -#define SRV "chat.freenode.org" -#define PORT 6667 - -enum { ChanLen = 64, LineLen = 512, MaxChans = 16, BufSz = 2048, LogSz = 4096 }; - -char nick[64]; -int quit, winchg; -int sfd; /* Server file descriptor. */ -struct { - int x; - int y; - WINDOW *sw, *mw, *iw; -} scr; /* Screen relative data. */ -struct Chan { - char name[ChanLen]; - char *buf, *eol; - int n; /* Scroll offset. */ - size_t sz; /* size of buf. */ -} chl[MaxChans]; -int nch, ch; /* Current number of channels, and current channel. */ -char outb[BufSz], *outp=outb; /* Output buffer. */ - -static void scmd(char *, char *, char *, char *); -static void tdrawbar(void); -static void tredraw(void); -static void treset(void); - -static void -panic(const char *m) -{ - treset(); - fprintf(stderr, "Panic: %s\n", m); - exit(1); -} - -static void -sndf(const char *fmt, ...) -{ - va_list vl; - size_t n, l=BufSz-(outp-outb); - - if (l<2) return; - va_start(vl, fmt); - n=vsnprintf(outp, l-2, fmt, vl); - va_end(vl); - outp += n>l-2 ? l-2 : n; - *outp++ = '\r'; - *outp++ = '\n'; -} - -static int -srd(void) -{ - static char l[BufSz], *p=l; - char *s, *usr, *cmd, *par, *data; - int rd; - - if (p-l>=BufSz) p=l; /* Input buffer overflow, there should something better to do. */ - rd=read(sfd, p, BufSz-(p-l)); - if (rd<0) { - if (errno==EINTR) return 1; - panic("IO error while reading."); - } - if (rd==0) return 0; - p+=rd; - for (;;) { /* Cycle on all received lines. */ - if (!(s=memchr(l, '\n', p-l))) - return 1; - if (s>l && s[-1]=='\r') - s[-1]=0; - *s++ = 0; - if (*l==':') { - if (!(cmd=strchr(l, ' '))) goto lskip; - *cmd++ = 0; - usr = l+1; - } else { - usr = 0; - cmd = l; - } - if (!(par=strchr(cmd, ' '))) goto lskip; - *par++ = 0; - if ((data=strchr(par, ':'))) - *data++ = 0; - scmd(usr, cmd, par, data); - lskip: - memmove(l, s, p-s); - p-=s-l; - } -} - -static int -dial(const char *host, short port) -{ - int f; - struct sockaddr_in sin; - struct addrinfo *ai, hai = { 0 }; - - hai.ai_family = AF_INET; - hai.ai_socktype = SOCK_STREAM; - if (getaddrinfo(host, 0, &hai, &ai)) - panic("Cannot resolve host."); - memcpy(&sin, ai->ai_addr, sizeof sin); - sin.sin_port = htons(port); - freeaddrinfo(ai); - f = socket(AF_INET, SOCK_STREAM, 0); - if (f<0) - panic("Cannot create socket."); - if (connect(f, (struct sockaddr *)&sin, sizeof sin)<0) - panic("Cannot connect to host."); - return f; -} - -static int -chadd(char *name) -{ - if (nch>=MaxChans || strlen(name)>=ChanLen) - return -1; - strcpy(chl[nch].name, name); - chl[nch].sz=LogSz; - chl[nch].buf=malloc(LogSz); - if (!chl[nch].buf) - panic("Out of memory."); - chl[nch].eol=chl[nch].buf; - chl[nch].n=0; - ch=nch++; - tdrawbar(); - return nch; -} - -static inline int -chfind(char *name) -{ - int i; - - assert(name); - for (i=nch-1; i>0; i--) - if (!strcmp(chl[i].name, name)) - break; - return i; -} - -static int -chdel(char *name) -{ - int n; - - if (!(n=chfind(name))) return 0; - nch--; - free(chl[n].buf); - memmove(&chl[n], &chl[n+1], (nch-n)*sizeof(struct Chan)); - ch=nch-1; - tdrawbar(); - return 1; -} - -static void -pushf(int cn, const char *fmt, ...) -{ - struct Chan *const c=&chl[cn]; - size_t n, blen=c->eol-c->buf; - va_list vl; - time_t t; - struct tm *tm; - - if (blen+LineLen>=c->sz) { - c->sz *= 2; - c->buf=realloc(c->buf, c->sz); - if (!c->buf) panic("Out of memory."); - c->eol=c->buf+blen; - } - t=time(0); - if (!(tm=localtime(&t))) panic("Localtime failed."); - n=strftime(c->eol, LineLen, DATEFMT, tm); - c->eol[n++] = ' '; - va_start(vl, fmt); - n+=vsnprintf(c->eol+n, LineLen-n-1, fmt, vl); - va_end(vl); - strcat(c->eol, "\n"); - if (n>=LineLen-1) - c->eol+=LineLen-1; - else - c->eol+=n+1; - if (cn==ch && c->n==0) { - char *p=c->eol-n-1; - if (p!=c->buf) waddch(scr.mw, '\n'); - for (; peol-1; p++) - waddch(scr.mw, *p); - wrefresh(scr.mw); - } -} - -static void -scmd(char *usr, char *cmd, char *par, char *data) -{ - int s; - char *pm=strtok(par, " "); - - if (!usr) usr="?"; - else { - char *bang=strchr(usr, '!'); - if (bang) - *bang=0; - } - if (!strcmp(cmd, "PRIVMSG")) { - if (!pm || !data) return; - pushf(chfind(pm), PFMT, usr, data); - } else if (!strcmp(cmd, "PING")) { - sndf("PONG :%s", data?data:"(null)"); - } else if (!strcmp(cmd, "PART")) { - if (!pm) return; - pushf(chfind(pm), "-!- %s has left %s", usr, pm); - } else if (!strcmp(cmd, "JOIN")) { - if (!pm) return; - pushf(chfind(pm), "-!- %s has joined %s", usr, pm); - } else if (!strcmp(cmd, "470")) { /* Channel forwarding. */ - char *ch=strtok(0, " "), *fch=strtok(0, " "); - if (!ch || !fch || !(s=chfind(ch))) return; - chl[s].name[0] = 0; - strncat(chl[s].name, fch, ChanLen-1); - tdrawbar(); - } else if (!strcmp(cmd, "471") || !strcmp(cmd, "473") - || !strcmp(cmd, "474") || !strcmp(cmd, "475")) { /* Join error. */ - if ((pm=strtok(0, " "))) { - chdel(pm); - pushf(0, "-!- Cannot join channel %s (%s)", pm, cmd); - tredraw(); - } - } else if (!strcmp(cmd, "QUIT")) { /* Commands we don't care about. */ - return; - } else if (!strcmp(cmd, "NOTICE") || !strcmp(cmd, "375") - || !strcmp(cmd, "372") || !strcmp(cmd, "376")) { - pushf(0, "%s", data?data:""); - } else - pushf(0, "%s - %s %s", cmd, par, data?data:"(null)"); -} - -static void -uparse(char *m) -{ - char *p=m; - - if (!p[0] || (p[1]!=' ' && p[1]!=0)) { - pmsg: - if (ch==0) return; - m+=strspn(m, " "); - if (!*m) return; - pushf(ch, PFMT, nick, m); - sndf("PRIVMSG %s :%s", chl[ch].name, m); - return; - } - switch (*p) { - case 'j': /* Join channels. */ - p+=1+(p[1]==' '); - p=strtok(p, " "); - while (p) { - if (chadd(p)<0) break; - sndf("JOIN %s", p); - p=strtok(0, " "); - } - tredraw(); - return; - case 'l': /* Leave channels. */ - p+=1+(p[1]==' '); - if (!*p) { - if (ch==0) return; /* Cannot leave server window. */ - strcat(p, chl[ch].name); - } - p=strtok(p, " "); - while (p) { - if (chdel(p)) - sndf("PART %s", p); - p=strtok(0, " "); - } - tredraw(); - return; - case 'm': /* Private message. */ - m=p+1+(p[1]==' '); - if (!(p=strchr(m, ' '))) return; - *p++ = 0; - sndf("PRIVMSG %s :%s", m, p); - return; - case 'r': /* Send raw. */ - if (p[1]) - sndf("%s", &p[2]); - return; - case 'q': /* Quit. */ - quit=1; - return; - default: /* Send on current channel. */ - goto pmsg; - } -} - -static void -sigwinch(int sig) -{ - if (sig) winchg=1; -} - -static void -tinit(void) -{ - setlocale(LC_ALL, ""); - signal(SIGWINCH, sigwinch); - initscr(); - raw(); - noecho(); - getmaxyx(stdscr, scr.y, scr.x); - if (scr.y<4) panic("Screen too small."); - if ((scr.sw=newwin(1, scr.x, 0, 0))==0 - || (scr.mw=newwin(scr.y-2, scr.x, 1, 0))==0 - || (scr.iw=newwin(1, scr.x, scr.y-1, 0))==0) - panic("Cannot create windows."); - keypad(scr.iw, 1); - scrollok(scr.mw, 1); - if (has_colors()==TRUE) { - start_color(); - init_pair(1, COLOR_WHITE, COLOR_BLUE); - wbkgd(scr.sw, COLOR_PAIR(1)); - } -} - -static void -tresize(void) -{ - struct winsize ws; - - winchg=0; - if (ioctl(0, TIOCGWINSZ, &ws)<0) - panic("Ioctl (TIOCGWINSZ) failed."); - resizeterm(scr.y=ws.ws_row, scr.x=ws.ws_col); - if (scr.y<3 || scr.x<10) - panic("Screen too small."); - wresize(scr.mw, scr.y-2, scr.x); - wresize(scr.iw, 1, scr.x); - wresize(scr.sw, 1, scr.x); - mvwin(scr.iw, scr.y-1, 0); - tredraw(); - tdrawbar(); -} - -static void -tredraw(void) -{ - struct Chan *const c=&chl[ch]; - char *q, *p; - int llen=0, nl=-1; - - if (c->eol==c->buf) { - wclear(scr.mw); - wrefresh(scr.mw); - return; - } - p=c->eol-1; - if (c->n) { - int i=c->n; - for (; p>c->buf; p--) - if (*p=='\n' && !i--) break; - if (p==c->buf) c->n-=i; - } - q=p; - while (nlc->buf) - q--, llen++; - nl += 1+llen/scr.x; - if (q==c->buf) break; - q--; - } - if (q!=c->buf) q+=2; - for (llen=0; nl>scr.y-2; ) { /* Maybe we must split the top line. */ - if (q[llen]=='\n' || llen>=scr.x) { - q+=llen+(q[llen]=='\n'); - llen=0; - nl--; - } else llen++; - } - wclear(scr.mw); - wmove(scr.mw, 0, 0); - for (; q0 && l=len) return; - memmove(&l[cu], &l[cu+1], len-cu-1); - dirty=cu; - len--; - break; - case KEY_BACKSPACE: - if (cu==0) return; - memmove(&l[cu-1], &l[cu], len-cu); - dirty=--cu; - len--; - break; - case '\n': - l[len]=0; - uparse(l); - dirty=cu=len=0; - break; - default: - if (c>CHAR_MAX || len>=BufSz-1) return; /* Skip other curses codes. */ - memmove(&l[cu+1], &l[cu], len-cu); - dirty=cu; - len++; - l[cu++]=c; - break; - } - while (cu=scr.x/2 ? scr.x/2 : shft; - while (cu>=scr.x+shft) - dirty=0, shft += scr.x/2; - if (dirty<=shft) - i=shft; - else if (dirty>scr.x+shft || dirty>len) - goto mvcur; - else - i=dirty; - wmove(scr.iw, 0, i-shft); - wclrtoeol(scr.iw); - for (; i-shft=0) - switch (o) { - case 'h': - case '?': - usage: - fputs("Usage: irc [-n NICK] [-u USER] [-s SERVER] [-p PORT] [-h]\n", stderr); - exit(0); - case 'n': - if (strlen(optarg)>=sizeof nick) goto usage; - strcpy(nick, optarg); - break; - case 'u': - user = optarg; - break; - case 's': - server = optarg; - break; - case 'p': - if (!(port=strtol(optarg, 0, 0))) goto usage; - break; - } - if (!nick[0] && ircnick && strlen(ircnick)