]> jfr.im git - irc/quakenet/newserv.git/blobdiff - chanserv/usercmds/cleanupdb.c
CHANSERV: only update channels as active if they have at least one known op, and...
[irc/quakenet/newserv.git] / chanserv / usercmds / cleanupdb.c
index 7378cf9ad3c5c5e3f1bf859c2f3ffed60957bc32..0dfb3e1052cc4b7e45cd2ba71618beaf18e66651 100644 (file)
 #include <stdio.h>
 #include <string.h>
 
-int csu_docleanupdb(void *source, int cargc, char **cargv) {
-  nick *sender=source;
+unsigned int cleanupdb_active;
+
+void csu_docleanupdb_real(DBConn *dbconn, void *arg) {
+  nick *sender=getnickbynumeric((unsigned long)arg);
   reguser *vrup, *srup, *founder;
   regchanuser *rcup, *nrcup;
   authname *anp;
   int i,j;
-  time_t t;
-  long to_age, unused_age, maxchan_age;
+  time_t t, to_age, unused_age, maxchan_age, authhistory_age;
   int expired = 0, unauthed = 0, chansvaped = 0;
   chanindex *cip, *ncip;
   regchan *rcp;
-
+  DBResult *pgres;
+  unsigned int themarker;
+  unsigned int id;
+  
   t = time(NULL);
   to_age = t - (CLEANUP_ACCOUNT_INACTIVE * 3600 * 24);  
   unused_age = t - (CLEANUP_ACCOUNT_UNUSED * 3600 * 24);
   maxchan_age = t - (CLEANUP_CHANNEL_INACTIVE * 3600 * 24);
+  authhistory_age = t - (CLEANUP_AUTHHISTORY * 3600 * 24);
+
+  themarker=nextauthnamemarker();
+  
+  if (!dbconn) {
+    if (sender)
+      chanservsendmessage(sender, "No DB connection, aborting cleanup.");
+    goto out;
+  }
+
+  pgres=dbgetresult(dbconn);
+  
+  if (!dbquerysuccessful(pgres)) {
+    Error("chanserv", ERR_ERROR, "Error loading cleanupdb data.");
+    if (sender) 
+      chanservsendmessage(sender, "DB error, aborting cleanup.");
+    goto out;
+  }
+  
+  while (dbfetchrow(pgres)) {
+    id=strtoul(dbgetvalue(pgres, 0), NULL, 10);
+    anp=findauthname(id);
+    if (anp)
+      anp->marker=themarker;
+  }
+  
+  dbclear(pgres);
 
   cs_log(sender, "CLEANUPDB started");
 
-  chanservsendmessage(sender, "Scanning regusers...");
+  if (sender)
+    chanservsendmessage(sender, "Scanning regusers...");
   for (i=0;i<REGUSERHASHSIZE;i++) {
     for (vrup=regusernicktable[i]; vrup; vrup=srup) {
       srup=vrup->nextbyname;
       if (!(anp=findauthname(vrup->ID)))
         continue; /* should maybe raise hell instead */
 
-      if(!anp->nicks && !UHasHelperPriv(vrup) && !UIsCleanupExempt(vrup)) {
+      /* If this user has the right marker, this means the authtracker data
+       * indicates that they have been active recently */
+      if (anp->marker == themarker)
+        continue;
+
+      if(!anp->nicks && !UHasStaffPriv(vrup) && !UIsCleanupExempt(vrup)) {
         if(vrup->lastauth && (vrup->lastauth < to_age)) {
           expired++;
-          cs_log(sender, "CLEANUPDB inactive user %s", vrup->username);
+          cs_log(sender, "CLEANUPDB inactive user %s %u", vrup->username, vrup->ID);
         } else if(!vrup->lastauth && (vrup->created < unused_age)) {
           unauthed++;
-          cs_log(sender, "CLEANUPDB unused user %s", vrup->username);
+          cs_log(sender, "CLEANUPDB unused user %s %u", vrup->username, vrup->ID);
         } else {
           continue;
         }
@@ -58,13 +95,30 @@ int csu_docleanupdb(void *source, int cargc, char **cargv) {
     }
   }
 
-  chanservsendmessage(sender, "Scanning chanindicies...");
+  if (sender)
+    chanservsendmessage(sender, "Scanning chanindicies...");
+    
   for (i=0;i<CHANNELHASHSIZE;i++) {
     for (cip=chantable[i];cip;cip=ncip) {
       ncip=cip->next;
       if (!(rcp=cip->exts[chanservext]))
         continue;
 
+      /* there's a bug here... if no joins or modes are done within the threshold
+       * and someone leaves just before the cleanup then the channel will be nuked.
+       */
+
+      /* this is one possible soln but relies on cleanupdb being run more frequently than
+       * the threshold:
+       */ 
+      if(cip->channel && cs_ischannelactive(cip->channel, rcp)) {
+        rcp->lastactive = t;
+        if (rcp->lastcountersync < (t - COUNTERSYNCINTERVAL)) {
+          csdb_updatechannelcounters(rcp);
+          rcp->lastcountersync=t;
+        }
+      }
+
       if(rcp->lastactive < maxchan_age) {
         /* don't remove channels with the original founder as an oper */
         founder=findreguserbyID(rcp->founder);
@@ -72,7 +126,7 @@ int csu_docleanupdb(void *source, int cargc, char **cargv) {
           continue;
 
         cs_log(sender, "CLEANUPDB inactive channel %s", cip->name?cip->name->content:"??");
-        cs_removechannel(rcp);
+        cs_removechannel(rcp, "Channel deleted due to lack of activity.");
         chansvaped++;
       }
       
@@ -82,7 +136,8 @@ int csu_docleanupdb(void *source, int cargc, char **cargv) {
           nrcup=rcup->nextbychan;
           
           if (!rcup->flags) {
-            chanservsendmessage(sender, "Removing user %s from channel %s (no flags)",rcup->user->username,rcp->index->name->content);
+            if (sender)
+              chanservsendmessage(sender, "Removing user %s from channel %s (no flags)",rcup->user->username,rcp->index->name->content);
             csdb_deletechanuser(rcup);
             delreguserfromchannel(rcp, rcup->user);
           }
@@ -91,7 +146,40 @@ int csu_docleanupdb(void *source, int cargc, char **cargv) {
     }
   }
   
+  if (sender)
+    chanservsendmessage(sender, "Starting history database cleanup (will run in background).");
+    
+  csdb_cleanuphistories(authhistory_age);
+  
   cs_log(sender, "CLEANUPDB complete %d inactive accounts %d unused accounts %d channels", expired, unauthed, chansvaped);
-  chanservsendmessage(sender, "Cleanup complete, %d accounts inactive for %d days, %d accounts weren't used within %d days, %d channels were inactive for %d days.", expired, CLEANUP_ACCOUNT_INACTIVE, unauthed, CLEANUP_ACCOUNT_UNUSED, chansvaped, CLEANUP_CHANNEL_INACTIVE);
+  if (sender)
+    chanservsendmessage(sender, "Cleanup complete, %d accounts inactive for %d days, %d accounts weren't used within %d days, %d channels were inactive for %d days.", expired, CLEANUP_ACCOUNT_INACTIVE, unauthed, CLEANUP_ACCOUNT_UNUSED, chansvaped, CLEANUP_CHANNEL_INACTIVE);
+
+out:
+  cleanupdb_active=0;
+}
+
+int csu_docleanupdb(void *source, int cargc, char **cargv) {
+  nick *sender=source;
+  unsigned int to_age;
+  
+  to_age = time(NULL) - (CLEANUP_ACCOUNT_INACTIVE * 3600 * 24);
+  
+  if (cleanupdb_active) {
+    chanservsendmessage(sender, "Cleanup already in progress.\n");
+    return CMD_ERROR;
+  }
+
+  /* This query returns a single column containing the userids of all users
+   * who have active sessions now, or sessions which ended in the last
+   * CLEANUP_ACCOUNT_INACTIVE days.  */
+  q9u_asyncquery(csu_docleanupdb_real, (void *)sender->numeric,
+    "SELECT userID from chanserv.authhistory WHERE disconnecttime=0 OR disconnecttime > %d GROUP BY userID", to_age);
+  
+  chanservsendmessage(sender, "Retrieving auth history data, cleanup will proceed when done.");
+  
+  cleanupdb_active=1;
+  
   return CMD_OK;
 }
+