]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Merge default.
authorGunnar Beutner <redacted>
Thu, 8 Aug 2013 21:32:10 +0000 (23:32 +0200)
committerGunnar Beutner <redacted>
Thu, 8 Aug 2013 21:32:10 +0000 (23:32 +0200)
--HG--
branch : shroudnoperserv

16 files changed:
INSTALL [new file with mode: 0644]
MODULES [new file with mode: 0644]
README [new file with mode: 0644]
chanfix/chanfix.c
chanfix/chanfix.h
core/hooks.h
newsearch/formats.c
newsearch/ns-age.c
newsearch/ns-server.c
nick/nick.c
trusts/trusts_migration.c
whowas/Makefile
whowas/whowas.c
whowas/whowas.h
whowas/whowas_channels.c [new file with mode: 0644]
whowas/whowas_commands.c

diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..9b9ca38
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,72 @@
+newserv Installation
+~~~~~~~~~~~~~~~~~~~
+
+In order to install newserv you will have to run the configure script:
+
+$ ./configure
+
+The configure script will list any missing dependencies. If you're unsure why
+a certain library or header file was not found you can run the configure script
+with the -v option or check the .configure.log file after your first configure
+run.
+
+Please refer to the "Local Settings" section in this file if you're
+using non-standard library/header search paths. Once you've resolved all
+dependency issues you can build newserv:
+
+$ make
+
+This might take a while. After all modules are built you can install
+newserv:
+
+$ make install
+
+By default the newserv binary and the modules are installed into your
+source tree. The recommended setup is to now create a separate directory
+and symlink the "newserv" binary and the "modules" directory into it:
+
+$ cd
+$ mkdir newserv-install && cd newserv-install
+$ mkdir data # Some modules depend on this directory being available
+$ ln -s ../newserv-src/newserv
+$ ln -s ../newserv-src/modules
+
+You will also need to copy the newserv.conf.example configuration file to your
+installation directory and rename it to newserv.conf.
+
+After you have updated your newserv.conf file you can start newserv:
+
+$ ./newserv
+
+newserv does not detach from the console. Consider running it in a
+screen(1) session.
+
+Local Settings
+~~~~~~~~~~~~~
+
+If you are using non-standard library/include paths you can create a file
+called configure.ini.local (using configure.ini.local.example as a template)
+to override some of the settings.
+
+Workspaces
+~~~~~~~~~
+
+If you're planning to write your own modules you might consider using
+workspace.
+
+For this to work you will need to create a directory for your modules:
+
+$ mkdir custom
+
+Create a skeleton configure.ini in your new module directory:
+
+[modules]
+mymodule=
+
+And finally add your workspace to the workspaces.ini file:
+
+[workspaces]
+custom=
+
+You will need to re-run configure for it to pick up your new
+workspace and whatever modules you have in it.
diff --git a/MODULES b/MODULES
new file mode 100644 (file)
index 0000000..eb4aa65
--- /dev/null
+++ b/MODULES
@@ -0,0 +1,219 @@
+newserv Modules
+~~~~~~~~~~~~~~
+
+This is a brief overview of the newserv modules.
+
+core
+~~~
+
+This is not actually a module. Instead, this is the code of the "newserv" binary
+which provides minimal support for loading modules.
+
+authext, bans, chanindex, channel, irc, nick, server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These modules provide basic support for accounts, channels, nicks and server
+connections. Virtually all other modules depend on at least some of these
+modules.
+
+localuser
+~~~~~~~~
+
+Implements functionality for creating local users that are "connected" to the
+newserv instance.
+
+control
+~~~~~~
+
+Spawns the control user for your newserv instance. The control user provides
+an IRC-based interface for newserv commands, e.g. to manage loaded modules
+and modify user accounts.
+
+Other modules can register their own commands.
+
+You can create a user on your control instance using /msg N hello (where N is
+the nick of your control instance). You need to be opered in order to use this
+command.
+
+Once you have an account you should have a look at /msg N showcommands for a
+list of available commands.
+
+Configuration:
+
+[control]
+nick=N3
+
+auth
+~~~
+
+Supports sending AC tokens. You should only use this module if you don't have
+some other form of authentication service on your network (such as Q). This
+module lets opers use arbitrary account names and IDs.
+
+chanfix
+~~~~~~
+
+Keeps track of channel ops and can be used to re-op opless channels.
+
+chanserv
+~~~~~~~
+
+This is QuakeNet's channel service (Q). In order to load this module you will
+need also need to load the pqsql module.
+
+pqsql
+~~~~
+
+Provides support for PostgreSQL database queries.
+
+Configuration:
+
+[pqsql]
+host=127.0.0.1
+port=5432
+username=gunnar
+password=changeme
+
+dbapi2
+~~~~~
+
+Implements database functionality used by some other modules. In addition to
+loading the dbapi2 module you will also need to load one of the database
+provider modules: sqlite-dbapi2 or pqsql-dbapi2
+
+fakeusers
+~~~~~~~~
+
+Provides a way to spawn fake users.
+
+glines
+~~~~~
+
+Implements gline commands and general gline functionality that is used by other
+modules.
+
+helpmod2
+~~~~~~~
+
+This is QuakeNet's G service. It is primarily used on official support channels.
+
+invalidbans
+~~~~~~~~~~
+
+This module automatically removes invalid IPv6 bans as these can desync channel
+modes on snircd 1.3.4a.
+
+jupe
+~~~
+
+Provides commands to set, list and remove jupes.
+
+lua
+~~
+
+Provides support for Lua scripts. For an example of a fairly complex script
+have a look at the labspace repository at http://hg.quakenet.org/lua-labspace/
+
+Configuration:
+
+[lua]
+scriptdir=./luascripts
+script=labspace
+
+Note: You will need to create the script directory in your newserv
+installation directory (e.g. "luascripts" in this example) and symlink the
+lua/lib directory into it.
+
+newsearch
+~~~~~~~~
+
+Provides functionality to search for nicks and channels based on certain
+criteria.
+
+miscreply
+~~~~~~~~
+
+Implements rping and various other status query commands.
+
+proxyscan
+~~~~~~~~
+
+Does on-connect proxy scans and glines open proxies.
+
+request
+~~~~~~
+
+This is QuakeNet's channel service request bot (R). Some of the module
+parameters are not configurable - instead you will have to modify the
+request/request.h header file and recompile the module.
+
+serverlist
+~~~~~~~~~
+
+Implements the serverlist command which shows various information about
+connected servers (including their network latency).
+
+settime
+~~~~~~
+
+Provides commands to set the network time.
+
+splitlist
+~~~~~~~~
+
+Keeps track of servers that were lost during a netsplit. This module is used
+by chanfix to determine when it shouldn't re-op users.
+
+trojanscan
+~~~~~~~~~
+
+Used to find and gline drones on the network.
+
+trusts
+~~~~~
+
+Implements connection limits. Supports the TRUST protocol which is used
+by quakenet-iauthd to determine whether to allow users on the network.
+
+You will need to load the trusts_master module on one of your newserv
+instances. All other instances should load the trusts_slave module in order
+to receive replication updates from the trusts master:
+
+[trusts]
+master=1
+#masterserver=trusts.services.netsplit.net # Only used if master=0
+
+In most cases you will also want to load the trusts_management module on
+your trusts master. This module provides commands to add, modify and delete
+trusts.
+
+If you want to enforce connection limits on your network you can use the
+trusts_policy module:
+
+[trusts_policy]
+enforcepolicy_irc=1
+enforcepolicy_auth=0
+trustport=5776
+server=gnb.netsplit.net,changeme
+server=test.gnb.netsplit.net,changeme
+
+You can use the QuakeNet IAuth daemon available at
+http://hg.quakenet.org/iauthd/ to enforce connection limits using IAuth rather
+than g:lines.
+
+whowas
+~~~~~
+
+Keeps track of historical user records. Used by the glines module to chase
+nicks and by newsearch.
+
+xsb
+~~
+
+Provides replication capabilities. Used by the trusts modules to sync
+trusts between newserv instances.
+
+Configuration:
+
+[xsb]
+servicemask=*.services.netsplit.net
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e077007
--- /dev/null
+++ b/README
@@ -0,0 +1,56 @@
+
+              _    _    _    _    _    _    _  
+             / \  / \  / \  / \  / \  / \  / \ 
+            ( n )( e )( w )( s )( e )( r )( v )
+             \_/  \_/  \_/  \_/  \_/  \_/  \_/ 
+                        
+
+newserv is an IRC P10 protocol services daemon developed for the QuakeNet IRC Network since April 2002. It is modular, fast and easily customizable.
+
+newserv is available for download and use under the XXX open source license. 
+
+The official website for newserv is http://dev.quakenet.org/
+
+Requirements
+~~~~~~~~~~~
+
+* IRC Server running the P10 Protocol. Full support for all modules may require use of QuakeNet's snircd IRC server [available from https://www.quakenet.org/development], which is based upon Undernet's IRCU server [http://coder-com.undernet.org/].
+
+* Please read the INSTALL file for build and installation instructions.
+
+Features
+~~~~~~~
+
+ * Role-based access checks for oper commands
+
+ * Search functionality
+ * Lua integration
+ * Proxy detection (P)
+
+ * Connection limits ("trusts")
+
+ * Transactional g:line support
+
+ * Jupes
+
+ * Chanfix
+
+ * Chanserv (Q)
+ * Help Service (G)
+
+ * Channel Service Request (R)
+
+ * QA/Tutor Bots
+
+ * Server list with latency checks
+
+Support & Development
+~~~~~~~~~~~~~~~~~~~~
+
+Please read the documentation provided before you ask us for support. You may find some assistance in #dev on QuakeNet for specific questions.
+
+If you've found any bugs or you're working on any cool new features please give us a shout.
+
index 698511b48f17151fc6cf993831e2d42c60cb9411..d7ad18901510d2d6d44bb504e862f61fa546db69 100644 (file)
@@ -23,7 +23,8 @@ extern nick *mynick;
 
 int cfext;
 int cfnext;
-int cffailedinit;
+
+static int cffailedinit;
 
 /* user accessible commands */
 int cfcmd_debug(void *source, int cargc, char **cargv);
@@ -66,89 +67,89 @@ void _init() {
   if (cfext < 0 || cfnext < 0) {
     Error("chanfix", ERR_ERROR, "Couldn't register channel and/or nick extension");
     cffailedinit = 1;
-  } else {
-    schedulerecurring(time(NULL), 0, CFSAMPLEINTERVAL, &cfsched_dosample, NULL);
-    schedulerecurring(time(NULL), 0, CFEXPIREINTERVAL, &cfsched_doexpire, NULL);
-    schedulerecurring(time(NULL), 0, CFAUTOSAVEINTERVAL, &cfsched_dosave, NULL);
+    return;
+  }
 
-    registercontrolhelpcmd("cfdebug", NO_DEVELOPER, 1, &cfcmd_debug, "Display Debug Information on chanfix data for channel");
-    registercontrolhelpcmd("cfhistogram", NO_DEVELOPER, 1, &cfcmd_debughistogram, "Display Debug Histogram of chanfix data for channel");
+  schedulerecurring(time(NULL), 0, CFSAMPLEINTERVAL, &cfsched_dosample, NULL);
+  schedulerecurring(time(NULL), 0, CFEXPIREINTERVAL, &cfsched_doexpire, NULL);
+  schedulerecurring(time(NULL), 0, CFAUTOSAVEINTERVAL, &cfsched_dosave, NULL);
+
+  registercontrolhelpcmd("cfdebug", NO_DEVELOPER, 1, &cfcmd_debug, "Display Debug Information on chanfix data for channel");
+  registercontrolhelpcmd("cfhistogram", NO_DEVELOPER, 1, &cfcmd_debughistogram, "Display Debug Histogram of chanfix data for channel");
 #if CFDEBUG
-    registercontrolhelpcmd("cfsample", NO_DEVELOPER, 1, &cfcmd_debugsample, "DEBUG Command - must not be loaded on live instances");
-    registercontrolhelpcmd("cfexpire", NO_DEVELOPER, 1, &cfcmd_debugexpire, "DEBUG Command - must not be loaded on live instances");
+  registercontrolhelpcmd("cfsample", NO_DEVELOPER, 1, &cfcmd_debugsample, "DEBUG Command - must not be loaded on live instances");
+  registercontrolhelpcmd("cfexpire", NO_DEVELOPER, 1, &cfcmd_debugexpire, "DEBUG Command - must not be loaded on live instances");
 #endif
-    registercontrolhelpcmd("chanopstat", NO_OPER, 1, &cfcmd_chanopstat, "Shows chanop statistics for a given channel");
-    registercontrolhelpcmd("chanoplist", NO_OPER, 1, &cfcmd_chanoplist, "Shows lists of known chanops, including scores");
+  registercontrolhelpcmd("chanopstat", NO_OPER, 1, &cfcmd_chanopstat, "Shows chanop statistics for a given channel");
+  registercontrolhelpcmd("chanoplist", NO_OPER, 1, &cfcmd_chanoplist, "Shows lists of known chanops, including scores");
 
-    registercontrolhelpcmd("chanfix", NO_OPER, 1, &cfcmd_chanfix, "Perform a chanfix on a channel to op known users only");
-    registercontrolhelpcmd("showregs", NO_OPER, 1, &cfcmd_showregs, "Show regular ops known on a channel (including services)");
+  registercontrolhelpcmd("chanfix", NO_OPER, 1, &cfcmd_chanfix, "Perform a chanfix on a channel to op known users only");
+  registercontrolhelpcmd("showregs", NO_OPER, 1, &cfcmd_showregs, "Show regular ops known on a channel (including services)");
 #if CFDEBUG
-    /* should we disable this in the 'final' build? */
-    /* registercontrolcmd("requestop", 0, 2, &cfcmd_requestop); */
+  /* should we disable this in the 'final' build? */
+  /* registercontrolcmd("requestop", 0, 2, &cfcmd_requestop); */
 #endif
-    registercontrolhelpcmd("cfsave", NO_DEVELOPER, 0, &cfcmd_save, "Force save of chanfix data");
-    registercontrolhelpcmd("cfload", NO_DEVELOPER, 0, &cfcmd_load, "Force load of chanfix data");
+  registercontrolhelpcmd("cfsave", NO_DEVELOPER, 0, &cfcmd_save, "Force save of chanfix data");
+  registercontrolhelpcmd("cfload", NO_DEVELOPER, 0, &cfcmd_load, "Force load of chanfix data");
 
 #if CFAUTOFIX
-    registerhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
-    registerhook(HOOK_CHANNEL_PART, &cfhook_autofix);
-    registerhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
-    registerhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
+  registerhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
+  registerhook(HOOK_CHANNEL_PART, &cfhook_autofix);
+  registerhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
+  registerhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
 #endif
 
-    registerhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
-    registerhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
+  registerhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
+  registerhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
 
-    cf_loadchanfix();
+  cf_loadchanfix();
 
-    cffailedinit = 0;
-  }
+  cffailedinit = 0;
 }
 
 void _fini() {
-  if (cffailedinit == 0) {
-    deleteschedule(NULL, &cfsched_dosample, NULL);
-    deleteschedule(NULL, &cfsched_doexpire, NULL);
-    deleteschedule(NULL, &cfsched_dosave, NULL);
+  if (cffailedinit == 0)
+    return;
 
-    cf_storechanfix();
+  deleteschedule(NULL, &cfsched_dosample, NULL);
+  deleteschedule(NULL, &cfsched_doexpire, NULL);
+  deleteschedule(NULL, &cfsched_dosave, NULL);
 
-    cf_free();
+  cf_storechanfix();
+
+  cf_free();
 
-    deregistercontrolcmd("cfdebug", &cfcmd_debug);
-    deregistercontrolcmd("cfhistogram", &cfcmd_debughistogram);
+  deregistercontrolcmd("cfdebug", &cfcmd_debug);
+  deregistercontrolcmd("cfhistogram", &cfcmd_debughistogram);
 #if CFDEBUG
-    deregistercontrolcmd("cfsample", &cfcmd_debugsample);
-    deregistercontrolcmd("cfexpire", &cfcmd_debugexpire);
+  deregistercontrolcmd("cfsample", &cfcmd_debugsample);
+  deregistercontrolcmd("cfexpire", &cfcmd_debugexpire);
 #endif
-    deregistercontrolcmd("chanopstat", &cfcmd_chanopstat);
-    deregistercontrolcmd("chanoplist", &cfcmd_chanoplist);
-    deregistercontrolcmd("chanfix", &cfcmd_chanfix);
-    deregistercontrolcmd("showregs", &cfcmd_showregs);
+  deregistercontrolcmd("chanopstat", &cfcmd_chanopstat);
+  deregistercontrolcmd("chanoplist", &cfcmd_chanoplist);
+  deregistercontrolcmd("chanfix", &cfcmd_chanfix);
+  deregistercontrolcmd("showregs", &cfcmd_showregs);
 #if CFDEBUG
-//    deregistercontrolcmd("requestop", &cfcmd_requestop);
+//  deregistercontrolcmd("requestop", &cfcmd_requestop);
 #endif
-    deregistercontrolcmd("cfsave", &cfcmd_save);
-    deregistercontrolcmd("cfload", &cfcmd_load);
+  deregistercontrolcmd("cfsave", &cfcmd_save);
+  deregistercontrolcmd("cfload", &cfcmd_load);
 
 #if CFAUTOFIX
-    deregisterhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
-    deregisterhook(HOOK_CHANNEL_PART, &cfhook_autofix);
-    deregisterhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
-    deregisterhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
+  deregisterhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
+  deregisterhook(HOOK_CHANNEL_PART, &cfhook_autofix);
+  deregisterhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
+  deregisterhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
 #endif
 
-    deregisterhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
-    deregisterhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
-  }
+  deregisterhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
+  deregisterhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
 
-  if (cfext >= 0) {
+  if (cfext >= 0)
     releasechanext(cfext);
-  }
 
-  if (cfnext >= 0) {
+  if (cfnext >= 0)
     releasenickext(cfnext);
-  }
 }
 
 int cfcmd_debug(void *source, int cargc, char **cargv) {
@@ -158,11 +159,8 @@ int cfcmd_debug(void *source, int cargc, char **cargv) {
   regop *ro;
   int i;
 
-  if (cargc < 1) {
-    controlreply(np, "Syntax: cfdebug <#channel>");
-
-    return CMD_ERROR;
-  }
+  if (cargc < 1)
+    return CMD_USAGE;
 
   cip = findchanindex(cargv[0]);
 
@@ -170,8 +168,9 @@ int cfcmd_debug(void *source, int cargc, char **cargv) {
     controlreply(np, "No such channel.");
 
     return CMD_ERROR;
-  } else
-    controlreply(np, "Found channel %s. Retrieving chanfix information...", cargv[0]);
+  }
+
+  controlreply(np, "Found channel %s. Retrieving chanfix information...", cargv[0]);
 
   cf = cip->exts[cfext];
 
@@ -179,8 +178,9 @@ int cfcmd_debug(void *source, int cargc, char **cargv) {
     controlreply(np, "No chanfix information for %s", cargv[0]);
 
     return CMD_ERROR;
-  } else
-    controlreply(np, "Found chanfix information. Dumping...");
+  }
+
+  controlreply(np, "Found chanfix information. Dumping...");
 
   for (i=0;i<cf->regops.cursi;i++) {
     ro = ((regop**)cf->regops.content)[i];
@@ -283,9 +283,8 @@ int cf_getsortedregops(chanfix *cf, int max, regop **list) {
 
   qsort(cf->regops.content, cf->regops.cursi, sizeof(regop*), cmpregop);
 
-  for (i = 0; i < min(max, cf->regops.cursi); i++) {
+  for (i = 0; i < min(max, cf->regops.cursi); i++)
     list[i] = ((regop**)cf->regops.content)[i];
-  }
 
   return i;
 }
@@ -300,11 +299,8 @@ int cfcmd_chanopstat(void *source, int cargc, char **cargv) {
   int i, a, count;
   int *scores;
 
-  if (cargc < 1) {
-    controlreply(np, "Syntax: chanopstat <#channel>");
-
-    return CMD_ERROR;
-  }
+  if (cargc < 1)
+    return CMD_USAGE;
 
   cp = findchannel(cargv[0]);
 
@@ -326,9 +322,8 @@ int cfcmd_chanopstat(void *source, int cargc, char **cargv) {
   count = cf_getsortedregops(cf, 10, rolist);
   controlreply(np, "Scores of \"best ops\" on %s are:", cargv[0]);
 
-  for (i=0;i<count;i++) {
+  for (i=0;i<count;i++)
     controlreply(np, "  %d", rolist[i]->score);
-  }
 
   /* current ops */
   scores = (int*)malloc(sizeof(int) * cp->users->hashsize);
@@ -374,11 +369,8 @@ int cfcmd_chanoplist(void *source, int cargc, char **cargv) {
   char date[50];
   unsigned long *hand;
 
-  if (cargc < 1) {
-    controlreply(np, "Syntax: chanoplist <#channel>");
-
-    return CMD_ERROR;
-  }
+  if (cargc < 1)
+    return CMD_USAGE;
 
   cip = findchanindex(cargv[0]);
 
@@ -432,11 +424,8 @@ int cfcmd_chanfix(void *source, int cargc, char **cargv) {
   channel *cp;
   int ret;
 
-  if (cargc < 1) {
-    controlreply(np, "Syntax: chanfix <#channel>");
-
-    return CMD_ERROR;
-  }
+  if (cargc < 1)
+    return CMD_USAGE;
 
   cp = findchannel(cargv[0]);
 
@@ -480,11 +469,8 @@ int cfcmd_showregs(void *source, int cargc, char **cargv) {
   int i, count, ops;
   regop *rolist[50];
 
-  if (cargc < 1) {
-    controlreply(np, "Syntax: showregs <#channel>");
-
-    return CMD_ERROR;
-  }
+  if (cargc < 1)
+    return CMD_USAGE;
 
   cp = findchannel(cargv[0]);
 
@@ -545,11 +531,8 @@ int cfcmd_requestop(void *source, int cargc, char **cargv) {
   unsigned long *hand;
   modechanges changes;
 
-  if (cargc < 1) {
-    controlreply(np, "Syntax: requestop <#channel> [nick]");
-
-    return CMD_ERROR;
-  }
+  if (cargc < 1)
+    return CMD_USAGE;
 
   cp = findchannel(cargv[0]);
 
@@ -675,18 +658,17 @@ int cf_hasauthedcloneonchan(nick *np, channel *cp) {
 }
 
 void cfsched_dosample(void *arg) {
-  int i,a,now,cfscore,cfnewro,cfuhost,diff;
+  int i,a,now,cfscore,cfnewro,diff;
   channel *cp;
   chanindex *cip;
   nick *np;
   regop *ro, *roh;
   struct timeval start;
   struct timeval end;
-  char buf[USERLEN+1+HOSTLEN+1];
 
   now = getnettime();
 
-  cfuhost = cfscore = cfnewro = 0;
+  cfscore = cfnewro = 0;
 
   if (sp_countsplitservers(SERVERTYPEFLAG_USER_STATE) > CFMAXSPLITSERVERS)
     return;
@@ -704,7 +686,7 @@ void cfsched_dosample(void *arg) {
         if ((cp->users->content[a] != nouser) && (cp->users->content[a] & CUMODE_OP)) {
           np = getnickbynumeric(cp->users->content[a]);
 
-          if (np)
+          if (!np)
             continue;
 
 #if !CFDEBUG
@@ -722,34 +704,23 @@ void cfsched_dosample(void *arg) {
 
           /* lastopped == now if the user has clones, we obviously
            * don't want to give them points in this case */
-          if (ro && ro->lastopped != now) {
-            if (ro->type != CFHOST || !cf_hasauthedcloneonchan(np, cp)) {
-              ro->score++;
-              cfscore++;
-            }
-
-            /* merge any matching CFHOST records */
-            if (roh && roh->type == CFHOST && ro->type == CFACCOUNT) {
-              /* hmm */
-              ro->score += roh->score;
-
-              cf_deleteregop(cip, roh);
-            }
-
-            /* store the user's account/host if we have to */
-            if (ro->uh == NULL && ro->score >= CFMINSCOREUH) {
-              if (ro->type == CFACCOUNT)
-                ro->uh = getsstring(np->authname, ACCOUNTLEN);
-              else {
-                snprintf(buf, sizeof(buf), "%s@%s", np->ident, np->host->name->content);
-                roh->uh = getsstring(buf, USERLEN+1+HOSTLEN);
-              }
-
-              cfuhost++;
-            }
-
-            ro->lastopped = now;
+          if (!ro || ro->lastopped == now)
+            continue;
+
+          if (ro->type != CFHOST || !cf_hasauthedcloneonchan(np, cp)) {
+            ro->score++;
+            cfscore++;
           }
+
+          /* merge any matching CFHOST records */
+          if (roh && roh->type == CFHOST && ro->type == CFACCOUNT) {
+            /* hmm */
+            ro->score += roh->score;
+
+            cf_deleteregop(cip, roh);
+          }
+
+          ro->lastopped = now;
         }
       }
     }
@@ -764,8 +735,8 @@ void cfsched_dosample(void *arg) {
            (start.tv_sec * 1000 + start.tv_usec / 1000);
 
     sendmessagetochannel(mynick, cp, "sampled chanfix scores, assigned %d new"
-                         " points, %d new regops, %d user@hosts added, deltaT: %dms", cfscore,
-                         cfnewro, cfuhost, diff);
+                         " points, %d new regops, deltaT: %dms", cfscore,
+                         cfnewro, diff);
   }
 }
 
@@ -774,14 +745,14 @@ void cfsched_doexpire(void *arg) {
   chanindex *cip;
   chanindex *ncip;
   chanfix *cf;
-  int i,a,cfscore,cfregop,cffreeuh,diff;
+  int i,a,cfscore,cfregop,diff;
   regop **rolist;
   regop *ro;
   struct timeval start;
   struct timeval end;
   time_t currenttime;
 
-  cffreeuh = cfscore = cfregop = 0;
+  cfscore = cfregop = 0;
 
   gettimeofday(&start, NULL);
   currenttime=getnettime();
@@ -801,13 +772,6 @@ void cfsched_doexpire(void *arg) {
             cfscore++;
           }
 
-          if ((ro->score < CFMINSCOREUH) && ro->uh) {
-            freesstring(ro->uh);
-            ro->uh = NULL;
-
-            cffreeuh++;
-          }
-
           if (ro->score == 0 || ro->lastopped < (currenttime - CFREMEMBEROPS)) {
             cf_deleteregop(cip, ro);
             cfregop++;
@@ -838,8 +802,8 @@ void cfsched_doexpire(void *arg) {
            (start.tv_sec * 1000 + start.tv_usec / 1000);
 
     sendmessagetochannel(mynick, cp, "expired chanfix scores, purged %d points,"
-                         " scrapped %6d regops, %d user@hosts freed, deltaT: %dms", cfscore,
-                         cfregop, cffreeuh, diff);
+                         " scrapped %6d regops, deltaT: %dms", cfscore,
+                         cfregop, diff);
   }
 
 }
@@ -1065,6 +1029,7 @@ regop *cf_createregop(nick *np, chanindex *cip) {
   chanfix *cf = cip->exts[cfext];
   int slot, type;
   regop **rolist;
+  char buf[USERLEN+1+HOSTLEN+1];
 
   if (cf == NULL) {
     cf = (chanfix*)malloc(sizeof(chanfix));
@@ -1081,14 +1046,18 @@ regop *cf_createregop(nick *np, chanindex *cip) {
 
   rolist[slot] = (regop*)malloc(sizeof(regop));
 
-  if (IsAccount(np))
+  if (IsAccount(np)) {
     type = CFACCOUNT;
-  else
+    rolist[slot]->uh = getsstring(np->authname, ACCOUNTLEN);
+  } else {
     type = CFHOST;
 
+    snprintf(buf, sizeof(buf), "%s@%s", np->ident, np->host->name->content);
+    rolist[slot]->uh = getsstring(buf, USERLEN+1+HOSTLEN);
+  }
+
   rolist[slot]->type = type;
   rolist[slot]->hash = cf_gethash(np, type);
-  rolist[slot]->uh = NULL;
   rolist[slot]->lastopped = 0;
   rolist[slot]->score = 0;
 
@@ -1277,11 +1246,7 @@ int cf_parseline(char *line) {
   rolist[slot]->hash = hash;
   rolist[slot]->lastopped = lastopped;
   rolist[slot]->score = score;
-
-  if (count >= 6)
-    rolist[slot]->uh = getsstring(host, USERLEN+1+HOSTLEN);
-  else
-    rolist[slot]->uh = NULL;
+  rolist[slot]->uh = getsstring(host, USERLEN+1+HOSTLEN);
 
   return 1;
 }
index 0d3b0db013ecba8fdb18f3858f74a379ac05fe01..21d4074ab2aba0ca691500c686de84f291c89d14 100644 (file)
@@ -40,9 +40,6 @@ extern int cfnext;
 /* if you lose a channel after 30 minutes then
    you really don't need a channel at all */
 #define CFMINSCORE 6
-/* a user needs this many points to have his account/host
-   stored in the regop struct */
-#define CFMINSCOREUH 48
 /* chanfix won't ever reop more users than this */
 #define CFMAXOPS 10
 /* where we store our chanfix data */
index e02e1db8880f4513561c891be928c6bfcd8f2672..d6bfe68fbe22d7c0c11f1fa8bcb17776c61ed502 100644 (file)
@@ -99,6 +99,9 @@
 
 #define HOOK_SIGNONTRACKER_HAVETIME 1100 /* Argument is nick* */
 
+#define HOOK_WHOWAS_NEWRECORD      1200 /* Argument is void*[2] (whowas *, nick *) */
+#define HOOK_WHOWAS_LOSTRECORD     1201 /* Argument is whowas * */
+
 #define PRIORITY_DEFAULT           0
 
 #define PRIORITY_MAX               LONG_MIN
index c511bdb9889d31626921f40f2153dce24a4a6edf..edc0ebce016d081846471e587669c22a47209071 100644 (file)
@@ -152,4 +152,5 @@ void printuser(searchCtx *ctx, nick *sender, authname *aup) {
 
 void printwhowas(searchCtx *ctx, nick *sender, whowas *ww) {
   ctx->reply(sender,"%s", whowas_format(ww));
+  ctx->reply(sender,"%s", whowas_formatchannels(ww));
 }
index 6e764b04b217a39f41bcffb20c9f99c23871ab12..7a0b5a4e4d2a95cbf057a1faa89ecd439c9fa7ab 100644 (file)
@@ -2,6 +2,7 @@
  * age functionality
  */
 
+#include "../irc/irc.h"
 #include "newsearch.h"
 
 #include <stdio.h>
index aff9886d4bed167698846efecf57fed9a167ebb6..eb44078657c3f58139700a1ca2f5308cc984c012 100644 (file)
@@ -86,7 +86,7 @@ void *server_exe_str(searchCtx *ctx, struct searchNode *thenode, void *theinput)
   sstring *n = serverlist[homeserver(np->numeric)].name;
 
   if(!n)
-    return NULL;
+    return "";
 
   return n->content;
 }
index 33e32386cfb23b782698c0fe45badd25ccf65a5f..0235fa7419ca291191537bf71a2aab4b6f6e6e8b 100644 (file)
@@ -465,6 +465,9 @@ void clearcloaktargets(nick *cloaked)
   nick *tnp;
   int j;
 
+  if (cloaked->cloak_count == 0)
+    return;
+
   for(j=0;j<NICKHASHSIZE;j++)
     for(tnp=nicktable[j];tnp;tnp=tnp->next)
       if (tnp->cloak_extra == cloaked)
index 73ec6886331c57ea97a38918da63a5b0f49fde52..b67d1441c0638f1e9ea57b9485adaf4fbb7b1557 100644 (file)
@@ -1,8 +1,11 @@
+#include "../lib/version.h"
 #include "../control/control.h"
 #include "../lib/irc_string.h"
 #include "../core/config.h"
 #include "trusts.h"
 
+MODULE_VERSION("");
+
 int trusts_migration_start(TrustDBMigrationCallback, void *);
 void trusts_migration_stop(void);
 static void registercommands(int, void *);
index d144a691c02266fd2aa1c48dc9341a3b5def144a..2346b397f1cb810b3c213a5b8ee4e6da1804c7ef 100644 (file)
@@ -1,7 +1,9 @@
 include ../build.mk
 .PHONY: all
-all: whowas.so whowas_commands.so
+all: whowas.so whowas_channels.so whowas_commands.so
 
 whowas.so: whowas.o
 
+whowas_channels.so: whowas_channels.o
+
 whowas_commands.so: whowas_commands.o
index c2cece6d743f41be19dd10763a06871e9545faf4..5764ecac0bd154b3a9e5da11d1a6741796f77f53 100644 (file)
@@ -16,6 +16,7 @@ whowas *whowas_fromnick(nick *np, int standalone) {
   whowas *ww;
   nick *wnp;
   struct irc_in_addr ipaddress_canonical;
+  void *args[2];
 
   /* Create a new record. */
   if (standalone)
@@ -66,6 +67,10 @@ whowas *whowas_fromnick(nick *np, int standalone) {
   ww->timestamp = getnettime();
   ww->type = WHOWAS_USED;
 
+  args[0] = ww;
+  args[1] = np;
+  triggerhook(HOOK_WHOWAS_NEWRECORD, args);
+
   return ww;
 }
 
@@ -75,6 +80,8 @@ void whowas_clean(whowas *ww) {
   if (!ww || ww->type == WHOWAS_UNUSED)
     return;
 
+  triggerhook(HOOK_WHOWAS_LOSTRECORD, ww);
+
   np = &ww->nick;
   freesstring(np->host->name);
   freehost(np->host);
@@ -184,6 +191,32 @@ const char *whowas_format(whowas *ww) {
   return buf;
 }
 
+const char *whowas_formatchannels(whowas *ww) {
+  static char buf[512];
+  int i, first = 1;
+
+  strcpy(buf, "Channels: ");
+
+  for (i = 0; i < WW_MAXCHANNELS; i++) {
+    if (!ww->channels[i])
+      break;
+
+    if (!first)
+      strncat(buf, ", ", sizeof(buf));
+    else
+      first = 0;
+
+    strncat(buf, ww->channels[i]->name->content, sizeof(buf));
+  }
+
+  if (!ww->channels[0])
+    strncat(buf, "(No channels.)", sizeof(buf));
+
+  buf[sizeof(buf) - 1] = '\0';
+
+  return buf;
+}
+
 unsigned int nextwhowasmarker() {
   whowas *ww;
   int i;
@@ -205,6 +238,8 @@ unsigned int nextwhowasmarker() {
 }
 
 void _init(void) {
+  memset(whowasrecs, 0, sizeof(whowasrecs));
+
   registerhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
   registerhook(HOOK_NICK_KILL, whowas_handlequitorkill);
   registerhook(HOOK_NICK_RENAME, whowas_handlerename);
index b24aff30523597c84946f4f7f6e8ac67e4c1a0e1..8d02892a7f1f8e6c73006b0917de1b08bcd23bf5 100644 (file)
@@ -2,7 +2,8 @@
 #define __WHOWAS_H
 
 #define WW_MAXAGE 3600
-#define WW_MAXENTRIES 250000
+#define WW_MAXCHANNELS 20
+#define WW_MAXENTRIES 100000
 #define WW_MASKLEN (HOSTLEN + USERLEN + NICKLEN)
 #define WW_REASONLEN 512
 
@@ -10,6 +11,7 @@ typedef struct whowas {
   int type;
   time_t timestamp;
   nick nick; /* unlinked nick */
+  chanindex *channels[WW_MAXCHANNELS];
 
   /* WHOWAS_QUIT or WHOWAS_KILL */
   sstring *reason;
@@ -37,6 +39,7 @@ nick *whowas_tonick(whowas *ww);
 void whowas_freenick(nick *np);
 whowas *whowas_chase(const char *target, int maxage);
 const char *whowas_format(whowas *ww);
+const char *whowas_formatchannels(whowas *ww);
 void whowas_clean(whowas *ww);
 void whowas_free(whowas *ww);
 
diff --git a/whowas/whowas_channels.c b/whowas/whowas_channels.c
new file mode 100644 (file)
index 0000000..0813bcb
--- /dev/null
@@ -0,0 +1,117 @@
+#include <string.h>
+#include <assert.h>
+#include "../lib/version.h"
+#include "../nick/nick.h"
+#include "../chanindex/chanindex.h"
+#include "../channel/channel.h"
+#include "../core/hooks.h"
+#include "whowas.h"
+
+MODULE_VERSION("");
+
+static int wwcnext, wwccext;
+
+static void wwc_refchannel(chanindex *cip) {
+  uintptr_t *refcount = (uintptr_t *)&cip->exts[wwccext];
+  (*refcount)++;
+}
+
+static void wwc_derefchannel(chanindex *cip) {
+  uintptr_t *refcount = (uintptr_t *)&cip->exts[wwccext];
+  (*refcount)--;
+
+  assert(*refcount >= 0);
+
+  if (*refcount == 0)
+    releasechanindex(cip);
+}
+
+static void wwc_hook_joincreate(int hooknum, void *arg) {
+  void **args = arg;
+  channel *cp = args[0];
+  nick *np = args[1];
+  chanindex **wchans = np->exts[wwcnext];
+
+  if (!wchans) {
+    wchans = calloc(sizeof(chanindex *), WW_MAXCHANNELS);
+    np->exts[wwcnext] = wchans;
+  }
+
+  wwc_refchannel(cp->index);
+
+  memmove(&wchans[1], &wchans[0], sizeof(chanindex *) * (WW_MAXCHANNELS - 1));
+  wchans[0] = cp->index;
+}
+
+static void wwc_hook_lostnick(int hooknum, void *arg) {
+  nick *np = arg;
+  chanindex **wchans = np->exts[wwcnext];
+  int i;
+
+  if (!wchans)
+    return;
+
+  for (i = 0; i < WW_MAXCHANNELS; i++) {
+    if (!wchans[i])
+      break;
+
+    wwc_derefchannel(wchans[i]);
+  }
+
+  free(wchans);
+}
+
+static void wwc_hook_newrecord(int hooknum, void *arg) {
+  void **args = arg;
+  whowas *ww = args[0];
+  nick *np = args[1];
+  chanindex **wchans = np->exts[wwcnext];
+  int i;
+
+  memset(ww->channels, 0, sizeof(ww->channels));
+
+  if (!wchans)
+    return;
+
+  for (i = 0; i < WW_MAXCHANNELS; i++) {
+    if (!wchans[i])
+      break;
+
+    wwc_refchannel(wchans[i]);
+    ww->channels[i] = wchans[i];
+  }
+}
+
+static void wwc_hook_lostrecord(int hooknum, void *arg) {
+  whowas *ww = arg;
+  int i;
+
+  for (i = 0; i < WW_MAXCHANNELS; i++) {
+    if (!ww->channels[i])
+      break;
+
+    wwc_derefchannel(ww->channels[i]);
+  }
+}
+
+void _init(void) {
+  wwcnext = registernickext("whowas_channels");
+  wwccext = registerchanext("whowas_channels");
+
+  registerhook(HOOK_CHANNEL_JOIN, &wwc_hook_joincreate);
+  registerhook(HOOK_CHANNEL_CREATE, &wwc_hook_joincreate);
+  registerhook(HOOK_NICK_LOSTNICK, &wwc_hook_lostnick);
+  registerhook(HOOK_WHOWAS_NEWRECORD, &wwc_hook_newrecord);
+  registerhook(HOOK_WHOWAS_LOSTRECORD, &wwc_hook_lostrecord);
+}
+
+void _fini(void) {
+  releasenickext(wwcnext);
+  releasechanext(wwccext);
+
+  deregisterhook(HOOK_CHANNEL_JOIN, &wwc_hook_joincreate);
+  deregisterhook(HOOK_CHANNEL_CREATE, &wwc_hook_joincreate);
+  deregisterhook(HOOK_NICK_LOSTNICK, &wwc_hook_lostnick);
+  deregisterhook(HOOK_WHOWAS_NEWRECORD, &wwc_hook_newrecord);
+  deregisterhook(HOOK_WHOWAS_LOSTRECORD, &wwc_hook_lostrecord);
+}
index 946111ea52166b60e5e497fa60425e19bcfdfbf2..50337b4c52a9704f2f138abba0ddc6bfeaa38c91 100644 (file)
@@ -38,9 +38,10 @@ static int whowas_cmdwhowas(void *source, int cargc, char **cargv) {
     if (match2strings(pattern, hostmask)) {
       matches++;
 
-      if (matches <= limit)
+      if (matches <= limit) {
         controlreply(sender, "%s", whowas_format(ww));
-      else if (matches == limit + 1)
+        controlreply(sender, "%s", whowas_formatchannels(ww));
+      } else if (matches == limit + 1)
         controlreply(sender, "--- More than %d matches, skipping the rest", limit);
     }
   }
@@ -65,6 +66,7 @@ static int whowas_cmdwhowaschase(void *source, int cargc, char **cargv) {
   }
 
   controlreply(sender, "%s", whowas_format(ww));
+  controlreply(sender, "%s", whowas_formatchannels(ww));
   controlreply(sender, "Done.");
 
   return CMD_OK;