diff options
-rw-r--r-- | include/ctables.h | 3 | ||||
-rw-r--r-- | include/inspircd.h | 2 | ||||
-rw-r--r-- | include/modules.h | 3 | ||||
-rw-r--r-- | src/commands/cmd_notice.cpp | 9 | ||||
-rw-r--r-- | src/commands/cmd_privmsg.cpp | 9 | ||||
-rw-r--r-- | src/modules/m_spanningtree/compat.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree/main.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree/postcommand.cpp | 78 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket.h | 8 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket1.cpp | 10 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket2.cpp | 734 | ||||
-rw-r--r-- | src/modules/m_spanningtree/utils.cpp | 56 | ||||
-rw-r--r-- | src/modules/m_spanningtree/utils.h | 2 |
13 files changed, 441 insertions, 477 deletions
diff --git a/include/ctables.h b/include/ctables.h index a2f4e9bb3..dd83a05a3 100644 --- a/include/ctables.h +++ b/include/ctables.h @@ -46,6 +46,7 @@ enum RouteType ROUTE_TYPE_LOCALONLY, ROUTE_TYPE_BROADCAST, ROUTE_TYPE_UNICAST, + ROUTE_TYPE_MESSAGE, ROUTE_TYPE_OPT_BCAST, ROUTE_TYPE_OPT_UCAST }; @@ -74,6 +75,8 @@ struct RouteDescriptor #define ROUTE_BROADCAST (RouteDescriptor(ROUTE_TYPE_BROADCAST, "")) /** Route this command to a single server (do nothing if own server name specified) */ #define ROUTE_UNICAST(x) (RouteDescriptor(ROUTE_TYPE_UNICAST, x)) +/** Route this command as a message with the given target (any of user, #channel, @#channel, $servermask) */ +#define ROUTE_MESSAGE(x) (RouteDescriptor(ROUTE_TYPE_MESSAGE, x)) /** Route this command to all servers wrapped via ENCAP, so ignored if not understood */ #define ROUTE_OPT_BCAST (RouteDescriptor(ROUTE_TYPE_OPT_BCAST, "")) /** Route this command to a single server wrapped via ENCAP, so ignored if not understood */ diff --git a/include/inspircd.h b/include/inspircd.h index a5e40102a..b80bba7ab 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -933,7 +933,7 @@ class CommandModule : public Module Version GetVersion() { - return Version(cmd.command, VF_VENDOR); + return Version(cmd.command, VF_VENDOR|VF_CORE); } }; diff --git a/include/modules.h b/include/modules.h index ff52cd600..edfe31007 100644 --- a/include/modules.h +++ b/include/modules.h @@ -35,7 +35,8 @@ enum ModuleFlags { VF_VENDOR = 2, // module is a vendor module (came in the original tarball, not 3rd party) VF_SERVICEPROVIDER = 4, // module provides a service to other modules (can be a dependency) VF_COMMON = 8, // module needs to be common on all servers in a network to link - VF_OPTCOMMON = 16 // module should be common on all servers for unsurprising behavior + VF_OPTCOMMON = 16, // module should be common on all servers for unsurprising behavior + VF_CORE = 32 // module is a core command, can be assumed loaded on all servers }; /** Used with SendToMode() diff --git a/src/commands/cmd_notice.cpp b/src/commands/cmd_notice.cpp index a14473643..41dbe5b3b 100644 --- a/src/commands/cmd_notice.cpp +++ b/src/commands/cmd_notice.cpp @@ -30,6 +30,15 @@ class CommandNotice : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + if (IS_LOCAL(user)) + // This is handled by the OnUserNotice hook to split the LoopCall pieces + return ROUTE_LOCALONLY; + else + return ROUTE_MESSAGE(parameters[0]); + } }; diff --git a/src/commands/cmd_privmsg.cpp b/src/commands/cmd_privmsg.cpp index 0eacfd0bc..868a5864b 100644 --- a/src/commands/cmd_privmsg.cpp +++ b/src/commands/cmd_privmsg.cpp @@ -31,6 +31,15 @@ class CommandPrivmsg : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + if (IS_LOCAL(user)) + // This is handled by the OnUserMessage hook to split the LoopCall pieces + return ROUTE_LOCALONLY; + else + return ROUTE_MESSAGE(parameters[0]); + } }; CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, User *user) diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp index 6d804aa71..acd5ff158 100644 --- a/src/modules/m_spanningtree/compat.cpp +++ b/src/modules/m_spanningtree/compat.cpp @@ -73,7 +73,7 @@ void TreeSocket::WriteLine(std::string line) ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Rewriting SAVE for 1201-protocol server"); std::string::size_type c = line.find(' ', b + 1); std::string uid = line.substr(b, c - b); - line = ":" + ServerInstance->Config->GetSID() + " SVSNICK " + uid + line.substr(b); + line = ":" + ServerInstance->Config->GetSID() + " SVSNICK" + uid + line.substr(b); } else if (proto_version < 1202 && command == "AWAY") { diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 4442ae784..a9fbff7c8 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -246,6 +246,8 @@ void ModuleSpanningTree::DoPingChecks(time_t curtime) void ModuleSpanningTree::ConnectServer(Autoconnect* y) { + if (!y) + return; y->position++; while (y->position < (int)y->servers.size()) { diff --git a/src/modules/m_spanningtree/postcommand.cpp b/src/modules/m_spanningtree/postcommand.cpp index 1b1f618b8..fae734d52 100644 --- a/src/modules/m_spanningtree/postcommand.cpp +++ b/src/modules/m_spanningtree/postcommand.cpp @@ -27,8 +27,12 @@ void ModuleSpanningTree::OnPostCommand(const std::string &command, const std::vector<std::string>& parameters, User *user, CmdResult result, const std::string &original_line) { - if (result != CMD_SUCCESS) - return; + if (result == CMD_SUCCESS) + Utils->RouteCommand(NULL, command, parameters, user); +} + +void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string &command, const parameterlist& parameters, User *user) +{ if (!ServerInstance->IsValidModuleCommand(command, parameters.size(), user)) return; @@ -52,7 +56,7 @@ void ModuleSpanningTree::OnPostCommand(const std::string &command, const std::ve } else if (routing.type == ROUTE_TYPE_OPT_UCAST) { - TreeServer* sdest = Utils->FindServer(routing.serverdest); + TreeServer* sdest = FindServer(routing.serverdest); if (!sdest) { ServerInstance->Logs->Log("m_spanningtree",ERROR,"Trying to route ENCAP to nonexistant server %s", @@ -68,7 +72,7 @@ void ModuleSpanningTree::OnPostCommand(const std::string &command, const std::ve Module* srcmodule = thiscmd->creator; Version ver = srcmodule->GetVersion(); - if (!(ver.Flags & VF_COMMON)) + if (!(ver.Flags & (VF_COMMON | VF_CORE))) { ServerInstance->Logs->Log("m_spanningtree",ERROR,"Routed command %s from non-VF_COMMON module %s", command.c_str(), srcmodule->ModuleSourceFile.c_str()); @@ -81,8 +85,66 @@ void ModuleSpanningTree::OnPostCommand(const std::string &command, const std::ve params.push_back(output_text); - if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) - Utils->DoOneToMany(user->uuid, sent_cmd, params); - else - Utils->DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest); + if (routing.type == ROUTE_TYPE_MESSAGE) + { + char pfx = 0; + std::string dest = routing.serverdest; + if (ServerInstance->Modes->FindPrefix(dest[0])) + { + pfx = dest[0]; + dest = dest.substr(1); + } + if (dest[0] == '#') + { + Channel* c = ServerInstance->FindChan(dest); + if (!c) + return; + TreeServerList list; + // TODO OnBuildExemptList hook was here + GetListOfServersForChannel(c,list,pfx, CUList()); + std::string data = ":" + user->uuid + " " + sent_cmd; + for (unsigned int x = 0; x < params.size(); x++) + data += " " + params[x]; + for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) + { + TreeSocket* Sock = i->second->GetSocket(); + if (origin && origin->GetSocket() == Sock) + continue; + if (Sock) + Sock->WriteLine(data); + } + } + else if (dest[0] == '$') + { + if (origin) + DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName()); + else + DoOneToMany(user->uuid, sent_cmd, params); + } + else + { + // user target? + User* d = ServerInstance->FindNick(dest); + if (!d) + return; + TreeServer* tsd = BestRouteTo(d->server); + if (tsd == origin) + // huh? no routing stuff around in a circle, please. + return; + DoOneToOne(user->uuid, sent_cmd, params, d->server); + } + } + else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) + { + if (origin) + DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName()); + else + DoOneToMany(user->uuid, sent_cmd, params); + } + else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) + { + if (origin && routing.serverdest == origin->GetName()) + return; + DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest); + } } diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index 520026a99..2081c2a92 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -375,13 +375,15 @@ class TreeSocket : public BufferedSocket */ bool Inbound_Server(parameterlist ¶ms); - /** Handle netsplit + /** Handle IRC line split */ - void Split(const std::string &line, parameterlist &n); + void Split(const std::string &line, std::string& prefix, std::string& command, parameterlist ¶ms); /** Process complete line from buffer */ - bool ProcessLine(std::string &line); + void ProcessLine(std::string &line); + + void ProcessConnectedLine(std::string& prefix, std::string& command, parameterlist& params); /** Get this server's name */ diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index 46effe48c..ad15a33c8 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -167,6 +167,7 @@ void TreeSocket::SendError(const std::string &errormessage) /* Display the error locally as well as sending it remotely */ ServerInstance->SNO->WriteToSnoMask('l', "Sent \2ERROR\2 to %s: %s", (this->InboundServerName.empty() ? this->IP.c_str() : this->InboundServerName.c_str()), errormessage.c_str()); WriteLine("ERROR :"+errormessage); + SetError(errormessage); } /** This function forces this server to quit, removing this server @@ -254,14 +255,7 @@ void TreeSocket::OnDataReady() */ if (ret.find("\r") != std::string::npos) ret = recvq.substr(0,recvq.find("\r")-1); - /* Process this one, abort if it - * didnt return true. - */ - if (!this->ProcessLine(ret)) - { - SetError("ProcessLine returned false"); - break; - } + ProcessLine(ret); } Utils->Creator->loopCall = false; } diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index 928f8e262..7ba406b5e 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -37,53 +37,55 @@ bool TreeSocket::Error(parameterlist ¶ms) return false; } -void TreeSocket::Split(const std::string &line, parameterlist &n) +void TreeSocket::Split(const std::string& line, std::string& prefix, std::string& command, parameterlist& params) { - n.clear(); irc::tokenstream tokens(line); + + if (!tokens.GetToken(prefix)) + return; + + if (prefix[0] == ':') + { + prefix = prefix.substr(1); + + if (prefix.empty()) + { + this->SendError("BUG (?) Empty prefix received: " + line); + return; + } + if (!tokens.GetToken(command)) + { + this->SendError("BUG (?) Empty command received: " + line); + return; + } + } + else + { + command = prefix; + prefix.clear(); + } + if (command.empty()) + this->SendError("BUG (?) Empty command received: " + line); + std::string param; while (tokens.GetToken(param)) { - n.push_back(param); + params.push_back(param); } - return; } -bool TreeSocket::ProcessLine(std::string &line) +void TreeSocket::ProcessLine(std::string &line) { - parameterlist params; - irc::string command; std::string prefix; - - line = line.substr(0, line.find_first_of("\r\n")); - - if (line.empty()) - return true; + std::string command; + parameterlist params; ServerInstance->Logs->Log("m_spanningtree",DEBUG, "S[%d] I %s", this->GetFd(), line.c_str()); - this->Split(line.c_str(),params); + Split(line, prefix, command, params); - if (params.empty()) - return true; - - if ((params[0][0] == ':') && (params.size() > 1)) - { - prefix = params[0].substr(1); - - if (prefix.empty()) - { - this->SendError("BUG (?) Empty prefix recieved: " + line); - return false; - } - command = params[1].c_str(); - params.erase(params.begin(), params.begin() + 2); - } - else - { - command = params[0].c_str(); - params.erase(params.begin()); - } + if (command.empty()) + return; switch (this->LinkState) { @@ -109,25 +111,23 @@ bool TreeSocket::ProcessLine(std::string &line) } else if (command == "SERVER") { - return this->Inbound_Server(params); + this->Inbound_Server(params); } else if (command == "ERROR") { - return this->Error(params); + this->Error(params); } else if (command == "USER") { this->SendError("Client connections to this port are prohibited."); - return false; } else if (command == "CAPAB") { - return this->Capab(params); + this->Capab(params); } else { this->SendError(std::string("Invalid command in negotiation phase: ") + command.c_str()); - return false; } break; case WAIT_AUTH_2: @@ -144,7 +144,6 @@ bool TreeSocket::ProcessLine(std::string &line) * Both of these aren't allowable, so block them here. -- w */ this->SendError("You may not re-authenticate or commence netburst without sending BURST."); - return true; } else if (command == "BURST") { @@ -156,7 +155,7 @@ bool TreeSocket::ProcessLine(std::string &line) { ServerInstance->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((long)delta)); SendError("Your clocks are out by "+ConvToStr(abs((long)delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!"); - return false; + return; } else if ((delta < -30) || (delta > 30)) { @@ -179,17 +178,17 @@ bool TreeSocket::ProcessLine(std::string &line) sparams.push_back(InboundSID); sparams.push_back(":"+InboundDescription); Utils->DoOneToAllButSender(ServerInstance->Config->GetSID(),"SERVER",sparams,InboundServerName); - Utils->DoOneToAllButSenderRaw(line, InboundServerName, prefix, command, params); + Utils->DoOneToAllButSender(prefix, "BURST", params, InboundServerName); Node->bursting = true; this->DoBurst(Node); } else if (command == "ERROR") { - return this->Error(params); + this->Error(params); } else if (command == "CAPAB") { - return this->Capab(params); + this->Capab(params); } break; @@ -203,392 +202,329 @@ bool TreeSocket::ProcessLine(std::string &line) if (command == "SERVER") { // Our credentials have been accepted, send netburst. (this puts US into the CONNECTED state) - return this->Outbound_Reply_Server(params); + this->Outbound_Reply_Server(params); } else if (command == "ERROR") { - return this->Error(params); + this->Error(params); } else if (command == "CAPAB") { - return this->Capab(params); + this->Capab(params); } break; case CONNECTED: /* - * State CONNECTED: + * State CONNECTED: * Credentials have been exchanged, we've gotten their 'BURST' (or sent ours). * Anything from here on should be accepted a little more reasonably. */ - if (!prefix.empty()) - { - /* - * Check for fake direction here, and drop any instances that are found. - * What is fake direction? Imagine the following server setup: - * 0AA <-> 0AB <-> 0AC - * Fake direction would be 0AC sending a message to 0AB claiming to be from - * 0AA, or something similar. Basically, a message taking a path that *cannot* - * be correct. - * - * When would this be seen? - * Well, hopefully never. It could be caused by race conditions, bugs, or - * "miscreant" servers, though, so let's check anyway. -- w - * - * We also check here for totally invalid prefixes (prefixes that are neither - * a valid SID or a valid UUID, so that invalid UUID or SID never makes it - * to the higher level functions. -- B - */ - std::string direction = prefix; + this->ProcessConnectedLine(prefix, command, params); + break; + } +} - User *t = ServerInstance->FindUUID(prefix); - if (t) - { - /* Find UID */ - direction = t->server; - } - else if (!this->Utils->FindServer(direction)) - { - /* Find SID */ - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Protocol violation: Invalid prefix '%s' from connection '%s'", direction.c_str(), this->GetName().c_str()); - return true; - } +void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, parameterlist& params) +{ + User* who = ServerInstance->FindUUID(prefix); + std::string direction; - TreeServer* route_back_again = Utils->BestRouteTo(direction); - if ((!route_back_again) || (route_back_again->GetSocket() != this)) - { - if (route_back_again) - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str()); - return true; - } - } - else - { - /* - * Empty prefix from a server to server link: - * This is somewhat bad/naughty, so let's set the prefix - * to be the link that we got it from, so we don't break anything. -- w - */ - TreeServer* n = Utils->FindServer(GetName()); - if (n) - prefix = n->GetID(); - else - prefix = GetName(); - } + if (who) + { + direction = who->server; + } + else + { + TreeServer* ServerSource = Utils->FindServer(prefix); + if (prefix.empty()) + ServerSource = Utils->FindServer(GetName()); - /* - * First up, check for any malformed commands (e.g. MODE without a timestamp) - * and rewrite commands where necessary (SVSMODE -> MODE for services). -- w + if (ServerSource) + { + who = Utils->ServerUser; + Utils->ServerUser->SetFakeServer(ServerSource->GetName()); + Utils->ServerUser->uuid = ServerSource->GetID(); + direction = prefix; + } + else + { + /* It is important that we don't close the link here, unknown prefix can occur + * due to various race conditions such as the KILL message for a user somehow + * crossing the users QUIT further upstream from the server. Thanks jilles! */ - if (command == "SVSMODE") // This isn't in an "else if" so we still force FMODE for changes on channels. - command = "MODE"; + ServerInstance->Logs->Log("m_spanningtree", DEBUG, "Command '%s' from unknown prefix '%s'! Dropping entire command.", + command.c_str(), prefix.c_str()); + return; + } + } - /* - * Now, check for (and parse) commands as appropriate. -- w - */ + // Make sure prefix is still good + prefix = who->uuid; + + /* + * Check for fake direction here, and drop any instances that are found. + * What is fake direction? Imagine the following server setup: + * 0AA <-> 0AB <-> 0AC + * Fake direction would be 0AC sending a message to 0AB claiming to be from + * 0AA, or something similar. Basically, a message taking a path that *cannot* + * be correct. + * + * When would this be seen? + * Well, hopefully never. It could be caused by race conditions, bugs, or + * "miscreant" servers, though, so let's check anyway. -- w + * + * We also check here for totally invalid prefixes (prefixes that are neither + * a valid SID or a valid UUID, so that invalid UUID or SID never makes it + * to the higher level functions. -- B + */ + TreeServer* route_back_again = Utils->BestRouteTo(direction); + if ((!route_back_again) || (route_back_again->GetSocket() != this)) + { + if (route_back_again) + ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Protocol violation: Fake direction '%s' from connection '%s'", + prefix.c_str(),this->GetName().c_str()); + return; + } - /* Find the server that this command originated from, used in the handlers below */ - TreeServer *ServerSource = Utils->FindServer(prefix); - if (ServerSource) - { - Utils->ServerUser->SetFakeServer(ServerSource->GetName()); - Utils->ServerUser->uuid = ServerSource->GetID(); - } + /* + * First up, check for any malformed commands (e.g. MODE without a timestamp) + * and rewrite commands where necessary (SVSMODE -> MODE for services). -- w + */ + if (command == "SVSMODE") // This isn't in an "else if" so we still force FMODE for changes on channels. + command = "MODE"; - /* Find the link we just got this from so we don't bounce it back incorrectly */ - std::string sourceserv = this->myhost; - if (!this->InboundServerName.empty()) - { - sourceserv = this->InboundServerName; - } + // TODO move all this into Commands + if (command == "UID") + { + this->ParseUID(prefix, params); + } + else if (command == "FJOIN") + { + this->ForceJoin(prefix,params); + } + else if (command == "STATS") + { + this->Stats(prefix, params); + } + else if (command == "MOTD") + { + this->Motd(prefix, params); + } + else if (command == "MODULES") + { + this->Modules(prefix, params); + } + else if (command == "ADMIN") + { + this->Admin(prefix, params); + } + else if (command == "MAP") + { + Utils->Creator->HandleMap(params, who); + } + else if (command == "SERVER") + { + this->RemoteServer(prefix,params); + } + else if (command == "ERROR") + { + this->Error(params); + } + else if (command == "OPERTYPE") + { + this->OperType(prefix,params); + } + else if (command == "AWAY") + { + this->Away(prefix,params); + } + else if (command == "FMODE") + { + this->ForceMode(prefix,params); + } + else if (command == "FTOPIC") + { + this->ForceTopic(prefix,params); + } + else if (command == "METADATA") + { + this->MetaData(prefix,params); + } + else if (command == "PING") + { + this->LocalPing(prefix,params); + } + else if (command == "PONG") + { + TreeServer *s = Utils->FindServer(prefix); + if (s && s->bursting) + { + ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", prefix.c_str()); + s->FinishBurst(); + } + this->LocalPong(prefix,params); + } + else if (command == "VERSION") + { + this->ServerVersion(prefix,params); + } + else if (command == "FHOST") + { + this->ChangeHost(prefix,params); + } + else if (command == "FNAME") + { + this->ChangeName(prefix,params); + } + else if (command == "FIDENT") + { + this->ChangeIdent(prefix,params); + } + else if (command == "ADDLINE") + { + this->AddLine(prefix,params); + } + else if (command == "DELLINE") + { + this->DelLine(prefix,params); + } + else if (command == "SVSNICK") + { + this->SVSNick(prefix,params); + } + else if (command == "SAVE") + { + this->ForceNick(prefix,params); + } + else if (command == "OPERQUIT") + { + this->OperQuit(prefix,params); + } + else if (command == "IDLE") + { + this->Whois(prefix,params); + } + else if (command == "PUSH") + { + this->Push(prefix,params); + } + else if (command == "TIME") + { + this->Time(prefix,params); + } + else if (command == "SVSJOIN") + { + this->ServiceJoin(prefix,params); + } + else if (command == "SVSPART") + { + this->ServicePart(prefix,params); + } + else if (command == "SQUIT") + { + if (params.size() == 2) + { + this->Squit(Utils->FindServer(params[0]),params[1]); + } + } + else if (command == "MODENOTICE") + { + if (params.size() >= 2) + { + ServerInstance->Users->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", + who->nick.c_str(), params[1].c_str()); + } + Utils->DoOneToAllButSender(prefix, command, params, prefix); + } + else if (command == "SNONOTICE") + { + if (params.size() >= 2) + { + ServerInstance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + who->nick + ": "+ params[1]); + Utils->DoOneToAllButSender(prefix, command, params, prefix); + } + } + else if (command == "BURST") + { + // Set prefix server as bursting + if (!IS_SERVER(who)) + { + ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got BURST from a non-server(?): %s", prefix.c_str()); + return; + } - /* - * XXX one of these days, this needs to be moved into class Commands. - */ - if (command == "UID") - { - return this->ParseUID(prefix, params); - } - else if (command == "FJOIN") - { - return this->ForceJoin(prefix,params); - } - else if ((command == "NOTICE" || command == "PRIVMSG") && (Utils->IsServer(prefix))) - { - return ServerMessage(assign(command), prefix, params, sourceserv); - } - else if (command == "STATS") - { - return this->Stats(prefix, params); - } - else if (command == "MOTD") - { - return this->Motd(prefix, params); - } - else if (command == "KILL" && ServerSource) - { - // Kill from a server - return this->RemoteKill(prefix,params); - } - else if (command == "MODULES") - { - return this->Modules(prefix, params); - } - else if (command == "ADMIN") - { - return this->Admin(prefix, params); - } - else if (command == "MAP") - { - User* user = ServerInstance->FindNick(prefix); - if (user) - { - return Utils->Creator->HandleMap(params, user); - } - } - else if (command == "SERVER") - { - return this->RemoteServer(prefix,params); - } - else if (command == "ERROR") - { - return this->Error(params); - } - else if (command == "OPERTYPE") - { - return this->OperType(prefix,params); - } - else if (command == "AWAY") - { - return this->Away(prefix,params); - } - else if (command == "FMODE") - { - return this->ForceMode(prefix,params); - } - else if (command == "FTOPIC") - { - return this->ForceTopic(prefix,params); - } - else if (command == "METADATA") - { - return this->MetaData(prefix,params); - } - else if (command == "PING") - { - return this->LocalPing(prefix,params); - } - else if (command == "PONG") - { - TreeServer *s = Utils->FindServer(prefix); - if (s && s->bursting) - { - ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", prefix.c_str()); - s->FinishBurst(); - } - return this->LocalPong(prefix,params); - } - else if (command == "VERSION") - { - return this->ServerVersion(prefix,params); - } - else if (command == "FHOST") - { - return this->ChangeHost(prefix,params); - } - else if (command == "FNAME") - { - return this->ChangeName(prefix,params); - } - else if (command == "FIDENT") - { - return this->ChangeIdent(prefix,params); - } - else if (command == "ADDLINE") - { - return this->AddLine(prefix,params); - } - else if (command == "DELLINE") - { - return this->DelLine(prefix,params); - } - else if (command == "SVSNICK") - { - return this->SVSNick(prefix,params); - } - else if (command == "SAVE") - { - return this->ForceNick(prefix,params); - } - else if (command == "OPERQUIT") - { - return this->OperQuit(prefix,params); - } - else if (command == "IDLE") - { - return this->Whois(prefix,params); - } - else if (command == "PUSH") - { - return this->Push(prefix,params); - } - else if (command == "TIME") - { - return this->Time(prefix,params); - } - else if (command == "SVSJOIN") - { - return this->ServiceJoin(prefix,params); - } - else if (command == "SVSPART") - { - return this->ServicePart(prefix,params); - } - else if (command == "SQUIT") - { - if (params.size() == 2) - { - this->Squit(Utils->FindServer(params[0]),params[1]); - } - return true; - } - else if (command == "MODENOTICE") - { - if (params.size() >= 2) - { - if (ServerSource) - ServerInstance->Users->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str()), params[1].c_str()); - } - return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params); - } - else if (command == "SNONOTICE") - { - if (params.size() >= 2) - { - std::string oldprefix; - if (!ServerSource) - { - oldprefix = prefix; - User *u = ServerInstance->FindNick(prefix); - if (!u) - return true; - prefix = u->nick; - } + route_back_again->bursting = true; + Utils->DoOneToAllButSender(prefix, command, params, prefix); + } + else if (command == "ENDBURST") + { + if (!IS_SERVER(who)) + { + ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got ENDBURST from a non-server(?): %s", prefix.c_str()); + return; + } - ServerInstance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + (ServerSource ? ServerSource->GetName().c_str() : prefix) + ": "+ params[1]); - prefix = oldprefix; - return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params); - } + route_back_again->FinishBurst(); + Utils->DoOneToAllButSender(prefix, command, params, prefix); + } + else if (command == "ENCAP") + { + this->Encap(prefix, params); + } + else if (command == "NICK") + { + if (params.size() != 2) + { + SendError("Protocol violation: NICK message without TS - :"+std::string(who->uuid)+" NICK "+params[0]); + return; + } - } - else if (command == "BURST") - { - // Set prefix server as bursting - if (!ServerSource) - { - ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got BURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str())); - return false; - } + if (IS_SERVER(who)) + { + SendError("Protocol violation: Server changing nick"); + return; + } - ServerSource->bursting = true; - return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params); - } - else if (command == "ENDBURST") - { - if (!ServerSource) - { - ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got ENDBURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str())); - return false; - } + /* Update timestamp on user when they change nicks */ + who->age = atoi(params[1].c_str()); - ServerSource->FinishBurst(); - return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params); - } - else if (command == "ENCAP") - { - return this->Encap(prefix, params); - } - else + /* + * On nick messages, check that the nick doesnt already exist here. + * If it does, perform collision logic. + */ + User* x = ServerInstance->FindNickOnly(params[0]); + if ((x) && (x != who)) + { + int collideret = 0; + /* x is local, who is remote */ + collideret = this->DoCollision(x, who->age, who->ident, who->GetIPString(), who->uuid); + if (collideret != 1) { /* - * Not a special s2s command. Emulate the user doing it. - * This saves us having a huge ugly command parser again. + * Remote client lost, or both lost, parsing or passing on this + * nickchange would be pointless, as the incoming client's server will + * soon recieve SVSNICK to change its nick to its UID. :) -- w00t */ - User* who = ServerInstance->FindUUID(prefix); - - if (ServerSource) - { - who = Utils->ServerUser; - } - else if (!who) - { - /* this looks ugly because command is an irc::string - * It is important that we dont close the link here, unknown prefix can occur - * due to various race conditions such as the KILL message for a user somehow - * crossing the users QUIT further upstream from the server. Thanks jilles! - */ - ServerInstance->Logs->Log("m_spanningtree", DEBUG, "Command " + std::string(command.c_str()) + " from unknown prefix " + prefix + "! Dropping entire command."); - return true; - } - - if (command == "NICK") - { - if (params.size() != 2) - { - SendError("Protocol violation: NICK message without TS - :"+std::string(who->uuid)+" NICK "+params[0]); - return false; - } - /* Update timestamp on user when they change nicks */ - who->age = atoi(params[1].c_str()); - - /* - * On nick messages, check that the nick doesnt already exist here. - * If it does, perform collision logic. - */ - User* x = ServerInstance->FindNickOnly(params[0]); - if ((x) && (x != who)) - { - int collideret = 0; - /* x is local, who is remote */ - collideret = this->DoCollision(x, who->age, who->ident, who->GetIPString(), who->uuid); - if (collideret != 1) - { - /* - * Remote client lost, or both lost, parsing or passing on this - * nickchange would be pointless, as the incoming client's server will - * soon recieve SVSNICK to change its nick to its UID. :) -- w00t - */ - return true; - } - } - } - - switch (ServerInstance->CallCommandHandler(command.c_str(), params, who)) - { - case CMD_INVALID: - /* - * XXX: command is irc::string, hence ugliness - */ - this->SendError("Unrecognised or malformed command '" + std::string(command.c_str()) + "' -- possibly loaded mismatched modules"); - return false; - break; - case CMD_FAILURE: - /* - * CMD_LOCALONLY is aliased to CMD_FAILURE, so this won't go out onto the network. - */ - return true; - break; - default: - /* CMD_SUCCESS falls through here */ - break; - } - - return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params); - + return; } - return true; - break; // end of state CONNECTED (phew). + } + who->ForceNickChange(params[0].c_str()); + Utils->RouteCommand(route_back_again, command, params, who); + } + else + { + Command* cmd = ServerInstance->Parser->GetHandler(command); + CmdResult res = CMD_INVALID; + if (cmd && params.size() >= cmd->min_params) + { + res = cmd->Handle(params, who); + } + + if (res == CMD_INVALID) + SendError("Unrecognised or malformed command '" + command + "' -- possibly loaded mismatched modules"); + if (res == CMD_SUCCESS) + Utils->RouteCommand(route_back_again, command, params, who); } - return true; } std::string TreeSocket::GetName() diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index 5862d95e7..7b6ea1565 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -221,63 +221,7 @@ void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeServerLis bool SpanningTreeUtilities::DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, parameterlist ¶ms) { - char pfx = 0; TreeServer* omitroute = this->BestRouteTo(omit); - if ((command == "NOTICE") || (command == "PRIVMSG")) - { - if (params.size() >= 2) - { - /* Prefixes */ - if (ServerInstance->Modes->FindPrefix(params[0][0])) - { - pfx = params[0][0]; - params[0] = params[0].substr(1, params[0].length()-1); - } - if ((*(params[0].c_str()) != '#') && (*(params[0].c_str()) != '$')) - { - // special routing for private messages/notices - User* d = ServerInstance->FindNick(params[0]); - if (d) - { - parameterlist par; - par.push_back(params[0]); - par.push_back(":"+params[1]); - this->DoOneToOne(prefix,command.c_str(),par,d->server); - return true; - } - } - else if (*(params[0].c_str()) == '$') - { - parameterlist par; - par.push_back(params[0]); - par.push_back(":"+params[1]); - this->DoOneToAllButSender(prefix,command.c_str(),par,omitroute->GetName()); - return true; - } - else - { - Channel* c = ServerInstance->FindChan(params[0]); - User* u = ServerInstance->FindNick(prefix); - if (c) - { - CUList elist; - TreeServerList list; - FOREACH_MOD(I_OnBuildExemptList, OnBuildExemptList((command == "PRIVMSG" ? MSG_PRIVMSG : MSG_NOTICE), c, u, pfx, elist, params[1])); - GetListOfServersForChannel(c,list,pfx,elist); - - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if ((Sock) && (i->second->GetName() != omit) && (omitroute != i->second)) - { - Sock->WriteLine(data); - } - } - return true; - } - } - } - } unsigned int items =this->TreeRoot->ChildCount(); for (unsigned int x = 0; x < items; x++) { diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h index a80b60e46..d8bf765b5 100644 --- a/src/modules/m_spanningtree/utils.h +++ b/src/modules/m_spanningtree/utils.h @@ -158,6 +158,8 @@ class SpanningTreeUtilities : public classbase */ ~SpanningTreeUtilities(); + void RouteCommand(TreeServer*, const std::string&, const parameterlist&, User*); + /** Send a message from this server to one other local or remote */ bool DoOneToOne(const std::string &prefix, const std::string &command, parameterlist ¶ms, std::string target); |