]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Factored out the ban code into a separate module.
authorsplidge <redacted>
Sat, 2 Jun 2007 11:24:48 +0000 (12:24 +0100)
committersplidge <redacted>
Sat, 2 Jun 2007 11:24:48 +0000 (12:24 +0100)
This allows modules that want to use the chanban structure to represent bans
to work without the channel module being loaded.

bans/Makefile [new file with mode: 0644]
bans/bans.c [new file with mode: 0644]
bans/bans.h [new file with mode: 0644]
channel/channel.c
channel/channel.h
channel/channelalloc.c
channel/channelbans.c

diff --git a/bans/Makefile b/bans/Makefile
new file mode 100644 (file)
index 0000000..36a165f
--- /dev/null
@@ -0,0 +1,6 @@
+
+.PHONY: all
+all: bans.so
+
+bans.so: bans.o
+       ld -shared -Bdynamic -o $@ $^
diff --git a/bans/bans.c b/bans/bans.c
new file mode 100644 (file)
index 0000000..fede146
--- /dev/null
@@ -0,0 +1,467 @@
+/* channelbans.c */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include "bans.h"
+
+#include "../nick/nick.h"
+#include "../lib/irc_string.h"
+#include "../irc/irc_config.h"
+#include "../core/nsmalloc.h"
+#include "../lib/flags.h"
+
+#define ALLOCUNIT 100
+
+chanban *freebans;
+
+void _init() {
+  freebans=NULL;  
+}
+
+void _fini() {
+  nsfreeall(POOL_BANS);
+}
+
+chanban *getchanban() {
+  int i;
+  chanban *cbp;
+
+  if (freebans==NULL) {
+    freebans=(chanban *)nsmalloc(POOL_BANS, ALLOCUNIT*sizeof(chanban));
+    for (i=0;i<ALLOCUNIT-1;i++) {
+      freebans[i].next=(struct chanban *)&(freebans[i+1]);
+    }
+    freebans[ALLOCUNIT-1].next=NULL;
+  }
+
+  cbp=freebans;
+  freebans=cbp->next;
+
+  cbp->nick=NULL;
+  cbp->user=NULL;
+  cbp->host=NULL;
+
+  return cbp;
+}
+
+void freechanban(chanban *cbp) {
+  cbp->next=(struct chanban *)freebans;
+
+  if (cbp->nick)
+    freesstring(cbp->nick);
+  if (cbp->user)
+    freesstring(cbp->user);
+  if (cbp->host)
+    freesstring(cbp->host);
+
+  freebans=cbp;
+}
+
+/*
+ * makeban:
+ *  Converts the specified ban into a ban structure
+ */
+chanban *makeban(const char *mask) {
+  int len;
+  int foundat=-1,foundbang=-1;
+  int dotcount=0;
+  int notip=0;
+  int foundwild=0;
+  int foundslash=0;
+  int i;
+  int checklen;
+  chanban *cbp;
+  
+  cbp=getchanban();  
+  len=strlen(mask);
+  
+  cbp->flags=0;
+  
+  /* Let's catch a silly case first */
+  if (!strcmp(mask,"*")) {
+    cbp->flags=CHANBAN_HOSTANY | CHANBAN_USERANY | CHANBAN_NICKANY;
+    cbp->nick=NULL;
+    cbp->user=NULL;
+    cbp->host=NULL;
+    cbp->timeset=time(NULL);
+    return cbp;
+  }
+  
+  for (i=(len-1);i>=0;i--) {
+    if (mask[i]=='@') {
+      /* Got @ sign: everything after here is host */
+      if ((len-i)-1 > HOSTLEN) {
+        /* This is too long, we need to truncate it */
+        cbp->host=getsstring(&mask[len-HOSTLEN],HOSTLEN);
+        cbp->host->content[0]='*';
+        cbp->flags |= CHANBAN_HOSTMASK;
+      } else if (i==(len-1)) {
+        /* Ban ending with @, just mark it invalid */
+        /* Note that "moo@*" overrides "moo@", so mark it as having a host too */ 
+        cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTNULL);
+        cbp->host=NULL;
+      } else if (i==(len-2) && mask[i+1]=='*') {
+        /* Special case: "@*" */
+        cbp->flags |= CHANBAN_HOSTANY;
+        cbp->host=NULL;      
+      } else if (foundslash) {
+        /* If we found a slash (/), this can only be a CIDR ban */
+        /* However, it might be broken, so we need to retain the exact string
+         * to track it accurately */
+        cbp->host=getsstring(&mask[i+1],HOSTLEN);
+        if ((notip || dotcount!=3) && !foundwild) {
+          cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTEXACT);
+        } 
+        if (foundwild) {
+          cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTMASK);
+        }
+        cbp->flags |= (CHANBAN_HOSTEXACT | CHANBAN_CIDR);        
+      } else {
+        /* We have some string with between 1 and HOSTLEN characters.. */
+        cbp->host=getsstring(&mask[i+1],HOSTLEN);
+        if (foundwild) {
+          /* We check all characters after the last wildcard (if any).. if they match
+           * the corresponding bits of the hidden host string we mark it accordingly */
+          if (!(checklen=len-foundwild-1)) { /* Ban ends in *, mark it anyway.. */
+            cbp->flags |= CHANBAN_HIDDENHOST;
+          } else {
+            if (checklen>=strlen(HIS_HIDDENHOST)) {
+              if (!ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST))
+                cbp->flags |= CHANBAN_HIDDENHOST;
+            } else {
+              if (!ircd_strcmp(cbp->host->content+(cbp->host->length-checklen), 
+                               (HIS_HIDDENHOST)+strlen(HIS_HIDDENHOST)-checklen))
+                cbp->flags |= CHANBAN_HIDDENHOST;
+            }
+          }
+          cbp->flags |= CHANBAN_HOSTMASK;
+          if (!notip && dotcount<=3)
+            cbp->flags |= CHANBAN_IP;
+        } else {
+          /* Exact host: see if it ends with the "hidden host" string */
+          cbp->flags |= CHANBAN_HOSTEXACT;
+          if ((cbp->host->length > (strlen(HIS_HIDDENHOST)+1)) && 
+              !ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST))
+            cbp->flags |= CHANBAN_HIDDENHOST;
+          else if (!notip && dotcount==3)
+            cbp->flags |= CHANBAN_IP;
+        }
+      }
+      foundat=i;
+      break;
+    } else if (mask[i]=='/') {
+      foundslash=1;
+    } else if (mask[i]=='.') {
+      dotcount++;
+    } else if (mask[i]=='?' || mask[i]=='*') {
+      if (!foundwild)  /* Mark last wildcard in string */
+        foundwild=i;
+    } else if (mask[i]<'0' || mask[i]>'9') {
+      notip=1;
+    }
+  }
+
+  if (foundat<0) {
+    /* If there wasn't an @, this ban matches any host */
+    cbp->host=NULL;
+    cbp->flags |= CHANBAN_HOSTANY;
+  }
+  
+  foundwild=0;
+  
+  for (i=0;i<foundat;i++) {
+    if (mask[i]=='!') {
+      if (i==0) {
+        /* Invalid mask: nick is empty */
+        cbp->flags |= CHANBAN_NICKNULL;
+        cbp->nick=NULL;
+      } else if (i==1 && mask[0]=='*') {
+        /* matches any nick */
+        cbp->flags |= CHANBAN_NICKANY;
+        cbp->nick=NULL;
+      } else {
+        if (i>NICKLEN) {
+          /* too long: just take the first NICKLEN chars */
+          cbp->nick=getsstring(mask,NICKLEN);
+        } else {
+          cbp->nick=getsstring(mask,i);
+        }
+        if (foundwild)
+          cbp->flags |= CHANBAN_NICKMASK;
+        else
+          cbp->flags |= CHANBAN_NICKEXACT;
+      }
+      foundbang=i;
+      break;
+    } else if (mask[i]=='?' || mask[i]=='*') {
+      if (i<NICKLEN) {
+        foundwild=1;
+      }
+    }
+  }
+  
+  if (foundbang<0) {
+    /* We didn't find a !, what we do now depends on what happened
+     * with the @ */
+    if (foundat<0) {
+      /* A ban with no ! or @ is treated as a nick ban only */
+      /* Note that we've special-cased "*" at the top, so we can only 
+       * hit the MASK or EXACT case here. */
+      if (len>NICKLEN) 
+        cbp->nick=getsstring(mask,NICKLEN);
+      else
+        cbp->nick=getsstring(mask,len);
+        
+      if (foundwild)
+        cbp->flags |= CHANBAN_NICKMASK;
+      else
+        cbp->flags |= CHANBAN_NICKEXACT;
+        
+      cbp->flags |= (CHANBAN_USERANY | CHANBAN_HOSTANY);
+      cbp->host=NULL;
+      cbp->user=NULL;
+    } else {
+      /* A ban with @ only is treated as user@host */
+      cbp->nick=NULL;
+      cbp->flags |= CHANBAN_NICKANY;
+    }
+  }
+  
+  if (foundat>=0) {
+    /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
+    /* This is true even if there was no !.. */
+    if (foundat==(foundbang+1)) {
+      /* empty ident matches nothing */
+      cbp->flags |= (CHANBAN_INVALID | CHANBAN_USERNULL);
+      cbp->user=NULL;
+    } else if (foundat - foundbang - 1 > USERLEN) {
+      /* It's too long.. */
+      cbp->user=getsstring(&mask[foundat-USERLEN],USERLEN);
+      cbp->user->content[0]='*';
+      cbp->flags |= CHANBAN_USERMASK;
+    } else if ((foundat - foundbang - 1 == 1) && mask[foundbang+1]=='*') {
+      cbp->user=NULL;
+      cbp->flags |= CHANBAN_USERANY;
+    } else {
+      cbp->user=getsstring(&mask[foundbang+1],(foundat-foundbang-1));
+      if (strchr(cbp->user->content,'*') || strchr(cbp->user->content,'?'))
+        cbp->flags |= CHANBAN_USERMASK;
+      else
+        cbp->flags |= CHANBAN_USEREXACT;
+    }
+  }
+
+  assert(cbp->flags & (CHANBAN_USEREXACT | CHANBAN_USERMASK | CHANBAN_USERANY | CHANBAN_USERNULL));
+  assert(cbp->flags & (CHANBAN_NICKEXACT | CHANBAN_NICKMASK | CHANBAN_NICKANY | CHANBAN_NICKNULL));
+  assert(cbp->flags & (CHANBAN_HOSTEXACT | CHANBAN_HOSTMASK | CHANBAN_HOSTANY | CHANBAN_HOSTNULL));
+
+  cbp->timeset=time(NULL);
+
+  return cbp;
+}      
+
+/* banoverlap:
+ *  Returns nonzero iff bana is a SUPERSET of banb
+ */
+
+int banoverlap(const chanban *bana, const chanban *banb) {
+  /* This function works by looking for cases where bana DOESN'T overlap banb */
+
+  /* NICK section */
+  /* If bana has CHANBAN_NICKANY then it clearly overlaps 
+   * in the nick section so there are no checks */
+
+  if ((bana->flags & CHANBAN_NICKNULL) && !(banb->flags & CHANBAN_NICKNULL)) {
+    return 0;
+  }
+
+  if (bana->flags & CHANBAN_NICKMASK) {
+    if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKNULL)) {
+      return 0;
+    }
+    if ((banb->flags & CHANBAN_NICKMASK) && !match2patterns(bana->nick->content, banb->nick->content)) {
+      return 0;
+    }
+    if ((banb->flags & CHANBAN_NICKEXACT) && !match2strings(bana->nick->content, banb->nick->content)) {
+      return 0;
+    }
+  }
+  
+  if (bana->flags & CHANBAN_NICKEXACT) {
+    if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKMASK | CHANBAN_NICKNULL)) {
+      return 0;
+    }
+    if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick)) {
+      return 0;
+    }
+    if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content)) {
+      return 0;
+    }
+  }
+
+  /* USER section */
+  /* If bana has CHANBAN_USERANY then it clearly overlaps 
+   * in the user section so there are no checks */
+
+  if ((bana->flags & CHANBAN_USERNULL) && !(banb->flags & CHANBAN_USERNULL)) {
+    return 0;
+  }
+
+  if (bana->flags & CHANBAN_USERMASK) {
+    if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERNULL)) {
+      return 0;
+    }
+    if ((banb->flags & CHANBAN_USERMASK) && !match2patterns(bana->user->content, banb->user->content)) {
+      return 0;
+    }
+    if ((banb->flags & CHANBAN_USEREXACT) && !match2strings(bana->user->content, banb->user->content)) {
+      return 0;
+    }
+  }
+  
+  if (bana->flags & CHANBAN_USEREXACT) {
+    if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERMASK | CHANBAN_USERNULL)) {
+      return 0;
+    }
+    if ((!bana->user && banb->user) || (bana->user && !banb->user)) {
+      return 0;
+    }
+    if (bana->user && ircd_strcmp(bana->user->content,banb->user->content)) {
+      return 0;
+    }
+  }
+
+  /* HOST section */
+  /* If bana has CHANBAN_HOSTANY then it clearly overlaps 
+   * in the host section so there are no checks */
+
+  if ((bana->flags & CHANBAN_HOSTNULL) && !(banb->flags & CHANBAN_HOSTNULL)) {
+    return 0;
+  }
+
+  if (bana->flags & CHANBAN_HOSTMASK) {
+    if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTNULL)) {
+      return 0;
+    }
+    if ((banb->flags & CHANBAN_HOSTMASK) && !match2patterns(bana->host->content, banb->host->content)) {
+      return 0;
+    }
+    if ((banb->flags & CHANBAN_HOSTEXACT) && !match2strings(bana->host->content, banb->host->content)) {
+      return 0;
+    }
+  }
+  
+  if (bana->flags & CHANBAN_HOSTEXACT) {
+    if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTMASK | CHANBAN_HOSTNULL)) {
+      return 0;
+    }
+    if ((!bana->host && banb->host) || (bana->host && !banb->host)) {
+      return 0;
+    }
+    if (bana->host && ircd_strcmp(bana->host->content,banb->host->content)) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+/*
+ * banequal:
+ *  Returns nonzero iff the bans are EXACTLY the same
+ */
+int banequal(chanban *bana, chanban *banb) {
+  if (bana->flags != banb->flags) 
+    return 0;
+
+  if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick))
+    return 0;
+  if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content))
+    return 0;
+
+  if ((!bana->user && banb->user) || (bana->user && !banb->user))
+    return 0;
+  if (bana->user && ircd_strcmp(bana->user->content,banb->user->content))
+    return 0;
+
+  if ((!bana->host && banb->host) || (bana->host && !banb->host))
+    return 0;
+  if (bana->host && ircd_strcmp(bana->host->content,banb->host->content))
+    return 0;
+
+  return 1;
+}
+
+/*
+ * bantostring:
+ *  Convert the specified ban to a string
+ */
+
+char *bantostring(chanban *bp) {
+  static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
+  int strpos=0;
+
+  if (bp->flags & CHANBAN_NICKANY) {
+    strpos += sprintf(outstring+strpos,"*");
+  } else if (bp->nick) {
+    strpos += sprintf(outstring+strpos,"%s",bp->nick->content);
+  }
+
+  strpos += sprintf(outstring+strpos,"!");
+
+  if (bp->flags & CHANBAN_USERANY) {
+    strpos += sprintf(outstring+strpos,"*");
+  } else if (bp->user) {
+    strpos += sprintf(outstring+strpos,"%s",bp->user->content);
+  }
+
+  strpos += sprintf(outstring+strpos,"@");
+
+  if (bp->flags & CHANBAN_HOSTANY) {
+    strpos += sprintf(outstring+strpos,"*");
+  } else if (bp->host) {
+    strpos += sprintf(outstring+strpos,"%s",bp->host->content);
+  }
+
+  return outstring;
+} 
+
+/*
+ * bantostringdebug:
+ *  Convert the specified ban to a string (debugging version)
+ */
+
+char *bantostringdebug(chanban *bp) {
+  static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
+  int strpos=0;
+
+  strpos += sprintf(outstring+strpos, "flags=%04x ",bp->flags);
+
+  if (bp->nick) {
+    strpos += sprintf(outstring+strpos, "nick=%s ",bp->nick->content);
+  } else {
+    strpos += sprintf(outstring+strpos, "nonick ");
+  }
+
+  if (bp->user) {
+    strpos += sprintf(outstring+strpos, "user=%s ",bp->user->content);
+  } else {
+    strpos += sprintf(outstring+strpos, "nouser ");
+  }
+
+  if (bp->host) {
+    strpos += sprintf(outstring+strpos, "host=%s ",bp->host->content);
+  } else {
+    strpos += sprintf(outstring+strpos, "nohost ");
+  }
+
+
+  return outstring;
+} 
+
diff --git a/bans/bans.h b/bans/bans.h
new file mode 100644 (file)
index 0000000..741fc2e
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _BANS_H
+#define _BANS_H
+
+#include "../lib/flags.h"
+#include "../lib/sstring.h"
+#include <time.h>
+
+#define CHANBAN_NICKEXACT   0x0001  /* Ban includes an exact nick (no wildcards) */
+#define CHANBAN_NICKMASK    0x0002  /* Ban includes a nick mask with wildcards */
+#define CHANBAN_NICKANY     0x0004  /* Ban is *!.. */
+#define CHANBAN_NICKNULL    0x0008  /* Ban has no nick */
+#define CHANBAN_USEREXACT   0x0010  /* Ban includes an exact user (no wildcards) */
+#define CHANBAN_USERMASK    0x0020  /* Ban includes a user mask with wildcards */
+#define CHANBAN_USERANY     0x0040  /* Ban is ..!*@.. */
+#define CHANBAN_USERNULL    0x0080  /* Ban has no user */
+#define CHANBAN_HOSTEXACT   0x0100  /* Ban includes an exact host */
+#define CHANBAN_HOSTMASK    0x0200  /* Ban includes a host mask */
+#define CHANBAN_HOSTANY     0x0400  /* Ban is ..@* */
+#define CHANBAN_HOSTNULL    0x0800  /* Ban has no host */
+#define CHANBAN_IP          0x1000  /* Ban could match against IP address */
+#define CHANBAN_CIDR        0x2000  /* Ban includes a CIDR mask (e.g. 192.168.0.0/16 ) */
+#define CHANBAN_INVALID     0x4000  /* Ban is nonsensical, i.e. has at least one really NULL component*/
+#define CHANBAN_HIDDENHOST  0x8000  /* Ban could possibly match hidden host */
+
+
+typedef struct chanban {
+  flag_t          flags;
+  sstring        *nick;
+  sstring        *user;
+  sstring        *host;
+  time_t          timeset;
+  struct chanban *next;
+} chanban;
+            
+chanban *getchanban();
+void freechanban(chanban *cbp);
+
+chanban *makeban(const char *mask);
+
+int banoverlap(const chanban *bana, const chanban *banb);
+int banequal(chanban *bana, chanban *banb);
+char *bantostring(chanban *bp);
+char *bantostringdebug(chanban *bp);
+
+
+#endif
index 3ab8f66770216b1aabdcb377da4ed9e94d125d61..88c215fce26c84022cbfa6ca6a45ff75d7eeeaba 100644 (file)
@@ -9,6 +9,7 @@
 #include "../irc/irc.h"
 #include "../lib/base64.h"
 #include "../lib/version.h"
+#include "../core/nsmalloc.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -73,6 +74,11 @@ void _init() {
 }
 
 void _fini() {
+  unsigned int i;
+  struct channel *cp;
+  struct chanindex *cip, *ncip;
+  nick *np;
+
   deregisterserverhandler("B",&handleburstmsg);
   deregisterserverhandler("J",&handlejoinmsg);
   deregisterserverhandler("C",&handlecreatemsg);
@@ -88,6 +94,27 @@ void _fini() {
   deregisterhook(HOOK_CORE_STATSREQUEST,&channelstats);
   deregisterhook(HOOK_IRC_SENDBURSTBURSTS,&sendchanburst);
   deregisterhook(HOOK_NICK_WHOISCHANNELS,&handlewhoischannels);
+  /* Free all the channels */
+  for(i=0;i<CHANNELHASHSIZE;i++) {
+    for (cip=chantable[i];cip;cip=ncip) {
+      ncip=cip->next;
+      if (!(cp=cip->channel))
+        continue;
+
+      delchannel(cp);
+    }
+  }
+  
+  /* We also need to remove the channels array from each user */
+  for (i=0;i<NICKHASHSIZE;i++) {
+    for (np=nicktable[i];np;np=np->next) {
+      array_free(np->channels);
+      free(np->channels);
+    }
+  }
+  
+  nsfreeall(POOL_CHANNEL);
 }
 
 int addnicktochannel(channel *cp, long numeric) {
@@ -405,3 +432,4 @@ unsigned int countuniquehosts(channel *cp) {
   
   return count;
 }
+
index 5f6d2e697c2b661feec1d4c85a382b3c23a9411a..3cc7a82eb41159df45cb580986639b7c2fcdab5b 100644 (file)
@@ -12,6 +12,7 @@
 #include "../core/error.h"
 #include "../nick/nick.h"
 #include "../chanindex/chanindex.h"
+#include "../bans/bans.h"
 
 #include <time.h>
 #include <stdlib.h>
 
 #define CHANMODE_ALL        0xFFFF
 
-#define CHANBAN_NICKEXACT   0x0001  /* Ban includes an exact nick (no wildcards) */
-#define CHANBAN_NICKMASK    0x0002  /* Ban includes a nick mask with wildcards */
-#define CHANBAN_NICKANY     0x0004  /* Ban is *!.. */
-#define CHANBAN_NICKNULL    0x0008  /* Ban has no nick */
-#define CHANBAN_USEREXACT   0x0010  /* Ban includes an exact user (no wildcards) */
-#define CHANBAN_USERMASK    0x0020  /* Ban includes a user mask with wildcards */
-#define CHANBAN_USERANY     0x0040  /* Ban is ..!*@.. */
-#define CHANBAN_USERNULL    0x0080  /* Ban has no user */
-#define CHANBAN_HOSTEXACT   0x0100  /* Ban includes an exact host */
-#define CHANBAN_HOSTMASK    0x0200  /* Ban includes a host mask */
-#define CHANBAN_HOSTANY     0x0400  /* Ban is ..@* */
-#define CHANBAN_HOSTNULL    0x0800  /* Ban has no host */
-#define CHANBAN_IP          0x1000  /* Ban could match against IP address */
-#define CHANBAN_CIDR        0x2000  /* Ban includes a CIDR mask (e.g. 192.168.0.0/16 ) */
-#define CHANBAN_INVALID     0x4000  /* Ban is nonsensical, i.e. has at least one really NULL component*/
-#define CHANBAN_HIDDENHOST  0x8000  /* Ban could possibly match hidden host */
-
 #define IsNoExtMsg(x)   ((x)->flags & CHANMODE_NOEXTMSG)
 #define IsTopicLimit(x) ((x)->flags & CHANMODE_TOPICLIMIT)
 #define IsSecret(x)     ((x)->flags & CHANMODE_SECRET)
 #define MODECHANGE_USERS   0x00000002
 #define MODECHANGE_BANS    0x00000004
 
-typedef struct chanban {
-  flag_t          flags;
-  sstring        *nick;
-  sstring        *user;
-  sstring        *host;
-  time_t          timeset;
-  struct chanban *next;
-} chanban;
-
 typedef struct chanuserhash {
   unsigned short  hashsize;
   unsigned short  totalusers;
@@ -185,16 +160,9 @@ channel *newchan();
 void freechan(channel *cp);
 chanuserhash *newchanuserhash(int numbuckets);
 void freechanuserhash(chanuserhash *cuhp);
-chanban *getchanban();
-void freechanban(chanban *cbp);
 
 /* functions from channelbans.c */
-chanban *makeban(const char *mask);
-int banoverlap(const chanban *bana, const chanban *banb);
-int banequal(chanban *bana, chanban *banb);
-char *bantostring(chanban *bp);
-char *bantostringdebug(chanban *bp);
-void setban(channel *cp, const char *ban);
+int setban(channel *cp, const char *ban);
 int clearban(channel *cp, const char *ban, int optional);
 void clearallbans(channel *cp);
 int nickmatchban(nick *np, chanban *bp);
index f1b3e024407bac01b8b7035d4fcdf7d7401e92e2..5add18f6a06766e62212397c7b7000a26dd37127 100644 (file)
@@ -3,17 +3,16 @@
 #include <stdlib.h>
 #include "channel.h"
 #include <assert.h>
+#include "../core/nsmalloc.h"
 
 #define ALLOCUNIT  100
 
 channel *freechans;
 chanuserhash *freehash;
-chanban *freebans;
 
 void initchannelalloc() {
   freechans=NULL;
   freehash=NULL;
-  freebans=NULL;
 }
 
 /* channel records don't have next pointers.  
@@ -24,7 +23,7 @@ channel *newchan() {
   channel *cp;
   
   if (freechans==NULL) {
-    freechans=(channel *)malloc(ALLOCUNIT*sizeof(channel));
+    freechans=(channel *)nsmalloc(POOL_CHANNEL,ALLOCUNIT*sizeof(channel));
     for (i=0;i<(ALLOCUNIT-1);i++) {
       freechans[i].index=(struct chanindex *)&(freechans[i+1]);
     }
@@ -57,7 +56,7 @@ chanuserhash *newchanuserhash(int hashsize) {
   chanuserhash *cuhp;
   
   if (freehash==NULL) {
-    freehash=(chanuserhash *)malloc(ALLOCUNIT*sizeof(chanuserhash));
+    freehash=(chanuserhash *)nsmalloc(POOL_CHANNEL,ALLOCUNIT*sizeof(chanuserhash));
     for (i=0;i<(ALLOCUNIT-1);i++) {
       freehash[i].content=(unsigned long *)&(freehash[i+1]);
     }    
@@ -67,7 +66,7 @@ chanuserhash *newchanuserhash(int hashsize) {
   cuhp=freehash;
   freehash=(chanuserhash *)cuhp->content;
   
-
+  /* Don't use nsmalloc() here since we will free this in freechanuserhash() */
   cuhp->content=(unsigned long *)malloc(hashsize*sizeof(unsigned long));
   for (i=0;i<hashsize;i++) {
     cuhp->content[i]=nouser;
@@ -84,39 +83,3 @@ void freechanuserhash(chanuserhash *cuhp) {
   cuhp->content=(unsigned long *)freehash; 
   freehash=cuhp;
 }
-
-chanban *getchanban() {
-  int i;
-  chanban *cbp;
-  
-  if (freebans==NULL) {
-    freebans=(chanban *)malloc(ALLOCUNIT*sizeof(chanban));
-    for (i=0;i<ALLOCUNIT-1;i++) {
-      freebans[i].next=(struct chanban *)&(freebans[i+1]);
-    }
-    freebans[ALLOCUNIT-1].next=NULL;
-  }
-  
-  cbp=freebans;
-  freebans=cbp->next;
-  
-  cbp->nick=NULL;
-  cbp->user=NULL;
-  cbp->host=NULL;
-
-  return cbp;
-}
-
-void freechanban(chanban *cbp) {
-  cbp->next=(struct chanban *)freebans;
-
-  if (cbp->nick)
-    freesstring(cbp->nick);
-  if (cbp->user)
-    freesstring(cbp->user);
-  if (cbp->host)
-    freesstring(cbp->host);
-
-  freebans=cbp;
-}
-
index f4dc299ce67d063f3e9da2efe6a5d7c9e7845966..3b3be05b3f563ffdf9dd266782ba45e52c808482 100644 (file)
 #include "../irc/irc_config.h"
 #include "../irc/irc.h"
 
-/*
- * makeban:
- *  Converts the specified ban into a ban structure
- */
-chanban *makeban(const char *mask) {
-  int len;
-  int foundat=-1,foundbang=-1;
-  int dotcount=0;
-  int notip=0;
-  int foundwild=0;
-  int foundslash=0;
-  int i;
-  int checklen;
-  chanban *cbp;
-  
-  cbp=getchanban();  
-  len=strlen(mask);
-  
-  cbp->flags=0;
-  
-  /* Let's catch a silly case first */
-  if (!strcmp(mask,"*")) {
-    cbp->flags=CHANBAN_HOSTANY | CHANBAN_USERANY | CHANBAN_NICKANY;
-    cbp->nick=NULL;
-    cbp->user=NULL;
-    cbp->host=NULL;
-    cbp->timeset=time(NULL);
-    return cbp;
-  }
-  
-  for (i=(len-1);i>=0;i--) {
-    if (mask[i]=='@') {
-      /* Got @ sign: everything after here is host */
-      if ((len-i)-1 > HOSTLEN) {
-        /* This is too long, we need to truncate it */
-        cbp->host=getsstring(&mask[len-HOSTLEN],HOSTLEN);
-        cbp->host->content[0]='*';
-        cbp->flags |= CHANBAN_HOSTMASK;
-      } else if (i==(len-1)) {
-        /* Ban ending with @, just mark it invalid */
-        /* Note that "moo@*" overrides "moo@", so mark it as having a host too */ 
-        cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTNULL);
-        cbp->host=NULL;
-      } else if (i==(len-2) && mask[i+1]=='*') {
-        /* Special case: "@*" */
-        cbp->flags |= CHANBAN_HOSTANY;
-        cbp->host=NULL;      
-      } else if (foundslash) {
-        /* If we found a slash (/), this can only be a CIDR ban */
-        /* However, it might be broken, so we need to retain the exact string
-         * to track it accurately */
-        cbp->host=getsstring(&mask[i+1],HOSTLEN);
-        if ((notip || dotcount!=3) && !foundwild) {
-          cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTEXACT);
-        } 
-        if (foundwild) {
-          cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTMASK);
-        }
-        cbp->flags |= (CHANBAN_HOSTEXACT | CHANBAN_CIDR);        
-      } else {
-        /* We have some string with between 1 and HOSTLEN characters.. */
-        cbp->host=getsstring(&mask[i+1],HOSTLEN);
-        if (foundwild) {
-          /* We check all characters after the last wildcard (if any).. if they match
-           * the corresponding bits of the hidden host string we mark it accordingly */
-          if (!(checklen=len-foundwild-1)) { /* Ban ends in *, mark it anyway.. */
-            cbp->flags |= CHANBAN_HIDDENHOST;
-          } else {
-            if (checklen>=strlen(HIS_HIDDENHOST)) {
-              if (!ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST))
-                cbp->flags |= CHANBAN_HIDDENHOST;
-            } else {
-              if (!ircd_strcmp(cbp->host->content+(cbp->host->length-checklen), 
-                               (HIS_HIDDENHOST)+strlen(HIS_HIDDENHOST)-checklen))
-                cbp->flags |= CHANBAN_HIDDENHOST;
-            }
-          }
-          cbp->flags |= CHANBAN_HOSTMASK;
-          if (!notip && dotcount<=3)
-            cbp->flags |= CHANBAN_IP;
-        } else {
-          /* Exact host: see if it ends with the "hidden host" string */
-          cbp->flags |= CHANBAN_HOSTEXACT;
-          if ((cbp->host->length > (strlen(HIS_HIDDENHOST)+1)) && 
-              !ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST))
-            cbp->flags |= CHANBAN_HIDDENHOST;
-          else if (!notip && dotcount==3)
-            cbp->flags |= CHANBAN_IP;
-        }
-      }
-      foundat=i;
-      break;
-    } else if (mask[i]=='/') {
-      foundslash=1;
-    } else if (mask[i]=='.') {
-      dotcount++;
-    } else if (mask[i]=='?' || mask[i]=='*') {
-      if (!foundwild)  /* Mark last wildcard in string */
-        foundwild=i;
-    } else if (mask[i]<'0' || mask[i]>'9') {
-      notip=1;
-    }
-  }
-
-  if (foundat<0) {
-    /* If there wasn't an @, this ban matches any host */
-    cbp->host=NULL;
-    cbp->flags |= CHANBAN_HOSTANY;
-  }
-  
-  foundwild=0;
-  
-  for (i=0;i<foundat;i++) {
-    if (mask[i]=='!') {
-      if (i==0) {
-        /* Invalid mask: nick is empty */
-        cbp->flags |= CHANBAN_NICKNULL;
-        cbp->nick=NULL;
-      } else if (i==1 && mask[0]=='*') {
-        /* matches any nick */
-        cbp->flags |= CHANBAN_NICKANY;
-        cbp->nick=NULL;
-      } else {
-        if (i>NICKLEN) {
-          /* too long: just take the first NICKLEN chars */
-          cbp->nick=getsstring(mask,NICKLEN);
-        } else {
-          cbp->nick=getsstring(mask,i);
-        }
-        if (foundwild)
-          cbp->flags |= CHANBAN_NICKMASK;
-        else
-          cbp->flags |= CHANBAN_NICKEXACT;
-      }
-      foundbang=i;
-      break;
-    } else if (mask[i]=='?' || mask[i]=='*') {
-      if (i<NICKLEN) {
-        foundwild=1;
-      }
-    }
-  }
-  
-  if (foundbang<0) {
-    /* We didn't find a !, what we do now depends on what happened
-     * with the @ */
-    if (foundat<0) {
-      /* A ban with no ! or @ is treated as a nick ban only */
-      /* Note that we've special-cased "*" at the top, so we can only 
-       * hit the MASK or EXACT case here. */
-      if (len>NICKLEN) 
-        cbp->nick=getsstring(mask,NICKLEN);
-      else
-        cbp->nick=getsstring(mask,len);
-        
-      if (foundwild)
-        cbp->flags |= CHANBAN_NICKMASK;
-      else
-        cbp->flags |= CHANBAN_NICKEXACT;
-        
-      cbp->flags |= (CHANBAN_USERANY | CHANBAN_HOSTANY);
-      cbp->host=NULL;
-      cbp->user=NULL;
-    } else {
-      /* A ban with @ only is treated as user@host */
-      cbp->nick=NULL;
-      cbp->flags |= CHANBAN_NICKANY;
-    }
-  }
-  
-  if (foundat>=0) {
-    /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
-    /* This is true even if there was no !.. */
-    if (foundat==(foundbang+1)) {
-      /* empty ident matches nothing */
-      cbp->flags |= (CHANBAN_INVALID | CHANBAN_USERNULL);
-      cbp->user=NULL;
-    } else if (foundat - foundbang - 1 > USERLEN) {
-      /* It's too long.. */
-      cbp->user=getsstring(&mask[foundat-USERLEN],USERLEN);
-      cbp->user->content[0]='*';
-      cbp->flags |= CHANBAN_USERMASK;
-    } else if ((foundat - foundbang - 1 == 1) && mask[foundbang+1]=='*') {
-      cbp->user=NULL;
-      cbp->flags |= CHANBAN_USERANY;
-    } else {
-      cbp->user=getsstring(&mask[foundbang+1],(foundat-foundbang-1));
-      if (strchr(cbp->user->content,'*') || strchr(cbp->user->content,'?'))
-        cbp->flags |= CHANBAN_USERMASK;
-      else
-        cbp->flags |= CHANBAN_USEREXACT;
-    }
-  }
-
-  assert(cbp->flags & (CHANBAN_USEREXACT | CHANBAN_USERMASK | CHANBAN_USERANY | CHANBAN_USERNULL));
-  assert(cbp->flags & (CHANBAN_NICKEXACT | CHANBAN_NICKMASK | CHANBAN_NICKANY | CHANBAN_NICKNULL));
-  assert(cbp->flags & (CHANBAN_HOSTEXACT | CHANBAN_HOSTMASK | CHANBAN_HOSTANY | CHANBAN_HOSTNULL));
-
-  cbp->timeset=time(NULL);
-
-  return cbp;
-}      
-
-/* banoverlap:
- *  Returns nonzero iff bana is a SUPERSET of banb
- */
-
-int banoverlap(const chanban *bana, const chanban *banb) {
-  /* This function works by looking for cases where bana DOESN'T overlap banb */
-
-  /* NICK section */
-  /* If bana has CHANBAN_NICKANY then it clearly overlaps 
-   * in the nick section so there are no checks */
-
-  if ((bana->flags & CHANBAN_NICKNULL) && !(banb->flags & CHANBAN_NICKNULL)) {
-    return 0;
-  }
-
-  if (bana->flags & CHANBAN_NICKMASK) {
-    if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKNULL)) {
-      return 0;
-    }
-    if ((banb->flags & CHANBAN_NICKMASK) && !match2patterns(bana->nick->content, banb->nick->content)) {
-      return 0;
-    }
-    if ((banb->flags & CHANBAN_NICKEXACT) && !match2strings(bana->nick->content, banb->nick->content)) {
-      return 0;
-    }
-  }
-  
-  if (bana->flags & CHANBAN_NICKEXACT) {
-    if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKMASK | CHANBAN_NICKNULL)) {
-      return 0;
-    }
-    if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick)) {
-      return 0;
-    }
-    if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content)) {
-      return 0;
-    }
-  }
-
-  /* USER section */
-  /* If bana has CHANBAN_USERANY then it clearly overlaps 
-   * in the user section so there are no checks */
-
-  if ((bana->flags & CHANBAN_USERNULL) && !(banb->flags & CHANBAN_USERNULL)) {
-    return 0;
-  }
-
-  if (bana->flags & CHANBAN_USERMASK) {
-    if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERNULL)) {
-      return 0;
-    }
-    if ((banb->flags & CHANBAN_USERMASK) && !match2patterns(bana->user->content, banb->user->content)) {
-      return 0;
-    }
-    if ((banb->flags & CHANBAN_USEREXACT) && !match2strings(bana->user->content, banb->user->content)) {
-      return 0;
-    }
-  }
-  
-  if (bana->flags & CHANBAN_USEREXACT) {
-    if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERMASK | CHANBAN_USERNULL)) {
-      return 0;
-    }
-    if ((!bana->user && banb->user) || (bana->user && !banb->user)) {
-      return 0;
-    }
-    if (bana->user && ircd_strcmp(bana->user->content,banb->user->content)) {
-      return 0;
-    }
-  }
-
-  /* HOST section */
-  /* If bana has CHANBAN_HOSTANY then it clearly overlaps 
-   * in the host section so there are no checks */
-
-  if ((bana->flags & CHANBAN_HOSTNULL) && !(banb->flags & CHANBAN_HOSTNULL)) {
-    return 0;
-  }
-
-  if (bana->flags & CHANBAN_HOSTMASK) {
-    if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTNULL)) {
-      return 0;
-    }
-    if ((banb->flags & CHANBAN_HOSTMASK) && !match2patterns(bana->host->content, banb->host->content)) {
-      return 0;
-    }
-    if ((banb->flags & CHANBAN_HOSTEXACT) && !match2strings(bana->host->content, banb->host->content)) {
-      return 0;
-    }
-  }
-  
-  if (bana->flags & CHANBAN_HOSTEXACT) {
-    if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTMASK | CHANBAN_HOSTNULL)) {
-      return 0;
-    }
-    if ((!bana->host && banb->host) || (bana->host && !banb->host)) {
-      return 0;
-    }
-    if (bana->host && ircd_strcmp(bana->host->content,banb->host->content)) {
-      return 0;
-    }
-  }
-
-  return 1;
-}
-
-/*
- * banequal:
- *  Returns nonzero iff the bans are EXACTLY the same
- */
-int banequal(chanban *bana, chanban *banb) {
-  if (bana->flags != banb->flags) 
-    return 0;
-
-  if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick))
-    return 0;
-  if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content))
-    return 0;
-
-  if ((!bana->user && banb->user) || (bana->user && !banb->user))
-    return 0;
-  if (bana->user && ircd_strcmp(bana->user->content,banb->user->content))
-    return 0;
-
-  if ((!bana->host && banb->host) || (bana->host && !banb->host))
-    return 0;
-  if (bana->host && ircd_strcmp(bana->host->content,banb->host->content))
-    return 0;
-
-  return 1;
-}
-
-/*
- * bantostring:
- *  Convert the specified ban to a string
- */
-
-char *bantostring(chanban *bp) {
-  static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
-  int strpos=0;
-
-  if (bp->flags & CHANBAN_NICKANY) {
-    strpos += sprintf(outstring+strpos,"*");
-  } else if (bp->nick) {
-    strpos += sprintf(outstring+strpos,"%s",bp->nick->content);
-  }
-
-  strpos += sprintf(outstring+strpos,"!");
-
-  if (bp->flags & CHANBAN_USERANY) {
-    strpos += sprintf(outstring+strpos,"*");
-  } else if (bp->user) {
-    strpos += sprintf(outstring+strpos,"%s",bp->user->content);
-  }
-
-  strpos += sprintf(outstring+strpos,"@");
-
-  if (bp->flags & CHANBAN_HOSTANY) {
-    strpos += sprintf(outstring+strpos,"*");
-  } else if (bp->host) {
-    strpos += sprintf(outstring+strpos,"%s",bp->host->content);
-  }
-
-  return outstring;
-} 
-
-/*
- * bantostringdebug:
- *  Convert the specified ban to a string (debugging version)
- */
-
-char *bantostringdebug(chanban *bp) {
-  static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
-  int strpos=0;
-
-  strpos += sprintf(outstring+strpos, "flags=%04x ",bp->flags);
-
-  if (bp->nick) {
-    strpos += sprintf(outstring+strpos, "nick=%s ",bp->nick->content);
-  } else {
-    strpos += sprintf(outstring+strpos, "nonick ");
-  }
-
-  if (bp->user) {
-    strpos += sprintf(outstring+strpos, "user=%s ",bp->user->content);
-  } else {
-    strpos += sprintf(outstring+strpos, "nouser ");
-  }
-
-  if (bp->host) {
-    strpos += sprintf(outstring+strpos, "host=%s ",bp->host->content);
-  } else {
-    strpos += sprintf(outstring+strpos, "nohost ");
-  }
-
-
-  return outstring;
-} 
-
 /*
  * nickmatchban:
  *  Returns true iff the supplied nick* matches the supplied ban* 
@@ -522,13 +115,25 @@ int nickbanned(nick *np, channel *cp) {
  * setban:
  *  Set the specified ban; if it completely encloses any existing bans
  *  then remove them.
+ *
+ * Returns 1 if the ban was set, or 0 if the ban was not set because an
+ * existing ban overlapped it.
  */  
 
-void setban(channel *cp, const char *ban) {
+int setban(channel *cp, const char *ban) {
   chanban **cbh,*cbp,*cbp2;
 
   cbp=makeban(ban);
   
+  /* Don't set our ban if something encloses it */
+  for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
+    if (banoverlap(cbp2, cbp)) {
+      /* This ban overlaps the one we are adding.  Abort. */
+      freechanban(cbp);
+      return 0;
+    }
+  }
+    
   /* Remove enclosed bans first */
   for (cbh=&(cp->bans);*cbh;) {
     if (banoverlap(cbp,*cbh)) {
@@ -547,6 +152,8 @@ void setban(channel *cp, const char *ban) {
   /* Now set the new ban */
   cbp->next=(struct chanban *)cp->bans;
   cp->bans=cbp;
+  
+  return 1;
 }
 
 /*