2 #include "../lib/irc_string.h"
6 static void cleanupdb(void *arg
);
7 static void schedulecleanup(int hooknum
, void *arg
);
9 static unsigned int cleanupdb_active
;
10 static DBModuleIdentifier q9cleanupdbid
;
13 q9cleanupdbid
= dbgetid();
15 registerhook(HOOK_CHANSERV_DBLOADED
, schedulecleanup
);
18 schedulecleanup(HOOK_CHANSERV_DBLOADED
, NULL
);
22 deleteallschedules(cleanupdb
);
23 dbfreeid(q9cleanupdbid
);
26 static void schedulecleanup(int hooknum
, void *arg
) {
27 /* run at 1am but only if we're more than 15m away from it, otherwise run tomorrow */
29 time_t t
= time(NULL
);
30 time_t next_run
= ((t
/ 86400) * 86400 + 86400) + 3600;
31 if(next_run
- t
< 900)
34 schedulerecurring(next_run
,0,86400,cleanupdb
,NULL
);
37 __attribute__ ((format (printf
, 1, 2)))
38 static void cleanuplog(char *format
, ...) {
43 vsnprintf(buf
, sizeof(buf
), format
, va
);
46 cs_log(NULL
, "CLEANUPDB %s", buf
);
47 chanservwallmessage("CLEANUPDB: %s", buf
);
50 static void cleanupdb_real(DBConn
*dbconn
, void *arg
) {
51 reguser
*vrup
, *srup
, *founder
;
52 regchanuser
*rcup
, *nrcup
;
55 time_t t
, to_age
, unused_age
, maxchan_age
, authhistory_age
;
56 int expired
= 0, unauthed
= 0, chansvaped
= 0;
57 chanindex
*cip
, *ncip
;
60 unsigned int themarker
;
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);
69 themarker
=nextauthnamemarker();
72 cleanuplog("No DB connection, aborting.");
76 pgres
=dbgetresult(dbconn
);
78 if (!dbquerysuccessful(pgres
)) {
79 cleanuplog("DB error, aborting.");
83 while (dbfetchrow(pgres
)) {
84 id
=strtoul(dbgetvalue(pgres
, 0), NULL
, 10);
87 anp
->marker
=themarker
;
92 cleanuplog("Phase 1 complete, starting phase 2 (regusers scan)...");
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 */
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
)
105 if(!anp
->nicks
&& !UHasStaffPriv(vrup
) && !UIsCleanupExempt(vrup
)) {
106 if(vrup
->lastauth
&& (vrup
->lastauth
< to_age
)) {
108 cs_log(NULL
, "CLEANUPDB inactive user %s %u", vrup
->username
, vrup
->ID
);
109 } else if(!vrup
->lastauth
&& (vrup
->created
< unused_age
)) {
111 cs_log(NULL
, "CLEANUPDB unused user %s %u", vrup
->username
, vrup
->ID
);
121 cleanuplog("Phase 2 complete, starting phase 3 (chanindex scan)...");
123 for (i
=0;i
<CHANNELHASHSIZE
;i
++) {
124 for (cip
=chantable
[i
];cip
;cip
=ncip
) {
126 if (!(rcp
=cip
->exts
[chanservext
]))
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.
133 /* this is one possible soln but relies on cleanupdb being run more frequently than
136 /* slug: no longer required as we scan the entire network every 1h (cs_hourlyfunc) */
138 if(cip->channel && cs_ischannelactive(cip->channel, rcp)) {
140 if (rcp->lastcountersync < (t - COUNTERSYNCINTERVAL)) {
141 csdb_updatechannelcounters(rcp);
142 rcp->lastcountersync=t;
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
))
153 cs_log(NULL
, "CLEANUPDB inactive channel %s", cip
->name
?cip
->name
->content
:"??");
154 cs_removechannel(rcp
, "Channel deleted due to lack of activity.");
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
;
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
);
173 cleanuplog("Phase 3 complete, starting phase 4 (history database cleanup) -- runs in the background.");
175 csdb_cleanuphistories(authhistory_age
);
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
);
183 void cs_cleanupdb(nick
*np
) {
187 static void cleanupdb(void *arg
) {
189 nick
*np
= (nick
*)arg
;
191 to_age
= time(NULL
) - (CLEANUP_ACCOUNT_INACTIVE
* 3600 * 24);
194 cleanuplog("Manually started by %s.", np
->nick
);
196 cleanuplog("Automatically started.");
199 if (cleanupdb_active
) {
200 cleanuplog("ABORTED! Cleanup already in progress! BUG BUG BUG!");
204 cleanuplog("Phase 1 started (auth history data retrieval)...");
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. */
209 q9cleanup_asyncquery(cleanupdb_real
, NULL
,
210 "SELECT userID from chanserv.authhistory WHERE disconnecttime=0 OR disconnecttime > %d GROUP BY userID", to_age
);