diff options
-rw-r--r-- | include/modules.h | 5 | ||||
-rw-r--r-- | src/commands.cpp | 9 | ||||
-rw-r--r-- | src/modules.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree.cpp | 149 |
4 files changed, 159 insertions, 6 deletions
diff --git a/include/modules.h b/include/modules.h index a4173060d..5e217d078 100644 --- a/include/modules.h +++ b/include/modules.h @@ -416,6 +416,11 @@ class Module : public classbase * If your method returns nonzero, the nickchange is silently forbidden, and it is down to your * module to generate some meaninful output. */ + + virtual void OnUserMessage(userrec* user, void* dest, int target_type, std::string text); + + virtual void OnUserNotice(userrec* user, void* dest, int target_type, std::string text); + virtual int OnUserPreNick(userrec* user, std::string newnick); /** Called after any nickchange, local or remote. This can be used to track users after nickchanges diff --git a/src/commands.cpp b/src/commands.cpp index 0aacf9112..d07b2e1fe 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -607,7 +607,7 @@ void handle_privmsg(char **parameters, int pcnt, userrec *user) } ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]); - + FOREACH_MOD OnUserMessage(user,chan,TYPE_CHANNEL,parameters[1]); } else { @@ -635,13 +635,13 @@ void handle_privmsg(char **parameters, int pcnt, userrec *user) } parameters[1] = (char*)temp.c_str(); - - if (!strcmp(dest->server,user->server)) { // direct write, same server WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]); } + + FOREACH_MOD OnUserMessage(user,dest,TYPE_USER,parameters[1]); } else { @@ -692,6 +692,7 @@ void handle_notice(char **parameters, int pcnt, userrec *user) ChanExceptSender(chan, user, "NOTICE %s :%s", chan->name, parameters[1]); + FOREACH_MOD OnUserNotice(user,chan,TYPE_CHANNEL,parameters[1]); } else { @@ -718,6 +719,8 @@ void handle_notice(char **parameters, int pcnt, userrec *user) // direct write, same server WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]); } + + FOREACH_MOD OnUserNotice(user,dest,TYPE_USER,parameters[1]); } else { diff --git a/src/modules.cpp b/src/modules.cpp index cb0f1e634..3d009a4bf 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -359,6 +359,8 @@ void Module::OnRawSocketAccept(int fd, std::string ip, int localport) { }; int Module::OnRawSocketWrite(int fd, char* buffer, int count) { return 0; }; void Module::OnRawSocketClose(int fd) { }; int Module::OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) { return 0; }; +void OnUserMessage(userrec* user, void* dest, int target_type, std::string text) { }; +void OnUserNotice(userrec* user, void* dest, int target_type, std::string text) { }; // server is a wrapper class that provides methods to all of the C-style // exports in the core diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index 724e8da6a..7f42456bd 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -47,9 +47,17 @@ enum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED }; typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash; extern user_hash clientlist; +const char* OneToEither[] = { "PRIVMSG", "NOTICE", NULL }; +const char* OneToMany[] = { "NICK", "QUIT", "JOIN", "PART", "MODE", "INVITE", "KICK", "KILL", NULL }; +const char* OneToOne[] = { "REHASH", "DIE", "TRACE", "WHOIS", NULL }; + class TreeServer; class TreeSocket; +bool DoOneToOne(std::string prefix, std::string command, std::deque<std::string> params, std::string target); +bool DoOneToAllButSender(std::string prefix, std::string command, std::deque<std::string> params, std::string omit); +bool DoOneToMany(std::string prefix, std::string command, std::deque<std::string> params); + class TreeServer { TreeServer* Parent; @@ -216,6 +224,23 @@ TreeServer* BestRouteTo(std::string ServerName) } } +bool LookForServer(TreeServer* Current, std::string ServerName) +{ + if (ServerName == Current->GetName()) + return true; + for (unsigned int q = 0; q < Current->ChildCount(); q++) + { + if (LookForServer(Current->GetChild(q),ServerName)) + return true; + } + return false; +} + +bool IsServer(std::string ServerName) +{ + return LookForServer(TreeRoot,ServerName); +} + class TreeSocket : public InspSocket { std::string myhost; @@ -338,6 +363,7 @@ class TreeSocket : public InspSocket clientlist[tempnick]->chans[i].channel = NULL; clientlist[tempnick]->chans[i].uc_modes = 0; } + DoOneToAllButSender(source,"NICK",params,source); return true; } @@ -603,6 +629,7 @@ class TreeSocket : public InspSocket // This is the 'authenticated' state, when all passwords // have been exchanged and anything past this point is taken // as gospel. + std::string target = ""; if ((command == "NICK") && (params.size() > 1)) { return this->IntroduceClient(prefix,params); @@ -613,9 +640,15 @@ class TreeSocket : public InspSocket // Emulate the actual user doing the command, // this saves us having a huge ugly parser. userrec* who = Srv->FindNick(prefix); + std::string sourceserv = this->myhost; + if (this->InboundServerName != "") + { + sourceserv = this->InboundServerName; + } if (who) { // its a user + target = who->server; char* strparams[127]; for (unsigned int q = 0; q < params.size(); q++) { @@ -626,8 +659,17 @@ class TreeSocket : public InspSocket else { // its not a user. Its either a server, or somethings screwed up. - log(DEBUG,"Command with unknown origin '%s'",prefix.c_str()); + if (IsServer(prefix)) + { + target = Srv->GetServerName(); + } + else + { + log(DEBUG,"Command with unknown origin '%s'",prefix.c_str()); + return true; + } } + return DoOneToAllButSender(prefix,command,params,sourceserv); } return true; @@ -636,7 +678,7 @@ class TreeSocket : public InspSocket return true; } - virtual void OnTimeout() + virtual void OnTimeout() { if (this->LinkState = CONNECTING) { @@ -644,7 +686,7 @@ class TreeSocket : public InspSocket } } - virtual void OnClose() + virtual void OnClose() { } @@ -656,6 +698,70 @@ class TreeSocket : public InspSocket } }; +bool DoOneToAllButSender(std::string prefix, std::string command, std::deque<std::string> params, std::string omit) +{ + // TODO: Special stuff with privmsg and notice + std::string FullLine = ":" + prefix + " " + command; + for (unsigned int x = 0; x < params.size(); x++) + { + FullLine = FullLine + " " + params[x]; + } + for (unsigned int x = 0; x < TreeRoot->ChildCount(); x++) + { + TreeServer* Route = TreeRoot->GetChild(x); + if ((Route->GetSocket()) && (Route->GetName() != omit)) + { + TreeSocket* Sock = Route->GetSocket(); + Sock->WriteLine(FullLine); + } + } + return true; +} + +bool DoOneToMany(std::string prefix, std::string command, std::deque<std::string> params) +{ + std::string FullLine = ":" + prefix + " " + command; + for (unsigned int x = 0; x < params.size(); x++) + { + FullLine = FullLine + " " + params[x]; + } + for (unsigned int x = 0; x < TreeRoot->ChildCount(); x++) + { + TreeServer* Route = TreeRoot->GetChild(x); + if (Route->GetSocket()) + { + TreeSocket* Sock = Route->GetSocket(); + Sock->WriteLine(FullLine); + } + } + return true; +} + +bool DoOneToOne(std::string prefix, std::string command, std::deque<std::string> params, std::string target) +{ + TreeServer* Route = BestRouteTo(target); + if (Route) + { + std::string FullLine = ":" + prefix + " " + command; + for (unsigned int x = 0; x < params.size(); x++) + { + FullLine = FullLine + " " + params[x]; + } + if (Route->GetSocket()) + { + TreeSocket* Sock = Route->GetSocket(); + Sock->WriteLine(FullLine); + } + return true; + } + else + { + log(DEBUG,"Could not route message with target %s: %s",target.c_str(),command.c_str()); + return true; + } +} + + class ModuleSpanningTree : public Module { std::vector<TreeSocket*> Bindings; @@ -782,6 +888,43 @@ class ModuleSpanningTree : public Module return 0; } + virtual void OnUserMessage(userrec* user, void* dest, int target_type, std::string text) + { + if (target_type = TYPE_USER) + { + // route private messages which are targetted at clients only to the server + // which needs to receive them + userrec* d = (userrec*)dest; + if ((std::string(d->server) != Srv->GetServerName()) && (std::string(user->server) == Srv->GetServerName())) + { + std::deque<std::string> params; + params.clear(); + params.push_back(d->nick); + params.push_back(text); + DoOneToOne(user->nick,"PRIVMSG",params,d->server); + } + } + } + + virtual void OnUserJoin(userrec* user, chanrec* channel) + { + // Only do this for local users + if (std::string(user->server) == Srv->GetServerName()) + { + log(DEBUG,"**** User on %s JOINS %s",user->server,channel->name); + std::deque<std::string> params; + params.clear(); + params.push_back(channel->name); + if (*channel->key) + { + log(DEBUG,"**** With key %s",channel->key); + // if the channel has a key, force the join by emulating the key. + params.push_back(channel->key); + } + DoOneToMany(user->nick,"JOIN",params); + } + } + virtual ~ModuleSpanningTree() { delete Srv; |