Track user names to properly show joins and parts - irc - A minimalistic IRC cl… | |
git clone git://vernunftzentrum.de/irc.git | |
Log | |
Files | |
Refs | |
README | |
--- | |
commit e5ae717f4ac681933c42f9bb82ffd01386545522 | |
parent a68ac08f9543bbb869b49f1329fdf9281d412127 | |
Author: Christian Kellermann <[email protected]> | |
Date: Fri, 6 Apr 2018 23:03:04 +0200 | |
Track user names to properly show joins and parts | |
Diffstat: | |
irc.c | 145 +++++++++++++++++++++++++++++-- | |
1 file changed, 136 insertions(+), 9 deletions(-) | |
--- | |
diff --git a/irc.c b/irc.c | |
@@ -36,7 +36,8 @@ | |
enum { | |
ChanLen = 64, | |
LineLen = 512, | |
- MaxChans = 16, | |
+ MaxChans = 32, | |
+ MaxKnownUsers = 2048, | |
BufSz = 2048, | |
LogSz = 4096, | |
MaxRecons = 10, /* -1 for infinitely many */ | |
@@ -62,6 +63,12 @@ static struct Chan { | |
char join; /* Channel was 'j'-oined. */ | |
} chl[MaxChans]; | |
+static struct User { | |
+ char nick[64]; | |
+ uint32_t channels; /* Needs to match MaxChans */ | |
+ char inuse; | |
+} usrs[MaxKnownUsers]; | |
+ | |
static int ssl; | |
static struct { | |
int fd; | |
@@ -84,6 +91,8 @@ static void tdrawbar(void); | |
static void tredraw(void); | |
static void treset(void); | |
+static void usrchandrop(int); | |
+ | |
static void | |
panic(const char *m) | |
{ | |
@@ -326,6 +335,7 @@ chdel(char *name) | |
if (!(n = chfind(name))) | |
return 0; | |
+ usrchandrop(n); | |
nch--; | |
free(chl[n].buf); | |
memmove(&chl[n], &chl[n + 1], (nch - n) * sizeof(struct Chan)); | |
@@ -334,6 +344,81 @@ chdel(char *name) | |
return 1; | |
} | |
+static void | |
+usrchandrop(int chan) | |
+{ | |
+ for (size_t i = 0; i < MaxKnownUsers; i++) | |
+ if (usrs[i].channels == (1 << chan)) { | |
+ usrs[i].channels = 0; | |
+ usrs[i].inuse = 0; | |
+ bzero(usrs[i].nick, 64); | |
+ } | |
+} | |
+ | |
+static size_t | |
+usrfind(char *nick) | |
+{ | |
+ size_t i = 0; | |
+ for (i = MaxKnownUsers - 1; i > 0; i--){ | |
+ if (usrs[i].inuse && !strcmp(nick, usrs[i].nick)) | |
+ break; | |
+ } | |
+ return i; | |
+} | |
+ | |
+static void | |
+usradd(char* nick, int chan) | |
+{ | |
+ size_t i; | |
+ i = usrfind(nick); | |
+ if (!i) { | |
+ for (i = MaxKnownUsers - 1; i > 0; i--) | |
+ if (!usrs[i].inuse) | |
+ break; | |
+ } | |
+ if (!i) | |
+ panic("Too many users!"); | |
+ strlcpy(usrs[i].nick, nick, 64); | |
+ usrs[i].channels |= 1 << chan; | |
+ usrs[i].inuse = 1; | |
+} | |
+ | |
+static void | |
+usrdel(char* nick, int chan) | |
+{ | |
+ size_t h; | |
+ | |
+ h = usrfind(nick); | |
+ if (!h) | |
+ return; | |
+ if (!chan) | |
+ usrs[h].channels = 0; | |
+ | |
+ usrs[h].channels &= ~(1 << chan); | |
+ | |
+ if (!usrs[h].channels) { | |
+ usrs[h].inuse = 0; | |
+ bzero(usrs[h].nick, 64); | |
+ } | |
+} | |
+ | |
+static void | |
+usrchange(char* old, char* new) | |
+{ | |
+ size_t h; | |
+ | |
+ h = usrfind(old); | |
+ if(!h) | |
+ panic("Missed a user!"); | |
+ strlcpy(usrs[h].nick, new, 64); | |
+} | |
+ | |
+static uint32_t | |
+usrchans(char* nick) | |
+{ | |
+ return usrs[usrfind(nick)].channels; | |
+} | |
+ | |
static char * | |
pushl(char *p, char *e) | |
{ | |
@@ -461,7 +546,7 @@ scmd(char *usr, char *cmd, char *par, char *data) | |
tdrawbar(); | |
} | |
} else if (!strcmp(cmd, "NICK")) { | |
- if (!data || !pm) | |
+ if (!data) | |
return; | |
if (!strcmp(usr, nick)){ | |
for (int c=0; c < nch; c++){ | |
@@ -469,21 +554,33 @@ scmd(char *usr, char *cmd, char *par, char *data) | |
} | |
strlcpy(nick, data, sizeof(nick)); | |
} else { | |
- pushf(chfind(pm), "%s - is now known as %s", usr, data… | |
+ pushf(chfind(data), "%s - is now known as %s", usr, da… | |
+ usrchange(usr, data); | |
} | |
tredraw(); | |
return; | |
} else if (!strcmp(cmd, "PING")) { | |
sndf("PONG :%s", data ? data : "(null)"); | |
} else if (!strcmp(cmd, "PART")) { | |
+ int ch = 0; | |
if (!pm) | |
return; | |
- pushf(chfind(pm), "-!- %s has left %s", usr, pm); | |
+ ch = chfind(pm); | |
+ pushf(ch, "-!- %s has left %s", usr, pm); | |
+ usrdel(usr, ch); | |
} else if (!strcmp(cmd, "JOIN")) { /* some servers pass the channel as… | |
- if (pm) | |
- pushf(chfind(pm), "-!- %s has joined %s", usr, pm); | |
- else if (data) | |
- pushf(chfind(data), "-!- %s has joined %s", usr, data); | |
+ int ch; | |
+ char *chan; | |
+ if (pm) { | |
+ ch = chfind(pm); | |
+ chan = pm; | |
+ } else if (data) { | |
+ ch = chfind(data); | |
+ chan = data; | |
+ } | |
+ | |
+ pushf(ch, "-!- %s has joined %s", usr, chan); | |
+ usradd(usr, ch); | |
return; | |
} else if (!strcmp(cmd, "470")) { /* Channel forwarding. */ | |
char *ch = strtok(0, " "), *fch = strtok(0, " "); | |
@@ -500,6 +597,23 @@ scmd(char *usr, char *cmd, char *par, char *data) | |
return; | |
pushf(chfind(chan), "Topic for %s: %s", chan, data); | |
tredraw(); | |
+ } else if (!strcmp(cmd, "353")) { /* RPL_NAMREPLY */ | |
+ pushf(0, "Names %s", data ? data : ""); | |
+ if ((pm = strtok(0, " ")) && (!strcmp(pm, "=") || !strcmp(pm, … | |
+ char *n; | |
+ char *chan = strtok(0, " "); | |
+ int c = chfind(chan); | |
+ if (!chan || !data || !c) | |
+ return; | |
+ n = strtok(data, " "); | |
+ if (!n) | |
+ return; | |
+ do { | |
+ if (n[0] == '@' || n[0] == '+') | |
+ n+=1; | |
+ usradd(n, c); | |
+ } while ((n = strtok(0, " "))); | |
+ } | |
} else if (!strcmp(cmd, "471") || !strcmp(cmd, "473") | |
|| !strcmp(cmd, "474") || !strcmp(cmd, "475")) { /* Join er… | |
if ((pm = strtok(0, " "))) { | |
@@ -513,7 +627,19 @@ scmd(char *usr, char *cmd, char *par, char *data) | |
return; | |
pushf(0, "-!- Cannot change to nick %s: %s", pm, data); | |
tredraw(); | |
- } else if (!strcmp(cmd, "QUIT")) { /* Commands we don't care about. */ | |
+ } else if (!strcmp(cmd, "QUIT")) { | |
+ char *msg = ""; | |
+ if (!usr) | |
+ return; | |
+ uint64_t chans = usrchans(usr); | |
+ usrdel(usr, 0); | |
+ if (data) | |
+ msg = data; | |
+ for (int c = 0; c < MaxChans; c++) { | |
+ if (1<<c & chans) | |
+ pushf(c, "-!- %s has left ('%s').", usr, msg); | |
+ } | |
+ tredraw(); | |
return; | |
} else if (!strcmp(cmd, "NOTICE") || !strcmp(cmd, "375") | |
|| !strcmp(cmd, "372") || !strcmp(cmd, "376")) { | |
@@ -894,6 +1020,7 @@ main(int argc, char *argv[]) | |
strcpy(nick, user); | |
if (!nick[0]) | |
goto usage; | |
+ bzero(usrs, MaxKnownUsers * sizeof(*usrs)); | |
tinit(); | |
err = dial(server, port); | |
if (err) |