-#include <stdio.h>
#include <string.h>
+#include <stdio.h>
#include "../core/hooks.h"
#include "../control/control.h"
#include "../irc/irc.h"
MODULE_VERSION("");
-whowas *whowas_head = NULL, *whowas_tail = NULL;
-int whowas_count = 0;
+whowas whowasrecs[WW_MAXENTRIES];
+int whowasoffset = 0;
-whowas *whowas_fromnick(nick *np) {
+whowas *whowas_fromnick(nick *np, int standalone) {
whowas *ww;
+ nick *wnp;
+ struct irc_in_addr ipaddress_canonical;
/* Create a new record. */
- ww = malloc(sizeof(whowas));
+ if (standalone)
+ ww = malloc(sizeof(whowas));
+ else {
+ ww = &whowasrecs[whowasoffset];
+ whowas_clean(ww);
+ whowasoffset = (whowasoffset + 1) % WW_MAXENTRIES;
+ }
+
memset(ww, 0, sizeof(whowas));
- strncpy(ww->nick, np->nick, NICKLEN);
- strncpy(ww->ident, np->ident, USERLEN);
- strncpy(ww->host, np->host->name->content, HOSTLEN);
- strncpy(ww->realname, np->realname->name->content, REALLEN);
- ww->seen = getnettime();
- return ww;
-}
+ wnp = &ww->nick;
+ memset(wnp, 0, sizeof(nick));
+ strncpy(wnp->nick, np->nick, NICKLEN + 1);
+ wnp->numeric = np->numeric;
+ strncpy(wnp->ident, np->ident, USERLEN + 1);
+
+ wnp->host = newhost();
+ memset(wnp->host, 0, sizeof(host));
+ wnp->host->name = getsstring(np->host->name->content, HOSTLEN);
+
+ wnp->realname = newrealname();
+ memset(wnp->realname, 0, sizeof(realname));
+ wnp->realname->name = getsstring(np->realname->name->content, REALLEN);
+ wnp->shident = np->shident ? getsstring(np->shident->content, 512) : NULL;
+ wnp->sethost = np->sethost ? getsstring(np->sethost->content, 512) : NULL;
+ wnp->opername = np->opername ? getsstring(np->opername->content, 512) : NULL;
+ wnp->umodes = np->umodes;
+ if (np->auth) {
+ wnp->auth = newauthname();
+ memset(wnp->auth, 0, sizeof(authname));
+ wnp->auth->userid = np->auth->userid;
+ strncpy(wnp->auth->name, np->auth->name, ACCOUNTLEN + 1);
+ wnp->authname = wnp->auth->name;
+ }
+ wnp->timestamp = np->timestamp;
+ wnp->accountts = np->accountts;
+ wnp->away = np->away ? getsstring(np->away->content, 512) : NULL;
-void whowas_linkrecord(whowas *ww) {
- if (whowas_head)
- whowas_head->prev = ww;
+ memcpy(&wnp->ipaddress, &np->ipaddress, sizeof(struct irc_in_addr));
- ww->next = whowas_head;
- whowas_head = ww;
+ ip_canonicalize_tunnel(&ipaddress_canonical, &np->ipaddress);
+ wnp->ipnode = refnode(iptree, &ipaddress_canonical, PATRICIA_MAXBITS);
- ww->prev = NULL;
+ wnp->next = (nick *)ww; /* Yuck. */
- if (!whowas_tail)
- whowas_tail = ww;
+ ww->timestamp = getnettime();
+ ww->type = WHOWAS_USED;
- whowas_count++;
+ return ww;
}
-void whowas_unlinkrecord(whowas *ww) {
- if (!ww->next)
- whowas_tail = ww->prev;
-
- if (ww->prev)
- ww->prev->next = NULL;
- else
- whowas_head = ww->prev;
-
- whowas_count--;
+void whowas_clean(whowas *ww) {
+ nick *np;
+
+ if (!ww || ww->type == WHOWAS_UNUSED)
+ return;
+
+ np = &ww->nick;
+ freesstring(np->host->name);
+ freehost(np->host);
+ freesstring(np->realname->name);
+ freerealname(np->realname);
+ freesstring(np->shident);
+ freesstring(np->sethost);
+ freesstring(np->opername);
+ freeauthname(np->auth);
+ freesstring(np->away);
+
+ freesstring(ww->reason);
+ ww->type = WHOWAS_UNUSED;
}
-static void whowas_cleanup(void) {
- time_t now;
-
- time(&now);
-
- /* Clean up old records. */
- while (whowas_tail && (whowas_tail->seen < now - WW_MAXAGE || whowas_count >= WW_MAXENTRIES)) {
- whowas_unlinkrecord(whowas_tail);
- free(whowas_tail);
- }
+void whowas_free(whowas *ww) {
+ whowas_clean(ww);
+ free(ww);
}
static void whowas_handlequitorkill(int hooknum, void *arg) {
char resbuf[512];
whowas *ww;
- whowas_cleanup();
-
/* Create a new record. */
- ww = whowas_fromnick(np);
+ ww = whowas_fromnick(np, 0);
if (hooknum == HOOK_NICK_KILL) {
if ((rreason = strchr(reason, ' '))) {
}
ww->type = WHOWAS_KILL;
- } else
- ww->type = WHOWAS_QUIT;
+ } else {
+ if (strncmp(reason, "G-lined", 7) == 0)
+ ww->type = WHOWAS_KILL;
+ else
+ ww->type = WHOWAS_QUIT;
+ }
ww->reason = getsstring(reason, WW_REASONLEN);
-
- whowas_linkrecord(ww);
}
static void whowas_handlerename(int hooknum, void *arg) {
nick *np = args[0];
char *oldnick = args[1];
whowas *ww;
+ nick *wnp;
- whowas_cleanup();
-
- ww = whowas_fromnick(np);
+ ww = whowas_fromnick(np, 0);
ww->type = WHOWAS_RENAME;
- ww->newnick = getsstring(ww->nick, NICKLEN);
- strncpy(ww->nick, oldnick, NICKLEN);
- ww->nick[NICKLEN] = '\0';
+ wnp = &ww->nick;
+ ww->newnick = getsstring(wnp->nick, NICKLEN);
+ strncpy(wnp->nick, oldnick, NICKLEN + 1);
+}
+
+whowas *whowas_chase(const char *target, int maxage) {
+ whowas *ww;
+ nick *wnp;
+ time_t now;
+ int i;
- whowas_linkrecord(ww);
+ now = getnettime();
+
+ for (i = whowasoffset + WW_MAXENTRIES - 1; i >= whowasoffset; i--) {
+ ww = &whowasrecs[i % WW_MAXENTRIES];
+
+ if (ww->type == WHOWAS_UNUSED)
+ continue;
+
+ wnp = &ww->nick;
+
+ if (ww->timestamp < now - maxage)
+ break; /* records are in timestamp order, we're done */
+
+ if (ircd_strcmp(wnp->nick, target) == 0)
+ return ww;
+ }
+
+ return NULL;
+}
+
+const char *whowas_format(whowas *ww) {
+ nick *np = &ww->nick;
+ static char buf[512];
+ char timebuf[30];
+ char hostmask[512];
+
+ snprintf(hostmask, sizeof(hostmask), "%s!%s@%s%s%s [%s] (%s)",
+ np->nick, np->ident, np->host->name->content,
+ np->auth ? "/" : "", np->auth ? np->authname : "",
+ IPtostr(np->ipaddress),
+ printflags(np->umodes, umodeflags));
+ strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&(ww->timestamp)));
+
+ if (ww->type == WHOWAS_RENAME)
+ snprintf(buf, sizeof(buf), "[%s] NICK %s r(%s) -> %s", timebuf, hostmask, np->realname->name->content, ww->newnick->content);
+ else
+ snprintf(buf, sizeof(buf), "[%s] %s %s r(%s): %s", timebuf, (ww->type == WHOWAS_QUIT) ? "QUIT" : "KILL", hostmask, np->realname->name->content, ww->reason->content);
+
+ return buf;
+}
+
+unsigned int nextwhowasmarker() {
+ whowas *ww;
+ int i;
+ static unsigned int whowasmarker=0;
+
+ whowasmarker++;
+
+ if (!whowasmarker) {
+ /* If we wrapped to zero, zap the marker on all records */
+ for (i = 0; i < WW_MAXENTRIES; i++) {
+ ww = &whowasrecs[i % WW_MAXENTRIES];
+ ww->marker=0;
+ }
+
+ whowasmarker++;
+ }
+
+ return whowasmarker;
}
void _init(void) {
}
void _fini(void) {
+ int i;
+ whowas *ww;
+
deregisterhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
deregisterhook(HOOK_NICK_KILL, whowas_handlequitorkill);
deregisterhook(HOOK_NICK_RENAME, whowas_handlerename);
- while (whowas_head)
- whowas_unlinkrecord(whowas_head);
+ for (i = 0; i < WW_MAXENTRIES; i++) {
+ ww = &whowasrecs[i];
+ whowas_clean(ww);
+ }
}