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