]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands/cmd_whowas.cpp
Wheee, mass commit! this adds const stafety, throwing a compile error if anyone does...
[user/henk/code/inspircd.git] / src / commands / cmd_whowas.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "commands/cmd_whowas.h"
16
17 WhoWasMaintainTimer * timer;
18
19 extern "C" DllExport Command* init_command(InspIRCd* Instance)
20 {
21         return new CommandWhowas(Instance);
22 }
23
24 CommandWhowas::CommandWhowas(InspIRCd* Instance) : Command(Instance, "WHOWAS", 0, 1, false, 2)
25 {
26         syntax = "<nick>{,<nick>}";
27         timer = new WhoWasMaintainTimer(Instance, 3600);
28         Instance->Timers->AddTimer(timer);
29 }
30
31 CmdResult CommandWhowas::Handle (const char* const* parameters, int, User* user)
32 {
33         /* if whowas disabled in config */
34         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
35         {
36                 user->WriteServ("421 %s %s :This command has been disabled.",user->nick,command.c_str());
37                 return CMD_FAILURE;
38         }
39
40         whowas_users::iterator i = whowas.find(parameters[0]);
41
42         if (i == whowas.end())
43         {
44                 user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);
45                 user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
46                 return CMD_FAILURE;
47         }
48         else
49         {
50                 whowas_set* grp = i->second;
51                 if (grp->size())
52                 {
53                         for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++)
54                         {
55                                 WhoWasGroup* u = *ux;
56                                 time_t rawtime = u->signon;
57                                 tm *timeinfo;
58                                 char b[MAXBUF];
59         
60                                 timeinfo = localtime(&rawtime);
61                                 
62                                 /* XXX - 'b' could be only 25 chars long and then strlcpy() would terminate it for us too? */
63                                 strlcpy(b,asctime(timeinfo),MAXBUF);
64                                 b[24] = 0;
65
66                                 user->WriteServ("314 %s %s %s %s * :%s",user->nick,parameters[0],u->ident,u->dhost,u->gecos);
67                                 
68                                 if (IS_OPER(user))
69                                         user->WriteServ("379 %s %s :was connecting from *@%s", user->nick, parameters[0], u->host);
70                                 
71                                 if (*ServerInstance->Config->HideWhoisServer && !IS_OPER(user))
72                                         user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], ServerInstance->Config->HideWhoisServer, b);
73                                 else
74                                         user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], u->server, b);
75                         }
76                 }
77                 else
78                 {
79                         user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);
80                         user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
81                         return CMD_FAILURE;
82                 }
83         }
84
85         user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
86         return CMD_SUCCESS;
87 }
88
89 CmdResult CommandWhowas::HandleInternal(const unsigned int id, const std::deque<classbase*> &parameters)
90 {
91         switch (id)
92         {
93                 case WHOWAS_ADD:
94                         AddToWhoWas((User*)parameters[0]);
95                 break;
96
97                 case WHOWAS_STATS:
98                         GetStats((Extensible*)parameters[0]);
99                 break;
100
101                 case WHOWAS_PRUNE:
102                         PruneWhoWas(ServerInstance->Time());
103                 break;
104
105                 case WHOWAS_MAINTAIN:
106                         MaintainWhoWas(ServerInstance->Time());
107                 break;
108
109                 default:
110                 break;
111         }
112         return CMD_SUCCESS;
113 }
114
115 void CommandWhowas::GetStats(Extensible* ext)
116 {
117         int whowas_size = 0;
118         int whowas_bytes = 0;
119         whowas_users_fifo::iterator iter;
120         for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++)
121         {
122                 whowas_set* n = (whowas_set*)whowas.find(iter->second)->second;
123                 if (n->size())
124                 {
125                         whowas_size += n->size();
126                         whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) );
127                 }
128         }
129         stats.assign("Whowas(MAPSETS) " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)");
130         ext->Extend("stats", stats.c_str());
131 }
132
133 void CommandWhowas::AddToWhoWas(User* user)
134 {
135         /* if whowas disabled */
136         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
137         {
138                 return;
139         }
140
141         whowas_users::iterator iter = whowas.find(user->nick);
142
143         if (iter == whowas.end())
144         {
145                 whowas_set* n = new whowas_set;
146                 WhoWasGroup *a = new WhoWasGroup(user);
147                 n->push_back(a);
148                 whowas[user->nick] = n;
149                 whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick));
150
151                 if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
152                 {
153                         whowas_users::iterator iter2 = whowas.find(whowas_fifo[0].second);
154                         if (iter2 != whowas.end())
155                         {
156                                 whowas_set* n2 = (whowas_set*)iter2->second;
157
158                                 if (n2->size())
159                                 {
160                                         while (n2->begin() != n2->end())
161                                         {
162                                                 WhoWasGroup *a2 = *(n2->begin());
163                                                 delete a2;
164                                                 n2->pop_front();
165                                         }
166                                 }
167
168                                 delete n2;
169                                 whowas.erase(iter2);
170                         }
171                         whowas_fifo.pop_front();
172                 }
173         }
174         else
175         {
176                 whowas_set* group = (whowas_set*)iter->second;
177                 WhoWasGroup *a = new WhoWasGroup(user);
178                 group->push_back(a);
179
180                 if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)
181                 {
182                         WhoWasGroup *a2 = (WhoWasGroup*)*(group->begin());
183                         delete a2;
184                         group->pop_front();
185                 }
186         }
187 }
188
189 /* on rehash, refactor maps according to new conf values */
190 void CommandWhowas::PruneWhoWas(time_t t)
191 {
192         /* config values */
193         int groupsize = ServerInstance->Config->WhoWasGroupSize;
194         int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
195         int maxkeep =   ServerInstance->Config->WhoWasMaxKeep;
196
197         /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
198         whowas_users::iterator iter;
199         int fifosize;
200         while ((fifosize = (int)whowas_fifo.size()) > 0)
201         {
202                 if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)
203                 {
204                         iter = whowas.find(whowas_fifo[0].second);
205
206                         /* hopefully redundant integrity check, but added while debugging r6216 */
207                         if (iter == whowas.end())
208                         {
209                                 /* this should never happen, if it does maps are corrupt */
210                                 ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (1)");
211                                 return;
212                         }
213
214                         whowas_set* n = (whowas_set*)iter->second;
215
216                         if (n->size())
217                         {
218                                 while (n->begin() != n->end())
219                                 {
220                                         WhoWasGroup *a = *(n->begin());
221                                         delete a;
222                                         n->pop_front();
223                                 }
224                         }
225
226                         delete n;
227                         whowas.erase(iter);
228                         whowas_fifo.pop_front();
229                 }
230                 else
231                         break;
232         }
233
234         /* Then cut the whowas sets to new size (groupsize) */
235         fifosize = (int)whowas_fifo.size();
236         for (int i = 0; i < fifosize; i++)
237         {
238                 iter = whowas.find(whowas_fifo[0].second);
239                 /* hopefully redundant integrity check, but added while debugging r6216 */
240                 if (iter == whowas.end())
241                 {
242                         /* this should never happen, if it does maps are corrupt */
243                         ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (2)");
244                         return;
245                 }
246                 whowas_set* n = (whowas_set*)iter->second;
247                 if (n->size())
248                 {
249                         int nickcount = n->size();
250                         while (n->begin() != n->end() && nickcount > groupsize)
251                         {
252                                 WhoWasGroup *a = *(n->begin());
253                                 delete a;
254                                 n->pop_front();
255                                 nickcount--;
256                         }
257                 }
258         }
259 }
260
261 /* call maintain once an hour to remove expired nicks */
262 void CommandWhowas::MaintainWhoWas(time_t t)
263 {
264         for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++)
265         {
266                 whowas_set* n = (whowas_set*)iter->second;
267                 if (n->size())
268                 {
269                         while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))
270                         {
271                                 WhoWasGroup *a = *(n->begin());
272                                 delete a;
273                                 n->erase(n->begin());
274                         }
275                 }
276         }
277 }
278
279 CommandWhowas::~CommandWhowas()
280 {
281         if (timer)
282         {
283                 ServerInstance->Timers->DelTimer(timer);
284         }
285
286         whowas_users::iterator iter;
287         int fifosize;
288         while ((fifosize = (int)whowas_fifo.size()) > 0)
289         {
290                 iter = whowas.find(whowas_fifo[0].second);
291
292                 /* hopefully redundant integrity check, but added while debugging r6216 */
293                 if (iter == whowas.end())
294                 {
295                         /* this should never happen, if it does maps are corrupt */
296                         ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (3)");
297                         return;
298                 }
299
300                 whowas_set* n = (whowas_set*)iter->second;
301
302                 if (n->size())
303                 {
304                         while (n->begin() != n->end())
305                         {
306                                 WhoWasGroup *a = *(n->begin());
307                                 delete a;
308                                 n->pop_front();
309                         }
310                 }
311
312                 delete n;
313                 whowas.erase(iter);
314                 whowas_fifo.pop_front();
315         }
316 }
317
318 WhoWasGroup::WhoWasGroup(User* user) : host(NULL), dhost(NULL), ident(NULL), server(NULL), gecos(NULL), signon(user->signon)
319 {
320         this->host = strdup(user->host);
321         this->dhost = strdup(user->dhost);
322         this->ident = strdup(user->ident);
323         this->server = user->server;
324         this->gecos = strdup(user->fullname);
325 }
326
327 WhoWasGroup::~WhoWasGroup()
328 {
329         if (host)
330                 free(host);
331         if (dhost)
332                 free(dhost);
333         if (ident)
334                 free(ident);
335         if (gecos)
336                 free(gecos);
337 }
338
339 /* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
340 void WhoWasMaintainTimer::Tick(time_t)
341 {
342         Command* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
343         if (whowas_command)
344         {
345                 std::deque<classbase*> params;
346                 whowas_command->HandleInternal(WHOWAS_MAINTAIN, params);
347         }
348 }