]> jfr.im git - irc/quakenet/newserv.git/blob - 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
1 /* Automatically generated by refactor.pl.
2 *
3 *
4 * CMDNAME: cleanupdb
5 * CMDLEVEL: QCMD_DEV
6 * CMDARGS: 0
7 * CMDDESC: Clean up database.
8 * CMDFUNC: csu_docleanupdb
9 * CMDPROTO: int csu_docleanupdb(void *source, int cargc, char **cargv);
10 * CMDHELP: Usage: cleanupdb
11 * CMDHELP: Cleans up inactive accounts, unused accounts and inactive channels.
12 */
13
14 #include "../chanserv.h"
15 #include "../../lib/irc_string.h"
16 #include <stdio.h>
17 #include <string.h>
18
19 unsigned int cleanupdb_active;
20
21 void csu_docleanupdb_real(DBConn *dbconn, void *arg) {
22 nick *sender=getnickbynumeric((unsigned long)arg);
23 reguser *vrup, *srup, *founder;
24 regchanuser *rcup, *nrcup;
25 authname *anp;
26 int i,j;
27 time_t t, to_age, unused_age, maxchan_age, authhistory_age;
28 int expired = 0, unauthed = 0, chansvaped = 0;
29 chanindex *cip, *ncip;
30 regchan *rcp;
31 DBResult *pgres;
32 unsigned int themarker;
33 unsigned int id;
34
35 t = time(NULL);
36 to_age = t - (CLEANUP_ACCOUNT_INACTIVE * 3600 * 24);
37 unused_age = t - (CLEANUP_ACCOUNT_UNUSED * 3600 * 24);
38 maxchan_age = t - (CLEANUP_CHANNEL_INACTIVE * 3600 * 24);
39 authhistory_age = t - (CLEANUP_AUTHHISTORY * 3600 * 24);
40
41 themarker=nextauthnamemarker();
42
43 if (!dbconn) {
44 if (sender)
45 chanservsendmessage(sender, "No DB connection, aborting cleanup.");
46 goto out;
47 }
48
49 pgres=dbgetresult(dbconn);
50
51 if (!dbquerysuccessful(pgres)) {
52 Error("chanserv", ERR_ERROR, "Error loading cleanupdb data.");
53 if (sender)
54 chanservsendmessage(sender, "DB error, aborting cleanup.");
55 goto out;
56 }
57
58 while (dbfetchrow(pgres)) {
59 id=strtoul(dbgetvalue(pgres, 0), NULL, 10);
60 anp=findauthname(id);
61 if (anp)
62 anp->marker=themarker;
63 }
64
65 dbclear(pgres);
66
67 cs_log(sender, "CLEANUPDB started");
68
69 if (sender)
70 chanservsendmessage(sender, "Scanning regusers...");
71 for (i=0;i<REGUSERHASHSIZE;i++) {
72 for (vrup=regusernicktable[i]; vrup; vrup=srup) {
73 srup=vrup->nextbyname;
74 if (!(anp=findauthname(vrup->ID)))
75 continue; /* should maybe raise hell instead */
76
77 /* If this user has the right marker, this means the authtracker data
78 * indicates that they have been active recently */
79 if (anp->marker == themarker)
80 continue;
81
82 if(!anp->nicks && !UHasStaffPriv(vrup) && !UIsCleanupExempt(vrup)) {
83 if(vrup->lastauth && (vrup->lastauth < to_age)) {
84 expired++;
85 cs_log(sender, "CLEANUPDB inactive user %s %u", vrup->username, vrup->ID);
86 } else if(!vrup->lastauth && (vrup->created < unused_age)) {
87 unauthed++;
88 cs_log(sender, "CLEANUPDB unused user %s %u", vrup->username, vrup->ID);
89 } else {
90 continue;
91 }
92
93 cs_removeuser(vrup);
94 }
95 }
96 }
97
98 if (sender)
99 chanservsendmessage(sender, "Scanning chanindicies...");
100
101 for (i=0;i<CHANNELHASHSIZE;i++) {
102 for (cip=chantable[i];cip;cip=ncip) {
103 ncip=cip->next;
104 if (!(rcp=cip->exts[chanservext]))
105 continue;
106
107 /* there's a bug here... if no joins or modes are done within the threshold
108 * and someone leaves just before the cleanup then the channel will be nuked.
109 */
110
111 /* this is one possible soln but relies on cleanupdb being run more frequently than
112 * the threshold:
113 */
114 if(cip->channel && cs_ischannelactive(cip->channel, rcp)) {
115 rcp->lastactive = t;
116 if (rcp->lastcountersync < (t - COUNTERSYNCINTERVAL)) {
117 csdb_updatechannelcounters(rcp);
118 rcp->lastcountersync=t;
119 }
120 }
121
122 if(rcp->lastactive < maxchan_age) {
123 /* don't remove channels with the original founder as an oper */
124 founder=findreguserbyID(rcp->founder);
125 if(founder && UHasOperPriv(founder))
126 continue;
127
128 cs_log(sender, "CLEANUPDB inactive channel %s", cip->name?cip->name->content:"??");
129 cs_removechannel(rcp, "Channel deleted due to lack of activity.");
130 chansvaped++;
131 }
132
133 /* Get rid of any dead chanlev entries */
134 for (j=0;j<REGCHANUSERHASHSIZE;j++) {
135 for (rcup=rcp->regusers[j];rcup;rcup=nrcup) {
136 nrcup=rcup->nextbychan;
137
138 if (!rcup->flags) {
139 if (sender)
140 chanservsendmessage(sender, "Removing user %s from channel %s (no flags)",rcup->user->username,rcp->index->name->content);
141 csdb_deletechanuser(rcup);
142 delreguserfromchannel(rcp, rcup->user);
143 }
144 }
145 }
146 }
147 }
148
149 if (sender)
150 chanservsendmessage(sender, "Starting history database cleanup (will run in background).");
151
152 csdb_cleanuphistories(authhistory_age);
153
154 cs_log(sender, "CLEANUPDB complete %d inactive accounts %d unused accounts %d channels", expired, unauthed, chansvaped);
155 if (sender)
156 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);
157
158 out:
159 cleanupdb_active=0;
160 }
161
162 int csu_docleanupdb(void *source, int cargc, char **cargv) {
163 nick *sender=source;
164 unsigned int to_age;
165
166 to_age = time(NULL) - (CLEANUP_ACCOUNT_INACTIVE * 3600 * 24);
167
168 if (cleanupdb_active) {
169 chanservsendmessage(sender, "Cleanup already in progress.\n");
170 return CMD_ERROR;
171 }
172
173 /* This query returns a single column containing the userids of all users
174 * who have active sessions now, or sessions which ended in the last
175 * CLEANUP_ACCOUNT_INACTIVE days. */
176 q9u_asyncquery(csu_docleanupdb_real, (void *)sender->numeric,
177 "SELECT userID from chanserv.authhistory WHERE disconnecttime=0 OR disconnecttime > %d GROUP BY userID", to_age);
178
179 chanservsendmessage(sender, "Retrieving auth history data, cleanup will proceed when done.");
180
181 cleanupdb_active=1;
182
183 return CMD_OK;
184 }
185