]> jfr.im git - irc/quakenet/newserv.git/commitdiff
gline playground
authorPaul <redacted>
Thu, 1 Jan 2009 23:42:03 +0000 (23:42 +0000)
committerPaul <redacted>
Thu, 1 Jan 2009 23:42:03 +0000 (23:42 +0000)
--HG--
branch : paul

gline/Makefile.in [new file with mode: 0644]
gline/gline.c [new file with mode: 0644]
gline/gline.h [new file with mode: 0644]
gline/gline_alloc.c [new file with mode: 0644]
gline/gline_commands.c [new file with mode: 0644]
gline/gline_handler.c [new file with mode: 0644]
gline/gline_hash.c [new file with mode: 0644]

diff --git a/gline/Makefile.in b/gline/Makefile.in
new file mode 100644 (file)
index 0000000..68de83c
--- /dev/null
@@ -0,0 +1,9 @@
+@include@ @includel@../build.mk@includel@
+
+CFLAGS+=$(INCPGSQL) ${INCPCRE}
+LDFLAGS+=$(LIBPGSQL) ${LIBPCRE}
+
+.PHONY: all
+all: gline.so
+
+gline.so: gline_hash.o gline_alloc.o gline_handler.o gline.o
diff --git a/gline/gline.c b/gline/gline.c
new file mode 100644 (file)
index 0000000..6847c5d
--- /dev/null
@@ -0,0 +1,354 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "../control/control.h"
+#include "../nick/nick.h"
+#include "../localuser/localuserchannel.h"
+#include "../core/hooks.h"
+#include "../server/server.h"
+#include "../parser/parser.h"
+#include "../core/schedule.h"
+#include "../lib/array.h"
+#include "../lib/base64.h"
+#include "../lib/irc_string.h"
+#include "../lib/splitline.h"
+
+#include "gline.h"
+
+gline* glinelist = 0, *glinelistnonnode = 0;
+
+int glinecount = 0;
+int badchancount = 0;
+int rnglinecount = 0;
+int gl_nodeext = 0;
+
+/* 
+  <prefix> GL <target> [!][+|-|>|<]<mask> [<expiration>] [<lastmod>]
+    [<lifetime>] [:<reason>]
+
+ */
+
+void _init() {
+  gl_nodeext = registernodeext("gline");
+
+  if ( !gl_nodeext ) {
+    Error("gline", ERR_FATAL, "Could not register a required node extension (gline)");
+    return;
+  }
+
+  registerserverhandler("GL", &handleglinemsg, 6);
+
+  /* send reburst command to get glines from before we registered handler */
+  irc_send("%s RB G", mynumeric->content);
+}
+
+void _fini() {
+  gline *gl, *ngl;
+
+  deregisterserverhandler("GL", &handleglinemsg);
+
+  for (gl=glinelist;gl;gl=ngl) { 
+    ngl=gl->next;
+    freegline(gl);    
+  }
+  glinelist = NULL;
+  if (gl_nodeext) 
+    releasenodeext(gl_nodeext);
+}
+
+int gline_setnick(nick *np, int duration, char *reason ) {
+
+}
+
+int gline_setnode(patricia_node_t *node ) {
+
+}
+
+int gline_setmask(char *mask, int duration, char *reason ) {
+
+}
+
+gline* gline_add(long creatornum, sstring *creator, char *mask, char *reason, time_t expires, time_t lastmod, time_t lifetime) {
+  gline* gl;
+  char glineiddata[1024];
+
+  if ( !(gl=gline_processmask(mask))) { /* sets up nick,user,host,node and flags */
+    /* couldn't process gline mask */
+    Error("gline", ERR_WARNING, "Tried to add malformed G-Line %s!", mask);
+    return 0;
+  }
+
+  gl->creator = creator;
+  gl->numeric = creatornum;
+
+  /* it's not unreasonable to assume gline is active, if we're adding a deactivated gline, we can remove this later */
+  gl->flags = GLINE_ACTIVE;
+
+
+  /* set up gline id */
+  snprintf(glineiddata, sizeof(glineiddata), "gline %s %s", mask, reason);
+  gl->glineid = crc32(glineiddata);  
+
+  gl->reason = getsstring(reason, 255); /*TODO@@@ */ 
+  gl->expires = expires;
+  gl->lastmod = lastmod;
+  gl->lifetime = lifetime; 
+
+  /* Storage of glines */
+  /* ipbased glines are stored at node->ext[gl_nodeext]   
+   * other glines are stored in seperate linked list (for now) */
+  if (gl->flags & GLINE_IPMASK) {
+    gl->nextbynode = gl->node->exts[gl_nodeext];
+    gl->node->exts[gl_nodeext] = gl; 
+  } else {
+    gl->nextbynonnode = glinelistnonnode;
+    glinelistnonnode = gl;
+  }  
+
+  gl->next = glinelist;
+  glinelist = gl;
+
+  return gl;
+}
+
+/* returns 1 on success, 0 on a bad mask */
+gline* gline_processmask(char *mask) {
+  /* populate gl-> user,host,node,nick and set appropriate flags */
+  int len;
+  int foundat=-1,foundbang=-1;
+  int foundwild=0;
+  int i;
+  struct irc_in_addr sin;
+  unsigned char bits;
+  gline *gl = NULL;
+
+  if (!(gl = newgline())) {
+    Error("gline", ERR_ERROR, "Failed to allocate new gline");
+    return 0;
+  }
+
+  len=strlen(mask);
+
+  switch (*mask ) {
+    case '#':
+    case '&':
+      gl->flags |= GLINE_BADCHAN;
+      gl->user = getsstring(mask, CHANNELLEN);
+      return gl;
+    case '$':
+      switch (mask[1]) {
+        case 'R':
+          gl->flags |= GLINE_REALNAME;
+          break;
+        default: 
+          Error("gline", ERR_WARNING, "Tried to add malformed G-Line %s!", mask);
+          return 0;
+      }
+      gl->user = getsstring(mask,REALLEN);
+      return gl;
+    default:
+      /* Default case of some host/ip/cidr mask */
+      for (i=(len-1);i>=0;i--) {
+        if (mask[i]=='@') {
+          /* host */
+          if ((len-i)-1 > HOSTLEN) {
+            /* host too long */
+            return 0;
+          } else if (i==(len-1)) {
+            /* no host supplied aka gline ends @ */
+            return 0;
+          } else if (i==(len-2) && mask[i+1]=='*') {
+            /* Special case: "@*" */
+            gl->flags |= GLINE_HOSTANY;
+            gl->host=NULL;
+          } else {
+            if (ipmask_parse(&mask[i+1], &sin, &bits) == 0) {
+              /* we have some host string */
+              gl->host=getsstring(&mask[i+1],HOSTLEN);
+              if (foundwild) {
+                gl->flags |= GLINE_HOSTMASK;
+              } else {
+                gl->flags |= GLINE_HOSTEXACT;
+              } 
+            } else {
+              /* we have a / so cidr gline */
+              Error("gline", ERR_WARNING, "CIDR: %s", &mask[i+1]);
+              gl->node = refnode(iptree, &sin, bits);
+              gl->flags |= GLINE_IPMASK;
+            }
+          }
+          foundat=i;
+          break;
+        } else if (mask[i]=='?' || mask[i]=='*') {
+          if (!foundwild)  /* Mark last wildcard in string */
+            foundwild=i;
+        }
+      }
+  }
+  /*TODO set hostexact/hostmask */
+  if (foundat<0) {
+    /* If there wasn't an @, this ban matches any host */
+    gl->host=NULL;
+    gl->flags |= GLINE_HOSTANY;
+  }
+
+  foundwild=0;
+
+  for (i=0;i<foundat;i++) {
+    if (mask[i]=='!') {
+      if (i==0) {
+        /* Invalid mask: nick is empty */
+        gl->flags |= GLINE_NICKNULL;
+        gl->nick=NULL;
+      } else if (i==1 && mask[0]=='*') {
+        /* matches any nick */
+        gl->flags |= GLINE_NICKANY;
+        gl->nick=NULL;
+      } else {
+        if (i>NICKLEN) {
+          /* too long: just take the first NICKLEN chars */
+          gl->nick=getsstring(mask,NICKLEN);
+        } else {
+          gl->nick=getsstring(mask,i);
+        }
+        if (foundwild)
+          gl->flags |= GLINE_NICKMASK;
+        else
+          gl->flags |= GLINE_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 gline 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)
+        gl->nick=getsstring(mask,NICKLEN);
+      else
+        gl->nick=getsstring(mask,len);
+
+      if (foundwild)
+        gl->flags |= GLINE_NICKMASK;
+      else
+        gl->flags |= GLINE_NICKEXACT;
+
+      gl->flags |= (GLINE_USERANY | GLINE_HOSTANY);
+      gl->host=NULL;
+      gl->user=NULL;
+    } else {
+      /* A gline with @ only is treated as user@host */
+      gl->nick=NULL;
+      gl->flags |= GLINE_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 */ /*@@@TODO: * for glines? */
+      gl->flags |= (/*GLINE_INVALID |*/ GLINE_USERNULL);
+      gl->user=NULL;
+    } else if (foundat - foundbang - 1 > USERLEN) {
+      /* It's too long.. */
+      return 0;
+    } else if ((foundat - foundbang - 1 == 1) && mask[foundbang+1]=='*') {
+      gl->user=NULL;
+      gl->flags |= GLINE_USERANY;
+    } else {
+      gl->user=getsstring(&mask[foundbang+1],(foundat-foundbang-1));
+      if (strchr(gl->user->content,'*') || strchr(gl->user->content,'?'))
+        gl->flags |= GLINE_USERMASK;
+      else
+        gl->flags |= GLINE_USEREXACT;
+    }
+    /* Username part can't contain an @ */
+    if (gl->user && strchr(gl->user->content,'@')) {
+      //gl->flags |= CHANBAN_INVALID;
+    }
+  }
+
+  assert(gl->flags & (GLINE_USEREXACT | GLINE_USERMASK | GLINE_USERANY | GLINE_USERNULL));
+  assert(gl->flags & (GLINE_NICKEXACT | GLINE_NICKMASK | GLINE_NICKANY | GLINE_NICKNULL));
+  assert(gl->flags & (GLINE_HOSTEXACT | GLINE_HOSTMASK | GLINE_HOSTANY | GLINE_HOSTNULL | GLINE_IPMASK));
+
+  return gl;
+}
+
+gline *gline_find( char *mask) {
+  gline *gl;
+  gline *globalgline;
+
+  if( !(globalgline=gline_processmask(mask))) {
+    /* gline mask couldn't be processed */
+    return 0;
+  }
+
+  if (globalgline->flags & GLINE_IPMASK) {
+    gl = globalgline->node->exts[gl_nodeext];
+    while (gl) {
+      if ( gline_match( globalgline, gl) ) {
+        freegline(globalgline);
+        return gl;
+      }
+      gl = gl->nextbynode;
+    }
+  } else {
+    gl = glinelist;
+    while (gl) { 
+      if ( gline_match( globalgline, gl ) ) {
+        freegline(globalgline);
+        return gl;
+      }
+      gl = gl->nextbynonnode;
+    }
+  }
+  freegline(globalgline);
+  return 0;
+}
+
+/* returns non-zero on match */
+int gline_match ( gline *gla, gline *glb) {
+  if ((!gla->nick && glb->nick) || (gla->nick && !glb->nick))
+    return 0;
+
+  if (gla->nick && ircd_strcmp(gla->nick->content,glb->nick->content))
+    return 0;
+
+  if ((!gla->user && glb->user) || (gla->user && !glb->user))
+    return 0;
+
+  if (gla->user && ircd_strcmp(gla->user->content,glb->user->content))
+    return 0;
+
+  if ((!gla->host && glb->host) || (gla->host && !glb->host))
+    return 0;
+
+  if (gla->host && ircd_strcmp(gla->host->content,glb->host->content))
+    return 0;
+  
+  /* TODO @@@ match bits flags */
+  return 1;
+}
+
+void gline_send(gline *gl) {
+
+}
diff --git a/gline/gline.h b/gline/gline.h
new file mode 100644 (file)
index 0000000..601a746
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef _GLINE_H
+#define _GLINE_H
+
+#include <time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "../lib/sstring.h"
+#include "../lib/flags.h"
+#include "../nick/nick.h"
+#include "../channel/channel.h"
+#include "../parser/parser.h"
+#include "../localuser/localuserchannel.h"
+
+#define MAX_USERS_RN 1
+
+#define PASTWATCH       157680000       /* number of seconds in 5 years */
+
+/*
+ * If the expiration value, interpreted as an absolute timestamp, is
+ * more recent than 5 years in the past, we interpret it as an
+ * absolute timestamp; otherwise, we assume it's relative and convert
+ * it to an absolute timestamp.  Either way, the output of this macro
+ * is an absolute timestamp--not guaranteed to be a *valid* timestamp,
+ * but you can't have everything in a macro ;)
+ */
+#define abs_expire(exp)                                                 \
+  ((exp) >= getnettime() - PASTWATCH ? (exp) : (exp) + getnettime())
+
+#define gline_max(a,b) (((a)<(b)) ? (b) : (a))
+
+extern int gl_nodeext;
+
+typedef struct gline {
+  struct gline*    next;
+  struct gline*    nextbynode;
+  struct gline*    nextbynonnode;
+
+  long             glineid;
+  long             numeric;
+  sstring*         nick;
+  sstring*         user;
+  sstring*         host;
+  sstring*         reason;
+  sstring*         creator;
+
+  patricia_node_t* node;
+  time_t           expires;
+  time_t           lastmod;
+  time_t           lifetime;
+  unsigned int     flags;
+} gline;
+
+#define GLINE_NICKEXACT   0x00001  /* Gline includes an exact nick (no wildcards) */
+#define GLINE_NICKMASK    0x00002  /* Gline includes a nick mask with wildcards */
+#define GLINE_NICKANY     0x00004  /* Gline is *!.. */
+#define GLINE_NICKNULL    0x00008  /* Gline has no nick */
+#define GLINE_USEREXACT   0x00010  /* Gline includes an exact user (no wildcards) */
+#define GLINE_USERMASK    0x00020  /* Gline includes a user mask with wildcards */
+#define GLINE_USERANY     0x00040  /* Gline is ..!*@.. */
+#define GLINE_USERNULL    0x00080  /* Gline has no user */
+#define GLINE_HOSTEXACT   0x00100  /* Gline includes an exact host */
+#define GLINE_HOSTMASK    0x00200  /* Gline includes a host mask */
+#define GLINE_HOSTANY     0x00400  /* Gline is ..@* */
+#define GLINE_HOSTNULL    0x00800  /* Gline has no host */
+#define GLINE_BADCHAN     0x01000
+#define GLINE_REALNAME    0x02000
+#define GLINE_IPMASK      0x04000
+#define GLINE_FORCED      0x08000
+#define GLINE_ACTIVATE    0x10000
+#define GLINE_DEACTIVATE  0x20000
+#define GLINE_ACTIVE      0x40000
+#define GLINE_HOST        0x80000
+
+#define GlineIsBadChan(x)  ((x)->flags & GLINE_BADCHAN)
+#define GlineIsRealName(x) ((x)->flags & GLINE_REALNAME)
+#define GlineIsIpMask(x)   ((x)->flags & GLINE_IPMASK)
+#define GlineIsForced(x)   ((x)->flags & GLINE_FORCED)
+
+#define GlineNick(x)    ((x)->nick)
+#define GlineUser(x)    ((x)->user)
+#define GlineHost(x)    ((x)->host)
+#define GlineReason(x)  ((x)->reason)
+#define GlineCreator(x) ((x)->creator)
+#define GlineExpires(x) ((x)->expires)
+#define GlineLastMod(x) ((x)->lastmod)
+
+#define GLIST_COUNT    0x01 /* -c */
+#define GLIST_EXACT    0x02 /* -x */
+#define GLIST_FIND     0x04 /* -f */
+#define GLIST_REASON   0x10 /* -r */
+#define GLIST_OWNER    0x20 /* -o */
+#define GLIST_REALNAME 0x40 /* -R */
+
+extern gline* glinelist;
+extern gline* glinelistnonnode;
+extern gline* badchanlist;
+extern int glinecount;
+extern int badchancount;
+extern int rnglinecount;
+extern int hostglinecount;
+extern int ipglinecount;
+
+int gline_glist(void* source, int cargc, char** cargv);
+int gline_glgrep(void* source, int cargc, char** cargv);
+int gline_glstats(void* source, int cargc, char** cargv);
+int gline_ungline(void* source, int cargc, char** cargv);
+int gline_rawglinefile(void* source, int cargc, char** cargv);
+int gline_glinefile(void* source, int cargc, char** cargv);
+int gline_unglinefile(void* source, int cargc, char** cargv);
+int gline_saveglines(void* source, int cargc, char** cargv);
+int handleglinemsg(void* source, int cargc, char** cargv);
+int gline_gline(void* source, int cargc, char** cargv);
+int gline_rngline(void* source, int cargc, char** cargv);
+int gline_block(void* source, int cargc, char** cargv);
+
+gline *newgline();
+void freegline (gline *gl);
+
+gline* gline_processmask(char *mask);
+int gline_match ( gline *gla, gline *glb);
+
+gline* gline_add(long creatornum, sstring *creator, char *mask, char *reason, time_t expires, time_t lastmod, time_t lifetime);
+
+/*
+int gline_add(char* mask, char* reason, char* creator, time_t expires, time_t lastmod, unsigned int flags, int propagate);
+gline* make_gline(char* nick, char* user, char* host, char* reason, char* creator, time_t expires, time_t lastmod, unsigned int flags);
+gline* gline_find(char* mask);
+void gline_free(gline* g);
+int check_if_ipmask(const char* mask);
+void canon_userhost(char* mask, char** nick, char** user, char** host, char* def_user);
+*/
+
+#endif
diff --git a/gline/gline_alloc.c b/gline/gline_alloc.c
new file mode 100644 (file)
index 0000000..a53a90a
--- /dev/null
@@ -0,0 +1,121 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "../core/nsmalloc.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "gline.h"
+
+#define ALLOCUNIT  100
+
+gline *gline_freelist;
+
+gline *newgline() {
+  gline *gl;
+  int i;
+
+  if( gline_freelist ==NULL ) {
+    gline_freelist=(gline *)nsmalloc(POOL_GLINE,ALLOCUNIT*sizeof(gline));
+
+    for (i=0;i<(ALLOCUNIT-1);i++) {
+      gline_freelist[i].next=(gline *)&(gline_freelist[i+1]);
+    }
+    gline_freelist[ALLOCUNIT-1].next=NULL;
+  }
+
+  gl=gline_freelist;
+  gline_freelist=(gline *)gl->next;
+
+  gl->next=NULL;
+  gl->nextbynode=NULL;
+  gl->nextbynonnode=NULL;
+  
+  gl->glineid=0;
+  gl->numeric=0;
+
+  gl->nick=NULL;
+  gl->user=NULL;
+  gl->host=NULL;
+  gl->reason=NULL;
+  gl->creator=NULL;
+
+  gl->node=NULL;
+
+  gl->expires=0;
+  gl->lastmod=0;
+  gl->lifetime=0;
+
+  gl->flags=0;
+
+  return gl;
+}
+
+void removeglinefromlists( gline *gl) {
+  gline *gl2;
+
+  if (gl->flags & GLINE_IPMASK) {
+    if ( gl == gl->node->exts[gl_nodeext]) {
+      gl->node->exts[gl_nodeext] = gl->nextbynode;
+    } else {
+      gl2 = gl->node->exts[gl_nodeext];
+      while (gl2) {
+        if ( gl2->nextbynode == gl) {
+          gl2->nextbynode = gl->nextbynode; 
+          break;
+        }
+        gl2 = gl2->nextbynode;
+      }
+    }
+  } else {
+    if ( gl == glinelistnonnode) {
+      glinelistnonnode = gl->nextbynonnode;
+    } else {
+      gl2 = glinelistnonnode;
+      while (gl2) {
+        if ( gl2->nextbynonnode == gl) {
+          gl2->nextbynonnode = gl->nextbynonnode;
+          break;
+        }
+        gl2 = gl2->nextbynonnode;
+      }
+    }
+  }
+
+  if ( gl == glinelist) {
+    glinelist = gl->next;
+  } else {
+    gl2 = glinelist;
+    while (gl2) {
+      if ( gl2->next == gl) {
+        gl2->next = gl->next;
+        break;
+      }
+      gl2 = gl2->next;
+    }
+  }
+}
+
+void freegline (gline *gl) {
+  gl->next=(gline *)gline_freelist;
+
+  if (gl->nick)
+    freesstring(gl->nick);
+  if (gl->user)
+    freesstring(gl->user);
+  if (gl->host)
+    freesstring(gl->host);
+  if (gl->reason)
+    freesstring(gl->reason);
+  if (gl->creator)
+    freesstring(gl->creator);
+
+  if (gl->node) { 
+    derefnode(iptree, gl->node);
+  }
+  gline_freelist=gl;
+}
+
+void removegline( gline *gl) { 
+  removeglinefromlists(gl);
+  freegline(gl);
+}
diff --git a/gline/gline_commands.c b/gline/gline_commands.c
new file mode 100644 (file)
index 0000000..ac35407
--- /dev/null
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "../control/control.h"
+#include "../nick/nick.h"
+#include "../localuser/localuserchannel.h"
+#include "../core/hooks.h"
+#include "../server/server.h"
+#include "../parser/parser.h"
+#include "../core/schedule.h"
+#include "../lib/array.h"
+#include "../lib/base64.h"
+#include "../lib/irc_string.h"
+#include "../lib/splitline.h"
+
+#include "gline.h"
+
+void _init() {
+  registercontrolhelpcmd("glstats",NO_OPER,0,&gline_glstats,"Usage: glstats.");
+}
+
+void _fini() {
+  deregistercontrolcmd("glstats", gline_glstats);
+}
+
+int gline_glstats(void* source, int cargc, char** cargv) {
+  nick* sender = (nick*)source;
+  gline* g;
+  gline* sg;
+  time_t curtime = time(0);
+  int glinecount = 0, hostglinecount = 0, ipglinecount = 0, badchancount = 0, rnglinecount = 0;
+  int deactivecount =0, activecount = 0;
+
+  for (g = glinelist; g; g = sg) {
+    sg = g->next;
+
+    if (g->lifetime <= curtime)
+      continue;
+    if (g->flags & GLINE_ACTIVE) {
+      activecount++;
+    } else {
+      deactivecount++;
+    }
+
+    if(g->flags & GLINE_IPMASK)
+      ipglinecount++;
+    else if (g->flags & (GLINE_HOSTMASK | GLINE_HOSTEXACT))
+      hostglinecount++;
+    else if (g->flags & GLINE_REALNAME)
+      rnglinecount++;
+    else if (g->flags & GLINE_BADCHAN)
+      badchancount++;
+    glinecount++;
+  }
+
+  controlreply(sender, "Total G-Lines set: %d", glinecount);
+  controlreply(sender, "Hostmask G-Lines:  %d", hostglinecount);
+  controlreply(sender, "IPMask G-Lines:    %d", ipglinecount);
+  controlreply(sender, "Channel G-Lines:   %d", badchancount);
+  controlreply(sender, "Realname G-Lines:  %d", rnglinecount);
+
+  controlreply(sender, "Active G-Lines:    %d", activecount);
+  controlreply(sender, "De-Active G-Lines: %d", deactivecount);
+
+  /* TODO show top 10 creators here */
+  /* TODO show unique creators count */
+  /* TODO show glines per create %8.1f", ccount?((float)gcount/(float)ccount):0 */
+  return CMD_OK;
+}
+
diff --git a/gline/gline_handler.c b/gline/gline_handler.c
new file mode 100644 (file)
index 0000000..f73e516
--- /dev/null
@@ -0,0 +1,222 @@
+#include <string.h>
+
+#include "../control/control.h"
+#include "../nick/nick.h"
+#include "../localuser/localuserchannel.h"
+#include "../core/hooks.h"
+#include "../server/server.h"
+#include "../parser/parser.h"
+#include "../core/schedule.h"
+#include "../lib/array.h"
+#include "../lib/base64.h"
+#include "../lib/irc_string.h"
+#include "../lib/splitline.h"
+#include "gline.h"
+
+/*
+  <prefix> GL <target> [!][+|-|>|<]<mask> [<expiration>] [<lastmod>]
+        [<lifetime>] [:<reason>]
+*/
+
+int handleglinemsg(void* source, int cargc, char** cargv) {
+  char* sender = (char*)source;
+  char* target;
+  char* mask;
+  char* reason;
+  sstring *creator;
+  time_t lifetime = 0, expires = 0, lastmod = 0;
+  unsigned int flags = 0;
+  int numlen; 
+  long creatornum;
+  gline *agline;
+
+  nick* np;
+
+  int i;
+  for (i = 0; i <cargc; i++) {
+    Error("debuggline", ERR_WARNING, "Token %d is - %s", i, cargv[i]);
+  }
+
+  /* valid GL tokens have X params */
+  switch ( cargc ) {
+    case 5:
+      /* 1.3.x GL Token */
+      break;
+    case 6:
+      /* 1.4.0 and above GL token */
+      break;
+    default: 
+      Error("gline", ERR_WARNING, "Invalid number of arguments in GL token (%d)", cargc);
+      return CMD_ERROR;
+  }
+
+  /* gline creator can be either a nick or a server */
+  numlen = strlen(source);
+  switch (numlen) {
+    case 2:
+      creatornum = numerictolong(sender, 2);
+      if (creatornum < 0) {
+        Error("gline", ERR_WARNING, "Failed to resolve numeric to server (%s) when adding G-Line!", sender);
+        creator = getsstring("unknown", HOSTLEN);
+      } else 
+        creator = getsstring(serverlist[(int)creatornum].name->content, HOSTLEN);
+      break;
+    case 5:
+      creatornum = numerictolong(sender, 5);
+      if (!(np = getnickbynumeric(creatornum))) {
+        Error("gline", ERR_WARNING, "Failed to resolve numeric to nick when adding G-Line!", sender);
+        creator = getsstring("unknown", HOSTLEN);
+      } else
+        creator = getsstring( np->nick, NICKLEN);
+      break;
+    default:
+      Error("gline", ERR_WARNING, "Invalid numeric '%s' in G-Line message.", sender);
+  }
+
+  /* 1st param is target */
+  target = cargv[0];
+
+  /* 2nd param is mask */
+  mask = cargv[1];
+
+  if (*mask == '!') {
+    Error("gline", ERR_DEBUG, " forced flag ");
+    mask++;
+  }
+
+  switch (*mask) {
+    case '+':
+      flags |= GLINE_ACTIVATE;
+      mask++;
+      break;
+    case '-':
+      flags |= GLINE_DEACTIVATE;
+      mask++;
+      break;
+    case '>':
+    case '<':
+      Error("gline", ERR_WARNING, "Received local modification from %s.", sender);
+      return CMD_ERROR;
+  } 
+
+  /* anything other than a global G-Line is irrelevant */
+  if (strcmp(target, "*")) {
+    Error("gline", ERR_WARNING, "Received local g-line from %s - do they realise we're a service?", sender);
+    return CMD_ERROR;
+  }
+
+  if (flags & GLINE_ACTIVATE) {
+    /* activate gline */
+    expires = abs_expire(atoi(cargv[2]));
+    switch (cargc) {
+      case 4:
+        /* asuka U:d, no lastmod */
+        reason = cargv[3];
+        break;
+      case 5:
+        /*asuka lastmod */
+        lastmod = atoi(cargv[3]);
+        lifetime = gline_max(lastmod,expires); /* set lifetime = lastmod */ 
+        reason = cargv[4];
+        break;
+      case 6:
+        /* snircd */
+        lastmod = atoi(cargv[3]);
+        lifetime = atoi(cargv[4]); 
+        reason = cargv[5];
+        break;
+      default:
+         Error("gline", ERR_WARNING, "Gline Activate with invalid number (%d) of arguments", cargc);
+         return CMD_ERROR;
+    }
+
+    Error("debuggline", ERR_WARNING, "GL Received: Creator %s, Mask %s, Reason %s, Expire %lu, Lastmod %lu, Lifetime %lu", creator->content, mask, reason, expires, lastmod, lifetime);   
+    if ( (agline=gline_find(mask)) ) {
+      if (agline->flags & GLINE_ACTIVE ) { 
+        Error("debuggline", ERR_WARNING, "Duplicate Gline recieved for %s - old lastmod %lu, expire %lu, lifetime %lu, reason %s, creator %s", mask, agline->lastmod, agline->expires, agline->lifetime, agline->reason->content, agline->creator->content  );
+      } else {
+        /* we're reactivating a gline - check lastmod then assume the new gline is authoritive */
+        if ( lastmod > agline->lastmod ) {
+          agline->lastmod = lastmod;
+          agline->expires = expires;
+          agline->lifetime = lifetime;
+          agline->creator = creator;
+          freesstring(agline->reason);
+          agline->reason = getsstring(reason, 255); 
+          agline->flags |= GLINE_ACTIVE;
+        } else {
+          Error("debuggline", ERR_WARNING, "received a gline with a lower lastmod");
+          /* @@@TODO resend our gline ? */
+        } 
+      }
+      /* TODO */
+      return CMD_ERROR;
+    } else {
+      gline_add( creatornum, creator, mask, reason, expires, lastmod, lifetime); 
+    } 
+  } else if (flags & GLINE_DEACTIVATE) {
+    /* deactivate gline */
+    if ((agline = gline_find(mask))) {
+      switch (cargc) {
+        case 2:
+          /* asuka U:d, no last mod */
+          removegline(agline);
+          break;
+        case 5:
+          /* asuka last mod */
+          lastmod = atoi(cargv[3]);
+          gline_deactivate(agline, lastmod, 0);
+          break;
+        case 6:
+          /* snircd */
+          lastmod = atoi(cargv[3]);
+          gline_deactivate(agline, lastmod, 0);
+          break;
+        default:
+          Error("gline", ERR_WARNING, "Gline Deactivate with invalid number (%d) of arguments", cargc);
+          return CMD_ERROR;
+      }
+      return CMD_OK;
+    } else {
+       Error("gline", ERR_WARNING, "Gline addition - adding deactivated gline - mask not found (%s)", mask);
+       expires = abs_expire(atoi(cargv[2]));
+       switch (cargc) {
+         case 4:
+           /* asuka U:d, no lastmod */
+           reason = cargv[3];
+           break;
+         case 5:
+           /*asuka lastmod */
+           lastmod = atoi(cargv[3]);
+           lifetime = gline_max(lastmod,expires); /* set lifetime = lastmod */
+           reason = cargv[4];
+           break;
+         case 6:
+           /* snircd */
+           lastmod = atoi(cargv[3]);
+           lifetime = atoi(cargv[4]);
+           reason = cargv[5];
+           break;
+         default:
+           Error("gline", ERR_WARNING, "Gline DeActivate with invalid number (%d) of arguments", cargc);
+           return CMD_ERROR;
+      }
+
+      agline = gline_add( creatornum, creator, mask, reason, expires, lastmod, lifetime);
+      gline_deactivate(agline, lastmod, 0);       
+      return CMD_ERROR;
+    }
+  } else {
+    /* modification - only snircd 1.4.x */
+    Error("gline", ERR_WARNING, "Not Implemented");
+  }
+
+  Error("debuggline", ERR_WARNING, "Creator %s", creator->content);
+  return CMD_OK;
+}
+
+
+int gline_deactivate(gline *agline, time_t lastmod, int propagate) {
+  agline->flags &= ~GLINE_ACTIVE;
+  agline->lastmod = lastmod;
+}
diff --git a/gline/gline_hash.c b/gline/gline_hash.c
new file mode 100644 (file)
index 0000000..8197a6b
--- /dev/null
@@ -0,0 +1,3 @@
+#include "gline.h"
+
+//gline *glinetable[