]> jfr.im git - irc/quakenet/newserv.git/blobdiff - trojanscan/trojanscan.c
Add malloc checking to lua/nterfacer/trojanscan.
[irc/quakenet/newserv.git] / trojanscan / trojanscan.c
index 582efa6627b23965ee81e7a35c70af68bc260df2..960594b5937ccdf0fd3081113097567a8160a215 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Trojanscan version 2
  *
- * Trojanscan  copyright (C) Chris Porter 2002-2005
+ * Trojanscan  copyright (C) Chris Porter 2002-2007
  * Newserv bits copyright (C) David Mansell 2002-2003
  * 
  * TODO: CHECK::
 #include "trojanscan.h"
 #include "../lib/strlfunc.h"
 #include "../lib/version.h"
+#include "../core/nsmalloc.h"
 
-MODULE_VERSION(TROJANSCAN_VERSION " / $Id: trojanscan.c 741 2007-02-04 16:35:22Z newserv $")
+#define tmalloc(x)     nsmalloc(POOL_TROJANSCAN, x)
+#define tfree(x)       nsfree(POOL_TROJANSCAN, x)
+
+MODULE_VERSION(TROJANSCAN_VERSION);
+
+void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf);
+char *trojanscan_sanitise(char *input);
+void trojanscan_refresh_settings(void);
+static void trojanscan_part_watch(int hook, void *arg);
+static void trojanscan_connect_nick(void *);
+
+#define TROJANSCAN_SETTING_SIZE 256
+#define TROJANSCAN_MAX_SETTINGS 50
+
+static struct {
+  char setting[TROJANSCAN_SETTING_SIZE];
+  char value[TROJANSCAN_SETTING_SIZE];
+} trojanscan_settings[TROJANSCAN_MAX_SETTINGS];
+
+static int settingcount = 0;
+static char *versionreply;
+static int hooksregistered = 0;
+static void *trojanscan_connect_nick_schedule;
 
 void _init() {
   trojanscan_cmds = newcommandtree();
@@ -56,6 +79,9 @@ void _fini(void) {
   if (trojanscan_connect_schedule)
     deleteschedule(trojanscan_connect_schedule, &trojanscan_connect, NULL);
     
+  if (trojanscan_connect_nick_schedule)
+    deleteschedule(trojanscan_connect_nick_schedule, &trojanscan_connect_nick, NULL);
+    
   if(trojanscan_schedule)
     deleteschedule(trojanscan_schedule, &trojanscan_dojoin, NULL);
 
@@ -65,11 +91,14 @@ void _fini(void) {
   if(trojanscan_cloneschedule)
     deleteschedule(trojanscan_poolschedule, &trojanscan_registerclones, NULL);
   
+  if(hooksregistered)
+    deregisterhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
+
   while(rp) {
     deleteschedule(rp->schedule, &trojanscan_dopart, (void *)rp);
     oldrp = rp;
     rp = rp->next;
-    free(oldrp);
+    tfree(oldrp);
   }
   
   while(rj) {
@@ -77,7 +106,7 @@ void _fini(void) {
     freesstring(rj->channel);
     oldrj = rj;
     rj = rj->next;
-    free(oldrj);
+    tfree(oldrj);
   }
 
   if(trojanscan_initialschedule)
@@ -88,6 +117,7 @@ void _fini(void) {
   for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++)
     if(trojanscan_swarm[i].clone) {
       deregisterlocaluser(trojanscan_swarm[i].clone, NULL);
+      derefnode(iptree, trojanscan_swarm[i].fakeipnode);
       trojanscan_swarm[i].clone = NULL;
     }
   trojanscan_free_database();
@@ -99,12 +129,59 @@ void _fini(void) {
   for (i=0;i<trojanscan_tailpoolsize;i++)
     freesstring(trojanscan_tailpool[i]);
   trojanscan_database_close();
+
+  nscheckfreeall(POOL_TROJANSCAN);
 }
 
-void trojanscan_connect(void *arg) {
+static void trojanscan_connect_nick(void *arg) {
   sstring *mnick, *myident, *myhost, *myrealname, *myauthname;
-  sstring *dbhost, *dbuser, *dbpass, *db, *dbport, *temp;
   channel *cp;
+
+  mnick = getcopyconfigitem("trojanscan", "nick", "T", NICKLEN);
+  myident = getcopyconfigitem("trojanscan", "ident", "trojanscan", NICKLEN);
+  myhost = getcopyconfigitem("trojanscan", "hostname", "trojanscan.slug.netsplit.net", HOSTLEN);
+  myrealname = getcopyconfigitem("trojanscan", "realname", "Trojanscan v" TROJANSCAN_VERSION, REALLEN);
+  myauthname = getcopyconfigitem("trojanscan", "authname", "T", ACCOUNTLEN);
+
+  trojanscan_nick = registerlocaluser(mnick->content, myident->content, myhost->content, myrealname->content, myauthname->content, UMODE_SERVICE | UMODE_DEAF |
+                                                                                                                          UMODE_OPER | UMODE_INV |
+                                                                                                                          UMODE_ACCOUNT,
+                                                                                                                          &trojanscan_handlemessages);                                                                                                                            
+  freesstring(mnick);
+  freesstring(myident);
+  freesstring(myhost);
+  freesstring(myrealname);
+  freesstring(myauthname);
+
+  cp = findchannel(TROJANSCAN_OPERCHANNEL);
+  if (!cp) {
+    localcreatechannel(trojanscan_nick, TROJANSCAN_OPERCHANNEL);
+  } else {
+    if(!localjoinchannel(trojanscan_nick, cp))
+      localgetops(trojanscan_nick, cp);
+  }
+
+  cp = findchannel(TROJANSCAN_CHANNEL);
+  if (!cp) {
+    localcreatechannel(trojanscan_nick, TROJANSCAN_CHANNEL);
+  } else {
+    if(!localjoinchannel(trojanscan_nick, cp))
+      localgetops(trojanscan_nick, cp);
+  }
+
+#ifdef TROJANSCAN_PEONCHANNEL
+  cp = findchannel(TROJANSCAN_PEONCHANNEL);
+  if (!cp) {
+    localcreatechannel(trojanscan_nick, TROJANSCAN_PEONCHANNEL);
+  } else {
+    if(!localjoinchannel(trojanscan_nick, cp))
+      localgetops(trojanscan_nick, cp);
+  }
+#endif
+}
+
+void trojanscan_connect(void *arg) {
+  sstring *dbhost, *dbuser, *dbpass, *db, *dbport, *temp;
   int length, i;
   char buf[10];
   
@@ -122,12 +199,6 @@ void trojanscan_connect(void *arg) {
   trojanscan_database.glines = 0;
   trojanscan_database.detections = 0;
     
-  mnick = getcopyconfigitem("trojanscan", "nick", "T", NICKLEN);
-  myident = getcopyconfigitem("trojanscan", "ident", "trojanscan", NICKLEN);
-  myhost = getcopyconfigitem("trojanscan", "hostname", "trojanscan.slug.netsplit.net", HOSTLEN);
-  myrealname = getcopyconfigitem("trojanscan", "realname", "Trojanscan v" TROJANSCAN_VERSION, REALLEN);
-  myauthname = getcopyconfigitem("trojanscan", "authname", "T", ACCOUNTLEN);
-
   dbhost = getcopyconfigitem("trojanscan", "dbhost", "localhost", HOSTLEN);
   dbuser = getcopyconfigitem("trojanscan", "dbuser", "", NICKLEN);
   dbpass = getcopyconfigitem("trojanscan", "dbpass", "", REALLEN);
@@ -172,10 +243,7 @@ void trojanscan_connect(void *arg) {
   trojanscan_minchansize = atoi(temp->content);
   freesstring(temp);
 
-  trojanscan_nick = registerlocaluser(mnick->content, myident->content, myhost->content, myrealname->content, myauthname->content, UMODE_SERVICE | UMODE_DEAF |
-                                                                                                                          UMODE_OPER | UMODE_INV |
-                                                                                                                          UMODE_ACCOUNT,
-                                                                                                                          &trojanscan_handlemessages);                                                                                                                            
+  trojanscan_connect_nick(NULL);
 
   if (trojanscan_database_connect(dbhost->content, dbuser->content, dbpass->content, db->content, atoi(dbport->content)) < 0) {
     Error("trojanscan", ERR_FATAL, "Cannot connect to database host!");
@@ -188,47 +256,20 @@ void trojanscan_connect(void *arg) {
   trojanscan_database_query("CREATE TABLE channels (id INT(10) PRIMARY KEY AUTO_INCREMENT, channel VARCHAR(%d) NOT NULL, exempt BOOL DEFAULT 0)", CHANNELLEN);
   trojanscan_database_query("CREATE TABLE users (id INT(10) PRIMARY KEY AUTO_INCREMENT, authname VARCHAR(%d) NOT NULL, authlevel TINYINT(4) NOT NULL)", ACCOUNTLEN);
   trojanscan_database_query("CREATE TABLE hits (id INT(10) PRIMARY KEY AUTO_INCREMENT, nickname VARCHAR(%d) NOT NULL, ident VARCHAR(%d) NOT NULL, host VARCHAR(%d) NOT NULL, phrase INT(10) NOT NULL, ts TIMESTAMP, messagetype VARCHAR(1) NOT NULL DEFAULT 'm', glined BOOL DEFAULT 1)", NICKLEN, USERLEN, HOSTLEN);
-  trojanscan_database_query("CREATE TABLE settings (id INT(10) PRIMARY KEY AUTO_INCREMENT, setting VARCHAR(15) NOT NULL, value VARCHAR(15) NOT NULL)");
+  trojanscan_database_query("CREATE TABLE settings (id INT(10) PRIMARY KEY AUTO_INCREMENT, setting VARCHAR(255) NOT NULL UNIQUE, value VARCHAR(255) NOT NULL)");
   trojanscan_database_query("CREATE TABLE wwwlogs (id INT(10) PRIMARY KEY AUTO_INCREMENT, authid INT(10) NOT NULL, ip VARCHAR(15), action TEXT, ts TIMESTAMP)");
   trojanscan_database_query("CREATE TABLE unknownlog (id INT(10) PRIMARY KEY AUTO_INCREMENT, data TEXT, user VARCHAR(%d) NOT NULL, ts TIMESTAMP)", NICKLEN+USERLEN+HOSTLEN+3);
   
-  trojanscan_database_query("DELETE FROM settings");
+  trojanscan_database_query("DELETE FROM settings WHERE setting = 'rehash' OR setting = 'changed'");
   trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('rehash','0')");
   trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('changed','0')");
+
+  /* assumption: constants aren't supplied by someone evil */
+  trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('versionreply','" TROJANSCAN_DEFAULT_VERSION_REPLY "')");
   
+  trojanscan_refresh_settings();
   trojanscan_read_database(1);
  
-  cp = findchannel(TROJANSCAN_OPERCHANNEL);
-  if (!cp) {
-    localcreatechannel(trojanscan_nick, TROJANSCAN_OPERCHANNEL);
-  } else {
-    if(!localjoinchannel(trojanscan_nick, cp))
-      localgetops(trojanscan_nick, cp);
-  }
-
-  cp = findchannel(TROJANSCAN_CHANNEL);
-  if (!cp) {
-    localcreatechannel(trojanscan_nick, TROJANSCAN_CHANNEL);
-  } else {
-    if(!localjoinchannel(trojanscan_nick, cp))
-      localgetops(trojanscan_nick, cp);
-  }
-
-#ifdef TROJANSCAN_PEONCHANNEL
-  cp = findchannel(TROJANSCAN_PEONCHANNEL);
-  if (!cp) {
-    localcreatechannel(trojanscan_nick, TROJANSCAN_PEONCHANNEL);
-  } else {
-    if(!localjoinchannel(trojanscan_nick, cp))
-      localgetops(trojanscan_nick, cp);
-  }
-#endif
-
-  freesstring(mnick);
-  freesstring(myident);
-  freesstring(myhost);
-  freesstring(myrealname);
-  freesstring(myauthname);
   freesstring(dbhost);
   freesstring(dbuser);
   freesstring(dbpass);
@@ -238,47 +279,96 @@ void trojanscan_connect(void *arg) {
   
   trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
 
+  registerhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
+  hooksregistered = 1;
+}
+
+char *trojanscan_get_setting(char *setting) {
+  int i;
+
+  for(i=0;i<settingcount;i++)
+    if(!strcmp(trojanscan_settings[i].setting, setting))
+      return trojanscan_settings[i].value;
+
+  return NULL;
+}
+
+void trojanscan_refresh_settings(void) {
+  trojanscan_database_res *res;
+  trojanscan_database_row sqlrow;
+  int i = 0;
+
+  if(trojanscan_database_query("SELECT setting, value FROM settings"))
+    return;
+
+  if(!(res = trojanscan_database_store_result(&trojanscan_sql)))
+    return;
+
+  if (trojanscan_database_num_rows(res) <= 0)
+    return;
+
+  while((sqlrow = trojanscan_database_fetch_row(res))) {
+    strlcpy(trojanscan_settings[i].setting, sqlrow[0], TROJANSCAN_SETTING_SIZE);
+    strlcpy(trojanscan_settings[i].value, sqlrow[1], TROJANSCAN_SETTING_SIZE);
+
+    trojanscan_sanitise(trojanscan_settings[i].value);
+
+    if(++i == TROJANSCAN_MAX_SETTINGS)
+      break;
+  }
+
+  settingcount = i;
+
+  trojanscan_database_free_result(res);
+
+  /* optimisation hack */
+  versionreply = trojanscan_get_setting("versionreply");
 }
 
 void trojanscan_rehash_schedule(void *arg) {
+  char *v;
   trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
-  if (!(trojanscan_database_query("SELECT value FROM settings WHERE setting = 'rehash'"))) {
-    trojanscan_database_res *res;
-    if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
-      if (trojanscan_database_num_rows(res) > 0) {
-        trojanscan_database_row sqlrow = trojanscan_database_fetch_row(res);
-        if (sqlrow && (sqlrow[0][0] == '1')) {
-          trojanscan_mainchanmsg("n: rehash initiated by website. . .");
-          trojanscan_read_database(0);
-        }
-      }
-      trojanscan_database_free_result(res);
-    }
-  } 
-    
+
+  trojanscan_refresh_settings();
+
+  v = trojanscan_get_setting("rehash");
+  if(v && v[0] == '1') {
+    trojanscan_mainchanmsg("n: rehash initiated by website. . .");
+    trojanscan_read_database(0);
+  }
 }
 
 void trojanscan_free_database(void) {
   int i;
   for(i=0;i<trojanscan_database.total_channels;i++)
     freesstring(trojanscan_database.channels[i].name);
-  free(trojanscan_database.channels);
+  tfree(trojanscan_database.channels);
   for(i=0;i<trojanscan_database.total_phrases;i++) {
     if (trojanscan_database.phrases[i].phrase)
       pcre_free(trojanscan_database.phrases[i].phrase);
     if (trojanscan_database.phrases[i].hint)
       pcre_free(trojanscan_database.phrases[i].hint);
   }
-  free(trojanscan_database.phrases);
+  tfree(trojanscan_database.phrases);
   for(i=0;i<trojanscan_database.total_worms;i++)
     freesstring(trojanscan_database.worms[i].name);
-  free(trojanscan_database.worms);
+  tfree(trojanscan_database.worms);
   trojanscan_database.total_channels = 0;
   trojanscan_database.total_phrases = 0;
   trojanscan_database.total_worms = 0;
   
 }
 
+char *trojanscan_sanitise(char *input) {
+  char *p;
+
+  for(p=input;*p;p++)
+    if(*p == '\r' || *p == '\n')
+      *p = '!';
+
+  return input;
+}
+
 sstring *trojanscan_getsstring(char *string, int length) {
   int i;
   
@@ -388,11 +478,11 @@ void trojanscan_read_database(int first_time) {
     if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
       trojanscan_database.total_channels = trojanscan_database_num_rows(res);
       if (trojanscan_database.total_channels > 0) {
-        if ((trojanscan_database.channels = (trojanscan_channels *)malloc(sizeof(trojanscan_channels) * trojanscan_database.total_channels))) {
+        if ((trojanscan_database.channels = (trojanscan_channels *)tmalloc(sizeof(trojanscan_channels) * trojanscan_database.total_channels))) {
           if ((trojanscan_database.total_channels>0) && trojanscan_database.channels) {
             i = 0;
             while((sqlrow = trojanscan_database_fetch_row(res))) {
-              trojanscan_database.channels[i].name = trojanscan_getsstring(sqlrow[0], strlen(sqlrow[0]));
+              trojanscan_database.channels[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[0]), strlen(sqlrow[0]));
               trojanscan_database.channels[i].exempt = (sqlrow[1][0] == '1');
               i++;
             }
@@ -407,11 +497,11 @@ void trojanscan_read_database(int first_time) {
     if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
       trojanscan_database.total_worms = trojanscan_database_num_rows(res);
       if (trojanscan_database.total_worms > 0) {
-        if ((trojanscan_database.worms = (trojanscan_worms *)malloc(sizeof(trojanscan_worms) * trojanscan_database.total_worms))) {
+        if ((trojanscan_database.worms = (trojanscan_worms *)tmalloc(sizeof(trojanscan_worms) * trojanscan_database.total_worms))) {
           i = 0;
           while((sqlrow = trojanscan_database_fetch_row(res))) {
             trojanscan_database.worms[i].id = atoi(sqlrow[0]);
-            trojanscan_database.worms[i].name = trojanscan_getsstring(sqlrow[1], strlen(sqlrow[1]));
+            trojanscan_database.worms[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[1]), strlen(sqlrow[1]));
             tempresult = atoi(sqlrow[2]);
             trojanscan_database.worms[i].glineuser = (tempresult == 0);
             trojanscan_database.worms[i].glinehost = (tempresult == 1);
@@ -438,7 +528,7 @@ void trojanscan_read_database(int first_time) {
     if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
       trojanscan_database.total_phrases = trojanscan_database_num_rows(res);
       if (trojanscan_database.total_phrases > 0) {
-        if ((trojanscan_database.phrases = (trojanscan_phrases *)malloc(sizeof(trojanscan_phrases) * trojanscan_database.total_phrases))) {
+        if ((trojanscan_database.phrases = (trojanscan_phrases *)tmalloc(sizeof(trojanscan_phrases) * trojanscan_database.total_phrases))) {
           i = 0;
           while((sqlrow = trojanscan_database_fetch_row(res))) {
             trojanscan_database.phrases[i].id = atoi(sqlrow[0]);
@@ -462,7 +552,6 @@ void trojanscan_read_database(int first_time) {
   }
 
   trojanscan_database_query("UPDATE settings SET value = '0' where setting = 'rehash'");
-  
 }
 
 void trojanscan_log(nick *np, char *event, char *details, ...) {
@@ -486,9 +575,9 @@ void trojanscan_log(nick *np, char *event, char *details, ...) {
 void trojanscan_generateclone(void *arg) {
   int i, loops = 0, modes = UMODE_XOPER | UMODE_INV;
   char c_nick[NICKLEN+1], c_ident[USERLEN+1], c_host[HOSTLEN+1], c_real[REALLEN+1];
-  long fakeip;
+  patricia_node_t *fakeip;
 
-  i = (int)arg;
+  i = (int)((long)arg);
 
   /* PPA: unlikely to be infinite */
   do {
@@ -517,7 +606,7 @@ void trojanscan_generateclone(void *arg) {
     trojanscan_genreal(c_real, trojanscan_minmaxrand(15, TROJANSCAN_MMIN(50, REALLEN)));
 
   trojanscan_swarm[i].clone = registerlocaluser(c_nick, c_ident, c_host, c_real, NULL, modes, &trojanscan_clonehandlemessages);
-  trojanscan_swarm[i].fakeip = fakeip;
+  trojanscan_swarm[i].fakeipnode = fakeip;
 
   if(trojanscan_swarm[i].clone && !trojanscan_swarm_created) {
     nick *np = trojanscan_selectuser();
@@ -535,7 +624,7 @@ void trojanscan_free_channels(void) {
   if(trojanscan_chans) {
     for(i=0;i<trojanscan_activechans;i++) 
       freesstring(trojanscan_chans[i].channel);
-    free(trojanscan_chans);
+    tfree(trojanscan_chans);
     trojanscan_chans = NULL;
     trojanscan_activechans = 0;
   }
@@ -565,11 +654,11 @@ void trojanscan_registerclones(void *arg) {
   }
   
   for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++)
-    trojanscan_generateclone((void *)i);
+    trojanscan_generateclone((void *)((long)i));
   trojanscan_mainchanmsg("n: swarm (%d clones) created.", TROJANSCAN_CLONE_TOTAL);
   trojanscan_swarm_created = 1;
 
-  trojanscan_initialschedule = scheduleoneshot(time(NULL) + 5, &trojanscan_fill_channels, NULL);
+  trojanscan_initialschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_fill_channels, NULL);
 }
 
 int trojanscan_status(void *sender, int cargc, char **cargv) {
@@ -971,9 +1060,10 @@ struct trojanscan_clones *trojanscan_selectclone(char type) {
       if ((!rc->remaining) && (!rc->sitting)) {
         if (rc->clone) {
           deregisterlocaluser(rc->clone, NULL);
+          derefnode(iptree, rc->fakeipnode);
           rc->clone = NULL;
         }
-        trojanscan_generateclone((void *)rc->index);
+        trojanscan_generateclone((void *)((long)rc->index));
       }
     }
   }
@@ -985,13 +1075,13 @@ struct trojanscan_clones *trojanscan_selectclone(char type) {
 /* hack hack hack */
 int trojanscan_nickbanned(trojanscan_clones *np, channel *cp) {
   int ret;
-  long realip = np->clone->ipaddress;
+  patricia_node_t *realipnode = np->clone->ipnode;
 
-  np->clone->ipaddress = np->fakeip;
+  np->clone->ipnode = np->fakeipnode;
 
   ret = nickbanned(np->clone, cp);
 
-  np->clone->ipaddress = realip;
+  np->clone->ipnode = realipnode;
 
   return ret;
 }
@@ -1045,7 +1135,7 @@ struct trojanscan_realchannels *trojanscan_allocaterc(char *chan) {
     return NULL;
   }
 
-  rc = (struct trojanscan_realchannels *)malloc(sizeof(struct trojanscan_realchannels));
+  rc = (struct trojanscan_realchannels *)tmalloc(sizeof(struct trojanscan_realchannels));
 
   rc->next = NULL;
   rc->clone = clonep;
@@ -1110,6 +1200,7 @@ int trojanscan_userjoin(void *sender, int cargc, char **cargv) {
 
 int trojanscan_rehash(void *sender, int cargc, char **cargv) {
   nick *np = (void *)sender;
+  trojanscan_refresh_settings();
   trojanscan_read_database(0);
   trojanscan_log(np, "rehash", "");
   trojanscan_reply(np, "Done.");
@@ -1299,7 +1390,7 @@ int trojanscan_add_ll(struct trojanscan_prechannels **head, struct trojanscan_pr
   
   for(position=*head;position;lastitem=position,position=position->next) {
     if (!ircd_strcmp(position->name->content, newitem->name->content)) {
-      free(newitem);
+      tfree(newitem);
       return 0;
     }
     if (!location && (position->size < newitem->size)) {
@@ -1330,9 +1421,10 @@ void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count)
   struct trojanscan_templist *markedlist = NULL;
 
   if(count > 0) {
-    markedlist = (struct trojanscan_templist *)calloc(count, sizeof(struct trojanscan_templist));
+    markedlist = (struct trojanscan_templist *)tmalloc(count * sizeof(struct trojanscan_templist));
     if (!markedlist)
       return;
+    memset(markedlist, 0, sizeof(struct trojanscan_templist) * count);
   }
   
   for(i=0;i<trojanscan_activechans;i++) {
@@ -1353,7 +1445,7 @@ void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count)
     if(!marked && trojanscan_chans[i].watch_clone) {
       channel *cp = findchannel(trojanscan_chans[i].channel->content);
       if(cp)
-        localpartchannel(trojanscan_chans[i].watch_clone->clone, cp);
+        localpartchannel(trojanscan_chans[i].watch_clone->clone, cp, NULL);
     }
   }
   
@@ -1382,7 +1474,7 @@ void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count)
     }
   }
   
-  free(markedlist);
+  tfree(markedlist);
 }
 
 void trojanscan_fill_channels(void *arg) {
@@ -1392,7 +1484,7 @@ void trojanscan_fill_channels(void *arg) {
   chanindex *chn;
   
   for (count=i=0;i<trojanscan_database.total_channels;i++) {
-    lp = (trojanscan_prechannels *)malloc(sizeof(trojanscan_prechannels));
+    lp = (trojanscan_prechannels *)tmalloc(sizeof(trojanscan_prechannels));
     lp->name = trojanscan_database.channels[i].name;
     lp->size = 65535;
     lp->exempt = trojanscan_database.channels[i].exempt;
@@ -1404,7 +1496,7 @@ void trojanscan_fill_channels(void *arg) {
   for (i=0;i<CHANNELHASHSIZE;i++) {
     for(chn=chantable[i];chn;chn=chn->next) {
       if (chn->channel && !IsKey(chn->channel) && !IsInviteOnly(chn->channel) && !IsRegOnly(chn->channel) && (chn->channel->users->totalusers >= trojanscan_minchansize)) {
-        lp = (trojanscan_prechannels *)malloc(sizeof(trojanscan_prechannels));
+        lp = (trojanscan_prechannels *)tmalloc(sizeof(trojanscan_prechannels));
         lp->name = chn->name;
         lp->size = chn->channel->users->totalusers;
         lp->exempt = 0;
@@ -1420,7 +1512,8 @@ void trojanscan_fill_channels(void *arg) {
   trojanscan_watch_clone_update(head, count);
   
   trojanscan_free_channels();
-  trojanscan_chans = (struct trojanscan_inchannel *)calloc(count, sizeof(struct trojanscan_inchannel));
+  trojanscan_chans = (struct trojanscan_inchannel *)tmalloc(count * sizeof(struct trojanscan_inchannel));
+  memset(trojanscan_chans, 0, count * sizeof(struct trojanscan_inchannel));
   trojanscan_activechans = count;
   i = 0;
     
@@ -1430,11 +1523,11 @@ void trojanscan_fill_channels(void *arg) {
       trojanscan_chans[i++].watch_clone = lp->watch_clone;
     }
     if (last)
-      free(last);
+      tfree(last);
   }
 
   if (last)
-    free(last);
+    tfree(last);
 
   if (trojanscan_activechans > 0) {
     tempctime = trojanscan_cycletime / trojanscan_activechans;
@@ -1473,7 +1566,7 @@ void trojanscan_dopart(void *arg) {
   }
   
   if (rc->clone->clone && (!(rc->donotpart)))
-    localpartchannel(rc->clone->clone, rc->chan);
+    localpartchannel(rc->clone->clone, rc->chan, NULL);
 
   rc->clone->sitting--;
 
@@ -1484,7 +1577,7 @@ void trojanscan_dopart(void *arg) {
       } else {
         past->next = rp->next;
       }
-      free(rp);
+      tfree(rp);
       break;
     }
     past = rp;
@@ -1504,7 +1597,7 @@ void trojanscan_donickchange(void *arg) { /* just incase I choose to make this s
       } else {
         trojanscan_gennick(c_nick, trojanscan_minmaxrand(7, TROJANSCAN_MMIN(13, NICKLEN)));
       }
-    } while (c_nick && (getnickbynick(c_nick) != NULL));
+    } while (c_nick[0] && (getnickbynick(c_nick) != NULL));
 
     renamelocaluser(clone->clone, c_nick);
   }
@@ -1572,6 +1665,8 @@ void trojanscan_handlemessages(nick *target, int messagetype, void **args) {
 
       /* Split the line into params */
       cargc = splitline((char *)args[1], cargv, 50, 0);
+      if(cargc == 0 || !cargv[0])
+        return;
 
       cmd=findcommandintree(trojanscan_cmds, cargv[0], 1);
       if (!cmd) {
@@ -1634,7 +1729,7 @@ void trojanscan_handlemessages(nick *target, int messagetype, void **args) {
       
     case LU_KILLED:
       /* someone killed me?  Bastards */
-      trojanscan_connect_schedule = scheduleoneshot(time(NULL) + 1, &trojanscan_connect, NULL);
+      trojanscan_connect_nick_schedule = scheduleoneshot(time(NULL) + 1, &trojanscan_connect_nick, NULL);
       trojanscan_nick = NULL;
       break;
       
@@ -1643,6 +1738,13 @@ void trojanscan_handlemessages(nick *target, int messagetype, void **args) {
   }
 }
 
+static char trojanscan_getmtfromhooktype(int input) {
+  switch(input) {
+    case HOOK_CHANNEL_PART: return 'P';
+    default:                return '?';
+  }
+}
+
 char trojanscan_getmtfrommessagetype(int input) {
   switch(input) {
     case LU_PRIVMSG:    return 'm';
@@ -1654,16 +1756,78 @@ char trojanscan_getmtfrommessagetype(int input) {
   }
 }
 
+static void trojanscan_process(nick *sender, channel *cp, char mt, char *pretext) {
+  char text[513];
+  unsigned int len;
+  unsigned int i;
+  struct trojanscan_worms *worm;
+  int vector[30], detected = 0;
+
+  trojanscan_strip_codes(text, sizeof(text) - 1, pretext);
+      
+  len = strlen(text);
+      
+  for(i=0;i<trojanscan_database.total_phrases;i++) {
+    if (
+         (
+           (worm = trojanscan_database.phrases[i].worm)
+         ) &&
+         (
+           (
+             (
+               (mt == 'm') || (mt == 's') || (mt == 'n')
+             ) &&
+             (
+               (trojanscan_database.phrases[i].worm->hitpriv)
+             )
+           ) ||
+           (
+             (
+               (mt == 'M') || (mt == 'N') || (mt == 'P')
+             ) &&
+             (
+               (trojanscan_database.phrases[i].worm->hitchans)
+             )
+           )
+         ) &&
+         (trojanscan_database.phrases[i].phrase)
+       ) {
+      int pre = pcre_exec(trojanscan_database.phrases[i].phrase, trojanscan_database.phrases[i].hint, text, len, 0, 0, vector, 30);
+      if(pre >= 0) {
+        char matchbuf[513];
+        matchbuf[0] = 0;
+        matchbuf[512] = 0; /* hmm */
+   
+        if(pre > 1)
+          if(pcre_copy_substring(text, vector, pre, 1, matchbuf, sizeof(matchbuf) - 1) <= 0)
+            matchbuf[0] = 0;
+           
+        trojanscan_phrasematch(cp, sender, &trojanscan_database.phrases[i], mt, matchbuf);
+
+        detected = 1;
+        break;
+      }
+    }
+  }
+  if (!detected && (mt != 'N') && (mt != 'M')) {
+    char etext[TROJANSCAN_QUERY_TEMP_BUF_SIZE], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
+    trojanscan_database_escape_string(etext, text, len);
+    trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
+    trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
+    trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
+    trojanscan_database_query("INSERT INTO unknownlog (data, user) VALUES ('%s','%s!%s@%s')", etext, enick, eident, ehost);
+  }
+}
+
 void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args) {
-  char *pretext = NULL, etext[TROJANSCAN_QUERY_TEMP_BUF_SIZE], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE], text[513], detected = 0;
+  char *pretext = NULL;
   nick *sender;
   struct trojanscan_realchannels *rp;
   struct trojanscan_rejoinlist *rj;
-  unsigned int i, len;
-  struct trojanscan_worms *worm;
-  int vector[30];
   char mt = trojanscan_getmtfrommessagetype(messagetype);
   char *channel_name;
+  channel *cp = NULL;
+  int i;
 
   switch(messagetype) {
     case LU_PRIVMSG:
@@ -1674,13 +1838,15 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
     
     case LU_CHANMSG:
     case LU_CHANNOTICE:
-      
       sender = (nick *)args[0];
+
       if (strlen(sender->nick) < 2)
         break;
       
-      if (!pretext)
+      if (!pretext) {
         pretext = (char *)args[2];  
+        cp = args[1];
+      }
 
       if(strncmp(TROJANSCAN_VERSION_DETECT, pretext, sizeof(TROJANSCAN_VERSION_DETECT)-1)==0) {
         char p = pretext[sizeof(TROJANSCAN_VERSION_DETECT)-1];
@@ -1707,152 +1873,14 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
               sendnoticetouser(target, sender, "\001VERSION T clone, though since T is currently gone you'll have to version me again in a minute for confirmation.\001");
             }
           } else {
-            sendnoticetouser(target, sender,  "\001VERSION " TROJANSCAN_CLONE_VERSION_REPLY "\001");
+            sendnoticetouser(target, sender,  "\001VERSION %s\001", versionreply);
           }
         
           return;
         }
       }
       
-      trojanscan_strip_codes(text, sizeof(text) - 1, pretext);
-      
-      len = strlen(text);
-      
-      for(i=0;i<trojanscan_database.total_phrases;i++) {
-        if (
-             (
-               (worm = trojanscan_database.phrases[i].worm)
-             ) &&
-             (
-               (
-                 (
-                   (messagetype == LU_PRIVMSG) || (messagetype == LU_SECUREMSG) || (messagetype == LU_PRIVNOTICE)
-                 ) &&
-                 (
-                   (trojanscan_database.phrases[i].worm->hitpriv)
-                 )
-               ) ||
-               (
-                 (
-                   (messagetype == LU_CHANMSG) || (messagetype == LU_CHANNOTICE)
-                 ) &&
-                 (
-                   (trojanscan_database.phrases[i].worm->hitchans)
-                 )
-               )
-             ) &&
-             (trojanscan_database.phrases[i].phrase)
-           ) {
-          int pre = pcre_exec(trojanscan_database.phrases[i].phrase, trojanscan_database.phrases[i].hint, text, len, 0, 0, vector, 30);
-          if(pre >= 0) {
-            char glinemask[HOSTLEN + USERLEN + NICKLEN + 4];
-            char *userbit;
-            host *hp;
-            unsigned int j, usercount, frequency;
-            char ip[TROJANSCAN_IPLEN];
-            int glining = 1;
-            channel *chp = (channel *)args[1];
-            
-            nick *np = NULL; /* sigh at warnings */
-            
-            detected = 1;
-            
-            trojanscan_database.detections++;
-            
-            if (!(hp=findhost(sender->host->name->content))) {
-              trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 1 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
-              break;
-            } 
-
-            usercount = 0; /* stupid warnings */
-            if (worm->monitor) {
-              glining = 0;
-              usercount = -1;
-            } else if (worm->glinehost && (hp->clonecount <= TROJANSCAN_MAX_HOST_GLINE)) {
-              snprintf(glinemask, sizeof(glinemask) - 1, "*@%s", trojanscan_iptostr(ip, sizeof(ip) - 1, sender->ipaddress));
-              usercount = hp->clonecount;
-            }
-            else if (worm->glineuser || (worm->glinehost && hp->clonecount > TROJANSCAN_MAX_HOST_GLINE)) {
-              userbit = sender->ident;
-              if(userbit[0] == '~')
-                userbit++;
-              snprintf(glinemask, sizeof(glinemask) - 1, "*%s@%s", userbit, trojanscan_iptostr(ip, sizeof(ip) - 1, sender->ipaddress));
-              for (j=0;j<NICKHASHSIZE;j++) {
-                for (np=nicktable[j];np;np=np->next) {
-                  if ((np->host==hp) && (!ircd_strcmp(np->ident,sender->ident)))
-                    usercount++;
-                }
-              }
-            }
-            
-            if (!usercount) {
-              trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 2 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
-              break;
-            }
-             
-            if (glining && (usercount > trojanscan_maxusers)) {
-              trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too many users (%d) with mask: *!%s -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, usercount, glinemask, worm->name->content);
-              break;
-            }
-
-            if (glining && !worm->datalen) {
-              trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too lack of removal data with mask: *!%s (%d users) -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, glinemask, usercount, worm->name->content);
-              break;
-            }
-                        
-            trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
-            trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
-            trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
-            
-            frequency = 1;
-            
-            if (!(trojanscan_database_query("SELECT COUNT(*) FROM hits WHERE glined = %d AND host = '%s'", glining, ehost))) {
-              trojanscan_database_res *res;
-              if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
-                trojanscan_database_row sqlrow;
-                if ((trojanscan_database_num_rows(res) > 0) && (sqlrow = trojanscan_database_fetch_row(res)))
-                  frequency = atoi(sqlrow[0]) + 1;
-                trojanscan_database_free_result(res);
-              }
-            } 
-
-            if (!glining) {
-              char matchbuf[513];
-              matchbuf[0] = 0;
-              matchbuf[512] = 0; /* hmm */
-              
-              if(pre > 1)
-                if (pcre_copy_substring(text, vector, pre, 1, matchbuf, sizeof(matchbuf) - 1) <= 0)
-                  matchbuf[0] = 0;
-              
-              trojanscan_mainchanmsg("m: t: %c u: %s!%s@%s%s%s w: %s p: %d %s%s", mt, sender->nick, sender->ident, sender->host->name->content, mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", worm->name->content, trojanscan_database.phrases[i].id, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
-#ifdef TROJANSCAN_PEONCHANNEL
-              trojanscan_peonchanmsg("m: t: %c u: %s!%s@%s%s%s%s w: %s %s%s", mt, sender->nick, sender->ident, (IsHideHost(sender)&&IsAccount(sender))?sender->authname:sender->host->name->content, (IsHideHost(sender)&&IsAccount(sender))?"."HIS_HIDDENHOST:"", mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", worm->name->content, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
-#endif
-            } else {
-              int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
-              if(glinetime > 7 * 24)
-                glinetime = 7 * 24; /* can't set glines over 7 days with normal non U:lined glines */
-
-              trojanscan_database_query("INSERT INTO hits (nickname, ident, host, phrase, messagetype, glined) VALUES ('%s', '%s', '%s', %d, '%c', %d)", enick, eident, ehost, trojanscan_database.phrases[i].id, mt, glining);          
-              trojanscan_database.glines++;
-              
-              irc_send("%s GL * +%s %d :You (%s!%s@%s) are infected with a trojan (%s/%d), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, glinetime * 3600, sender->nick, sender->ident, sender->host->name->content, worm->name->content, trojanscan_database.phrases[i].id, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
-
-              trojanscan_mainchanmsg("g: *!%s t: %c u: %s!%s@%s%s%s c: %d w: %s%s p: %d f: %d", glinemask, mt, sender->nick, sender->ident, sender->host->name->content, mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", usercount, worm->name->content, worm->epidemic?"(E)":"", trojanscan_database.phrases[i].id, frequency);
-            }
-            
-            break;
-          }
-        }
-      }
-      if (!detected && (mt != 'N') && (mt != 'M')) {
-        trojanscan_database_escape_string(etext, text, len);
-        trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
-        trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
-        trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
-        trojanscan_database_query("INSERT INTO unknownlog (data, user) VALUES ('%s','%s!%s@%s')", etext, enick, eident, ehost);
-      }
+      trojanscan_process(sender, cp, mt, pretext);
       break;         
     case LU_KILLED:
       /* someone killed me?  Bastards */
@@ -1861,7 +1889,7 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
       for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++) {
         if (trojanscan_swarm[i].clone == target) {
           
-          scheduleoneshot(time(NULL)+1, &trojanscan_generateclone, (void *)i);
+          scheduleoneshot(time(NULL)+1, &trojanscan_generateclone, (void *)((long)i));
           if(i >= TROJANSCAN_CLONE_MAX) {
             int j;
             for(j=0;j<trojanscan_activechans;j++)
@@ -1872,6 +1900,7 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
               if ((rp->clone == &(trojanscan_swarm[i])))
                 rp->donotpart = 1;
           }
+          derefnode(iptree, trojanscan_swarm[i].fakeipnode);
           trojanscan_swarm[i].clone = NULL;
           trojanscan_swarm[i].remaining = 0; /* bah */
           break;
@@ -1899,7 +1928,7 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
       /*
         trojanscan_mainchanmsg("k: %s on %s by %s", target->nick, ((channel *)args[1])->index->name->content, (((nick *)args[0])->nick)?(((nick *)args[0])->nick):"(server)");
       */
-        rj = (struct trojanscan_rejoinlist *)malloc(sizeof(struct trojanscan_rejoinlist));
+        rj = (struct trojanscan_rejoinlist *)tmalloc(sizeof(struct trojanscan_rejoinlist));
         if (rj) {
           rj->rp = NULL;
           for(rp=trojanscan_realchanlist;rp;rp=rp->next)
@@ -1909,14 +1938,14 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
                 break;
               }
             if(!rj->rp) {
-              free(rj);
+              tfree(rj);
               return;
             }
 
             rj->channel = getsstring(((channel *)args[1])->index->name->content, ((channel *)args[1])->index->name->length);
             if(!rj->channel) {
               trojanscan_mainchanmsg("d: unable to allocate memory for channel: %s upon rejoin", ((channel *)args[1])->index->name->content);
-              free(rj);
+              tfree(rj);
               return;
             }
 
@@ -1933,6 +1962,112 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
   }
 }
 
+static void trojanscan_part_watch(int hook, void *arg) {
+  void **arglist = (void **)arg;
+  channel *cp = (channel *)arglist[0];
+  nick *np = arglist[1];
+  char *reason = arglist[2];
+
+  if(!cp || !np || !reason || (*reason == '\0'))
+    return;
+
+  trojanscan_process(np, cp, trojanscan_getmtfromhooktype(hook), reason);
+}
+
+static int trojanscan_hostcount(nick *sender, int hostmode, char *mask, int masklen) {
+  int usercount = 0, j;
+  nick *np = NULL; /* sigh at warnings */
+
+  if(hostmode)
+    for (j=0;j<NICKHASHSIZE;j++)
+      for (np=nicktable[j];np;np=np->next)
+        if (np->ipnode==sender->ipnode)
+          usercount++;
+
+  if(usercount > TROJANSCAN_MAX_HOST_GLINE) {
+    hostmode = 0;
+    usercount = 0;
+  }
+
+  if(!hostmode)
+    for (j=0;j<NICKHASHSIZE;j++)
+      for (np=nicktable[j];np;np=np->next)
+        if (np->ipnode==sender->ipnode && !ircd_strcmp(np->ident, sender->ident))
+          usercount++;
+
+  if(mask)
+    snprintf(mask, masklen, "%s@%s", hostmode?"*":sender->ident, IPtostr(sender->p_ipaddr));
+
+  return usercount;
+}
+
+void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf) {
+  char glinemask[HOSTLEN + USERLEN + NICKLEN + 4], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
+  unsigned int frequency;
+  int glining = 0, usercount;
+  struct trojanscan_worms *worm = phrase->worm;
+
+  trojanscan_database.detections++;
+  
+  usercount = 0;
+  if (worm->monitor) {
+    usercount = -1;
+  } else if(worm->glinehost || worm->glineuser) {
+    glining = 1;
+
+    usercount = trojanscan_hostcount(sender, worm->glinehost, glinemask, sizeof(glinemask));
+  }
+  
+  if (!usercount) {
+    trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 2 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
+    return;
+  }
+   
+  if (glining && (usercount > trojanscan_maxusers)) {
+    trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too many users (%d) with mask: *!%s -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, usercount, glinemask, worm->name->content);
+    return;
+  }
+
+  if (glining && !worm->datalen) {
+    trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too lack of removal data with mask: *!%s (%d users) -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, glinemask, usercount, worm->name->content);
+    return;
+  }
+    
+  trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
+  trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
+  trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
+  
+  frequency = 1;
+  
+  if (!(trojanscan_database_query("SELECT COUNT(*) FROM hits WHERE glined = %d AND host = '%s'", glining, ehost))) {
+    trojanscan_database_res *res;
+    if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
+      trojanscan_database_row sqlrow;
+      if ((trojanscan_database_num_rows(res) > 0) && (sqlrow = trojanscan_database_fetch_row(res)))
+        frequency = atoi(sqlrow[0]) + 1;
+      trojanscan_database_free_result(res);
+    }
+  } 
+
+  if (!glining) {
+    trojanscan_mainchanmsg("m: t: %c u: %s!%s@%s%s%s w: %s p: %d %s%s", messagetype, sender->nick, sender->ident, sender->host->name->content, messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", worm->name->content, phrase->id, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+#ifdef TROJANSCAN_PEONCHANNEL
+    trojanscan_peonchanmsg("m: t: %c u: %s!%s@%s%s%s%s w: %s %s%s", messagetype, sender->nick, sender->ident, (IsHideHost(sender)&&IsAccount(sender))?sender->authname:sender->host->name->content, (IsHideHost(sender)&&IsAccount(sender))?"."HIS_HIDDENHOST:"", messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", worm->name->content, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+#endif
+  } else {
+    int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
+    if(glinetime > 7 * 24)
+      glinetime = 7 * 24; /* can't set glines over 7 days with normal non U:lined glines */
+
+    trojanscan_database_query("INSERT INTO hits (nickname, ident, host, phrase, messagetype, glined) VALUES ('%s', '%s', '%s', %d, '%c', %d)", enick, eident, ehost, phrase->id, messagetype, glining);
+    trojanscan_database.glines++;
+    
+    irc_send("%s GL * +%s %d :You (%s!%s@%s) are infected with a trojan (%s/%d), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, glinetime * 3600, sender->nick, sender->ident, sender->host->name->content, worm->name->content, phrase->id, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
+
+    trojanscan_mainchanmsg("g: *!%s t: %c u: %s!%s@%s%s%s c: %d w: %s%s p: %d f: %d", glinemask, messagetype, sender->nick, sender->ident, sender->host->name->content, messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", usercount, worm->name->content, worm->epidemic?"(E)":"", phrase->id, frequency);
+  }
+}
+            
 void trojanscan_rejoin_channel(void *arg) {
   struct trojanscan_rejoinlist *rj2, *lrj, *rj = (struct trojanscan_rejoinlist *)arg;
   
@@ -1959,12 +2094,12 @@ void trojanscan_rejoin_channel(void *arg) {
 
   if (rj2 == rj) {
     trojanscan_schedulerejoins = rj->next;
-    free(rj);
+    tfree(rj);
   } else {
     for(rj2=trojanscan_schedulerejoins;rj2;lrj=rj2,rj2=rj2->next) {
       if (rj2 == rj) {
         lrj->next = rj2->next;
-        free(rj);
+        tfree(rj);
         break;
       }
     }
@@ -2092,9 +2227,10 @@ void trojanscan_genident(char *ptc, char size) {
   ptc[i] = '\0';
 }
 
-void trojanscan_genhost(char *ptc, char size, long *fakeip) {
+void trojanscan_genhost(char *ptc, char size, patricia_node_t **fakeipnode) {
   int dots = trojanscan_minmaxrand(2, 5), i, dotexist = 0, cur;
-  
+  struct irc_in_addr ipaddress;
+
   while (!dotexist) {
     for (i=0;i<size;i++) {
       ptc[i] = trojanscan_genchar(0);
@@ -2115,7 +2251,12 @@ void trojanscan_genhost(char *ptc, char size, long *fakeip) {
   }
   ptc[i] = '\0';
 
-  *fakeip = (trojanscan_minmaxrand(0, 65535) << 16) | trojanscan_minmaxrand(0, 65535);
+  memset(&ipaddress, 0, sizeof(ipaddress));
+  ((unsigned short *)(ipaddress.in6_16))[5] = 65535;
+  ((unsigned short *)(ipaddress.in6_16))[6] = trojanscan_minmaxrand(0, 65535);
+  ((unsigned short *)(ipaddress.in6_16))[7] = trojanscan_minmaxrand(0, 65535);
+
+  *fakeipnode = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
 }
 
 void trojanscan_genreal(char *ptc, char size) {
@@ -2224,7 +2365,9 @@ host *trojanscan_selecthost(void) {
   return NULL;
 }
 
-void trojanscan_generatehost(char *buf, int maxsize, long *fakeip) {
+void trojanscan_generatehost(char *buf, int maxsize, patricia_node_t **fakeip) {
+  struct irc_in_addr ipaddress;
+
   if(TROJANSCAN_HOST_MODE == TROJANSCAN_STEAL_HOST) {
     host *hp;
     int loops = 20;
@@ -2236,9 +2379,15 @@ void trojanscan_generatehost(char *buf, int maxsize, long *fakeip) {
       if(hp && (hp->clonecount <= TROJANSCAN_MAX_CLONE_COUNT) && !trojanscan_isip(hp->name->content)) {
         strlcpy(buf, hp->name->content, maxsize + 1);
         if(hp->nicks) {
-          *fakeip = hp->nicks->ipaddress;
+          *fakeip = hp->nicks->ipnode;
+         patricia_ref_prefix(hp->nicks->ipnode->prefix);
         } else {
-          *fakeip = (trojanscan_minmaxrand(0, 65535) << 16) | trojanscan_minmaxrand(0, 65535);
+          memset(&ipaddress, 0, sizeof(ipaddress));
+         ((unsigned short *)(ipaddress.in6_16))[5] = 65535; 
+          ((unsigned short *)(ipaddress.in6_16))[6] = trojanscan_minmaxrand(0, 65535);
+          ((unsigned short *)(ipaddress.in6_16))[7] = trojanscan_minmaxrand(0, 65535);
+
+          *fakeip = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
         }
         break;
       }
@@ -2246,8 +2395,8 @@ void trojanscan_generatehost(char *buf, int maxsize, long *fakeip) {
   } else {
     char *cpos;
     int pieces = trojanscan_minmaxrand(2, 4), totallen = 0, a = 0, i;
-    int *choices = malloc(sizeof(int) * (pieces + 1));
-    int *lengths = malloc(sizeof(int) * (pieces + 1));
+    int *choices = tmalloc(sizeof(int) * (pieces + 1));
+    int *lengths = tmalloc(sizeof(int) * (pieces + 1));
   
     choices[pieces] = trojanscan_minmaxrand(0, trojanscan_tailpoolsize-1);
     lengths[pieces] = strlen(trojanscan_tailpool[choices[pieces]]->content) + 1;
@@ -2276,10 +2425,15 @@ void trojanscan_generatehost(char *buf, int maxsize, long *fakeip) {
     }
 
     buf[a] = '\0';
-    free(choices);
-    free(lengths);
+    tfree(choices);
+    tfree(lengths);
+
+    memset(&ipaddress, 0, sizeof(ipaddress));
+    ((unsigned short *)(ipaddress.in6_16))[5] = 65535;
+    ((unsigned short *)(ipaddress.in6_16))[6] = trojanscan_minmaxrand(0, 65535);
+    ((unsigned short *)(ipaddress.in6_16))[7] = trojanscan_minmaxrand(0, 65535);
 
-    *fakeip = (trojanscan_minmaxrand(0, 65535) << 16) | trojanscan_minmaxrand(0, 65535);
+    *fakeip = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
   }
 }