]> jfr.im git - irc/quakenet/newserv.git/blobdiff - whowas/whowas.c
CHANSERV: remove accidental sendemail from SETEMAIL command.
[irc/quakenet/newserv.git] / whowas / whowas.c
index 7d62f6a19a92b5e3924037b010483e50743c5774..9e2cdb3c74d6f9e753a3e3445a24a2549e514a51 100644 (file)
@@ -5,23 +5,33 @@
 #include "../irc/irc.h"
 #include "../lib/irc_string.h"
 #include "../lib/version.h"
+#include "../core/config.h"
 #include "whowas.h"
 
 MODULE_VERSION("");
 
-whowas *whowas_head = NULL, *whowas_tail = NULL;
-int whowas_count = 0;
+whowas *whowasrecs;
+int whowasoffset = 0;
+int whowasmax;
 
-whowas *whowas_fromnick(nick *np) {
+whowas *whowas_fromnick(nick *np, int standalone) {
   whowas *ww;
   nick *wnp;
   struct irc_in_addr ipaddress_canonical;
+  void *args[2];
 
   /* Create a new record. */
-  ww = malloc(sizeof(whowas));
+  if (standalone)
+    ww = malloc(sizeof(whowas));
+  else {
+    ww = &whowasrecs[whowasoffset];
+    whowas_clean(ww);
+    whowasoffset = (whowasoffset + 1) % whowasmax;
+  }
+
   memset(ww, 0, sizeof(whowas));
 
-  wnp = newnick();
+  wnp = &ww->nick;
   memset(wnp, 0, sizeof(nick));
   strncpy(wnp->nick, np->nick, NICKLEN + 1);
   wnp->numeric = np->numeric;
@@ -43,9 +53,8 @@ whowas *whowas_fromnick(nick *np) {
     memset(wnp->auth, 0, sizeof(authname));
     wnp->auth->userid = np->auth->userid;
     strncpy(wnp->auth->name, np->auth->name, ACCOUNTLEN + 1);
-    wnp->auth = np->auth;
+    wnp->authname = wnp->auth->name;
   }
-  wnp->authname = wnp->auth->name;
   wnp->timestamp = np->timestamp;
   wnp->accountts = np->accountts;
   wnp->away = np->away ? getsstring(np->away->content, 512) : NULL;
@@ -57,47 +66,25 @@ whowas *whowas_fromnick(nick *np) {
 
   wnp->next = (nick *)ww; /* Yuck. */
 
-  ww->nick = wnp;
   ww->timestamp = getnettime();
+  ww->type = WHOWAS_USED;
 
-  return ww;
-}
-
-void whowas_linkrecord(whowas *ww) {
-  if (whowas_head)
-    whowas_head->prev = ww;
-
-  ww->next = whowas_head;
-  whowas_head = ww;
-
-  ww->prev = NULL;
-
-  if (!whowas_tail)
-    whowas_tail = ww;
-
-  whowas_count++;
-}
-
-void whowas_unlinkrecord(whowas *ww) {
-  if (!ww->next)
-    whowas_tail = ww->prev;
-
-  if (ww->prev)
-    ww->prev->next = NULL;
-  else
-    whowas_head = ww->prev;
+  args[0] = ww;
+  args[1] = np;
+  triggerhook(HOOK_WHOWAS_NEWRECORD, args);
 
-  whowas_count--;
+  return ww;
 }
 
-void whowas_free(whowas *ww) {
+void whowas_clean(whowas *ww) {
   nick *np;
 
-  if (!ww)
+  if (!ww || ww->type == WHOWAS_UNUSED)
     return;
 
-  np = ww->nick;
+  triggerhook(HOOK_WHOWAS_LOSTRECORD, ww);
 
+  np = &ww->nick;
   freesstring(np->host->name);
   freehost(np->host);
   freesstring(np->realname->name);
@@ -107,23 +94,15 @@ void whowas_free(whowas *ww) {
   freesstring(np->opername);
   freeauthname(np->auth);
   freesstring(np->away);
-  freenick(np);
+  derefnode(iptree, np->ipnode);
   freesstring(ww->reason);
-  free(ww);
+  freesstring(ww->newnick);
+  ww->type = WHOWAS_UNUSED;
 }
 
-static void whowas_cleanup(void) {
-  time_t now;
-  whowas *ww;
-
-  time(&now);
-
-  /* Clean up old records. */
-  while (whowas_tail && (whowas_tail->timestamp < now - WW_MAXAGE || whowas_count >= WW_MAXENTRIES)) {
-    ww = whowas_tail;
-    whowas_unlinkrecord(ww);
-    whowas_free(ww);
-  }
+void whowas_free(whowas *ww) {
+  whowas_clean(ww);
+  free(ww);
 }
 
 static void whowas_handlequitorkill(int hooknum, void *arg) {
@@ -134,10 +113,8 @@ 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, ' '))) {
@@ -146,12 +123,14 @@ static void whowas_handlequitorkill(int hooknum, void *arg) {
     }
 
     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) {
@@ -161,28 +140,33 @@ static void whowas_handlerename(int hooknum, void *arg) {
   whowas *ww;
   nick *wnp;
 
-  whowas_cleanup();
-
-  ww = whowas_fromnick(np);
+  ww = whowas_fromnick(np, 0);
   ww->type = WHOWAS_RENAME;
-  wnp = ww->nick;
+  wnp = &ww->nick;
   ww->newnick = getsstring(wnp->nick, NICKLEN);
   strncpy(wnp->nick, oldnick, NICKLEN + 1);
-
-  whowas_linkrecord(ww);
 }
 
-whowas *whowas_chase(const char *nick, int maxage) {
+whowas *whowas_chase(const char *target, int maxage) {
   whowas *ww;
+  nick *wnp;
   time_t now;
+  int i;
 
   now = getnettime();
 
-  for (ww = whowas_head; ww; ww = ww->next) {
+  for (i = whowasoffset + whowasmax - 1; i >= whowasoffset; i--) {
+    ww = &whowasrecs[i % whowasmax];
+
+    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(ww->nick->nick, nick) == 0)
+    if (ircd_strcmp(wnp->nick, target) == 0)
       return ww;
   }
 
@@ -190,7 +174,7 @@ whowas *whowas_chase(const char *nick, int maxage) {
 }
 
 const char *whowas_format(whowas *ww) {
-  nick *np = ww->nick;
+  nick *np = &ww->nick;
   static char buf[512];
   char timebuf[30];
   char hostmask[512];
@@ -198,7 +182,7 @@ const char *whowas_format(whowas *ww) {
   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->p_ipaddr),
+           IPtostr(np->ipaddress),
            printflags(np->umodes, umodeflags));
   strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&(ww->timestamp)));
 
@@ -210,16 +194,46 @@ const char *whowas_format(whowas *ww) {
   return buf;
 }
 
+const char *whowas_formatchannels(whowas *ww) {
+  static char buf[512];
+  int i, first = 1;
+
+  strcpy(buf, "Channels: ");
+
+  for (i = 0; i < WW_MAXCHANNELS; i++) {
+    if (!ww->channels[i])
+      break;
+
+    if (!first)
+      strncat(buf, ", ", sizeof(buf));
+    else
+      first = 0;
+
+    strncat(buf, ww->channels[i]->name->content, sizeof(buf));
+  }
+
+  if (!ww->channels[0])
+    strncat(buf, "(No channels.)", sizeof(buf));
+
+  buf[sizeof(buf) - 1] = '\0';
+
+  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 (ww = whowas_head; ww; ww = ww->next)
-        ww->marker=0;
+    for (i = 0; i < whowasmax; i++) {
+      ww = &whowasrecs[i % whowasmax];
+      ww->marker=0;
+    }
+
     whowasmarker++;
   }
 
@@ -227,16 +241,30 @@ unsigned int nextwhowasmarker() {
 }
 
 void _init(void) {
+  {
+    sstring *temp = getcopyconfigitem("whowas", "maxentries", XStringify(WW_DEFAULT_MAXENTRIES), 10);
+    whowasmax = atoi(temp->content);
+    freesstring(temp);
+  }
+  whowasrecs = calloc(whowasmax, sizeof(whowas));
+
   registerhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
   registerhook(HOOK_NICK_KILL, whowas_handlequitorkill);
   registerhook(HOOK_NICK_RENAME, whowas_handlerename);
 }
 
 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 < whowasmax; i++) {
+    ww = &whowasrecs[i];
+    whowas_clean(ww);
+  }
+
+  free(whowasrecs);
 }