]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/cmd_whowas.cpp
OOPS! We try again, since I'm smoking craq. LF is 0x0a NOT CR.
[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         stats.assign("Whowas(MAPSETS) " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)");
133         ext->Extend("stats", stats.c_str());
134 }
135
136 void cmd_whowas::AddToWhoWas(userrec* user)
137 {
138         /* if whowas disabled */
139         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
140         {
141                 return;
142         }
143
144         whowas_users::iterator iter = whowas.find(user->nick);
145
146         if (iter == whowas.end())
147         {
148                 whowas_set* n = new whowas_set;
149                 WhoWasGroup *a = new WhoWasGroup(user);
150                 n->push_back(a);
151                 whowas[user->nick] = n;
152                 whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick));
153
154                 if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
155                 {
156                         whowas_users::iterator iter = whowas.find(whowas_fifo[0].second);
157                         if (iter != whowas.end())
158                         {
159                                 whowas_set* n = (whowas_set*)iter->second;
160                                 if (n->size())
161                                 {
162                                         while (n->begin() != n->end())
163                                         {
164                                                 WhoWasGroup *a = *(n->begin());
165                                                 DELETE(a);
166                                                 n->pop_front();
167                                         }
168                                 }
169                                 DELETE(n);
170                                 whowas.erase(iter);
171                         }
172                         whowas_fifo.pop_front();
173                 }
174         }
175         else
176         {
177                 whowas_set* group = (whowas_set*)iter->second;
178                 WhoWasGroup *a = new WhoWasGroup(user);
179                 group->push_back(a);
180
181                 if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)
182                 {
183                         WhoWasGroup *a = (WhoWasGroup*)*(group->begin());
184                         DELETE(a);
185                         group->pop_front();
186                 }
187         }
188 }
189
190 /* on rehash, refactor maps according to new conf values */
191 void cmd_whowas::PruneWhoWas(time_t t)
192 {
193         /* config values */
194         int groupsize = ServerInstance->Config->WhoWasGroupSize;
195         int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
196         int maxkeep =   ServerInstance->Config->WhoWasMaxKeep;
197
198         /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
199         whowas_users::iterator iter;
200         int fifosize;
201         while ((fifosize = (int)whowas_fifo.size()) > 0)
202         {
203                 if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)
204                 {
205                         iter = whowas.find(whowas_fifo[0].second);
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                         whowas_set* n = (whowas_set*)iter->second;
214                         if (n->size())
215                         {
216                                 while (n->begin() != n->end())
217                                 {
218                                         WhoWasGroup *a = *(n->begin());
219                                         DELETE(a);
220                                         n->pop_front();
221                                 }
222                         }
223                         DELETE(n);
224                         whowas.erase(iter);
225                         whowas_fifo.pop_front();
226                 }
227                 else
228                         break;
229         }
230
231         /* Then cut the whowas sets to new size (groupsize) */
232         fifosize = (int)whowas_fifo.size();
233         for (int i = 0; i < fifosize; i++)
234         {
235                 iter = whowas.find(whowas_fifo[0].second);
236                 /* hopefully redundant integrity check, but added while debugging r6216 */
237                 if (iter == whowas.end())
238                 {
239                         /* this should never happen, if it does maps are corrupt */
240                         ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (2)");
241                         return;
242                 }
243                 whowas_set* n = (whowas_set*)iter->second;
244                 if (n->size())
245                 {
246                         int nickcount = n->size();
247                         while (n->begin() != n->end() && nickcount > groupsize)
248                         {
249                                 WhoWasGroup *a = *(n->begin());
250                                 DELETE(a);
251                                 n->pop_front();
252                                 nickcount--;
253                         }
254                 }
255         }
256 }
257
258 /* call maintain once an hour to remove expired nicks */
259 void cmd_whowas::MaintainWhoWas(time_t t)
260 {
261         for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++)
262         {
263                 whowas_set* n = (whowas_set*)iter->second;
264                 if (n->size())
265                 {
266                         while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))
267                         {
268                                 WhoWasGroup *a = *(n->begin());
269                                 DELETE(a);
270                                 n->erase(n->begin());
271                         }
272                 }
273         }
274 }
275
276 cmd_whowas::~cmd_whowas()
277 {
278         if (timer)
279         {
280                 ServerInstance->Timers->DelTimer(timer);
281         }
282
283         whowas_users::iterator iter;
284         int fifosize;
285         while ((fifosize = (int)whowas_fifo.size()) > 0)
286         {
287                 iter = whowas.find(whowas_fifo[0].second);
288                 /* hopefully redundant integrity check, but added while debugging r6216 */
289                 if (iter == whowas.end())
290                 {
291                         /* this should never happen, if it does maps are corrupt */
292                         ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (3)");
293                         return;
294                 }
295                 whowas_set* n = (whowas_set*)iter->second;
296                 if (n->size())
297                 {
298                         while (n->begin() != n->end())
299                         {
300                                 WhoWasGroup *a = *(n->begin());
301                                 DELETE(a);
302                                 n->pop_front();
303                         }
304                 }
305                 DELETE(n);
306                 whowas.erase(iter);
307                 whowas_fifo.pop_front();
308         }
309 }
310
311 WhoWasGroup::WhoWasGroup(userrec* user) : host(NULL), dhost(NULL), ident(NULL), server(NULL), gecos(NULL), signon(user->signon)
312 {
313         this->host = strdup(user->host);
314         this->dhost = strdup(user->dhost);
315         this->ident = strdup(user->ident);
316         this->server = user->server;
317         this->gecos = strdup(user->fullname);
318 }
319
320 WhoWasGroup::~WhoWasGroup()
321 {
322         if (host)
323                 free(host);
324         if (dhost)
325                 free(dhost);
326         if (ident)
327                 free(ident);
328         if (gecos)
329                 free(gecos);
330 }
331
332 /* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
333 void WhoWasMaintainTimer::Tick(time_t t)
334 {
335         command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
336         if (whowas_command)
337         {
338                 std::deque<classbase*> params;
339                 whowas_command->HandleInternal(WHOWAS_MAINTAIN, params);
340         }
341 }