]> jfr.im git - irc/quakenet/newserv.git/blame - chanserv/chanserv_cleanupdb.c
CHANSERV: fix 7h cleanup time
[irc/quakenet/newserv.git] / chanserv / chanserv_cleanupdb.c
CommitLineData
46542548
CP
1#include "chanserv.h"
2#include "../lib/irc_string.h"
3#include <stdio.h>
4#include <string.h>
5
6static void cleanupdb(void *arg);
7static void schedulecleanup(int hooknum, void *arg);
8
9static unsigned int cleanupdb_active;
10static DBModuleIdentifier q9cleanupdbid;
11
12void _init() {
13 q9cleanupdbid = dbgetid();
14
15 registerhook(HOOK_CHANSERV_DBLOADED, schedulecleanup);
16
17 if (chanservdb_ready)
18 schedulecleanup(HOOK_CHANSERV_DBLOADED, NULL);
19}
20
21void _fini() {
22 deleteallschedules(cleanupdb);
23 dbfreeid(q9cleanupdbid);
24}
25
26static void schedulecleanup(int hooknum, void *arg) {
321f10c6 27 /* run at 1am but only if we're more than 15m away from it, otherwise run tomorrow */
46542548
CP
28
29 time_t t = time(NULL);
321f10c6
CP
30 time_t next_run = ((t / 86400) * 86400 + 86400) + 3600;
31 if(next_run - t < 900)
32 next_run+=86400;
33
34 schedulerecurring(next_run,0,86400,cleanupdb,NULL);
46542548
CP
35}
36
37__attribute__ ((format (printf, 1, 2)))
38static void cleanuplog(char *format, ...) {
39 char buf[512];
40 va_list va;
41
42 va_start(va, format);
43 vsnprintf(buf, sizeof(buf), format, va);
44 va_end(va);
45
46 cs_log(NULL, "CLEANUPDB %s", buf);
47 chanservwallmessage("CLEANUPDB: %s", buf);
48}
49
50static void cleanupdb_real(DBConn *dbconn, void *arg) {
51 reguser *vrup, *srup, *founder;
52 regchanuser *rcup, *nrcup;
53 authname *anp;
54 int i,j;
55 time_t t, to_age, unused_age, maxchan_age, authhistory_age;
56 int expired = 0, unauthed = 0, chansvaped = 0;
57 chanindex *cip, *ncip;
58 regchan *rcp;
59 DBResult *pgres;
60 unsigned int themarker;
61 unsigned int id;
62
63 t = time(NULL);
64 to_age = t - (CLEANUP_ACCOUNT_INACTIVE * 3600 * 24);
65 unused_age = t - (CLEANUP_ACCOUNT_UNUSED * 3600 * 24);
66 maxchan_age = t - (CLEANUP_CHANNEL_INACTIVE * 3600 * 24);
67 authhistory_age = t - (CLEANUP_AUTHHISTORY * 3600 * 24);
68
69 themarker=nextauthnamemarker();
70
71 if (!dbconn) {
72 cleanuplog("No DB connection, aborting.");
73 goto out;
74 }
75
76 pgres=dbgetresult(dbconn);
77
78 if (!dbquerysuccessful(pgres)) {
79 cleanuplog("DB error, aborting.");
80 goto out;
81 }
82
83 while (dbfetchrow(pgres)) {
84 id=strtoul(dbgetvalue(pgres, 0), NULL, 10);
85 anp=findauthname(id);
86 if (anp)
87 anp->marker=themarker;
88 }
89
90 dbclear(pgres);
91
92 cleanuplog("Phase 1 complete, starting phase 2 (regusers scan)...");
93
94 for (i=0;i<REGUSERHASHSIZE;i++) {
95 for (vrup=regusernicktable[i]; vrup; vrup=srup) {
96 srup=vrup->nextbyname;
97 if (!(anp=findauthname(vrup->ID)))
98 continue; /* should maybe raise hell instead */
99
100 /* If this user has the right marker, this means the authtracker data
101 * indicates that they have been active recently */
102 if (anp->marker == themarker)
103 continue;
104
105 if(!anp->nicks && !UHasStaffPriv(vrup) && !UIsCleanupExempt(vrup)) {
106 if(vrup->lastauth && (vrup->lastauth < to_age)) {
107 expired++;
108 cs_log(NULL, "CLEANUPDB inactive user %s %u", vrup->username, vrup->ID);
109 } else if(!vrup->lastauth && (vrup->created < unused_age)) {
110 unauthed++;
111 cs_log(NULL, "CLEANUPDB unused user %s %u", vrup->username, vrup->ID);
112 } else {
113 continue;
114 }
115
116 cs_removeuser(vrup);
117 }
118 }
119 }
120
121 cleanuplog("Phase 2 complete, starting phase 3 (chanindex scan)...");
122
123 for (i=0;i<CHANNELHASHSIZE;i++) {
124 for (cip=chantable[i];cip;cip=ncip) {
125 ncip=cip->next;
126 if (!(rcp=cip->exts[chanservext]))
127 continue;
128
129 /* there's a bug here... if no joins or modes are done within the threshold
130 * and someone leaves just before the cleanup then the channel will be nuked.
131 */
132
133 /* this is one possible soln but relies on cleanupdb being run more frequently than
134 * the threshold:
135 */
321f10c6
CP
136 /* slug: no longer required as we scan the entire network every 1h (cs_hourlyfunc) */
137/*
46542548
CP
138 if(cip->channel && cs_ischannelactive(cip->channel, rcp)) {
139 rcp->lastactive = t;
140 if (rcp->lastcountersync < (t - COUNTERSYNCINTERVAL)) {
141 csdb_updatechannelcounters(rcp);
142 rcp->lastcountersync=t;
143 }
144 }
321f10c6 145*/
46542548
CP
146
147 if(rcp->lastactive < maxchan_age) {
148 /* don't remove channels with the original founder as an oper */
149 founder=findreguserbyID(rcp->founder);
150 if(founder && UHasOperPriv(founder))
151 continue;
152
153 cs_log(NULL, "CLEANUPDB inactive channel %s", cip->name?cip->name->content:"??");
154 cs_removechannel(rcp, "Channel deleted due to lack of activity.");
155 chansvaped++;
156 }
157
158 /* Get rid of any dead chanlev entries */
159 for (j=0;j<REGCHANUSERHASHSIZE;j++) {
160 for (rcup=rcp->regusers[j];rcup;rcup=nrcup) {
161 nrcup=rcup->nextbychan;
162
163 if (!rcup->flags) {
164 cs_log(NULL, "Removing user %s from channel %s (no flags)",rcup->user->username,rcp->index->name->content);
165 csdb_deletechanuser(rcup);
166 delreguserfromchannel(rcp, rcup->user);
167 }
168 }
169 }
170 }
171 }
172
173 cleanuplog("Phase 3 complete, starting phase 4 (history database cleanup) -- runs in the background.");
174
175 csdb_cleanuphistories(authhistory_age);
176
177 cleanuplog("Stats: %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);
178
179out:
180 cleanupdb_active=0;
181}
182
183void cs_cleanupdb(nick *np) {
184 cleanupdb(np);
185}
186
187static void cleanupdb(void *arg) {
188 unsigned int to_age;
189 nick *np = (nick *)arg;
190
191 to_age = time(NULL) - (CLEANUP_ACCOUNT_INACTIVE * 3600 * 24);
192
193 if(np) {
194 cleanuplog("Manually started by %s.", np->nick);
195 } else {
196 cleanuplog("Automatically started.");
197 }
198
199 if (cleanupdb_active) {
200 cleanuplog("ABORTED! Cleanup already in progress! BUG BUG BUG!");
201 return;
202 }
203
204 cleanuplog("Phase 1 started (auth history data retrieval)...");
205
206 /* This query returns a single column containing the userids of all users
207 * who have active sessions now, or sessions which ended in the last
208 * CLEANUP_ACCOUNT_INACTIVE days. */
1a17d1db
CP
209
210 dbquery("BEGIN TRANSACTION;");
211
212 /* increase memory for aggregate (GROUP BY) -- query can take hours if this spills to disk */
213 dbquery("SET LOCAL work_mem = '512MB';");
46542548 214 q9cleanup_asyncquery(cleanupdb_real, NULL,
1a17d1db
CP
215 "SELECT userID from chanserv.authhistory WHERE disconnecttime=0 OR disconnecttime > %d GROUP BY userID;", to_age);
216 dbquery("COMMIT;");
217
46542548
CP
218 cleanupdb_active=1;
219}