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

treesocket2.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 "channels.h"
00018 #include "modules.h"
00019 #include "commands/cmd_whois.h"
00020 #include "commands/cmd_stats.h"
00021 #include "socket.h"
00022 #include "wildcard.h"
00023 #include "xline.h"
00024 #include "transport.h"
00025 #include "socketengine.h"
00026 
00027 #include "m_spanningtree/main.h"
00028 #include "m_spanningtree/utils.h"
00029 #include "m_spanningtree/treeserver.h"
00030 #include "m_spanningtree/link.h"
00031 #include "m_spanningtree/treesocket.h"
00032 #include "m_spanningtree/resolvers.h"
00033 #include "m_spanningtree/handshaketimer.h"
00034 
00035 /* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
00036 
00037 static std::map<std::string, std::string> warned;       /* Server names that have had protocol violation warnings displayed for them */
00038 
00039 void TreeSocket::WriteLine(std::string line)
00040 {
00041         Instance->Log(DEBUG, "S[%d] -> %s", this->GetFd(), line.c_str());
00042         line.append("\r\n");
00043         this->Write(line);
00044 }
00045 
00046 
00047 /* Handle ERROR command */
00048 bool TreeSocket::Error(std::deque<std::string> &params)
00049 {
00050         if (params.size() < 1)
00051                 return false;
00052         this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str());
00053         /* we will return false to cause the socket to close. */
00054         return false;
00055 }
00056 
00057 bool TreeSocket::Modules(const std::string &prefix, std::deque<std::string> &params)
00058 {
00059         if (params.empty())
00060                 return true;
00061 
00062         if (!this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
00063         {
00064                 /* Pass it on, not for us */
00065                 Utils->DoOneToOne(prefix, "MODULES", params, params[0]);
00066                 return true;
00067         }
00068 
00069         char strbuf[MAXBUF];
00070         std::deque<std::string> par;
00071         par.push_back(prefix);
00072         par.push_back("");
00073 
00074         userrec* source = this->Instance->FindNick(prefix);
00075         if (!source)
00076                 return true;
00077 
00078         for (unsigned int i = 0; i < Instance->Config->module_names.size(); i++)
00079         {
00080                 Version V = Instance->modules[i]->GetVersion();
00081                 char modulename[MAXBUF];
00082                 char flagstate[MAXBUF];
00083                 *flagstate = 0;
00084                 if (V.Flags & VF_STATIC)
00085                         strlcat(flagstate,", static",MAXBUF);
00086                 if (V.Flags & VF_VENDOR)
00087                         strlcat(flagstate,", vendor",MAXBUF);
00088                 if (V.Flags & VF_COMMON)
00089                         strlcat(flagstate,", common",MAXBUF);
00090                 if (V.Flags & VF_SERVICEPROVIDER)
00091                         strlcat(flagstate,", service provider",MAXBUF);
00092                 if (!flagstate[0])
00093                         strcpy(flagstate,"  <no flags>");
00094                 strlcpy(modulename,Instance->Config->module_names[i].c_str(),256);
00095                 if (*source->oper)
00096                 {
00097                         snprintf(strbuf, MAXBUF, "::%s 702 %s :0x%08lx %d.%d.%d.%d %s (%s)",Instance->Config->ServerName,source->nick,(long unsigned int)Instance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2);
00098                 }
00099                 else
00100                 {
00101                         snprintf(strbuf, MAXBUF, "::%s 702 %s :%s",Instance->Config->ServerName,source->nick,ServerConfig::CleanFilename(modulename));
00102                 }
00103                 par[1] = strbuf;
00104                 Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
00105         }
00106         snprintf(strbuf, MAXBUF, "::%s 703 %s :End of MODULES list", Instance->Config->ServerName, source->nick);
00107         par[1] = strbuf;
00108         Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
00109         return true;
00110 }
00111 
00113 bool TreeSocket::Motd(const std::string &prefix, std::deque<std::string> &params)
00114 {
00115         if (params.size() > 0)
00116         {
00117                 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
00118                 {
00119                         /* It's for our server */
00120                         string_list results;
00121                         userrec* source = this->Instance->FindNick(prefix);
00122 
00123                         if (source)
00124                         {
00125                                 std::deque<std::string> par;
00126                                 par.push_back(prefix);
00127                                 par.push_back("");
00128 
00129                                 if (!Instance->Config->MOTD.size())
00130                                 {
00131                                         par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing.";
00132                                         Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00133                                         return true;
00134                                 }
00135 
00136                                 par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day";
00137                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00138 
00139                                 for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++)
00140                                 {
00141                                         par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i];
00142                                         Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00143                                 }
00144 
00145                                 par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" :End of message of the day.";
00146                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00147                         }
00148                 }
00149                 else
00150                 {
00151                         /* Pass it on */
00152                         userrec* source = this->Instance->FindNick(prefix);
00153                         if (source)
00154                                 Utils->DoOneToOne(prefix, "MOTD", params, params[0]);
00155                 }
00156         }
00157         return true;
00158 }
00159 
00161 bool TreeSocket::Admin(const std::string &prefix, std::deque<std::string> &params)
00162 {
00163         if (params.size() > 0)
00164         {
00165                 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
00166                 {
00167                         /* It's for our server */
00168                         string_list results;
00169                         userrec* source = this->Instance->FindNick(prefix);
00170                         if (source)
00171                         {
00172                                 std::deque<std::string> par;
00173                                 par.push_back(prefix);
00174                                 par.push_back("");
00175                                 par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName;
00176                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00177                                 par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name     - "+Instance->Config->AdminName;
00178                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00179                                 par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick;
00180                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00181                                 par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail   - "+Instance->Config->AdminEmail;
00182                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00183                         }
00184                 }
00185                 else
00186                 {
00187                         /* Pass it on */
00188                         userrec* source = this->Instance->FindNick(prefix);
00189                         if (source)
00190                                 Utils->DoOneToOne(prefix, "ADMIN", params, params[0]);
00191                 }
00192         }
00193         return true;
00194 }
00195 
00196 bool TreeSocket::Stats(const std::string &prefix, std::deque<std::string> &params)
00197 {
00198         /* Get the reply to a STATS query if it matches this servername,
00199          * and send it back as a load of PUSH queries
00200          */
00201         if (params.size() > 1)
00202         {
00203                 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1]))
00204                 {
00205                         /* It's for our server */
00206                         string_list results;
00207                         userrec* source = this->Instance->FindNick(prefix);
00208                         if (source)
00209                         {
00210                                 std::deque<std::string> par;
00211                                 par.push_back(prefix);
00212                                 par.push_back("");
00213                                 DoStats(this->Instance, *(params[0].c_str()), source, results);
00214                                 for (size_t i = 0; i < results.size(); i++)
00215                                 {
00216                                         par[1] = "::" + results[i];
00217                                         Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00218                                 }
00219                         }
00220                 }
00221                 else
00222                 {
00223                         /* Pass it on */
00224                         userrec* source = this->Instance->FindNick(prefix);
00225                         if (source)
00226                                 Utils->DoOneToOne(prefix, "STATS", params, params[1]);
00227                 }
00228         }
00229         return true;
00230 }
00231 
00232 
00236 bool TreeSocket::OperType(const std::string &prefix, std::deque<std::string> &params)
00237 {
00238         if (params.size() != 1)
00239                 return true;
00240         std::string opertype = params[0];
00241         userrec* u = this->Instance->FindNick(prefix);
00242         if (u)
00243         {
00244                 if (!u->IsModeSet('o'))
00245                         this->Instance->all_opers.push_back(u);
00246                 u->modes[UM_OPERATOR] = 1;
00247                 strlcpy(u->oper,opertype.c_str(),NICKMAX-1);
00248                 Utils->DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server);
00249                 this->Instance->SNO->WriteToSnoMask('o',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick,u->ident,u->host,irc::Spacify(opertype.c_str()));
00250         }
00251         return true;
00252 }
00253 
00257 bool TreeSocket::ForceNick(const std::string &prefix, std::deque<std::string> &params)
00258 {
00259         if (params.size() < 3)
00260                 return true;
00261 
00262         userrec* u = this->Instance->FindNick(params[0]);
00263 
00264         if (u)
00265         {
00266                 Utils->DoOneToAllButSender(prefix,"SVSNICK",params,prefix);
00267                 if (IS_LOCAL(u))
00268                 {
00269                         std::deque<std::string> par;
00270                         par.push_back(params[1]);
00271                         if (!u->ForceNickChange(params[1].c_str()))
00272                         {
00273                                 userrec::QuitUser(this->Instance, u, "Nickname collision");
00274                                 return true;
00275                         }
00276                         u->age = atoi(params[2].c_str());
00277                 }
00278         }
00279         return true;
00280 }
00281 
00282 bool TreeSocket::OperQuit(const std::string &prefix, std::deque<std::string> &params)
00283 {
00284         if (params.size() < 1)
00285                 return true;
00286 
00287         userrec* u = this->Instance->FindNick(prefix);
00288 
00289         if (u)
00290         {
00291                 u->SetOperQuit(params[0]);
00292                 params[0] = ":" + params[0];
00293                 Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix);
00294         }
00295         return true;
00296 }
00297 
00298 bool TreeSocket::ServiceJoin(const std::string &prefix, std::deque<std::string> &params)
00299 {
00300         if (params.size() < 2)
00301                 return true;
00302 
00303         if (!this->Instance->IsChannel(params[1].c_str()))
00304                 return true;
00305 
00306         userrec* u = this->Instance->FindNick(params[0]);
00307 
00308         if (u)
00309         {
00310                 /* only join if it's local, otherwise just pass it on! */
00311                 if (IS_LOCAL(u))
00312                         chanrec::JoinUser(this->Instance, u, params[1].c_str(), false, "", Instance->Time());
00313                 Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix);
00314         }
00315         return true;
00316 }
00317 
00318 bool TreeSocket::ServicePart(const std::string &prefix, std::deque<std::string> &params)
00319 {
00320         if (params.size() < 2)
00321                 return true;
00322 
00323         if (!this->Instance->IsChannel(params[1].c_str()))
00324                 return true;
00325 
00326         userrec* u = this->Instance->FindNick(params[0]);
00327         chanrec* c = this->Instance->FindChan(params[1]);
00328 
00329         if (u)
00330         {
00331                 /* only part if it's local, otherwise just pass it on! */
00332                 if (IS_LOCAL(u))
00333                         if (!c->PartUser(u, "Services forced part"))
00334                                 delete c;
00335                 Utils->DoOneToAllButSender(prefix,"SVSPART",params,prefix);
00336         }
00337 
00338         return true;
00339 }
00340 
00341 bool TreeSocket::RemoteRehash(const std::string &prefix, std::deque<std::string> &params)
00342 {
00343         if (params.size() < 1)
00344                 return false;
00345 
00346         std::string servermask = params[0];
00347         std::string parameter;
00348 
00349         if (params.size() > 1)
00350         {
00351                 parameter = params[1];
00352         }
00353 
00354         if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask))
00355         {
00356                 this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated by \002"+prefix+"\002.");
00357                 this->Instance->RehashServer();
00358                 Utils->ReadConfiguration(true);
00359                 FOREACH_MOD_I(this->Instance, I_OnRehash, OnRehash(NULL, parameter));
00360                 InitializeDisabledCommands(Instance->Config->DisabledCommands, Instance);
00361         }
00362         Utils->DoOneToAllButSender(prefix,"REHASH",params,prefix);
00363         return true;
00364 }
00365 
00366 bool TreeSocket::RemoteKill(const std::string &prefix, std::deque<std::string> &params)
00367 {        
00368         if (params.size() != 2)
00369                 return true;
00370 
00371         userrec* who = this->Instance->FindNick(params[0]);
00372 
00373         if (who)
00374         {
00375                 /* Prepend kill source, if we don't have one -- '[' is check for older 1.1 servers, and services, that prefix reason with servername. */
00376                 if ((*(params[1].c_str()) != 'K') && (*(params[1].c_str()) != '['))
00377                 {
00378                         params[1] = "Killed (" + params[1] +")";
00379                 }
00380                 std::string reason = params[1];
00381                 params[1] = ":" + params[1];
00382                 Utils->DoOneToAllButSender(prefix,"KILL",params,prefix);
00383                 // NOTE: This is safe with kill hiding on, as RemoteKill is only reached if we have a server prefix.
00384                 // in short this is not executed for USERS.
00385                 who->Write(":%s KILL %s :%s (%s)", prefix.c_str(), who->nick, prefix.c_str(), reason.c_str());
00386                 userrec::QuitUser(this->Instance,who,reason);
00387         }
00388         return true;
00389 }
00390 
00391 bool TreeSocket::LocalPong(const std::string &prefix, std::deque<std::string> &params)
00392 {
00393         if (params.size() < 1)
00394                 return true;
00395 
00396         if (params.size() == 1)
00397         {
00398                 TreeServer* ServerSource = Utils->FindServer(prefix);
00399                 if (ServerSource)
00400                 {
00401                         ServerSource->SetPingFlag();
00402                         timeval t;
00403                         gettimeofday(&t, NULL);
00404                         long ts = (t.tv_sec * 1000) + (t.tv_usec / 1000);
00405                         ServerSource->rtt = ts - ServerSource->LastPingMsec;
00406                 }
00407         }
00408         else
00409         {
00410                 std::string forwardto = params[1];
00411                 if (forwardto == this->Instance->Config->ServerName)
00412                 {
00413                         /*
00414                          * this is a PONG for us
00415                          * if the prefix is a user, check theyre local, and if they are,
00416                          * dump the PONG reply back to their fd. If its a server, do nowt.
00417                          * Services might want to send these s->s, but we dont need to yet.
00418                          */
00419                         userrec* u = this->Instance->FindNick(prefix);
00420                         if (u)
00421                         {
00422                                 u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str());
00423                         }
00424                 }
00425                 else
00426                 {
00427                         // not for us, pass it on :)
00428                         Utils->DoOneToOne(prefix,"PONG",params,forwardto);
00429                 }
00430         }
00431 
00432         return true;
00433 }
00434 
00435 bool TreeSocket::MetaData(const std::string &prefix, std::deque<std::string> &params)
00436 {
00437         if (params.size() < 2)
00438                 return true;
00439         else if (params.size() < 3)
00440                 params.push_back("");
00441         TreeServer* ServerSource = Utils->FindServer(prefix);
00442         if (ServerSource)
00443         {
00444                 Utils->SetRemoteBursting(ServerSource, false);
00445 
00446                 if (params[0] == "*")
00447                 {
00448                         FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2]));
00449                 }
00450                 else if (*(params[0].c_str()) == '#')
00451                 {
00452                         chanrec* c = this->Instance->FindChan(params[0]);
00453                         if (c)
00454                         {
00455                                 FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2]));
00456                         }
00457                 }
00458                 else if (*(params[0].c_str()) != '#')
00459                 {
00460                         userrec* u = this->Instance->FindNick(params[0]);
00461                         if (u)
00462                         {
00463                                 FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2]));
00464                         }
00465                 }
00466         }
00467 
00468         params[2] = ":" + params[2];
00469         Utils->DoOneToAllButSender(prefix,"METADATA",params,prefix);
00470         return true;
00471 }
00472 
00473 bool TreeSocket::ServerVersion(const std::string &prefix, std::deque<std::string> &params)
00474 {
00475         if (params.size() < 1)
00476                 return true;
00477 
00478         TreeServer* ServerSource = Utils->FindServer(prefix);
00479 
00480         if (ServerSource)
00481         {
00482                 ServerSource->SetVersion(params[0]);
00483         }
00484         params[0] = ":" + params[0];
00485         Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix);
00486         return true;
00487 }
00488 
00489 bool TreeSocket::ChangeHost(const std::string &prefix, std::deque<std::string> &params)
00490 {
00491         if (params.size() < 1)
00492                 return true;
00493         userrec* u = this->Instance->FindNick(prefix);
00494 
00495         if (u)
00496         {
00497                 u->ChangeDisplayedHost(params[0].c_str());
00498                 Utils->DoOneToAllButSender(prefix,"FHOST",params,u->server);
00499         }
00500         return true;
00501 }
00502 
00503 bool TreeSocket::AddLine(const std::string &prefix, std::deque<std::string> &params)
00504 {
00505         if (params.size() < 6)
00506                 return true;
00507         bool propogate = false;
00508         if (!this->bursting)
00509                 Utils->lines_to_apply = 0;
00510         switch (*(params[0].c_str()))
00511         {
00512                 case 'Z':
00513                         propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00514                         Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00515                         if (propogate)
00516                                 Utils->lines_to_apply |= APPLY_ZLINES;
00517                 break;
00518                 case 'Q':
00519                         propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00520                         Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00521                         if (propogate)
00522                                 Utils->lines_to_apply |= APPLY_QLINES;
00523                 break;
00524                 case 'E':
00525                         propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00526                         Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00527                 break;
00528                 case 'G':
00529                         propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00530                         Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00531                         if (propogate)
00532                                 Utils->lines_to_apply |= APPLY_GLINES;
00533                 break;
00534                 case 'K':
00535                         propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00536                         if (propogate)
00537                                 Utils->lines_to_apply |= APPLY_KLINES;
00538                 break;
00539                 default:
00540                         /* Just in case... */
00541                         this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!");
00542                         propogate = false;
00543                 break;
00544         }
00545         /* Send it on its way */
00546         if (propogate)
00547         {
00548                 if (atoi(params[4].c_str()))
00549                 {
00550                         time_t c_requires_crap = ConvToInt(params[4]) + Instance->Time();
00551                         this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),Instance->TimeString(c_requires_crap).c_str(),params[5].c_str());
00552                 }
00553                 else
00554                 {
00555                         this->Instance->SNO->WriteToSnoMask('x',"%s Added permanent %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str());
00556                 }
00557                 params[5] = ":" + params[5];
00558                 Utils->DoOneToAllButSender(prefix,"ADDLINE",params,prefix);
00559         }
00560         if (!this->bursting)
00561         {
00562                 Instance->XLines->apply_lines(Utils->lines_to_apply);
00563                 Utils->lines_to_apply = 0;
00564         }
00565         return true;
00566 }
00567 
00568 bool TreeSocket::ChangeName(const std::string &prefix, std::deque<std::string> &params)
00569 {
00570         if (params.size() < 1)
00571                 return true;
00572         userrec* u = this->Instance->FindNick(prefix);
00573         if (u)
00574         {
00575                 u->ChangeName(params[0].c_str());
00576                 params[0] = ":" + params[0];
00577                 Utils->DoOneToAllButSender(prefix,"FNAME",params,u->server);
00578         }
00579         return true;
00580 }
00581 
00582 bool TreeSocket::Whois(const std::string &prefix, std::deque<std::string> &params)
00583 {
00584         if (params.size() < 1)
00585                 return true;
00586         userrec* u = this->Instance->FindNick(prefix);
00587         if (u)
00588         {
00589                 // an incoming request
00590                 if (params.size() == 1)
00591                 {
00592                         userrec* x = this->Instance->FindNick(params[0]);
00593                         if ((x) && (IS_LOCAL(x)))
00594                         {
00595                                 userrec* x = this->Instance->FindNick(params[0]);
00596                                 char signon[MAXBUF];
00597                                 char idle[MAXBUF];
00598                                 snprintf(signon, MAXBUF, "%lu", (unsigned long)x->signon);
00599                                 snprintf(idle, MAXBUF, "%lu", (unsigned long)abs((x->idle_lastmsg) - Instance->Time(true)));
00600                                 std::deque<std::string> par;
00601                                 par.push_back(prefix);
00602                                 par.push_back(signon);
00603                                 par.push_back(idle);
00604                                 // ours, we're done, pass it BACK
00605                                 Utils->DoOneToOne(params[0], "IDLE", par, u->server);
00606                         }
00607                         else
00608                         {
00609                                 // not ours pass it on
00610                                 if (x)
00611                                         Utils->DoOneToOne(prefix, "IDLE", params, x->server);
00612                         }
00613                 }
00614                 else if (params.size() == 3)
00615                 {
00616                         std::string who_did_the_whois = params[0];
00617                         userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois);
00618                         if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
00619                         {
00620                                 // an incoming reply to a whois we sent out
00621                                 std::string nick_whoised = prefix;
00622                                 unsigned long signon = atoi(params[1].c_str());
00623                                 unsigned long idle = atoi(params[2].c_str());
00624                                 if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
00625                                 {
00626                                         do_whois(this->Instance, who_to_send_to, u, signon, idle, nick_whoised.c_str());
00627                                 }
00628                         }
00629                         else
00630                         {
00631                                 // not ours, pass it on
00632                                 if (who_to_send_to)
00633                                         Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server);
00634                         }
00635                 }
00636         }
00637         return true;
00638 }
00639 
00640 bool TreeSocket::Push(const std::string &prefix, std::deque<std::string> &params)
00641 {
00642         if (params.size() < 2)
00643                 return true;
00644         userrec* u = this->Instance->FindNick(params[0]);
00645         if (!u)
00646                 return true;
00647         if (IS_LOCAL(u))
00648         {
00649                 u->Write(params[1]);
00650         }
00651         else
00652         {
00653                 // continue the raw onwards
00654                 params[1] = ":" + params[1];
00655                 Utils->DoOneToOne(prefix,"PUSH",params,u->server);
00656         }
00657         return true;
00658 }
00659 
00660 bool TreeSocket::HandleSetTime(const std::string &prefix, std::deque<std::string> &params)
00661 {
00662         if (!params.size() || !Utils->EnableTimeSync)
00663                 return true;
00664 
00665         bool force = false;
00666 
00667         if ((params.size() == 2) && (params[1] == "FORCE"))
00668                 force = true;
00669 
00670         time_t them = atoi(params[0].c_str());
00671         time_t us = Instance->Time(false);
00672 
00673         time_t diff = them - us;
00674 
00675         Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix);
00676 
00677         if (force || (them != us))
00678         {
00679                 time_t old = Instance->SetTimeDelta(diff);
00680                 Instance->Log(DEBUG, "TS (diff %d) from %s applied (old delta was %d)", diff, prefix.c_str(), old);
00681         }
00682 
00683         return true;
00684 }
00685 
00686 bool TreeSocket::Time(const std::string &prefix, std::deque<std::string> &params)
00687 {
00688         // :source.server TIME remote.server sendernick
00689         // :remote.server TIME source.server sendernick TS
00690         if (params.size() == 2)
00691         {
00692                 // someone querying our time?
00693                 if (this->Instance->Config->ServerName == params[0])
00694                 {
00695                         userrec* u = this->Instance->FindNick(params[1]);
00696                         if (u)
00697                         {
00698                                 params.push_back(ConvToStr(Instance->Time(false)));
00699                                 params[0] = prefix;
00700                                 Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]);
00701                         }
00702                 }
00703                 else
00704                 {
00705                         // not us, pass it on
00706                         userrec* u = this->Instance->FindNick(params[1]);
00707                         if (u)
00708                                 Utils->DoOneToOne(prefix,"TIME",params,params[0]);
00709                 }
00710         }
00711         else if (params.size() == 3)
00712         {
00713                 // a response to a previous TIME
00714                 userrec* u = this->Instance->FindNick(params[1]);
00715                 if ((u) && (IS_LOCAL(u)))
00716                 {
00717                         time_t rawtime = atol(params[2].c_str());
00718                         struct tm * timeinfo;
00719                         timeinfo = localtime(&rawtime);
00720                         char tms[26];
00721                         snprintf(tms,26,"%s",asctime(timeinfo));
00722                         tms[24] = 0;
00723                         u->WriteServ("391 %s %s :%s",u->nick,prefix.c_str(),tms);
00724                 }
00725                 else
00726                 {
00727                         if (u)
00728                                 Utils->DoOneToOne(prefix,"TIME",params,u->server);
00729                 }
00730         }
00731         return true;
00732 }
00733 
00734 bool TreeSocket::LocalPing(const std::string &prefix, std::deque<std::string> &params)
00735 {
00736         if (params.size() < 1)
00737                 return true;
00738         if (params.size() == 1)
00739         {
00740                 std::string stufftobounce = params[0];
00741                 this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce);
00742                 return true;
00743         }
00744         else
00745         {
00746                 std::string forwardto = params[1];
00747                 if (forwardto == this->Instance->Config->ServerName)
00748                 {
00749                         // this is a ping for us, send back PONG to the requesting server
00750                         params[1] = params[0];
00751                         params[0] = forwardto;
00752                         Utils->DoOneToOne(forwardto,"PONG",params,params[1]);
00753                 }
00754                 else
00755                 {
00756                         // not for us, pass it on :)
00757                         Utils->DoOneToOne(prefix,"PING",params,forwardto);
00758                 }
00759                 return true;
00760         }
00761 }
00762 
00765 bool TreeSocket::RemoveStatus(const std::string &prefix, std::deque<std::string> &params)
00766 {
00767         if (params.size() < 1)
00768                 return true;
00769         chanrec* c = Instance->FindChan(params[0]);
00770         if (c)
00771         {
00772                 for (char modeletter = 'A'; modeletter <= 'z'; modeletter++)
00773                 {
00774                         ModeHandler* mh = Instance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);
00775                         if (mh)
00776                                 mh->RemoveMode(c);
00777                 }
00778         }
00779         return true;
00780 }
00781 
00782 bool TreeSocket::RemoteServer(const std::string &prefix, std::deque<std::string> &params)
00783 {
00784         if (params.size() < 4)
00785                 return false;
00786         std::string servername = params[0];
00787         std::string password = params[1];
00788         // hopcount is not used for a remote server, we calculate this ourselves
00789         std::string description = params[3];
00790         TreeServer* ParentOfThis = Utils->FindServer(prefix);
00791         if (!ParentOfThis)
00792         {
00793                 this->SendError("Protocol error - Introduced remote server from unknown server "+prefix);
00794                 return false;
00795         }
00796         TreeServer* CheckDupe = Utils->FindServer(servername);
00797         if (CheckDupe)
00798         {
00799                 this->SendError("Server "+servername+" already exists!");
00800                 this->Instance->SNO->WriteToSnoMask('l',"Server \2"+servername+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix);
00801                 return false;
00802         }
00803         Link* lnk = Utils->FindLink(servername);
00804         TreeServer* Node = new TreeServer(this->Utils,this->Instance,servername,description,ParentOfThis,NULL, lnk ? lnk->Hidden : false);
00805         ParentOfThis->AddChild(Node);
00806         params[3] = ":" + params[3];
00807         Utils->SetRemoteBursting(Node, true);
00808         Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix);
00809         this->Instance