]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands/cmd_whowas.cpp
5e77671a67d14508cdc0add761d4321af063cdc6
[user/henk/code/inspircd.git] / src / commands / cmd_whowas.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/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 CommandWhowas::CommandWhowas(InspIRCd* Instance, Module* parent) : Command(Instance,parent, "WHOWAS", 0, 1, false, 2)
20 {
21         syntax = "<nick>{,<nick>}";
22         timer = new WhoWasMaintainTimer(Instance, 3600);
23         Instance->Timers->AddTimer(timer);
24 }
25
26 CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, User* user)
27 {
28         /* if whowas disabled in config */
29         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
30         {
31                 user->WriteNumeric(421, "%s %s :This command has been disabled.",user->nick.c_str(),command.c_str());
32                 return CMD_FAILURE;
33         }
34
35         whowas_users::iterator i = whowas.find(assign(parameters[0]));
36
37         if (i == whowas.end())
38         {
39                 user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str());
40                 user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
41                 return CMD_FAILURE;
42         }
43         else
44         {
45                 whowas_set* grp = i->second;
46                 if (grp->size())
47                 {
48                         for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++)
49                         {
50                                 WhoWasGroup* u = *ux;
51                                 time_t rawtime = u->signon;
52                                 tm *timeinfo;
53                                 char b[25];
54
55                                 timeinfo = localtime(&rawtime);
56
57                                 strncpy(b,asctime(timeinfo),24);
58                                 b[24] = 0;
59
60                                 user->WriteNumeric(314, "%s %s %s %s * :%s",user->nick.c_str(),parameters[0].c_str(),
61                                         u->ident.c_str(),u->dhost.c_str(),u->gecos.c_str());
62
63                                 if (user->HasPrivPermission("users/auspex"))
64                                         user->WriteNumeric(379, "%s %s :was connecting from *@%s",
65                                                 user->nick.c_str(), parameters[0].c_str(), u->host.c_str());
66
67                                 if (*ServerInstance->Config->HideWhoisServer && !user->HasPrivPermission("servers/auspex"))
68                                         user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), ServerInstance->Config->HideWhoisServer, b);
69                                 else
70                                         user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), u->server, b);
71                         }
72                 }
73                 else
74                 {
75                         user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str());
76                         user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
77                         return CMD_FAILURE;
78                 }
79         }
80
81         user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str());
82         return CMD_SUCCESS;
83 }
84
85 CmdResult CommandWhowas::HandleInternal(const unsigned int id, const std::deque<classbase*> &parameters)
86 {
87         switch (id)
88         {
89                 case WHOWAS_ADD:
90                         AddToWhoWas(static_cast<User*>(parameters[0]));
91                 break;
92
93                 case WHOWAS_STATS:
94                         GetStats(static_cast<Extensible*>(parameters[0]));
95                 break;
96
97                 case WHOWAS_PRUNE:
98                         PruneWhoWas(ServerInstance->Time());
99                 break;
100
101                 case WHOWAS_MAINTAIN:
102                         MaintainWhoWas(ServerInstance->Time());
103                 break;
104
105                 default:
106                 break;
107         }
108         return CMD_SUCCESS;
109 }
110
111 void CommandWhowas::GetStats(Extensible* ext)
112 {
113         int whowas_size = 0;
114         int whowas_bytes = 0;
115         whowas_users_fifo::iterator iter;
116         for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++)
117         {
118                 whowas_set* n = (whowas_set*)whowas.find(iter->second)->second;
119                 if (n->size())
120                 {
121                         whowas_size += n->size();
122                         whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) );
123                 }
124         }
125         stats.assign("Whowas(MAPSETS) " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)");
126         ext->Extend("stats", stats.c_str());
127 }
128
129 void CommandWhowas::AddToWhoWas(User* user)
130 {
131         /* if whowas disabled */
132         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
133         {
134                 return;
135         }
136
137         whowas_users::iterator iter = whowas.find(irc::string(user->nick.c_str()));
138
139         if (iter == whowas.end())
140         {
141                 whowas_set* n = new whowas_set;
142                 WhoWasGroup *a = new WhoWasGroup(user);
143                 n->push_back(a);
144                 whowas[user->nick.c_str()] = n;
145                 whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick.c_str()));
146
147                 if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
148                 {
149                         whowas_users::iterator iter2 = whowas.find(whowas_fifo[0].second);
150                         if (iter2 != whowas.end())
151                         {
152                                 whowas_set* n2 = (whowas_set*)iter2->second;
153
154                                 if (n2->size())
155                                 {
156                                         while (n2->begin() != n2->end())
157                                         {
158                                                 WhoWasGroup *a2 = *(n2->begin());
159                                                 delete a2;
160                                                 n2->pop_front();
161                                         }
162                                 }
163
164                                 delete n2;
165                                 whowas.erase(iter2);
166                         }
167                         whowas_fifo.pop_front();
168                 }
169         }
170         else
171         {
172                 whowas_set* group = (whowas_set*)iter->second;
173                 WhoWasGroup *a = new WhoWasGroup(user);
174                 group->push_back(a);
175
176                 if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)
177                 {
178                         WhoWasGroup *a2 = (WhoWasGroup*)*(group->begin());
179                         delete a2;
180                         group->pop_front();
181                 }
182         }
183 }
184
185 /* on rehash, refactor maps according to new conf values */
186 void CommandWhowas::PruneWhoWas(time_t t)
187 {
188         /* config values */
189         int groupsize = ServerInstance->Config->WhoWasGroupSize;
190         int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
191         int maxkeep =   ServerInstance->Config->WhoWasMaxKeep;
192
193         /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
194         whowas_users::iterator iter;
195         int fifosize;
196         while ((fifosize = (int)whowas_fifo.size()) > 0)
197         {
198                 if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)
199                 {
200                         iter = whowas.find(whowas_fifo[0].second);
201
202                         /* hopefully redundant integrity check, but added while debugging r6216 */
203                         if (iter == whowas.end())
204                         {
205                                 /* this should never happen, if it does maps are corrupt */
206                                 ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (1)");
207                                 return;
208                         }
209
210                         whowas_set* n = (whowas_set*)iter->second;
211
212                         if (n->size())
213                         {
214                                 while (n->begin() != n->end())
215                                 {
216                                         WhoWasGroup *a = *(n->begin());
217                                         delete a;
218                                         n->pop_front();
219                                 }
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->Logs->Log("WHOWAS",DEFAULT, "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 CommandWhowas::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 CommandWhowas::~CommandWhowas()
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
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->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (3)");
293                         return;
294                 }
295
296                 whowas_set* n = (whowas_set*)iter->second;
297
298                 if (n->size())
299                 {
300                         while (n->begin() != n->end())
301                         {
302                                 WhoWasGroup *a = *(n->begin());
303                                 delete a;
304                                 n->pop_front();
305                         }
306                 }
307
308                 delete n;
309                 whowas.erase(iter);
310                 whowas_fifo.pop_front();
311         }
312 }
313
314 WhoWasGroup::WhoWasGroup(User* user) : host(user->host), dhost(user->dhost), ident(user->ident),
315         server(user->server), gecos(user->fullname), signon(user->signon)
316 {
317 }
318
319 WhoWasGroup::~WhoWasGroup()
320 {
321 }
322
323 /* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
324 void WhoWasMaintainTimer::Tick(time_t)
325 {
326         Command* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
327         if (whowas_command)
328         {
329                 std::deque<classbase*> params;
330                 whowas_command->HandleInternal(WHOWAS_MAINTAIN, params);
331         }
332 }
333
334 COMMAND_INIT(CommandWhowas)