The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download | Blog | Stats
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

cmd_whowas.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 #include "inspircd.h"
00015 #include "configreader.h"
00016 #include "users.h"
00017 #include "commands/cmd_whowas.h"
00018 
00019 WhoWasMaintainTimer * timer;
00020 
00021 extern "C" DllExport command_t* init_command(InspIRCd* Instance)
00022 {
00023         return new cmd_whowas(Instance);
00024 }
00025 
00026 cmd_whowas::cmd_whowas(InspIRCd* Instance)
00027 : command_t(Instance, "WHOWAS", 0, 1)
00028 {
00029         syntax = "<nick>{,<nick>}";
00030         timer = new WhoWasMaintainTimer(Instance, 3600);
00031         Instance->Timers->AddTimer(timer);
00032 }
00033 
00034 CmdResult cmd_whowas::Handle (const char** parameters, int pcnt, userrec* user)
00035 {
00036         /* if whowas disabled in config */
00037         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
00038         {
00039                 user->WriteServ("421 %s %s :This command has been disabled.",user->nick,command.c_str());
00040                 return CMD_FAILURE;
00041         }
00042 
00043         whowas_users::iterator i = whowas.find(parameters[0]);
00044 
00045         if (i == whowas.end())
00046         {
00047                 user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);
00048                 user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
00049                 return CMD_FAILURE;
00050         }
00051         else
00052         {
00053                 whowas_set* grp = i->second;
00054                 if (grp->size())
00055                 {
00056                         for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++)
00057                         {
00058                                 WhoWasGroup* u = *ux;
00059                                 time_t rawtime = u->signon;
00060                                 tm *timeinfo;
00061                                 char b[MAXBUF];
00062         
00063                                 timeinfo = localtime(&rawtime);
00064                                 
00065                                 /* XXX - 'b' could be only 25 chars long and then strlcpy() would terminate it for us too? */
00066                                 strlcpy(b,asctime(timeinfo),MAXBUF);
00067                                 b[24] = 0;
00068 
00069                                 user->WriteServ("314 %s %s %s %s * :%s",user->nick,parameters[0],u->ident,u->dhost,u->gecos);
00070                                 
00071                                 if (IS_OPER(user))
00072                                         user->WriteServ("379 %s %s :was connecting from *@%s", user->nick, parameters[0], u->host);
00073                                 
00074                                 if (*ServerInstance->Config->HideWhoisServer && !IS_OPER(user))
00075                                         user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], ServerInstance->Config->HideWhoisServer, b);
00076                                 else
00077                                         user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], u->server, b);
00078                         }
00079                 }
00080                 else
00081                 {
00082                         user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);
00083                         user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
00084                         return CMD_FAILURE;
00085                 }
00086         }
00087 
00088         user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
00089         return CMD_SUCCESS;
00090 }
00091 
00092 CmdResult cmd_whowas::HandleInternal(const unsigned int id, const std::deque<classbase*> &parameters)
00093 {
00094         switch (id)
00095         {
00096                 case WHOWAS_ADD:
00097                         AddToWhoWas((userrec*)parameters[0]);
00098                 break;
00099 
00100                 case WHOWAS_STATS:
00101                         GetStats((Extensible*)parameters[0]);
00102                 break;
00103 
00104                 case WHOWAS_PRUNE:
00105                         PruneWhoWas(ServerInstance->Time());
00106                 break;
00107 
00108                 case WHOWAS_MAINTAIN:
00109                         MaintainWhoWas(ServerInstance->Time());
00110                 break;
00111 
00112                 default:
00113                 break;
00114         }
00115         return CMD_SUCCESS;
00116 }
00117 
00118 void cmd_whowas::GetStats(Extensible* ext)
00119 {
00120         int whowas_size = 0;
00121         int whowas_bytes = 0;
00122         whowas_users_fifo::iterator iter;
00123         for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++)
00124         {
00125                 whowas_set* n = (whowas_set*)whowas.find(iter->second)->second;
00126                 if (n->size())
00127                 {
00128                         whowas_size += n->size();
00129                         whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) );
00130                 }
00131         }
00132         stats.assign("Whowas(MAPSETS) " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)");
00133         ext->Extend("stats", stats.c_str());
00134 }
00135 
00136 void cmd_whowas::AddToWhoWas(userrec* user)
00137 {
00138         /* if whowas disabled */
00139         if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
00140         {
00141                 return;
00142         }
00143 
00144         whowas_users::iterator iter = whowas.find(user->nick);
00145 
00146         if (iter == whowas.end())
00147         {
00148                 whowas_set* n = new whowas_set;
00149                 WhoWasGroup *a = new WhoWasGroup(user);
00150                 n->push_back(a);
00151                 whowas[user->nick] = n;
00152                 whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick));
00153 
00154                 if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
00155                 {
00156                         whowas_users::iterator iter = whowas.find(whowas_fifo[0].second);
00157                         if (iter != whowas.end())
00158                         {
00159                                 whowas_set* n = (whowas_set*)iter->second;
00160                                 if (n->size())
00161                                 {
00162                                         while (n->begin() != n->end())
00163                                         {
00164                                                 WhoWasGroup *a = *(n->begin());
00165                                                 DELETE(a);
00166                                                 n->pop_front();
00167                                         }
00168                                 }
00169                                 DELETE(n);
00170                                 whowas.erase(iter);
00171                         }
00172                         whowas_fifo.pop_front();
00173                 }
00174         }
00175         else
00176         {
00177                 whowas_set* group = (whowas_set*)iter->second;
00178                 WhoWasGroup *a = new WhoWasGroup(user);
00179                 group->push_back(a);
00180 
00181                 if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)
00182                 {
00183                         WhoWasGroup *a = (WhoWasGroup*)*(group->begin());
00184                         DELETE(a);
00185                         group->pop_front();
00186                 }
00187         }
00188 }
00189 
00190 /* on rehash, refactor maps according to new conf values */
00191 void cmd_whowas::PruneWhoWas(time_t t)
00192 {
00193         /* config values */
00194         int groupsize = ServerInstance->Config->WhoWasGroupSize;
00195         int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
00196         int maxkeep =   ServerInstance->Config->WhoWasMaxKeep;
00197 
00198         /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
00199         whowas_users::iterator iter;
00200         int fifosize;
00201         while ((fifosize = (int)whowas_fifo.size()) > 0)
00202         {
00203                 if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)
00204                 {
00205                         iter = whowas.find(whowas_fifo[0].second);
00206                         /* hopefully redundant integrity check, but added while debugging r6216 */
00207                         if (iter == whowas.end())
00208                         {
00209                                 /* this should never happen, if it does maps are corrupt */
00210                                 ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (1)");
00211                                 return;
00212                         }
00213                         whowas_set* n = (whowas_set*)iter->second;
00214                         if (n->size())
00215                         {
00216                                 while (n->begin() != n->end())
00217                                 {
00218                                         WhoWasGroup *a = *(n->begin());
00219                                         DELETE(a);
00220                                         n->pop_front();
00221                                 }
00222                         }
00223                         DELETE(n);
00224                         whowas.erase(iter);
00225                         whowas_fifo.pop_front();
00226                 }
00227                 else
00228                         break;
00229         }
00230 
00231         /* Then cut the whowas sets to new size (groupsize) */
00232         fifosize = (int)whowas_fifo.size();
00233         for (int i = 0; i < fifosize; i++)
00234         {
00235                 iter = whowas.find(whowas_fifo[0].second);
00236                 /* hopefully redundant integrity check, but added while debugging r6216 */
00237                 if (iter == whowas.end())
00238                 {
00239                         /* this should never happen, if it does maps are corrupt */
00240                         ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (2)");
00241                         return;
00242                 }
00243                 whowas_set* n = (whowas_set*)iter->second;
00244                 if (n->size())
00245                 {
00246                         int nickcount = n->size();
00247                         while (n->begin() != n->end() && nickcount > groupsize)
00248                         {
00249                                 WhoWasGroup *a = *(n->begin());
00250                                 DELETE(a);
00251                                 n->pop_front();
00252                                 nickcount--;
00253                         }
00254                 }
00255         }
00256 }
00257 
00258 /* call maintain once an hour to remove expired nicks */
00259 void cmd_whowas::MaintainWhoWas(time_t t)
00260 {
00261         for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++)
00262         {
00263                 whowas_set* n = (whowas_set*)iter->second;
00264                 if (n->size())
00265                 {
00266                         while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))
00267                         {
00268                                 WhoWasGroup *a = *(n->begin());
00269                                 DELETE(a);
00270                                 n->erase(n->begin());
00271                         }
00272                 }
00273         }
00274 }
00275 
00276 cmd_whowas::~cmd_whowas()
00277 {
00278         if (timer)
00279         {
00280                 ServerInstance->Timers->DelTimer(timer);
00281         }
00282 
00283         whowas_users::iterator iter;
00284         int fifosize;
00285         while ((fifosize = (int)whowas_fifo.size()) > 0)
00286         {
00287                 iter = whowas.find(whowas_fifo[0].second);
00288                 /* hopefully redundant integrity check, but added while debugging r6216 */
00289                 if (iter == whowas.end())
00290                 {
00291                         /* this should never happen, if it does maps are corrupt */
00292                         ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (3)");
00293                         return;
00294                 }
00295                 whowas_set* n = (whowas_set*)iter->second;
00296                 if (n->size())
00297                 {
00298                         while (n->begin() != n->end())
00299                         {
00300                                 WhoWasGroup *a = *(n->begin());
00301                                 DELETE(a);
00302                                 n->pop_front();
00303                         }
00304                 }
00305                 DELETE(n);
00306                 whowas.erase(iter);
00307                 whowas_fifo.pop_front();
00308         }
00309 }
00310 
00311 WhoWasGroup::WhoWasGroup(userrec* user) : host(NULL), dhost(NULL), ident(NULL), server(NULL), gecos(NULL), signon(user->signon)
00312 {
00313         this->host = strdup(user->host);
00314         this->dhost = strdup(user->dhost);
00315         this->ident = strdup(user->ident);
00316         this->server = user->server;
00317         this->gecos = strdup(user->fullname);
00318 }
00319 
00320 WhoWasGroup::~WhoWasGroup()
00321 {
00322         if (host)
00323                 free(host);
00324         if (dhost)
00325                 free(dhost);
00326         if (ident)
00327                 free(ident);
00328         if (gecos)
00329                 free(gecos);
00330 }
00331 
00332 /* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
00333 void WhoWasMaintainTimer::Tick(time_t t)
00334 {
00335         command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
00336         if (whowas_command)
00337         {
00338                 std::deque<classbase*> params;
00339                 whowas_command->HandleInternal(WHOWAS_MAINTAIN, params);
00340         }
00341 }