]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands/cmd_whowas.cpp
Merge pull request #301 from Adam-/insp20+bindrehash
[user/henk/code/inspircd.git] / src / commands / cmd_whowas.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
6  *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
7  *   Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
8  *
9  * This file is part of InspIRCd.  InspIRCd is free software: you can
10  * redistribute it and/or modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation, version 2.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "inspircd.h"
24 #include "commands/cmd_whowas.h"
25
26 WhoWasMaintainTimer * timer;
27
28 CommandWhowas::CommandWhowas( Module* parent) : Command(parent, "WHOWAS", 1)
29 {
30         syntax = "<nick>{,<nick>}";
31         Penalty = 2;
32         timer = new WhoWasMaintainTimer(3600);
33         ServerInstance->Timers->AddTimer(timer);
34 }
35
36 CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, User* user)
37 {
38         /* if whowas disabled in config */
39         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
40         {
41                 user->WriteNumeric(421, "%s %s :This command has been disabled.",user->nick.c_str(),name.c_str());
42                 return CMD_FAILURE;
43         }
44
45         whowas_users::iterator i = whowas.find(assign(parameters[0]));
46
47         if (i == whowas.end())
48         {
49                 user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str());
50                 user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
51                 return CMD_FAILURE;
52         }
53         else
54         {
55                 whowas_set* grp = i->second;
56                 if (grp->size())
57                 {
58                         for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++)
59                         {
60                                 WhoWasGroup* u = *ux;
61                                 time_t rawtime = u->signon;
62                                 tm *timeinfo;
63                                 char b[25];
64
65                                 timeinfo = localtime(&rawtime);
66
67                                 strncpy(b,asctime(timeinfo),24);
68                                 b[24] = 0;
69
70                                 user->WriteNumeric(314, "%s %s %s %s * :%s",user->nick.c_str(),parameters[0].c_str(),
71                                         u->ident.c_str(),u->dhost.c_str(),u->gecos.c_str());
72
73                                 if (user->HasPrivPermission("users/auspex"))
74                                         user->WriteNumeric(379, "%s %s :was connecting from *@%s",
75                                                 user->nick.c_str(), parameters[0].c_str(), u->host.c_str());
76
77                                 if (!ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
78                                         user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), ServerInstance->Config->HideWhoisServer.c_str(), b);
79                                 else
80                                         user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), u->server.c_str(), b);
81                         }
82                 }
83                 else
84                 {
85                         user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str());
86                         user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
87                         return CMD_FAILURE;
88                 }
89         }
90
91         user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
92         return CMD_SUCCESS;
93 }
94
95 std::string CommandWhowas::GetStats()
96 {
97         int whowas_size = 0;
98         int whowas_bytes = 0;
99         whowas_users_fifo::iterator iter;
100         for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++)
101         {
102                 whowas_set* n = (whowas_set*)whowas.find(iter->second)->second;
103                 if (n->size())
104                 {
105                         whowas_size += n->size();
106                         whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) );
107                 }
108         }
109         return "Whowas entries: " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)";
110 }
111
112 void CommandWhowas::AddToWhoWas(User* user)
113 {
114         /* if whowas disabled */
115         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
116         {
117                 return;
118         }
119
120         whowas_users::iterator iter = whowas.find(irc::string(user->nick.c_str()));
121
122         if (iter == whowas.end())
123         {
124                 whowas_set* n = new whowas_set;
125                 WhoWasGroup *a = new WhoWasGroup(user);
126                 n->push_back(a);
127                 whowas[user->nick.c_str()] = n;
128                 whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick.c_str()));
129
130                 if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
131                 {
132                         whowas_users::iterator iter2 = whowas.find(whowas_fifo[0].second);
133                         if (iter2 != whowas.end())
134                         {
135                                 whowas_set* n2 = (whowas_set*)iter2->second;
136
137                                 if (n2->size())
138                                 {
139                                         while (n2->begin() != n2->end())
140                                         {
141                                                 WhoWasGroup *a2 = *(n2->begin());
142                                                 delete a2;
143                                                 n2->pop_front();
144                                         }
145                                 }
146
147                                 delete n2;
148                                 whowas.erase(iter2);
149                         }
150                         whowas_fifo.pop_front();
151                 }
152         }
153         else
154         {
155                 whowas_set* group = (whowas_set*)iter->second;
156                 WhoWasGroup *a = new WhoWasGroup(user);
157                 group->push_back(a);
158
159                 if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)
160                 {
161                         WhoWasGroup *a2 = (WhoWasGroup*)*(group->begin());
162                         delete a2;
163                         group->pop_front();
164                 }
165         }
166 }
167
168 /* on rehash, refactor maps according to new conf values */
169 void CommandWhowas::PruneWhoWas(time_t t)
170 {
171         /* config values */
172         int groupsize = ServerInstance->Config->WhoWasGroupSize;
173         int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
174         int maxkeep =   ServerInstance->Config->WhoWasMaxKeep;
175
176         /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
177         whowas_users::iterator iter;
178         int fifosize;
179         while ((fifosize = (int)whowas_fifo.size()) > 0)
180         {
181                 if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)
182                 {
183                         iter = whowas.find(whowas_fifo[0].second);
184
185                         /* hopefully redundant integrity check, but added while debugging r6216 */
186                         if (iter == whowas.end())
187                         {
188                                 /* this should never happen, if it does maps are corrupt */
189                                 ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (1)");
190                                 return;
191                         }
192
193                         whowas_set* n = (whowas_set*)iter->second;
194
195                         if (n->size())
196                         {
197                                 while (n->begin() != n->end())
198                                 {
199                                         WhoWasGroup *a = *(n->begin());
200                                         delete a;
201                                         n->pop_front();
202                                 }
203                         }
204
205                         delete n;
206                         whowas.erase(iter);
207                         whowas_fifo.pop_front();
208                 }
209                 else
210                         break;
211         }
212
213         /* Then cut the whowas sets to new size (groupsize) */
214         fifosize = (int)whowas_fifo.size();
215         for (int i = 0; i < fifosize; i++)
216         {
217                 iter = whowas.find(whowas_fifo[0].second);
218                 /* hopefully redundant integrity check, but added while debugging r6216 */
219                 if (iter == whowas.end())
220                 {
221                         /* this should never happen, if it does maps are corrupt */
222                         ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (2)");
223                         return;
224                 }
225                 whowas_set* n = (whowas_set*)iter->second;
226                 if (n->size())
227                 {
228                         int nickcount = n->size();
229                         while (n->begin() != n->end() && nickcount > groupsize)
230                         {
231                                 WhoWasGroup *a = *(n->begin());
232                                 delete a;
233                                 n->pop_front();
234                                 nickcount--;
235                         }
236                 }
237         }
238 }
239
240 /* call maintain once an hour to remove expired nicks */
241 void CommandWhowas::MaintainWhoWas(time_t t)
242 {
243         for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++)
244         {
245                 whowas_set* n = (whowas_set*)iter->second;
246                 if (n->size())
247                 {
248                         while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))
249                         {
250                                 WhoWasGroup *a = *(n->begin());
251                                 delete a;
252                                 n->erase(n->begin());
253                         }
254                 }
255         }
256 }
257
258 CommandWhowas::~CommandWhowas()
259 {
260         if (timer)
261         {
262                 ServerInstance->Timers->DelTimer(timer);
263         }
264
265         whowas_users::iterator iter;
266         int fifosize;
267         while ((fifosize = (int)whowas_fifo.size()) > 0)
268         {
269                 iter = whowas.find(whowas_fifo[0].second);
270
271                 /* hopefully redundant integrity check, but added while debugging r6216 */
272                 if (iter == whowas.end())
273                 {
274                         /* this should never happen, if it does maps are corrupt */
275                         ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (3)");
276                         return;
277                 }
278
279                 whowas_set* n = (whowas_set*)iter->second;
280
281                 if (n->size())
282                 {
283                         while (n->begin() != n->end())
284                         {
285                                 WhoWasGroup *a = *(n->begin());
286                                 delete a;
287                                 n->pop_front();
288                         }
289                 }
290
291                 delete n;
292                 whowas.erase(iter);
293                 whowas_fifo.pop_front();
294         }
295 }
296
297 WhoWasGroup::WhoWasGroup(User* user) : host(user->host), dhost(user->dhost), ident(user->ident),
298         server(user->server), gecos(user->fullname), signon(user->signon)
299 {
300 }
301
302 WhoWasGroup::~WhoWasGroup()
303 {
304 }
305
306 /* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
307 void WhoWasMaintainTimer::Tick(time_t)
308 {
309         Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so");
310         if (whowas)
311         {
312                 WhowasRequest(whowas, whowas, WhowasRequest::WHOWAS_MAINTAIN).Send();
313         }
314 }
315
316 class ModuleWhoWas : public Module
317 {
318         CommandWhowas cmd;
319  public:
320         ModuleWhoWas() : cmd(this)
321         {
322                 ServerInstance->AddCommand(&cmd);
323         }
324
325         void OnRequest(Request& request)
326         {
327                 WhowasRequest& req = static_cast<WhowasRequest&>(request);
328                 switch (req.type)
329                 {
330                         case WhowasRequest::WHOWAS_ADD:
331                                 cmd.AddToWhoWas(req.user);
332                                 break;
333                         case WhowasRequest::WHOWAS_STATS:
334                                 req.value = cmd.GetStats();
335                                 break;
336                         case WhowasRequest::WHOWAS_PRUNE:
337                                 cmd.PruneWhoWas(ServerInstance->Time());
338                                 break;
339                         case WhowasRequest::WHOWAS_MAINTAIN:
340                                 cmd.MaintainWhoWas(ServerInstance->Time());
341                                 break;
342                 }
343         }
344
345         Version GetVersion()
346         {
347                 return Version("WHOWAS Command", VF_VENDOR);
348         }
349 };
350
351 MODULE_INIT(ModuleWhoWas)