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 (!IS_OPER(u))
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->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")");
00810         return true;
00811 }
00812 
00813 bool TreeSocket::ComparePass(const std::string &ours, const std::string &theirs)
00814 {
00815         if ((!strncmp(ours.c_str(), "HMAC-SHA256:", 12)) || (!strncmp(theirs.c_str(), "HMAC-SHA256:", 12)))
00816         {
00817                 /* One or both of us specified hmac sha256, but we don't have sha256 module loaded!
00818                  * We can't allow this password as valid.
00819                  */
00820                 if (!Instance->FindModule("m_sha256.so") || !Utils->ChallengeResponse)
00821                                 return false;
00822                 else
00823                         /* Straight string compare of hashes */
00824                         return ours == theirs;
00825         }
00826         else
00827                 /* Straight string compare of plaintext */
00828                 return ours == theirs;
00829 }
00830 
00831 bool TreeSocket::Outbound_Reply_Server(std::deque<std::string> &params)
00832 {
00833         if (params.size() < 4)
00834                 return false;
00835 
00836         irc::string servername = params[0].c_str();
00837         std::string sname = params[0];
00838         std::string password = params[1];
00839         std::string description = params[3];
00840         int hops = atoi(params[2].c_str());
00841 
00842         this->InboundServerName = sname;
00843         this->InboundDescription = description;
00844 
00845         if (!sentcapab)
00846                 this->SendCapabilities();
00847 
00848         if (hops)
00849         {
00850                 this->SendError("Server too far away for authentication");
00851                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
00852                 return false;
00853         }
00854 
00855         for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
00856         {
00857                 if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password)) || (x->RecvPass == password && (this->GetTheirChallenge().empty()))))
00858                 {
00859                         TreeServer* CheckDupe = Utils->FindServer(sname);
00860                         if (CheckDupe)
00861                         {
00862                                 this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
00863                                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
00864                                 return false;
00865                         }
00866                         // Begin the sync here. this kickstarts the
00867                         // other side, waiting in WAIT_AUTH_2 state,
00868                         // into starting their burst, as it shows
00869                         // that we're happy.
00870                         this->LinkState = CONNECTED;
00871                         // we should add the details of this server now
00872                         // to the servers tree, as a child of the root
00873                         // node.
00874                         TreeServer* Node = new TreeServer(this->Utils,this->Instance,sname,description,Utils->TreeRoot,this,x->Hidden);
00875                         Utils->TreeRoot->AddChild(Node);
00876                         params[3] = ":" + params[3];
00877                         Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,sname);
00878                         this->bursting = true;
00879                         this->DoBurst(Node);
00880                         return true;
00881                 }
00882         }
00883         this->SendError("Invalid credentials");
00884         this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
00885         return false;
00886 }
00887 
00888 bool TreeSocket::Inbound_Server(std::deque<std::string> &params)
00889 {
00890         if (params.size() < 4)
00891                 return false;
00892         irc::string servername = params[0].c_str();
00893         std::string sname = params[0];
00894         std::string password = params[1];
00895         std::string description = params[3];
00896         int hops = atoi(params[2].c_str());
00897 
00898         this->InboundServerName = sname;
00899         this->InboundDescription = description;
00900 
00901         if (!sentcapab)
00902                 this->SendCapabilities();
00903 
00904         if (hops)
00905         {
00906                 this->SendError("Server too far away for authentication");
00907                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
00908                 return false;
00909         }
00910 
00911         for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
00912         {
00913                 if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password) || x->RecvPass == password && (this->GetTheirChallenge().empty()))))
00914                 {
00915                         /* First check for instances of the server that are waiting between the inbound and outbound SERVER command */
00916                         TreeSocket* CheckDupeSocket = Utils->FindBurstingServer(sname);
00917                         if (CheckDupeSocket)
00918                         {
00919                                 /* If we find one, we abort the link to prevent a race condition */
00920                                 this->SendError("Negotiation collision");
00921                                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists in a negotiating state.");
00922                                 CheckDupeSocket->SendError("Negotiation collision");
00923                                 Instance->SE->DelFd(CheckDupeSocket);
00924                                 CheckDupeSocket->Close();
00925                                 return false;
00926                         }
00927                         /* Now check for fully initialized instances of the server */
00928                         TreeServer* CheckDupe = Utils->FindServer(sname);
00929                         if (CheckDupe)
00930                         {
00931                                 this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
00932                                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
00933                                 return false;
00934                         }
00935                         this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] ("+description+")");
00936                         if (this->Hook)
00937                         {
00938                                 std::string name = InspSocketNameRequest((Module*)Utils->Creator, this->Hook).Send();
00939                                 this->Instance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+name+"\2");
00940                         }
00941 
00942                         Utils->AddBurstingServer(sname,this);
00943 
00944                         // this is good. Send our details: Our server name and description and hopcount of 0,
00945                         // along with the sendpass from this block.
00946                         this->SendCapabilities();
00947                         this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
00948                         // move to the next state, we are now waiting for THEM.
00949                         this->LinkState = WAIT_AUTH_2;
00950                         return true;
00951                 }
00952         }
00953         this->SendError("Invalid credentials");
00954         this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
00955         return false;
00956 }
00957 
00958 void TreeSocket::Split(const std::string &line, std::deque<std::string> &n)
00959 {
00960         n.clear();
00961         irc::tokenstream tokens(line);
00962         std::string param;
00963         while (tokens.GetToken(param))
00964         {
00965                 n.push_back(param);
00966         }
00967         return;
00968 }
00969 
00970 bool TreeSocket::ProcessLine(std::string &line)
00971 {
00972         std::deque<std::string> params;
00973         irc::string command;
00974         std::string prefix;
00975 
00976         line = line.substr(0, line.find_first_of("\r\n"));
00977 
00978         if (line.empty())
00979                 return true;
00980 
00981         Instance->Log(DEBUG, "S[%d] <- %s", this->GetFd(), line.c_str());
00982 
00983         this->Split(line.c_str(),params);
00984         
00985         if (params.empty())
00986                 return true;
00987         
00988         if ((params[0][0] == ':') && (params.size() > 1))
00989         {
00990                 prefix = params[0].substr(1);
00991                 params.pop_front();
00992         }
00993         command = params[0].c_str();
00994         params.pop_front();
00995         switch (this->LinkState)
00996         {
00997                 TreeServer* Node;
00998 
00999                 case WAIT_AUTH_1:
01000                         // Waiting for SERVER command from remote server. Server initiating
01001                         // the connection sends the first SERVER command, listening server
01002                         // replies with theirs if its happy, then if the initiator is happy,
01003                         // it starts to send its net sync, which starts the merge, otherwise
01004                         // it sends an ERROR.
01005                         if (command == "PASS")
01006                         {
01007                                 /* Silently ignored */
01008                         }
01009                         else if (command == "SERVER")
01010                         {
01011                                 return this->Inbound_Server(params);
01012                         }
01013                         else if (command == "ERROR")
01014                         {
01015                                 return this->Error(params);
01016                         }
01017                         else if (command == "USER")
01018                         {
01019                                 this->SendError("Client connections to this port are prohibited.");
01020                                 return false;
01021                         }
01022                         else if (command == "CAPAB")
01023                         {
01024                                 return this->Capab(params);
01025                         }
01026                         else if ((command == "U") || (command == "S"))
01027                         {
01028                                 this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
01029                                 return false;
01030                         }
01031                         else
01032                         {
01033                                 irc::string error = "Invalid command in negotiation phase: " + command;
01034                                 this->SendError(assign(error));
01035                                 return false;
01036                         }
01037                 break;
01038                 case WAIT_AUTH_2:
01039                         // Waiting for start of other side's netmerge to say they liked our
01040                         // password.
01041                         if (command == "SERVER")
01042                         {
01043                                 // cant do this, they sent it to us in the WAIT_AUTH_1 state!
01044                                 // silently ignore.
01045                                 return true;
01046                         }
01047                         else if ((command == "U") || (command == "S"))
01048                         {
01049                                 this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
01050                                 return false;
01051                         }
01052                         else if (command == "BURST")
01053                         {
01054                                 if (params.size() && Utils->EnableTimeSync)
01055                                 {
01056                                         bool we_have_delta = (Instance->Time(false) != Instance->Time(true));
01057                                         time_t them = atoi(params[0].c_str());
01058                                         time_t delta = them - Instance->Time(false);
01059                                         if ((delta < -300) || (delta > 300))
01060                                         {
01061                                                 Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta));
01062                                                 SendError("Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
01063                                                 return false;
01064                                         }
01065                                         else if ((delta < -30) || (delta > 30))
01066                                         {
01067                                                 Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs(delta));
01068                                         }
01069 
01070                                         if (!Utils->MasterTime && !we_have_delta)
01071                                         {
01072                                                 this->Instance->SetTimeDelta(delta);
01073                                                 // Send this new timestamp to any other servers
01074                                                 Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);
01075                                         }
01076                                 }
01077                                 this->LinkState = CONNECTED;
01078                                 TreeServer* CheckDupe = Utils->FindServer(InboundServerName);
01079                                 if (CheckDupe)
01080                                 {
01081                                         this->SendError("Server "+InboundServerName+" already exists!");
01082                                         this->Instance->SNO->WriteToSnoMask('l',"Server \2"+InboundServerName+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix);
01083                                         return false;
01084                                 }
01085                                 Link* lnk = Utils->FindLink(InboundServerName);
01086                                 Node = new TreeServer(this->Utils,this->Instance, InboundServerName, InboundDescription, Utils->TreeRoot, this, lnk ? lnk->Hidden : false);
01087                                 Utils->DelBurstingServer(this);
01088                                 Utils->TreeRoot->AddChild(Node);
01089                                 params.clear();
01090                                 params.push_back(InboundServerName);
01091                                 params.push_back("*");
01092                                 params.push_back("1");
01093                                 params.push_back(":"+InboundDescription);
01094                                 Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,InboundServerName);
01095                                 this->bursting = true;
01096                                 this->DoBurst(Node);
01097                         }
01098                         else if (command == "ERROR")
01099                         {
01100                                 return this->Error(params);
01101                         }
01102                         else if (command == "CAPAB")
01103                         {
01104                                 return this->Capab(params);
01105                         }
01106 
01107                 break;
01108                 case LISTENER:
01109                         this->SendError("Internal error -- listening socket accepted its own descriptor!!!");
01110                         return false;
01111                 break;
01112                 case CONNECTING:
01113                         if (command == "SERVER")
01114                         {
01115                                 // another server we connected to, which was in WAIT_AUTH_1 state,
01116                                 // has just sent us their credentials. If we get this far, theyre
01117                                 // happy with OUR credentials, and they are now in WAIT_AUTH_2 state.
01118                                 // if we're happy with this, we should send our netburst which
01119                                 // kickstarts the merge.
01120                                 return this->Outbound_Reply_Server(params);
01121                         }
01122                         else if (command == "ERROR")
01123                         {
01124                                 return this->Error(params);
01125                         }
01126                         else if (command == "CAPAB")
01127                         {
01128                                 return this->Capab(params);
01129                         }
01130                 break;
01131                 case CONNECTED:
01132                         // This is the 'authenticated' state, when all passwords
01133                         // have been exchanged and anything past this point is taken
01134                         // as gospel.
01135 
01136                         if (!prefix.empty())
01137                         {
01138                                 std::string direction = prefix;
01139                                 userrec* t = this->Instance->FindNick(prefix);
01140                                 if (t)
01141                                 {
01142                                         direction = t->server;
01143                                 }
01144                                 TreeServer* route_back_again = Utils->BestRouteTo(direction);
01145                                 if ((!route_back_again) || (route_back_again->GetSocket() != this))
01146                                 {
01147                                         if (route_back_again)
01148                                                 Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str());
01149                                         return true;
01150                                 }
01151                                 /* Fix by brain:
01152                                  * When there is activity on the socket, reset the ping counter so
01153                                  * that we're not wasting bandwidth pinging an active server.
01154                                  */
01155                                 route_back_again->SetNextPingTime(time(NULL) + Utils->PingFreq);
01156                                 route_back_again->SetPingFlag();
01157                         }
01158                         else
01159                         {
01160                                 prefix = this->GetName();
01161                         }
01162 
01163                         if ((command == "MODE") && (params.size() >= 2))
01164                         {
01165                                 chanrec* channel = Instance->FindChan(params[0]);
01166                                 if (channel)
01167                                 {
01168                                         userrec* x = Instance->FindNick(prefix);
01169                                         if (x)
01170                                         {
01171                                                 if (warned.find(x->server) == warned.end())
01172                                                 {
01173                                                         Instance->Log(DEFAULT,"WARNING: I revceived modes '%s' from another server '%s'. This is not compliant with InspIRCd. Please check that server for bugs.", params[1].c_str(), x->server);
01174                                                         Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending nonstandard modes: '%s MODE %s' where FMODE should be used, and may cause desyncs.", x->server, x->nick, params[1].c_str());
01175                                                         warned[x->server] = x->nick;
01176                                                 }
01177                                         }
01178                                 }
01179                         }
01180 
01181                         if (command == "SVSMODE")
01182                         {
01183                                 /* Services expects us to implement
01184                                  * SVSMODE. In inspircd its the same as
01185                                  * MODE anyway.
01186                                  */
01187                                 command = "MODE";
01188                         }
01189                         std::string target;
01190                         /* Yes, know, this is a mess. Its reasonably fast though as we're
01191                          * working with std::string here.
01192                          */
01193                         if ((command == "NICK") && (params.size() >= 8))
01194                         {
01195                                 return this->IntroduceClient(prefix,params);
01196                         }
01197                         else if (command == "FJOIN")
01198                         {
01199                                 TreeServer* ServerSource = Utils->FindServer(prefix);
01200                                 if (ServerSource)
01201                                         Utils->SetRemoteBursting(ServerSource, false);
01202                                 return this->ForceJoin(prefix,params);
01203                         }
01204                         else if (command == "STATS")
01205                         {
01206                                 return this->Stats(prefix, params);
01207                         }
01208                         else if (command == "MOTD")
01209                         {
01210                                 return this->Motd(prefix, params);
01211                         }
01212                         else if (command == "KILL" && Utils->IsServer(prefix))
01213                         {
01214                                 return this->RemoteKill(prefix,params);
01215                         }
01216                         else if (command == "MODULES")
01217                         {
01218                                 return this->Modules(prefix, params);
01219                         }
01220                         else if (command == "ADMIN")
01221                         {
01222                                 return this->Admin(prefix, params);
01223                         }
01224                         else if (command == "SERVER")
01225                         {
01226                                 return this->RemoteServer(prefix,params);
01227                         }
01228                         else if (command == "ERROR")
01229                         {
01230                                 return this->Error(params);
01231                         }
01232                         else if (command == "OPERTYPE")
01233                         {
01234                                 return this->OperType(prefix,params);
01235                         }
01236                         else if (command == "FMODE")
01237                         {
01238                                 TreeServer* ServerSource = Utils->FindServer(prefix);
01239                                 if (ServerSource)
01240                                         Utils->SetRemoteBursting(ServerSource, false);
01241                                 return this->ForceMode(prefix,params);
01242                         }
01243                         else if (command == "FTOPIC")
01244                         {
01245                                 return this->ForceTopic(prefix,params);
01246                         }
01247                         else if (command == "REHASH")
01248                         {
01249                                 return this->RemoteRehash(prefix,params);
01250                         }
01251                         else if (command == "METADATA")
01252                         {
01253                                 return this->MetaData(prefix,params);
01254                         }
01255                         else if (command == "REMSTATUS")
01256                         {
01257                                 return this->RemoveStatus(prefix,params);
01258                         }
01259                         else if (command == "PING")
01260                         {
01261                                 if (prefix.empty())
01262                                         prefix = this->GetName();
01263                                 /*
01264                                  * We just got a ping from a server that's bursting.
01265                                  * This can't be right, so set them to not bursting, and
01266                                  * apply their lines.
01267                                  */
01268                                 TreeServer* ServerSource = Utils->FindServer(prefix);
01269                                 if (ServerSource)
01270                                         Utils->SetRemoteBursting(ServerSource, false);
01271 
01272                                 if (this->bursting)
01273                                 {
01274                                         this->bursting = false;
01275                                         Instance->XLines->apply_lines(Utils->lines_to_apply);
01276                                         Utils->lines_to_apply = 0;
01277                                 }
01278 
01279                                 return this->LocalPing(prefix,params);
01280                         }
01281                         else if (command == "PONG")
01282                         {
01283                                 if (prefix.empty())
01284                                         prefix = this->GetName();
01285                                 /*
01286                                  * We just got a pong from a server that's bursting.
01287                                  * This can't be right, so set them to not bursting, and
01288                                  * apply their lines.
01289                                  */
01290                                 TreeServer* ServerSource = Utils->FindServer(prefix);
01291                                 if (ServerSource)
01292                                         Utils->SetRemoteBursting(ServerSource, false);
01293 
01294                                 if (this->bursting)
01295                                 {
01296                                         this->bursting = false;
01297                                         Instance->XLines->apply_lines(Utils->lines_to_apply);
01298                                         Utils->lines_to_apply = 0;
01299                                 }
01300 
01301                                 return this->LocalPong(prefix,params);
01302                         }
01303                         else if (command == "VERSION")
01304                         {
01305                                 return this->ServerVersion(prefix,params);
01306                         }
01307                         else if (command == "FHOST")
01308                         {
01309                                 return this->ChangeHost(prefix,params);
01310                         }
01311                         else if (command == "FNAME")
01312                         {
01313                                 return this->ChangeName(prefix,params);
01314                         }
01315                         else if (command == "ADDLINE")
01316                         {
01317                                 TreeServer* ServerSource = Utils->FindServer(prefix);
01318                                 if (ServerSource)
01319                                         Utils->SetRemoteBursting(ServerSource, false);
01320                                 return this->AddLine(prefix,params);
01321                         }
01322                         else if (command == "SVSNICK")
01323                         {
01324                                 if (prefix.empty())
01325                                 {
01326                                         prefix = this->GetName();
01327                                 }
01328                                 return this->ForceNick(prefix,params);
01329                         }
01330                         else if (command == "OPERQUIT")
01331                         {
01332                                 return this->OperQuit(prefix,params);
01333                         }
01334                         else if (command == "IDLE")
01335                         {
01336                                 return this->Whois(prefix,params);
01337                         }
01338                         else if (command == "PUSH")
01339                         {
01340                                 return this->Push(prefix,params);
01341                         }
01342                         else if (command == "TIMESET")
01343                         {
01344                                 return this->HandleSetTime(prefix, params);
01345                         }
01346                         else if (command == "TIME")
01347                         {
01348                                 return this->Time(prefix,params);
01349                         }
01350                         else if ((command == "KICK") && (Utils->IsServer(prefix)))
01351                         {
01352                                 std::string sourceserv = this->myhost;
01353                                 if (params.size() == 3)
01354                                 {
01355                                         userrec* user = this->Instance->FindNick(params[1]);
01356                                         chanrec* chan = this->Instance->FindChan(params[0]);
01357                                         if (user && chan)
01358                                         {
01359                                                 if (!chan->ServerKickUser(user, params[2].c_str(), false))
01360                                                         /* Yikes, the channels gone! */
01361                                                         delete chan;
01362                                         }
01363                                 }
01364                                 if (!this->InboundServerName.empty())
01365                                 {
01366                                         sourceserv = this->InboundServerName;
01367                                 }
01368                                 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01369                         }
01370                         else if (command == "SVSJOIN")
01371                         {
01372                                 if (prefix.empty())
01373                                 {
01374                                         prefix = this->GetName();
01375                                 }
01376                                 return this->ServiceJoin(prefix,params);
01377                         }
01378                         else if (command == "SVSPART")
01379                         {
01380                                 if (prefix.empty())
01381                                         prefix = this->GetName();
01382                                 return this->ServicePart(prefix,params);
01383                         }
01384                         else if (command == "SQUIT")
01385                         {
01386                                 if (params.size() == 2)
01387                                 {
01388                                         this->Squit(Utils->FindServer(params[0]),params[1]);
01389                                 }
01390                                 return true;
01391                         }
01392                         else if (command == "OPERNOTICE")
01393                         {
01394                                 std::string sourceserv = this->myhost;
01395                                 if (!this->InboundServerName.empty())
01396                                         sourceserv = this->InboundServerName;
01397                                 if (params.size() >= 1)
01398                                         Instance->WriteOpers("*** From " + prefix + ": " + params[0]);
01399                                 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
01400                         }
01401                         else if (command == "MODENOTICE")
01402                         {
01403                                 std::string sourceserv = this->myhost;
01404                                 if (!this->InboundServerName.empty())
01405                                         sourceserv = this->InboundServerName;
01406                                 if (params.size() >= 2)
01407                                 {
01408                                         Instance->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", prefix.c_str(), params[1].c_str());
01409                                 }
01410                                 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
01411                         }
01412                         else if (command == "SNONOTICE")
01413                         {
01414                                 std::string sourceserv = this->myhost;
01415                                 if (!this->InboundServerName.empty())
01416                                         sourceserv = this->InboundServerName;
01417                                 if (params.size() >= 2)
01418                                 {
01419                                         Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + prefix + ": "+ params[1]);
01420                                 }
01421                                 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
01422                         }
01423                         else if (command == "ENDBURST")
01424                         {
01425                                 this->bursting = false;
01426                                 Instance->XLines->apply_lines(Utils->lines_to_apply);
01427                                 Utils->lines_to_apply = 0;
01428                                 std::string sourceserv = this->myhost;
01429                                 if (!this->InboundServerName.empty())
01430                                         sourceserv = this->InboundServerName;
01431                                 this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str());
01432 
01433                                 Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server");
01434                                 rmode.Send(Instance);
01435 
01436                                 return true;
01437                         }
01438                         else
01439                         {
01440                                 // not a special inter-server command.
01441                                 // Emulate the actual user doing the command,
01442                                 // this saves us having a huge ugly parser.
01443                                 userrec* who = this->Instance->FindNick(prefix);
01444                                 std::string sourceserv = this->myhost;
01445                                 if (!this->InboundServerName.empty())
01446                                 {
01447                                         sourceserv = this->InboundServerName;
01448                                 }
01449                                 if ((!who) && (command == "MODE"))
01450                                 {
01451                                         if (Utils->IsServer(prefix))
01452                                         {
01453                                                 const char* modelist[127];
01454                                                 for (size_t i = 0; i < params.size(); i++)
01455                                                         modelist[i] = params[i].c_str();
01456                                                 userrec* fake = new userrec(Instance);
01457                                                 fake->SetFd(FD_MAGIC_NUMBER);
01458                                                 this->Instance->SendMode(modelist, params.size(), fake);
01459 
01460                                                 delete fake;
01461                                                 /* Hot potato! pass it on! */
01462                                                 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01463                                         }
01464                                 }
01465                                 if (who)
01466                                 {
01467                                         if ((command == "NICK") && (params.size() > 0))
01468                                         {
01469                                                 /* On nick messages, check that the nick doesnt
01470                                                  * already exist here. If it does, kill their copy,
01471                                                  * and our copy.
01472                                                  */
01473                                                 userrec* x = this->Instance->FindNick(params[0]);
01474                                                 if ((x) && (x != who))
01475                                                 {
01476                                                         std::deque<std::string> p;
01477                                                         p.push_back(params[0]);
01478                                                         p.push_back(":Nickname collision ("+prefix+" -> "+params[0]+")");
01479                                                         Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
01480                                                         p.clear();
01481                                                         p.push_back(prefix);
01482                                                         p.push_back(":Nickname collision");
01483                                                         Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
01484                                                         userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")");
01485                                                         userrec* y = this->Instance->FindNick(prefix);
01486                                                         if (y)
01487                                                         {
01488                                                                 userrec::QuitUser(this->Instance,y,"Nickname collision");
01489                                                         }
01490                                                         return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01491                                                 }
01492                                         }
01493                                         // its a user
01494                                         target = who->server;
01495                                         const char* strparams[127];
01496                                         for (unsigned int q = 0; q < params.size(); q++)
01497                                         {
01498                                                 strparams[q] = params[q].c_str();
01499                                         }
01500                                         switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who))
01501                                         {
01502                                                 case CMD_INVALID:
01503                                                         this->SendError("Unrecognised or malformed command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules");
01504                                                         return false;
01505                                                 break;
01506                                                 case CMD_FAILURE:
01507                                                         return true;
01508                                                 break;
01509                                                 default:
01510                                                         /* CMD_SUCCESS and CMD_USER_DELETED fall through here */
01511                                                 break;
01512                                         }
01513                                 }
01514                                 else
01515                                 {
01516                                         // its not a user. Its either a server, or somethings screwed up.
01517                                         if (Utils->IsServer(prefix))
01518                                                 target = this->Instance->Config->ServerName;
01519                                         else
01520                                                 return true;
01521                                 }
01522                                 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01523 
01524                         }
01525                         return true;
01526                 break;
01527         }
01528         return true;
01529 }
01530 
01531 std::string TreeSocket::GetName()
01532 {
01533         std::string sourceserv = this->myhost;
01534         if (!this->InboundServerName.empty())
01535         {
01536                 sourceserv = this->InboundServerName;
01537         }
01538         return sourceserv;
01539 }
01540 
01541 void TreeSocket::OnTimeout()
01542 {
01543         if (this->LinkState == CONNECTING)
01544         {
01545                 Utils->Creator->RemoteMessage(NULL, "CONNECT: Connection to \002%s\002 timed out.", myhost.c_str());
01546                 Link* MyLink = Utils->FindLink(myhost);
01547                 if (MyLink)
01548                         Utils->DoFailOver(MyLink);
01549         }
01550 }
01551 
01552 void TreeSocket::OnClose()
01553 {
01554         // Test fix for big fuckup
01555         if (this->LinkState != CONNECTED)
01556                 return;
01557 
01558         // Connection closed.
01559         // If the connection is fully up (state CONNECTED)
01560         // then propogate a netsplit to all peers.
01561         std::string quitserver = this->myhost;
01562         if (!this->InboundServerName.empty())
01563         {
01564                 quitserver = this->InboundServerName;
01565         }
01566         TreeServer* s = Utils->FindServer(quitserver);
01567         if (s)
01568         {
01569                 Squit(s,"Remote host closed the connection");
01570         }
01571 
01572         if (!quitserver.empty())
01573         {
01574                 Utils->Creator->RemoteMessage(NULL,"Connection to '\2%s\2' failed.",quitserver.c_str());
01575                 time_t server_uptime = Instance->Time() - this->age;    
01576                 if (server_uptime)
01577                         Utils->Creator->RemoteMessage(NULL,"Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str());
01578         }
01579 }
01580 
01581 int TreeSocket::OnIncomingConnection(int newsock, char* ip)
01582 {
01583         /* To prevent anyone from attempting to flood opers/DDoS by connecting to the server port,
01584          * or discovering if this port is the server port, we don't allow connections from any
01585          * IPs for which we don't have a link block.
01586          */
01587         bool found = false;
01588 
01589         found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end());
01590         if (!found)
01591         {
01592                 for (vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++)
01593                         if (irc::sockets::MatchCIDR(ip, (*i).c_str()))
01594                                 found = true;
01595 
01596                 if (!found)
01597                 {
01598                         this->Instance->SNO->WriteToSnoMask('d',"Server connection from %s denied (no link blocks with that IP address", ip);
01599                         close(newsock);
01600                         return false;
01601                 }
01602         }
01603 
01604         TreeSocket* s = new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook);
01605         s = s; /* Whinge whinge whinge, thats all GCC ever does. */
01606         return true;
01607 }