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