X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_spanningtree.cpp;h=7e7e91382e44cad7cc3e2c6d0e31bf60e65cbf8c;hb=8144a16f89b75f527e4d860e7176c9c1a8b14eca;hp=72ae322f643fc8af70b3a0f0fe927e2a63148eb8;hpb=d7336f351d9740fc4bfc1289c2b090a0f272d201;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index 72ae322f6..7e7e91382 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -18,32 +18,27 @@ using namespace std; -#include -#include -#include -#include "globals.h" -#include "inspircd_config.h" -#include "hash_map.h" #include "configreader.h" #include "users.h" #include "channels.h" #include "modules.h" -#include "commands.h" #include "commands/cmd_whois.h" #include "commands/cmd_stats.h" #include "socket.h" -#include "helperfuncs.h" #include "inspircd.h" -#include "inspstring.h" -#include "hashcomp.h" -#include "message.h" +#include "wildcard.h" #include "xline.h" -#include "typedefs.h" #include "cull_list.h" #include "aes.h" #define nspace __gnu_cxx + +/** If you make a change which breaks the protocol, increment this. + * If you completely change the protocol, completely change the number. + */ +const long ProtocolVersion = 1101; + /* * The server list in InspIRCd is maintained as two structures * which hold the data in different ways. Most of the time, we @@ -69,14 +64,9 @@ using irc::sockets::MatchCIDR; class ModuleSpanningTree; static ModuleSpanningTree* TreeProtocolModule; +static InspIRCd* ServerInstance; -extern InspIRCd* ServerInstance; - -extern std::vector modules; -extern std::vector factory; -extern int MODCOUNT; - -/* Any socket can have one of five states at any one time. +/** Any socket can have one of five states at any one time. * The LISTENER state indicates a socket which is listening * for connections. It cannot receive data itself, only incoming * sockets. @@ -102,8 +92,6 @@ class TreeSocket; */ TreeServer *TreeRoot; -static Server* Srv; - /* This hash_map holds the hash equivalent of the server * tree, used for rapid linear lookups. */ @@ -116,7 +104,9 @@ typedef nspace::hash_map sid_hash; /* More forward declarations */ bool DoOneToOne(std::string prefix, std::string command, std::deque ¶ms, std::string target); bool DoOneToAllButSender(std::string prefix, std::string command, std::deque ¶ms, std::string omit); +bool DoOneToAllButSender(const char* prefix, const char* command, std::deque ¶ms, std::string omit); bool DoOneToMany(std::string prefix, std::string command, std::deque ¶ms); +bool DoOneToMany(const char* prefix, const char* command, std::deque ¶ms); bool DoOneToAllButSenderRaw(std::string data, std::string omit, std::string prefix, irc::string command, std::deque ¶ms); void ReadConfiguration(bool rebind); @@ -125,18 +115,6 @@ bool FlatLinks; /* Hide U-Lined servers in /MAP and /LINKS */ bool HideULines; -/* Imported from xline.cpp for use during netburst */ -extern std::vector klines; -extern std::vector glines; -extern std::vector zlines; -extern std::vector qlines; -extern std::vector elines; -extern std::vector pklines; -extern std::vector pglines; -extern std::vector pzlines; -extern std::vector pqlines; -extern std::vector pelines; - std::vector ValidIPs; class UserManager : public classbase @@ -187,7 +165,7 @@ class UserManager : public classbase }; -/* Each server in the tree is represented by one class of +/** Each server in the tree is represented by one class of * type TreeServer. A locally connected TreeServer can * have a class of type TreeSocket associated with it, for * remote servers, the TreeSocket entry will be NULL. @@ -201,9 +179,9 @@ class UserManager : public classbase * TreeServer items, deleting and inserting them as they * are created and destroyed. */ - class TreeServer : public classbase { + InspIRCd* ServerInstance; /* Creator */ TreeServer* Parent; /* Parent entry */ TreeServer* Route; /* Route entry */ std::vector Children; /* List of child objects */ @@ -218,43 +196,44 @@ class TreeServer : public classbase public: - /* We don't use this constructor. Its a dummy, and won't cause any insertion + /** We don't use this constructor. Its a dummy, and won't cause any insertion * of the TreeServer into the hash_map. See below for the two we DO use. */ - TreeServer() + TreeServer(InspIRCd* Instance) : ServerInstance(Instance) { Parent = NULL; ServerName = ""; ServerDesc = ""; VersionString = ""; UserCount = OperCount = 0; - VersionString = Srv->GetVersion(); + VersionString = ServerInstance->GetVersionString(); } - /* We use this constructor only to create the 'root' item, TreeRoot, which + /** We use this constructor only to create the 'root' item, TreeRoot, which * represents our own server. Therefore, it has no route, no parent, and * no socket associated with it. Its version string is our own local version. */ - TreeServer(std::string Name, std::string Desc) : ServerName(Name.c_str()), ServerDesc(Desc) + TreeServer(InspIRCd* Instance, std::string Name, std::string Desc) : ServerInstance(Instance), ServerName(Name.c_str()), ServerDesc(Desc) { Parent = NULL; VersionString = ""; UserCount = OperCount = 0; - VersionString = Srv->GetVersion(); + VersionString = ServerInstance->GetVersionString(); Route = NULL; Socket = NULL; /* Fix by brain */ AddHashEntry(); } - /* When we create a new server, we call this constructor to initialize it. + /** When we create a new server, we call this constructor to initialize it. * This constructor initializes the server's Route and Parent, and sets up * its ping counters so that it will be pinged one minute from now. */ - TreeServer(std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock) : Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock) + TreeServer(InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock) + : ServerInstance(Instance), Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock) { VersionString = ""; UserCount = OperCount = 0; - this->SetNextPingTime(time(NULL) + 120); + this->SetNextPingTime(time(NULL) + 60); this->SetPingFlag(); /* find the 'route' for this server (e.g. the one directly connected @@ -313,7 +292,7 @@ class TreeServer : public classbase int QuitUsers(const std::string &reason) { - log(DEBUG,"Removing all users from server %s",this->ServerName.c_str()); + ServerInstance->Log(DEBUG,"Removing all users from server %s",this->ServerName.c_str()); const char* reason_s = reason.c_str(); std::vector time_to_die; for (user_hash::iterator n = ServerInstance->clientlist.begin(); n != ServerInstance->clientlist.end(); n++) @@ -326,14 +305,14 @@ class TreeServer : public classbase for (std::vector::iterator n = time_to_die.begin(); n != time_to_die.end(); n++) { userrec* a = (userrec*)*n; - log(DEBUG,"Kill %s fd=%d",a->nick,a->fd); + ServerInstance->Log(DEBUG,"Kill %s fd=%d",a->nick,a->GetFd()); if (!IS_LOCAL(a)) userrec::QuitUser(ServerInstance,a,reason_s); } return time_to_die.size(); } - /* This method is used to add the structure to the + /** This method is used to add the structure to the * hash_map for linear searches. It is only called * by the constructors. */ @@ -345,7 +324,7 @@ class TreeServer : public classbase serverlist[this->ServerName.c_str()] = this; } - /* This method removes the reference to this object + /** This method removes the reference to this object * from the hash_map which is used for linear searches. * It is only called by the default destructor. */ @@ -357,10 +336,9 @@ class TreeServer : public classbase serverlist.erase(iter); } - /* These accessors etc should be pretty self- + /** These accessors etc should be pretty self- * explanitory. */ - TreeServer* GetRoute() { return Route; @@ -477,7 +455,7 @@ class TreeServer : public classbase return false; } - /* Removes child nodes of this node, and of that node, etc etc. + /** Removes child nodes of this node, and of that node, etc etc. * This is used during netsplits to automatically tidy up the * server tree. It is slow, we don't use it for much else. */ @@ -507,27 +485,30 @@ class TreeServer : public classbase } }; -/* The Link class might as well be a struct, +/** The Link class might as well be a struct, * but this is C++ and we don't believe in structs (!). * It holds the entire information of one * tag from the main config file. We maintain a list * of them, and populate the list on rehash/load. */ - class Link : public classbase { public: - irc::string Name; - std::string IPAddr; - int Port; - std::string SendPass; - std::string RecvPass; - unsigned long AutoConnect; - time_t NextConnectTime; - std::string EncryptionKey; - bool HiddenFromStats; + irc::string Name; + std::string IPAddr; + int Port; + std::string SendPass; + std::string RecvPass; + unsigned long AutoConnect; + time_t NextConnectTime; + std::string EncryptionKey; + bool HiddenFromStats; + irc::string FailOver; }; +void DoFailOver(Link* x); +Link* FindLink(const std::string& name); + /* The usual stuff for inspircd modules, * plus the vector of Link classes which we * use to store the tags from the config @@ -536,7 +517,7 @@ class Link : public classbase ConfigReader *Conf; std::vector LinkBlocks; -/* Yay for fast searches! +/** Yay for fast searches! * This is hundreds of times faster than recursion * or even scanning a linked list, especially when * there are more than a few servers to deal with. @@ -556,7 +537,7 @@ TreeServer* FindServer(std::string ServerName) } } -/* Returns the locally connected server we must route a +/** Returns the locally connected server we must route a * message through to reach server 'ServerName'. This * only applies to one-to-one and not one-to-many routing. * See the comments for the constructor of TreeServer @@ -577,7 +558,7 @@ TreeServer* BestRouteTo(std::string ServerName) } } -/* Find the first server matching a given glob mask. +/** Find the first server matching a given glob mask. * Theres no find-using-glob method of hash_map [awwww :-(] * so instead, we iterate over the list using an iterator * and match each one until we get a hit. Yes its slow, @@ -587,7 +568,7 @@ TreeServer* FindServerMask(std::string ServerName) { for (server_hash::iterator i = serverlist.begin(); i != serverlist.end(); i++) { - if (Srv->MatchText(i->first.c_str(),ServerName)) + if (match(i->first.c_str(),ServerName.c_str())) return i->second; } return NULL; @@ -604,30 +585,35 @@ class cmd_rconnect : public command_t { Module* Creator; public: - cmd_rconnect (Module* Callback) : command_t("RCONNECT", 'o', 2), Creator(Callback) + cmd_rconnect (InspIRCd* Instance, Module* Callback) : command_t(Instance, "RCONNECT", 'o', 2), Creator(Callback) { this->source = "m_spanningtree.so"; syntax = " "; } - void Handle (const char** parameters, int pcnt, userrec *user) + CmdResult Handle (const char** parameters, int pcnt, userrec *user) { user->WriteServ("NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick,parameters[0],parameters[1]); /* Is this aimed at our server? */ - if (Srv->MatchText(Srv->GetServerName(),parameters[0])) + if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0])) { /* Yes, initiate the given connect */ - WriteOpers("*** Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick,parameters[0],parameters[1]); + ServerInstance->SNO->WriteToSnoMask('l',"Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick,parameters[0],parameters[1]); const char* para[1]; para[0] = parameters[1]; - Creator->OnPreCommand("CONNECT", para, 1, user, true); + std::string original_command = std::string("CONNECT ") + parameters[1]; + Creator->OnPreCommand("CONNECT", para, 1, user, true, original_command); + + return CMD_SUCCESS; } + + return CMD_FAILURE; } }; -/* Every SERVER connection inbound or outbound is represented by +/** Every SERVER connection inbound or outbound is represented by * an object of type TreeSocket. * TreeSockets, being inherited from InspSocket, can be tied into * the core socket engine, and we cn therefore receive activity events @@ -638,7 +624,6 @@ class cmd_rconnect : public command_t * maintain a list of servers, some of which are directly connected, * some of which are not. */ - class TreeSocket : public InspSocket { std::string myhost; @@ -654,10 +639,12 @@ class TreeSocket : public InspSocket AES* ctx_in; AES* ctx_out; unsigned int keylength; - + std::string ModuleList; + std::map CapKeys; + public: - /* Because most of the I/O gubbins are encapsulated within + /** Because most of the I/O gubbins are encapsulated within * InspSocket, we just call the superclass constructor for * most of the action, and append a few of our own values * to it. @@ -680,7 +667,7 @@ class TreeSocket : public InspSocket this->ctx_out = NULL; } - /* When a listening socket gives us a new file descriptor, + /** When a listening socket gives us a new file descriptor, * we must associate it with a socket without creating a new * connection. This constructor is used for this purpose. */ @@ -708,17 +695,17 @@ class TreeSocket : public InspSocket ctx_in = new AES(); ctx_out = new AES(); - log(DEBUG,"Initialized AES key %s",key.c_str()); + Instance->Log(DEBUG,"Initialized AES key %s",key.c_str()); // key must be 16, 24, 32 etc bytes (multiple of 8) keylength = key.length(); if (!(keylength == 16 || keylength == 24 || keylength == 32)) { - WriteOpers("*** \2ERROR\2: Key length for encryptionkey is not 16, 24 or 32 bytes in length!"); - log(DEBUG,"Key length not 16, 24 or 32 characters!"); + this->Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Key length for encryptionkey is not 16, 24 or 32 bytes in length!"); + Instance->Log(DEBUG,"Key length not 16, 24 or 32 characters!"); } else { - WriteOpers("*** \2AES\2: Initialized %d bit encryption to server %s",keylength*8,SName.c_str()); + this->Instance->SNO->WriteToSnoMask('l',"\2AES\2: Initialized %d bit encryption to server %s",keylength*8,SName.c_str()); ctx_in->MakeKey(key.c_str(), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", keylength, keylength); ctx_out->MakeKey(key.c_str(), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ @@ -726,7 +713,7 @@ class TreeSocket : public InspSocket } } - /* When an outbound connection finishes connecting, we receive + /** When an outbound connection finishes connecting, we receive * this event, and must send our SERVER string to the other * side. If the other side is happy, as outlined in the server * to server docs on the inspircd.org site, the other side @@ -741,22 +728,22 @@ class TreeSocket : public InspSocket { if (x->Name == this->myhost) { - Srv->SendOpers("*** Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "" : this->GetIP())+"] established."); + this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "" : this->GetIP())+"] started."); this->SendCapabilities(); if (x->EncryptionKey != "") { if (!(x->EncryptionKey.length() == 16 || x->EncryptionKey.length() == 24 || x->EncryptionKey.length() == 32)) { - WriteOpers("\2WARNING\2: Your encryption key is NOT 16, 24 or 32 characters in length, encryption will \2NOT\2 be enabled."); + this->Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your encryption key is NOT 16, 24 or 32 characters in length, encryption will \2NOT\2 be enabled."); } else { - this->WriteLine("AES "+Srv->GetServerName()); + this->WriteLine(std::string("AES ")+this->Instance->Config->ServerName); this->InitAES(x->EncryptionKey,x->Name.c_str()); } } /* found who we're supposed to be connecting to, send the neccessary gubbins. */ - this->WriteLine("SERVER "+Srv->GetServerName()+" "+x->SendPass+" 0 :"+Srv->GetServerDescription()); + this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+x->SendPass+" 0 :"+this->Instance->Config->ServerDesc); return true; } } @@ -766,7 +753,7 @@ class TreeSocket : public InspSocket * If that happens the connection hangs here until it's closed. Unlikely * and rather harmless. */ - Srv->SendOpers("*** Connection to \2"+myhost+"\2 lost link tag(!)"); + this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2 lost link tag(!)"); return true; } @@ -778,7 +765,10 @@ class TreeSocket : public InspSocket */ if (e == I_ERR_CONNECT) { - Srv->SendOpers("*** Connection failed: Connection refused"); + this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Connection to \002"+myhost+"\002 refused"); + Link* MyLink = FindLink(myhost); + if (MyLink) + DoFailOver(MyLink); } } @@ -790,7 +780,7 @@ class TreeSocket : public InspSocket return true; } - /* Recursively send the server tree with distances as hops. + /** Recursively send the server tree with distances as hops. * This is used during network burst to inform the other server * (and any of ITS servers too) of what servers we know about. * If at any point any of these servers already exist on the other @@ -821,10 +811,10 @@ class TreeSocket : public InspSocket std::vector modlist; std::string capabilities = ""; - for (int i = 0; i <= MODCOUNT; i++) + for (int i = 0; i <= this->Instance->GetModuleCount(); i++) { - if ((modules[i]->GetVersion().Flags & VF_STATIC) || (modules[i]->GetVersion().Flags & VF_COMMON)) - modlist.push_back(ServerInstance->Config->module_names[i]); + if (this->Instance->modules[i]->GetVersion().Flags & VF_COMMON) + modlist.push_back(this->Instance->Config->module_names[i]); } sort(modlist.begin(),modlist.end()); for (unsigned int i = 0; i < modlist.size(); i++) @@ -838,37 +828,202 @@ class TreeSocket : public InspSocket void SendCapabilities() { - this->WriteLine("CAPAB "+MyCapabilities()); + irc::commasepstream modulelist(MyCapabilities()); + + this->WriteLine("CAPAB START"); + + /* Send module names, split at 509 length */ + std::string item = "*"; + std::string line = "CAPAB MODULES "; + while ((item = modulelist.GetToken()) != "") + { + if (line.length() + item.length() + 1 > 509) + { + this->WriteLine(line); + line = "CAPAB MODULES "; + } + + if (line != "CAPAB MODULES ") + line.append(","); + + line.append(item); + } + if (line != "CAPAB MODULES ") + this->WriteLine(line); + + int ip6 = 0; + int ip6support = 0; +#ifdef IPV6 + ip6 = 1; +#endif +#ifdef SUPPORT_IP6LINKS + ip6support = 1; +#endif + this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)); + + this->WriteLine("CAPAB END"); + } + + /* Check a comma seperated list for an item */ + bool HasItem(const std::string &list, const std::string &item) + { + irc::commasepstream seplist(list); + + std::string item2 = "*"; + while ((item2 = seplist.GetToken()) != "") + { + if (item2 == item) + return true; + } + + return false; + } + + /* Isolate and return the elements that are different between two comma seperated lists */ + std::string ListDifference(const std::string &one, const std::string &two) + { + irc::commasepstream list_one(one); + std::string item = "*"; + std::string result = ""; + while ((item = list_one.GetToken()) != "") + { + if (!HasItem(two, item)) + { + result.append(" "); + result.append(item); + } + } + return result; } bool Capab(std::deque params) { - if (params.size() != 1) + if (params.size() < 1) { - this->WriteLine("ERROR :Invalid number of parameters for CAPAB"); + this->WriteLine("ERROR :Invalid number of parameters for CAPAB - Mismatched version"); return false; } - if (params[0] != this->MyCapabilities()) + if (params[0] == "START") + { + this->ModuleList = ""; + this->CapKeys.clear(); + } + else if (params[0] == "END") { - std::string quitserver = this->myhost; - if (this->InboundServerName != "") + std::string reason = ""; + int ip6support = 0; +#ifdef SUPPORT_IP6LINKS + ip6support = 1; +#endif + /* Compare ModuleList and check CapKeys... + * Maybe this could be tidier? -- Brain + */ + if ((this->ModuleList != this->MyCapabilities()) && (this->ModuleList.length())) { - quitserver = this->InboundServerName; + std::string diff = ListDifference(this->ModuleList, this->MyCapabilities()); + if (!diff.length()) + { + diff = "your server:" + ListDifference(this->MyCapabilities(), this->ModuleList); + } + else + { + diff = "this server:" + diff; + } + if (diff.length() == 12) + reason = "Module list in CAPAB is not alphabetically ordered, cannot compare lists."; + else + reason = "Modules loaded on these servers are not correctly matched, these modules are not loaded on " + diff; } - WriteOpers("*** \2ERROR\2: Server '%s' does not have the same set of modules loaded, cannot link!",quitserver.c_str()); - WriteOpers("*** Our networked module set is: '%s'",this->MyCapabilities().c_str()); - WriteOpers("*** Other server's networked module set is: '%s'",params[0].c_str()); - WriteOpers("*** These lists must match exactly on both servers. Please correct these errors, and try again."); - this->WriteLine("ERROR :CAPAB mismatch; My capabilities: '"+this->MyCapabilities()+"'"); - return false; + if (((this->CapKeys.find("IP6SUPPORT") == this->CapKeys.end()) && (ip6support)) || ((this->CapKeys.find("IP6SUPPORT") != this->CapKeys.end()) && (this->CapKeys.find("IP6SUPPORT")->second != ConvToStr(ip6support)))) + reason = "We don't both support linking to IPV6 servers"; + + if (((this->CapKeys.find("IP6NATIVE") != this->CapKeys.end()) && (this->CapKeys.find("IP6NATIVE")->second == "1")) && (!ip6support)) + reason = "The remote server is IPV6 native, and we don't support linking to IPV6 servers"; + + if (((this->CapKeys.find("NICKMAX") == this->CapKeys.end()) || ((this->CapKeys.find("NICKMAX") != this->CapKeys.end()) && (this->CapKeys.find("NICKMAX")->second != ConvToStr(NICKMAX))))) + reason = "Maximum nickname lengths differ or remote nickname length not specified"; + + if (((this->CapKeys.find("PROTOCOL") == this->CapKeys.end()) || ((this->CapKeys.find("PROTOCOL") != this->CapKeys.end()) && (this->CapKeys.find("PROTOCOL")->second != ConvToStr(ProtocolVersion))))) + { + if (this->CapKeys.find("PROTOCOL") != this->CapKeys.end()) + { + reason = "Mismatched protocol versions "+this->CapKeys.find("PROTOCOL")->second+" and "+ConvToStr(ProtocolVersion); + } + else + { + reason = "Protocol version not specified"; + } + } + + if (((this->CapKeys.find("HALFOP") == this->CapKeys.end()) && (Instance->Config->AllowHalfop)) || ((this->CapKeys.find("HALFOP") != this->CapKeys.end()) && (this->CapKeys.find("HALFOP")->second != ConvToStr(Instance->Config->AllowHalfop)))) + reason = "We don't both have halfop support enabled/disabled identically"; + + if (((this->CapKeys.find("IDENTMAX") == this->CapKeys.end()) || ((this->CapKeys.find("IDENTMAX") != this->CapKeys.end()) && (this->CapKeys.find("IDENTMAX")->second != ConvToStr(IDENTMAX))))) + reason = "Maximum ident lengths differ or remote ident length not specified"; + + if (((this->CapKeys.find("CHANMAX") == this->CapKeys.end()) || ((this->CapKeys.find("CHANMAX") != this->CapKeys.end()) && (this->CapKeys.find("CHANMAX")->second != ConvToStr(CHANMAX))))) + reason = "Maximum channel lengths differ or remote channel length not specified"; + + if (((this->CapKeys.find("MAXMODES") == this->CapKeys.end()) || ((this->CapKeys.find("MAXMODES") != this->CapKeys.end()) && (this->CapKeys.find("MAXMODES")->second != ConvToStr(MAXMODES))))) + reason = "Maximum modes per line differ or remote modes per line not specified"; + + if (((this->CapKeys.find("MAXQUIT") == this->CapKeys.end()) || ((this->CapKeys.find("MAXQUIT") != this->CapKeys.end()) && (this->CapKeys.find("MAXQUIT")->second != ConvToStr(MAXQUIT))))) + reason = "Maximum quit lengths differ or remote quit length not specified"; + + if (((this->CapKeys.find("MAXTOPIC") == this->CapKeys.end()) || ((this->CapKeys.find("MAXTOPIC") != this->CapKeys.end()) && (this->CapKeys.find("MAXTOPIC")->second != ConvToStr(MAXTOPIC))))) + reason = "Maximum topic lengths differ or remote topic length not specified"; + + if (((this->CapKeys.find("MAXKICK") == this->CapKeys.end()) || ((this->CapKeys.find("MAXKICK") != this->CapKeys.end()) && (this->CapKeys.find("MAXKICK")->second != ConvToStr(MAXKICK))))) + reason = "Maximum kick lengths differ or remote kick length not specified"; + + if (((this->CapKeys.find("MAXGECOS") == this->CapKeys.end()) || ((this->CapKeys.find("MAXGECOS") != this->CapKeys.end()) && (this->CapKeys.find("MAXGECOS")->second != ConvToStr(MAXGECOS))))) + reason = "Maximum GECOS (fullname) lengths differ or remote GECOS length not specified"; + + if (((this->CapKeys.find("MAXAWAY") == this->CapKeys.end()) || ((this->CapKeys.find("MAXAWAY") != this->CapKeys.end()) && (this->CapKeys.find("MAXAWAY")->second != ConvToStr(MAXAWAY))))) + reason = "Maximum awaymessage lengths differ or remote awaymessage length not specified"; + + if (reason.length()) + { + this->WriteLine("ERROR :CAPAB negotiation failed: "+reason); + return false; + } + } + else if ((params[0] == "MODULES") && (params.size() == 2)) + { + if (!this->ModuleList.length()) + { + this->ModuleList.append(params[1]); + } + else + { + this->ModuleList.append(","); + this->ModuleList.append(params[1]); + } + } + else if ((params[0] == "CAPABILITIES") && (params.size() == 2)) + { + irc::tokenstream capabs(params[1]); + std::string item = "*"; + while ((item = capabs.GetToken()) != "") + { + /* Process each key/value pair */ + std::string::size_type equals = item.rfind('='); + if (equals != std::string::npos) + { + std::string var = item.substr(0, equals); + std::string value = item.substr(equals+1, item.length()); + this->Instance->Log(DEBUG,"Key='%s' Value='%s'",var.c_str(),value.c_str()); + CapKeys[var] = value; + } + } } return true; } - /* This function forces this server to quit, removing this server + /** This function forces this server to quit, removing this server * and any users on it (and servers and users below that, etc etc). * It's very slow and pretty clunky, but luckily unless your network * is having a REAL bad hair day, this function shouldnt be called @@ -890,7 +1045,7 @@ class TreeSocket : public InspSocket num_lost_users += Current->QuitUsers(from); } - /* This is a wrapper function for SquitServer above, which + /** This is a wrapper function for SquitServer above, which * does some validation first and passes on the SQUIT to all * other remaining servers. */ @@ -904,11 +1059,11 @@ class TreeSocket : public InspSocket DoOneToAllButSender(Current->GetParent()->GetName(),"SQUIT",params,Current->GetName()); if (Current->GetParent() == TreeRoot) { - Srv->SendOpers("Server \002"+Current->GetName()+"\002 split: "+reason); + this->Instance->WriteOpers("Server \002"+Current->GetName()+"\002 split: "+reason); } else { - Srv->SendOpers("Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason); + this->Instance->WriteOpers("Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason); } num_lost_servers = 0; num_lost_users = 0; @@ -917,15 +1072,15 @@ class TreeSocket : public InspSocket Current->Tidy(); Current->GetParent()->DelChild(Current); DELETE(Current); - WriteOpers("Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers); + this->Instance->WriteOpers("Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers); } else { - log(DEFAULT,"Squit from unknown server"); + Instance->Log(DEFAULT,"Squit from unknown server"); } } - /* FMODE command - server mode with timestamp checks */ + /** FMODE command - server mode with timestamp checks */ bool ForceMode(std::string source, std::deque ¶ms) { /* Chances are this is a 1.0 FMODE without TS */ @@ -939,7 +1094,7 @@ class TreeSocket : public InspSocket std::string sourceserv; /* Are we dealing with an FMODE from a user, or from a server? */ - userrec* who = Srv->FindNick(source); + userrec* who = this->Instance->FindNick(source); if (who) { /* FMODE from a user, set sourceserv to the users server name */ @@ -948,8 +1103,8 @@ class TreeSocket : public InspSocket else { /* FMODE from a server, create a fake user to receive mode feedback */ - who = new userrec(ServerInstance); - who->fd = FD_MAGIC_NUMBER; + who = new userrec(this->Instance); + who->SetFd(FD_MAGIC_NUMBER); smode = true; /* Setting this flag tells us we should free the userrec later */ sourceserv = source; /* Set sourceserv to the actual source string */ } @@ -975,7 +1130,7 @@ class TreeSocket : public InspSocket } /* Extract the TS value of the object, either userrec or chanrec */ - userrec* dst = Srv->FindNick(params[0]); + userrec* dst = this->Instance->FindNick(params[0]); chanrec* chan = NULL; time_t ourTS = 0; if (dst) @@ -984,7 +1139,7 @@ class TreeSocket : public InspSocket } else { - chan = Srv->FindChannel(params[0]); + chan = this->Instance->FindChan(params[0]); if (chan) { ourTS = chan->age; @@ -996,7 +1151,7 @@ class TreeSocket : public InspSocket */ if (TS == ourTS) { - log(DEBUG,"Entering TS equality check"); + Instance->Log(DEBUG,"Entering TS equality check"); ModeHandler* mh = NULL; unsigned long paramptr = 3; std::string to_bounce = ""; @@ -1024,7 +1179,7 @@ class TreeSocket : public InspSocket /* We only care about whats being set, * not whats being unset */ - mh = ServerInstance->ModeGrok->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); + mh = this->Instance->Modes->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); if ((mh) && (mh->GetNumParams(adding) > 0) && (!mh->IsListMode())) { @@ -1089,7 +1244,7 @@ class TreeSocket : public InspSocket } else { - mh = ServerInstance->ModeGrok->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); + mh = this->Instance->Modes->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); if (mh) { @@ -1106,7 +1261,7 @@ class TreeSocket : public InspSocket if ((mh->GetNumParams(adding) > 0) && (paramptr < params.size())) { - log(DEBUG,"Mode removal %d %d",adding, mh->GetNumParams(adding)); + Instance->Log(DEBUG,"Mode removal %d %d",adding, mh->GetNumParams(adding)); params_to_keep.push_back(params[paramptr++]); } } @@ -1114,7 +1269,7 @@ class TreeSocket : public InspSocket } else { - mh = ServerInstance->ModeGrok->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); + mh = this->Instance->Modes->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); if (mh) { @@ -1140,7 +1295,8 @@ class TreeSocket : public InspSocket newparams.push_back(params[0]); newparams.push_back(ConvToStr(ourTS)); newparams.push_back(to_bounce+params_to_bounce); - DoOneToOne(Srv->GetServerName(),"FMODE",newparams,sourceserv); + Instance->Log(DEBUG,"BOUNCE BACK: %s",(to_bounce+params_to_bounce).c_str()); + DoOneToOne(this->Instance->Config->ServerName,"FMODE",newparams,sourceserv); } if (to_keep.length()) @@ -1150,24 +1306,24 @@ class TreeSocket : public InspSocket modelist[0] = params[0].c_str(); modelist[1] = to_keep.c_str(); - if (params_to_keep.size() > 2) + if (params_to_keep.size() > 1) { - for (q = 2; (q < params_to_keep.size()) && (q < 64); q++) + for (q = 0; (q < params_to_keep.size()) && (q < 64); q++) { - log(DEBUG,"Item %d of %d", q, params_to_keep.size()); + Instance->Log(DEBUG,"KEEP Item %d of %d: %s", q, params_to_keep.size(), params_to_keep[q].c_str()); modelist[n++] = params_to_keep[q].c_str(); } } if (smode) { - log(DEBUG,"Send mode"); - Srv->SendMode(modelist, n+2, who); + Instance->Log(DEBUG,"Send mode"); + this->Instance->SendMode(modelist, n+2, who); } else { - log(DEBUG,"Send mode client"); - Srv->CallCommandHandler("MODE", modelist, n+2, who); + Instance->Log(DEBUG,"Send mode client"); + this->Instance->CallCommandHandler("MODE", modelist, n+2, who); } /* HOT POTATO! PASS IT ON! */ @@ -1176,7 +1332,7 @@ class TreeSocket : public InspSocket } else /* U-lined servers always win regardless of their TS */ - if ((TS > ourTS) && (!Srv->IsUlined(source))) + if ((TS > ourTS) && (!this->Instance->ULine(source.c_str()))) { /* Bounce the mode back to its sender.* We use our lower TS, so the other end * SHOULD accept it, if its clock is right. @@ -1221,7 +1377,7 @@ class TreeSocket : public InspSocket break; default: /* Find the mode handler for this mode */ - mh = ServerInstance->ModeGrok->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); + mh = this->Instance->Modes->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER); /* Got a mode handler? * This also prevents us bouncing modes we have no handler for. @@ -1280,24 +1436,24 @@ class TreeSocket : public InspSocket /* Update the parameters for FMODE with the new 'bounced' string */ newparams[2] = modebounce; /* Only send it back the way it came, no need to send it anywhere else */ - DoOneToOne(Srv->GetServerName(),"FMODE",newparams,sourceserv); - log(DEBUG,"FMODE bounced intelligently, our TS less than theirs and the other server is NOT a uline."); + DoOneToOne(this->Instance->Config->ServerName,"FMODE",newparams,sourceserv); + Instance->Log(DEBUG,"FMODE bounced intelligently, our TS less than theirs and the other server is NOT a uline."); } else { - log(DEBUG,"Allow modes, TS lower for sender"); + Instance->Log(DEBUG,"Allow modes, TS lower for sender"); /* The server was ulined, but something iffy is up with the TS. * Sound the alarm bells! */ - if ((Srv->IsUlined(sourceserv)) && (TS > ourTS)) + if ((this->Instance->ULine(sourceserv.c_str())) && (TS > ourTS)) { - WriteOpers("\2WARNING!\2 U-Lined server '%s' has bad TS for '%s' (accepted change): \2SYNC YOUR CLOCKS\2 to avoid this notice",sourceserv.c_str(),params[0].c_str()); + this->Instance->WriteOpers("\2WARNING!\2 U-Lined server '%s' has bad TS for '%s' (accepted change): \2SYNC YOUR CLOCKS\2 to avoid this notice",sourceserv.c_str(),params[0].c_str()); } /* Allow the mode, route it to either server or user command handling */ if (smode) - Srv->SendMode(modelist,n,who); + this->Instance->SendMode(modelist,n,who); else - Srv->CallCommandHandler("MODE", modelist, n, who); + this->Instance->CallCommandHandler("MODE", modelist, n, who); /* HOT POTATO! PASS IT ON! */ DoOneToAllButSender(source,"FMODE",params,sourceserv); @@ -1309,7 +1465,7 @@ class TreeSocket : public InspSocket return true; } - /* FTOPIC command */ + /** FTOPIC command */ bool ForceTopic(std::string source, std::deque ¶ms) { if (params.size() != 4) @@ -1317,7 +1473,7 @@ class TreeSocket : public InspSocket time_t ts = atoi(params[1].c_str()); std::string nsource = source; - chanrec* c = Srv->FindChannel(params[0]); + chanrec* c = this->Instance->FindChan(params[0]); if (c) { if ((ts >= c->topicset) || (!*c->topic)) @@ -1332,7 +1488,7 @@ class TreeSocket : public InspSocket */ if (oldtopic != params[3]) { - userrec* user = Srv->FindNick(source); + userrec* user = this->Instance->FindNick(source); if (!user) { c->WriteChannelWithServ(source.c_str(), "TOPIC %s :%s", c->name, c->topic); @@ -1353,7 +1509,7 @@ class TreeSocket : public InspSocket return true; } - /* FJOIN, similar to unreal SJOIN */ + /** FJOIN, similar to unreal SJOIN */ bool ForceJoin(std::string source, std::deque ¶ms) { if (params.size() < 3) @@ -1373,7 +1529,7 @@ class TreeSocket : public InspSocket time_t TS = atoi(params[1].c_str()); char* key = ""; - chanrec* chan = Srv->FindChannel(channel); + chanrec* chan = this->Instance->FindChan(channel); if (chan) { key = chan->key; @@ -1384,47 +1540,73 @@ class TreeSocket : public InspSocket * channel will let the other side apply their modes. */ time_t ourTS = time(NULL)+600; - chanrec* us = Srv->FindChannel(channel); + chanrec* us = this->Instance->FindChan(channel); if (us) { ourTS = us->age; } - log(DEBUG,"FJOIN detected, our TS=%lu, their TS=%lu",ourTS,TS); + /* XXX: PAY ATTENTION: + * In 1.1, if they have the newer channel, we immediately clear + * all status modes from our users. We then accept their modes. + * If WE have the newer channel its the other side's job to do this. + * Note that this causes the losing server to send out confirming + * FMODE lines. + */ + if ((ourTS > TS) || (this->Instance->ULine(source.c_str()))) + { + Instance->Log(DEBUG,"FJOIN detected, our TS=%lu, their TS=%lu",ourTS,TS); + std::deque param_list; + us->age = TS; + ourTS = TS; + param_list.push_back(chan->name); + Instance->Log(DEBUG,"REMOVE ALL STATUS MODES FROM OUR USERS *NOW*"); + this->RemoveStatus(Instance->Config->ServerName, param_list); + } + + irc::tokenstream users(params[2]); + std::string item = "*"; /* do this first, so our mode reversals are correctly received by other servers * if there is a TS collision. */ + params[2] = ":" + params[2]; DoOneToAllButSender(source,"FJOIN",params,source); - - for (unsigned int usernum = 2; usernum < params.size(); usernum++) + while (item != "") { - /* process one channel at a time, applying modes. */ - char* usr = (char*)params[usernum].c_str(); + item = users.GetToken(); + /* process one user at a time, applying modes. */ + char* usr = (char*)item.c_str(); /* Safety check just to make sure someones not sent us an FJOIN full of spaces * (is this even possible?) */ if (usr && *usr) { - char permissions = *usr; - switch (permissions) + char* permissions = usr; + int ntimes = 0; + while ((*permissions) && (*permissions != ',')) { - case '@': - usr++; - mode_users[modectr++] = usr; - strlcat(modestring,"o",MAXBUF); - break; - case '%': - usr++; - mode_users[modectr++] = usr; - strlcat(modestring,"h",MAXBUF); - break; - case '+': - usr++; - mode_users[modectr++] = usr; - strlcat(modestring,"v",MAXBUF); - break; + ModeHandler* mh = Instance->Modes->FindPrefix(*permissions); + if (mh) + { + ntimes++; + charlcat(modestring,mh->GetModeChar(),MAXBUF); + } + else + { + this->Instance->WriteOpers("ERROR: We received a user with an unknown prefix '%c'. Closed connection to avoid a desync.",mh->GetPrefix()); + this->WriteLine(std::string("ERROR :Invalid prefix '")+mh->GetModeChar()+"' in FJOIN"); + return false; + } + usr++; + permissions++; } - who = Srv->FindNick(usr); + usr++; + + /* Did they get any modes? How many times? */ + for (int k = 0; k < ntimes; k++) + mode_users[modectr++] = strdup(usr); + + who = this->Instance->FindNick(usr); if (who) { chanrec::JoinUser(this->Instance, who, channel.c_str(), true, key); @@ -1433,41 +1615,29 @@ class TreeSocket : public InspSocket /* theres a mode for this user. push them onto the mode queue, and flush it * if there are more than MAXMODES to go. */ - if ((ourTS >= TS) || (Srv->IsUlined(who->server))) + if ((ourTS >= TS) || (this->Instance->ULine(who->server))) { /* We also always let u-lined clients win, no matter what the TS value */ - log(DEBUG,"Our our channel newer than theirs, accepting their modes"); - Srv->SendMode((const char**)mode_users,modectr,who); + Instance->Log(DEBUG,"Our our channel newer than theirs, accepting their modes"); + this->Instance->SendMode((const char**)mode_users,modectr,who); if (ourTS != TS) { - log(DEFAULT,"Channel TS for %s changed from %lu to %lu",us->name,ourTS,TS); + Instance->Log(DEFAULT,"Channel TS for %s changed from %lu to %lu",us->name,ourTS,TS); us->age = TS; ourTS = TS; } } - else - { - log(DEBUG,"Their channel newer than ours, bouncing their modes"); - /* bouncy bouncy! */ - std::deque params; - /* modes are now being UNSET... */ - *mode_users[1] = '-'; - for (unsigned int x = 0; x < modectr; x++) - { - if (x == 1) - { - params.push_back(ConvToStr(us->age)); - } - params.push_back(mode_users[x]); - - } - // tell everyone to bounce the modes. bad modes, bad! - DoOneToMany(Srv->GetServerName(),"FMODE",params); - } strcpy(mode_users[1],"+"); + for (unsigned int f = 2; f < modectr; f++) + free(mode_users[f]); modectr = 2; } } + else + { + Instance->Log(SPARSE,"Warning! Invalid user in FJOIN to channel %s IGNORED", channel.c_str()); + continue; + } } } /* there werent enough modes built up to flush it during FJOIN, @@ -1477,62 +1647,30 @@ class TreeSocket : public InspSocket { if (ourTS >= TS) { - log(DEBUG,"Our our channel newer than theirs, accepting their modes"); - Srv->SendMode((const char**)mode_users,modectr,who); + Instance->Log(DEBUG,"Our our channel newer than theirs, accepting their modes"); + this->Instance->SendMode((const char**)mode_users,modectr,who); if (ourTS != TS) { - log(DEFAULT,"Channel TS for %s changed from %lu to %lu",us->name,ourTS,TS); + Instance->Log(DEFAULT,"Channel TS for %s changed from %lu to %lu",us->name,ourTS,TS); us->age = TS; ourTS = TS; } } - else - { - log(DEBUG,"Their channel newer than ours, bouncing their modes"); - std::deque params; - *mode_users[1] = '-'; - for (unsigned int x = 0; x < modectr; x++) - { - if (x == 1) - { - params.push_back(ConvToStr(us->age)); - } - params.push_back(mode_users[x]); - } - DoOneToMany(Srv->GetServerName(),"FMODE",params); - } - } - return true; - } - bool SyncChannelTS(std::string source, std::deque ¶ms) - { - if (params.size() >= 2) - { - chanrec* c = Srv->FindChannel(params[0]); - if (c) - { - time_t theirTS = atoi(params[1].c_str()); - time_t ourTS = c->age; - if (ourTS >= theirTS) - { - log(DEBUG,"Updating timestamp for %s, our timestamp was %lu and theirs is %lu",c->name,ourTS,theirTS); - c->age = theirTS; - } - } + for (unsigned int f = 2; f < modectr; f++) + free(mode_users[f]); } - DoOneToAllButSender(Srv->GetServerName(),"SYNCTS",params,source); return true; } - /* NICK command */ + /** NICK command */ bool IntroduceClient(std::string source, std::deque ¶ms) { if (params.size() < 8) return true; if (params.size() > 8) { - this->WriteLine(":"+Srv->GetServerName()+" KILL "+params[1]+" :Invalid client introduction ("+params[1]+"?)"); + this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction ("+params[1]+"?)"); return true; } // NICK age nick host dhost ident +modes ip :gecos @@ -1542,24 +1680,26 @@ class TreeSocket : public InspSocket /* This used to have a pretty craq'y loop doing the same thing, * now we just let the STL do the hard work (more efficiently) */ - params[5] = params[5].substr(params[5].find_first_not_of('+')); + std::string::size_type pos_after_plus = params[5].find_first_not_of('+'); + if (pos_after_plus != std::string::npos) + params[5] = params[5].substr(pos_after_plus); const char* tempnick = params[1].c_str(); - log(DEBUG,"Introduce client %s!%s@%s",tempnick,params[4].c_str(),params[2].c_str()); + Instance->Log(DEBUG,"Introduce client %s!%s@%s",tempnick,params[4].c_str(),params[2].c_str()); user_hash::iterator iter = this->Instance->clientlist.find(tempnick); if (iter != this->Instance->clientlist.end()) { // nick collision - log(DEBUG,"Nick collision on %s!%s@%s: %lu %lu",tempnick,params[4].c_str(),params[2].c_str(),(unsigned long)age,(unsigned long)iter->second->age); - this->WriteLine(":"+Srv->GetServerName()+" KILL "+tempnick+" :Nickname collision"); + Instance->Log(DEBUG,"Nick collision on %s!%s@%s: %lu %lu",tempnick,params[4].c_str(),params[2].c_str(),(unsigned long)age,(unsigned long)iter->second->age); + this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+tempnick+" :Nickname collision"); return true; } userrec* _new = new userrec(this->Instance); this->Instance->clientlist[tempnick] = _new; - _new->fd = FD_MAGIC_NUMBER; + _new->SetFd(FD_MAGIC_NUMBER); strlcpy(_new->nick, tempnick,NICKMAX-1); strlcpy(_new->host, params[2].c_str(),63); strlcpy(_new->dhost, params[3].c_str(),63); @@ -1572,12 +1712,14 @@ class TreeSocket : public InspSocket for (std::string::iterator v = params[5].begin(); v != params[5].end(); v++) _new->modes[(*v)-65] = 1; +#ifdef SUPPORT_IP6LINKS if (params[6].find_first_of(":") != std::string::npos) _new->SetSockAddr(AF_INET6, params[6].c_str(), 0); else +#endif _new->SetSockAddr(AF_INET, params[6].c_str(), 0); - WriteOpers("*** Client connecting at %s: %s!%s@%s [%s]",_new->server,_new->nick,_new->ident,_new->host, _new->GetIPString()); + this->Instance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s!%s@%s [%s]",_new->server,_new->nick,_new->ident,_new->host, _new->GetIPString()); params[7] = ":" + params[7]; DoOneToAllButSender(source,"NICK",params,source); @@ -1586,25 +1728,25 @@ class TreeSocket : public InspSocket TreeServer* SourceServer = FindServer(source); if (SourceServer) { - log(DEBUG,"Found source server of %s",_new->nick); + Instance->Log(DEBUG,"Found source server of %s",_new->nick); SourceServer->AddUserCount(); } return true; } - /* Send one or more FJOINs for a channel of users. + /** Send one or more FJOINs for a channel of users. * If the length of a single line is more than 480-NICKMAX * in length, it is split over multiple lines. */ void SendFJoins(TreeServer* Current, chanrec* c) { - log(DEBUG,"Sending FJOINs to other server for %s",c->name); + Instance->Log(DEBUG,"Sending FJOINs to other server for %s",c->name); char list[MAXBUF]; - std::string individual_halfops = ":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age); + std::string individual_halfops = std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age); size_t dlen, curlen; - dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",Srv->GetServerName().c_str(),c->name,(unsigned long)c->age); + dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age); int numusers = 0; char* ptr = list + dlen; @@ -1616,31 +1758,8 @@ class TreeSocket : public InspSocket for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) { - int x = cflags(i->second,c); - if ((x & UCMODE_HOP) && (x & UCMODE_OP)) - { - specific_halfop.push_back(i->second); - } - if (((x & UCMODE_HOP) || (x & UCMODE_OP)) && (x & UCMODE_VOICE)) - { - specific_voice.push_back(i->second); - } - - const char* n = ""; - if (x & UCMODE_OP) - { - n = "@"; - } - else if (x & UCMODE_HOP) - { - n = "%"; - } - else if (x & UCMODE_VOICE) - { - n = "+"; - } - - size_t ptrlen = snprintf(ptr, MAXBUF, " %s%s", n, i->second->nick); + // The first parameter gets a : before it + size_t ptrlen = snprintf(ptr, MAXBUF, " %s%s,%s", !numusers ? ":" : "", c->GetAllPrefixChars(i->second), i->second->nick); curlen += ptrlen; ptr += ptrlen; @@ -1650,109 +1769,81 @@ class TreeSocket : public InspSocket if (curlen > (480-NICKMAX)) { this->WriteLine(list); - dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",Srv->GetServerName().c_str(),c->name,(unsigned long)c->age); + dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age); ptr = list + dlen; ptrlen = 0; numusers = 0; - for (unsigned int y = 0; y < specific_voice.size(); y++) - { - modes.append("v"); - params.append(specific_voice[y]->nick).append(" "); - //this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +v "+specific_voice[y]->nick); - } - for (unsigned int y = 0; y < specific_halfop.size(); y++) - { - modes.append("h"); - params.append(specific_halfop[y]->nick).append(" "); - //this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +h "+specific_halfop[y]->nick); - } } } + if (numusers) - { this->WriteLine(list); - for (unsigned int y = 0; y < specific_voice.size(); y++) - { - modes.append("v"); - params.append(specific_voice[y]->nick).append(" "); - //this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +v "+specific_voice[y]->nick); - } - for (unsigned int y = 0; y < specific_halfop.size(); y++) - { - modes.append("h"); - params.append(specific_halfop[y]->nick).append(" "); - //this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +h "+specific_halfop[y]->nick); - } - } - //std::string modes = ""; - //std::string params = ""; + for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) { modes.append("b"); params.append(b->data).append(" "); } - /* XXX: Send each channel mode and its params -- we'll need a method for this in ModeHandler? */ - //FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(c->second,(Module*)TreeProtocolModule,(void*)this)); - this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +"+chanmodes(c,true)+modes+" "+params); + this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" +"+c->ChanModes(true)+modes+" "+params); } - /* Send G, Q, Z and E lines */ + /** Send G, Q, Z and E lines */ void SendXLines(TreeServer* Current) { char data[MAXBUF]; - std::string n = Srv->GetServerName(); + std::string n = this->Instance->Config->ServerName; const char* sn = n.c_str(); int iterations = 0; /* Yes, these arent too nice looking, but they get the job done */ - for (std::vector::iterator i = zlines.begin(); i != zlines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s",sn,i->ipaddr,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } - for (std::vector::iterator i = qlines.begin(); i != qlines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s",sn,i->nick,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } - for (std::vector::iterator i = glines.begin(); i != glines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE G %s %s %lu %lu :%s",sn,i->hostmask,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE G %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } - for (std::vector::iterator i = elines.begin(); i != elines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE E %s %s %lu %lu :%s",sn,i->hostmask,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE E %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } - for (std::vector::iterator i = pzlines.begin(); i != pzlines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s",sn,i->ipaddr,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } - for (std::vector::iterator i = pqlines.begin(); i != pqlines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s",sn,i->nick,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } - for (std::vector::iterator i = pglines.begin(); i != pglines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE G %s %s %lu %lu :%s",sn,i->hostmask,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE G %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } - for (std::vector::iterator i = pelines.begin(); i != pelines.end(); i++, iterations++) + for (std::vector::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE E %s %s %lu %lu :%s",sn,i->hostmask,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason); + snprintf(data,MAXBUF,":%s ADDLINE E %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); this->WriteLine(data); } } - /* Send channel modes and topics */ + /** Send channel modes and topics */ void SendChannelModes(TreeServer* Current) { char data[MAXBUF]; std::deque list; int iterations = 0; - std::string n = Srv->GetServerName(); + std::string n = this->Instance->Config->ServerName; const char* sn = n.c_str(); for (chan_hash::iterator c = this->Instance->chanlist.begin(); c != this->Instance->chanlist.end(); c++, iterations++) { @@ -1762,17 +1853,17 @@ class TreeSocket : public InspSocket snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s",sn,c->second->name,(unsigned long)c->second->topicset,c->second->setby,c->second->topic); this->WriteLine(data); } - FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(c->second,(Module*)TreeProtocolModule,(void*)this)); + FOREACH_MOD_I(this->Instance,I_OnSyncChannel,OnSyncChannel(c->second,(Module*)TreeProtocolModule,(void*)this)); list.clear(); c->second->GetExtList(list); for (unsigned int j = 0; j < list.size(); j++) { - FOREACH_MOD(I_OnSyncChannelMetaData,OnSyncChannelMetaData(c->second,(Module*)TreeProtocolModule,(void*)this,list[j])); + FOREACH_MOD_I(this->Instance,I_OnSyncChannelMetaData,OnSyncChannelMetaData(c->second,(Module*)TreeProtocolModule,(void*)this,list[j])); } } } - /* send all users and their oper state/modes */ + /** send all users and their oper state/modes */ void SendUsers(TreeServer* Current) { char data[MAXBUF]; @@ -1792,18 +1883,18 @@ class TreeSocket : public InspSocket { this->WriteLine(":"+std::string(u->second->nick)+" AWAY :"+std::string(u->second->awaymsg)); } - FOREACH_MOD(I_OnSyncUser,OnSyncUser(u->second,(Module*)TreeProtocolModule,(void*)this)); + FOREACH_MOD_I(this->Instance,I_OnSyncUser,OnSyncUser(u->second,(Module*)TreeProtocolModule,(void*)this)); list.clear(); u->second->GetExtList(list); for (unsigned int j = 0; j < list.size(); j++) { - FOREACH_MOD(I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)TreeProtocolModule,(void*)this,list[j])); + FOREACH_MOD_I(this->Instance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)TreeProtocolModule,(void*)this,list[j])); } } } } - /* This function is called when we want to send a netburst to a local + /** This function is called when we want to send a netburst to a local * server. There is a set order we must do this, because for example * users require their servers to exist, and channels require their * users to exist. You get the idea. @@ -1814,10 +1905,10 @@ class TreeSocket : public InspSocket std::string endburst = "ENDBURST"; // Because by the end of the netburst, it could be gone! std::string name = s->GetName(); - Srv->SendOpers("*** Bursting to \2"+name+"\2."); + this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2"+name+"\2."); this->WriteLine(burst); /* send our version string */ - this->WriteLine(":"+Srv->GetServerName()+" VERSION :"+Srv->GetVersion()); + this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" VERSION :"+this->Instance->GetVersionString()); /* Send server tree */ this->SendServers(TreeRoot,s,1); /* Send users and their oper status */ @@ -1825,12 +1916,12 @@ class TreeSocket : public InspSocket /* Send everything else (channel modes, xlines etc) */ this->SendChannelModes(s); this->SendXLines(s); - FOREACH_MOD(I_OnSyncOtherMetaData,OnSyncOtherMetaData((Module*)TreeProtocolModule,(void*)this)); + FOREACH_MOD_I(this->Instance,I_OnSyncOtherMetaData,OnSyncOtherMetaData((Module*)TreeProtocolModule,(void*)this)); this->WriteLine(endburst); - Srv->SendOpers("*** Finished bursting to \2"+name+"\2."); + this->Instance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+name+"\2."); } - /* This function is called when we receive data from a remote + /** This function is called when we receive data from a remote * server. We buffer the data in a std::string (it doesnt stay * there for long), reading using InspSocket::Read() which can * read up to 16 kilobytes in one operation. @@ -1863,14 +1954,14 @@ class TreeSocket : public InspSocket char result[1024]; memset(result,0,1024); memset(out,0,1024); - log(DEBUG,"Original string '%s'",ret.c_str()); + Instance->Log(DEBUG,"Original string '%s'",ret.c_str()); /* ERROR + CAPAB is still allowed unencryped */ if ((ret.substr(0,7) != "ERROR :") && (ret.substr(0,6) != "CAPAB ")) { int nbytes = from64tobits(out, ret.c_str(), 1024); if ((nbytes > 0) && (nbytes < 1024)) { - log(DEBUG,"m_spanningtree: decrypt %d bytes",nbytes); + Instance->Log(DEBUG,"m_spanningtree: decrypt %d bytes",nbytes); ctx_in->Decrypt(out, result, nbytes, 0); for (int t = 0; t < nbytes; t++) if (result[t] == '\7') result[t] = 0; @@ -1880,7 +1971,7 @@ class TreeSocket : public InspSocket } if (!this->ProcessLine(ret)) { - log(DEBUG,"ProcessLine says no!"); + Instance->Log(DEBUG,"ProcessLine says no!"); return false; } } @@ -1894,7 +1985,7 @@ class TreeSocket : public InspSocket int WriteLine(std::string line) { - log(DEBUG,"OUT: %s",line.c_str()); + Instance->Log(DEBUG,"OUT: %s",line.c_str()); if (this->ctx_out) { char result[10240]; @@ -1905,7 +1996,7 @@ class TreeSocket : public InspSocket int n = this->keylength - (line.length() % this->keylength); if (n) { - log(DEBUG,"Append %d chars to line to make it %d long from %d, key length %d",n,n+line.length(),line.length(),this->keylength); + Instance->Log(DEBUG,"Append %d chars to line to make it %d long from %d, key length %d",n,n+line.length(),line.length(),this->keylength); line.append(n,'\7'); } } @@ -1923,11 +2014,100 @@ class TreeSocket : public InspSocket { if (params.size() < 1) return false; - WriteOpers("*** ERROR from %s: %s",(InboundServerName != "" ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str()); + this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(InboundServerName != "" ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str()); /* we will return false to cause the socket to close. */ return false; } + /** remote MOTD. leet, huh? */ + bool Motd(std::string prefix, std::deque ¶ms) + { + if (params.size() > 0) + { + if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0])) + { + /* It's for our server */ + string_list results; + userrec* source = this->Instance->FindNick(prefix); + + if (source) + { + std::deque par; + par.push_back(prefix); + par.push_back(""); + + if (!Instance->Config->MOTD.size()) + { + par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing."; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + return true; + } + + par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day"; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + + for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++) + { + par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i]; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + } + + par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" End of message of the day."; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + } + } + else + { + /* Pass it on */ + userrec* source = this->Instance->FindNick(prefix); + if (source) + DoOneToOne(prefix, "MOTD", params, params[0]); + } + } + return true; + } + + /** remote ADMIN. leet, huh? */ + bool Admin(std::string prefix, std::deque ¶ms) + { + if (params.size() > 0) + { + if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0])) + { + /* It's for our server */ + string_list results; + userrec* source = this->Instance->FindNick(prefix); + + if (source) + { + std::deque par; + par.push_back(prefix); + par.push_back(""); + + par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + + par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name - "+Instance->Config->AdminName; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + + par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + + par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail - "+Instance->Config->AdminEmail; + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); + } + } + else + { + /* Pass it on */ + userrec* source = this->Instance->FindNick(prefix); + if (source) + DoOneToOne(prefix, "ADMIN", params, params[0]); + } + } + return true; + } + bool Stats(std::string prefix, std::deque ¶ms) { /* Get the reply to a STATS query if it matches this servername, @@ -1935,28 +2115,28 @@ class TreeSocket : public InspSocket */ if (params.size() > 1) { - if (Srv->MatchText(Srv->GetServerName(), params[1])) + if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1])) { /* It's for our server */ string_list results; - userrec* source = Srv->FindNick(prefix); + userrec* source = this->Instance->FindNick(prefix); if (source) { std::deque par; par.push_back(prefix); par.push_back(""); - DoStats(*(params[0].c_str()), source, results); + DoStats(this->Instance, *(params[0].c_str()), source, results); for (size_t i = 0; i < results.size(); i++) { par[1] = "::" + results[i]; - DoOneToOne(Srv->GetServerName(), "PUSH",par, source->server); + DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); } } } else { /* Pass it on */ - userrec* source = Srv->FindNick(prefix); + userrec* source = this->Instance->FindNick(prefix); if (source) DoOneToOne(prefix, "STATS", params, params[1]); } @@ -1965,18 +2145,18 @@ class TreeSocket : public InspSocket } - /* Because the core won't let users or even SERVERS set +o, + /** Because the core won't let users or even SERVERS set +o, * we use the OPERTYPE command to do this. */ bool OperType(std::string prefix, std::deque ¶ms) { if (params.size() != 1) { - log(DEBUG,"Received invalid oper type from %s",prefix.c_str()); + Instance->Log(DEBUG,"Received invalid oper type from %s",prefix.c_str()); return true; } std::string opertype = params[0]; - userrec* u = Srv->FindNick(prefix); + userrec* u = this->Instance->FindNick(prefix); if (u) { u->modes[UM_OPERATOR] = 1; @@ -1986,7 +2166,7 @@ class TreeSocket : public InspSocket return true; } - /* Because Andy insists that services-compatible servers must + /** Because Andy insists that services-compatible servers must * implement SVSNICK and SVSJOIN, that's exactly what we do :p */ bool ForceNick(std::string prefix, std::deque ¶ms) @@ -1994,7 +2174,7 @@ class TreeSocket : public InspSocket if (params.size() < 3) return true; - userrec* u = Srv->FindNick(params[0]); + userrec* u = this->Instance->FindNick(params[0]); if (u) { @@ -2022,7 +2202,7 @@ class TreeSocket : public InspSocket if (params.size() < 2) return true; - userrec* u = Srv->FindNick(params[0]); + userrec* u = this->Instance->FindNick(params[0]); if (u) { @@ -2039,10 +2219,10 @@ class TreeSocket : public InspSocket std::string servermask = params[0]; - if (Srv->MatchText(Srv->GetServerName(),servermask)) + if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask)) { - Srv->SendOpers("*** Remote rehash initiated from server \002"+prefix+"\002."); - Srv->RehashServer(); + this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated from server \002"+prefix+"\002."); + this->Instance->RehashServer(); ReadConfiguration(false); } DoOneToAllButSender(prefix,"REHASH",params,prefix); @@ -2055,8 +2235,8 @@ class TreeSocket : public InspSocket return true; std::string nick = params[0]; - userrec* u = Srv->FindNick(prefix); - userrec* who = Srv->FindNick(nick); + userrec* u = this->Instance->FindNick(prefix); + userrec* who = this->Instance->FindNick(nick); if (who) { @@ -2095,7 +2275,7 @@ class TreeSocket : public InspSocket else { std::string forwardto = params[1]; - if (forwardto == Srv->GetServerName()) + if (forwardto == this->Instance->Config->ServerName) { /* * this is a PONG for us @@ -2103,7 +2283,7 @@ class TreeSocket : public InspSocket * dump the PONG reply back to their fd. If its a server, do nowt. * Services might want to send these s->s, but we dont need to yet. */ - userrec* u = Srv->FindNick(prefix); + userrec* u = this->Instance->FindNick(prefix); if (u) { @@ -2131,22 +2311,22 @@ class TreeSocket : public InspSocket { if (params[0] == "*") { - FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2])); + FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2])); } else if (*(params[0].c_str()) == '#') { - chanrec* c = Srv->FindChannel(params[0]); + chanrec* c = this->Instance->FindChan(params[0]); if (c) { - FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2])); + FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2])); } } else if (*(params[0].c_str()) != '#') { - userrec* u = Srv->FindNick(params[0]); + userrec* u = this->Instance->FindNick(params[0]); if (u) { - FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2])); + FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2])); } } } @@ -2177,7 +2357,7 @@ class TreeSocket : public InspSocket if (params.size() < 1) return true; - userrec* u = Srv->FindNick(prefix); + userrec* u = this->Instance->FindNick(prefix); if (u) { @@ -2197,27 +2377,27 @@ class TreeSocket : public InspSocket switch (*(params[0].c_str())) { case 'Z': - propogate = add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); + propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); + Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'Q': - propogate = add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); + propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); + Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'E': - propogate = add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); + propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); + Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'G': - propogate = add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); + propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); + Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'K': - propogate = add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); + propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); break; default: /* Just in case... */ - Srv->SendOpers("*** \2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!"); + this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!"); propogate = false; break; } @@ -2227,19 +2407,19 @@ class TreeSocket : public InspSocket { if (atoi(params[4].c_str())) { - WriteOpers("*** %s Added %cLINE on %s to expire in %lu seconds (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),atoi(params[4].c_str()),params[5].c_str()); + this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire in %lu seconds (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),atoi(params[4].c_str()),params[5].c_str()); } else { - WriteOpers("*** %s Added permenant %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str()); + this->Instance->SNO->WriteToSnoMask('x',"%s Added permenant %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str()); } params[5] = ":" + params[5]; DoOneToAllButSender(prefix,"ADDLINE",params,prefix); } if (!this->bursting) { - log(DEBUG,"Applying lines..."); - apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); + Instance->Log(DEBUG,"Applying lines..."); + Instance->XLines->apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); } return true; } @@ -2249,7 +2429,7 @@ class TreeSocket : public InspSocket if (params.size() < 1) return true; - userrec* u = Srv->FindNick(prefix); + userrec* u = this->Instance->FindNick(prefix); if (u) { @@ -2265,23 +2445,22 @@ class TreeSocket : public InspSocket if (params.size() < 1) return true; - log(DEBUG,"In IDLE command"); - userrec* u = Srv->FindNick(prefix); + Instance->Log(DEBUG,"In IDLE command"); + userrec* u = this->Instance->FindNick(prefix); if (u) { - log(DEBUG,"USER EXISTS: %s",u->nick); + Instance->Log(DEBUG,"USER EXISTS: %s",u->nick); // an incoming request if (params.size() == 1) { - userrec* x = Srv->FindNick(params[0]); + userrec* x = this->Instance->FindNick(params[0]); if ((x) && (IS_LOCAL(x))) { - userrec* x = Srv->FindNick(params[0]); - log(DEBUG,"Got IDLE"); + userrec* x = this->Instance->FindNick(params[0]); char signon[MAXBUF]; char idle[MAXBUF]; - log(DEBUG,"Sending back IDLE 3"); + snprintf(signon,MAXBUF,"%lu",(unsigned long)x->signon); snprintf(idle,MAXBUF,"%lu",(unsigned long)abs((x->idle_lastmsg)-time(NULL))); std::deque par; @@ -2300,16 +2479,15 @@ class TreeSocket : public InspSocket else if (params.size() == 3) { std::string who_did_the_whois = params[0]; - userrec* who_to_send_to = Srv->FindNick(who_did_the_whois); + userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois); if ((who_to_send_to) && (IS_LOCAL(who_to_send_to))) { - log(DEBUG,"Got final IDLE"); // an incoming reply to a whois we sent out std::string nick_whoised = prefix; unsigned long signon = atoi(params[1].c_str()); unsigned long idle = atoi(params[2].c_str()); if ((who_to_send_to) && (IS_LOCAL(who_to_send_to))) - do_whois(who_to_send_to,u,signon,idle,nick_whoised.c_str()); + do_whois(this->Instance,who_to_send_to,u,signon,idle,nick_whoised.c_str()); } else { @@ -2326,7 +2504,7 @@ class TreeSocket : public InspSocket if (params.size() < 2) return true; - userrec* u = Srv->FindNick(params[0]); + userrec* u = this->Instance->FindNick(params[0]); if (!u) return true; @@ -2351,22 +2529,22 @@ class TreeSocket : public InspSocket if (params.size() == 2) { // someone querying our time? - if (Srv->GetServerName() == params[0]) + if (this->Instance->Config->ServerName == params[0]) { - userrec* u = Srv->FindNick(params[1]); + userrec* u = this->Instance->FindNick(params[1]); if (u) { char curtime[256]; snprintf(curtime,256,"%lu",(unsigned long)time(NULL)); params.push_back(curtime); params[0] = prefix; - DoOneToOne(Srv->GetServerName(),"TIME",params,params[0]); + DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]); } } else { // not us, pass it on - userrec* u = Srv->FindNick(params[1]); + userrec* u = this->Instance->FindNick(params[1]); if (u) DoOneToOne(prefix,"TIME",params,params[0]); } @@ -2374,7 +2552,7 @@ class TreeSocket : public InspSocket else if (params.size() == 3) { // a response to a previous TIME - userrec* u = Srv->FindNick(params[1]); + userrec* u = this->Instance->FindNick(params[1]); if ((u) && (IS_LOCAL(u))) { time_t rawtime = atol(params[2].c_str()); @@ -2402,13 +2580,13 @@ class TreeSocket : public InspSocket if (params.size() == 1) { std::string stufftobounce = params[0]; - this->WriteLine(":"+Srv->GetServerName()+" PONG "+stufftobounce); + this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce); return true; } else { std::string forwardto = params[1]; - if (forwardto == Srv->GetServerName()) + if (forwardto == this->Instance->Config->ServerName) { // this is a ping for us, send back PONG to the requesting server params[1] = params[0]; @@ -2424,6 +2602,52 @@ class TreeSocket : public InspSocket } } + bool RemoveStatus(std::string prefix, std::deque ¶ms) + { + if (params.size() < 1) + return true; + + chanrec* c = Instance->FindChan(params[0]); + + if (c) + { + CUList *ulist = c->GetUsers(); + for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) + { + std::string modesequence = Instance->Modes->ModeString(i->second, c); + if (modesequence.length()) + { + modesequence = "-" + modesequence; + + std::deque items; + const char* y[127]; + unsigned int z = 0; + std::string x = "*"; + irc::spacesepstream sep(modesequence); + + while ((x = sep.GetToken()) != "") + { + if (!z) + { + y[z++] = c->name; + items.push_back(c->name); + items.push_back(ConvToStr(c->age)); + } + items.push_back(x); + y[z++] = (items.end() - 1)->c_str(); + } + + DoOneToMany(Instance->Config->ServerName, "FMODE", items); + userrec* n = new userrec(Instance); + n->SetFd(FD_MAGIC_NUMBER); + Instance->SendMode(y,z,n); + delete n; + } + } + } + return true; + } + bool RemoteServer(std::string prefix, std::deque ¶ms) { if (params.size() < 4) @@ -2444,14 +2668,14 @@ class TreeSocket : public InspSocket if (CheckDupe) { this->WriteLine("ERROR :Server "+servername+" already exists!"); - Srv->SendOpers("*** Server connection from \2"+servername+"\2 denied, already exists"); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+servername+"\2 denied, already exists"); return false; } - TreeServer* Node = new TreeServer(servername,description,ParentOfThis,NULL); + TreeServer* Node = new TreeServer(this->Instance,servername,description,ParentOfThis,NULL); ParentOfThis->AddChild(Node); params[3] = ":" + params[3]; DoOneToAllButSender(prefix,"SERVER",params,prefix); - Srv->SendOpers("*** Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")"); + this->Instance->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")"); return true; } @@ -2468,7 +2692,7 @@ class TreeSocket : public InspSocket if (hops) { this->WriteLine("ERROR :Server too far away for authentication"); - Srv->SendOpers("*** Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); return false; } std::string description = params[3]; @@ -2480,7 +2704,7 @@ class TreeSocket : public InspSocket if (CheckDupe) { this->WriteLine("ERROR :Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - Srv->SendOpers("*** Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); return false; } // Begin the sync here. this kickstarts the @@ -2491,7 +2715,7 @@ class TreeSocket : public InspSocket // we should add the details of this server now // to the servers tree, as a child of the root // node. - TreeServer* Node = new TreeServer(sname,description,TreeRoot,this); + TreeServer* Node = new TreeServer(this->Instance,sname,description,TreeRoot,this); TreeRoot->AddChild(Node); params[3] = ":" + params[3]; DoOneToAllButSender(TreeRoot->GetName(),"SERVER",params,sname); @@ -2501,7 +2725,7 @@ class TreeSocket : public InspSocket } } this->WriteLine("ERROR :Invalid credentials"); - Srv->SendOpers("*** Server connection from \2"+sname+"\2 denied, invalid link credentials"); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); return false; } @@ -2518,7 +2742,7 @@ class TreeSocket : public InspSocket if (hops) { this->WriteLine("ERROR :Server too far away for authentication"); - Srv->SendOpers("*** Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); return false; } std::string description = params[3]; @@ -2530,7 +2754,7 @@ class TreeSocket : public InspSocket if (CheckDupe) { this->WriteLine("ERROR :Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - Srv->SendOpers("*** Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); return false; } /* If the config says this link is encrypted, but the remote side @@ -2540,22 +2764,22 @@ class TreeSocket : public InspSocket if ((x->EncryptionKey != "") && (!this->ctx_in)) { this->WriteLine("ERROR :This link requires AES encryption to be enabled. Plaintext connection refused."); - Srv->SendOpers("*** Server connection from \2"+sname+"\2 denied, remote server did not enable AES."); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, remote server did not enable AES."); return false; } - Srv->SendOpers("*** Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "" : this->GetIP())+"] ("+description+")"); + this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "" : this->GetIP())+"] ("+description+")"); this->InboundServerName = sname; this->InboundDescription = description; // this is good. Send our details: Our server name and description and hopcount of 0, // along with the sendpass from this block. - this->WriteLine("SERVER "+Srv->GetServerName()+" "+x->SendPass+" 0 :"+Srv->GetServerDescription()); + this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+x->SendPass+" 0 :"+this->Instance->Config->ServerDesc); // move to the next state, we are now waiting for THEM. this->LinkState = WAIT_AUTH_2; return true; } } this->WriteLine("ERROR :Invalid credentials"); - Srv->SendOpers("*** Server connection from \2"+sname+"\2 denied, invalid link credentials"); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); return false; } @@ -2580,7 +2804,7 @@ class TreeSocket : public InspSocket line = line.substr(0, line.find_first_of("\r\n")); - log(DEBUG,"IN: %s", line.c_str()); + Instance->Log(DEBUG,"IN: %s", line.c_str()); this->Split(line.c_str(),params); @@ -2608,7 +2832,7 @@ class TreeSocket : public InspSocket } else if ((this->ctx_in) && (command == "AES")) { - WriteOpers("*** \2AES\2: Encryption already enabled on this connection yet %s is trying to enable it twice!",params[0].c_str()); + this->Instance->SNO->WriteToSnoMask('l',"\2AES\2: Encryption already enabled on this connection yet %s is trying to enable it twice!",params[0].c_str()); } switch (this->LinkState) @@ -2676,17 +2900,17 @@ class TreeSocket : public InspSocket long delta = THEM-time(NULL); if ((delta < -600) || (delta > 600)) { - WriteOpers("*** \2ERROR\2: Your clocks are out by %d seconds (this is more than ten minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta)); + this->Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than ten minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta)); this->WriteLine("ERROR :Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than ten minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!"); return false; } else if ((delta < -60) || (delta > 60)) { - WriteOpers("*** \2WARNING\2: Your clocks are out by %d seconds, please consider synching your clocks.",abs(delta)); + this->Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds, please consider synching your clocks.",abs(delta)); } } this->LinkState = CONNECTED; - Node = new TreeServer(InboundServerName,InboundDescription,TreeRoot,this); + Node = new TreeServer(this->Instance,InboundServerName,InboundDescription,TreeRoot,this); TreeRoot->AddChild(Node); params.clear(); params.push_back(InboundServerName); @@ -2734,7 +2958,7 @@ class TreeSocket : public InspSocket if (prefix != "") { std::string direction = prefix; - userrec* t = Srv->FindNick(prefix); + userrec* t = this->Instance->FindNick(prefix); if (t) { direction = t->server; @@ -2743,7 +2967,7 @@ class TreeSocket : public InspSocket if ((!route_back_again) || (route_back_again->GetSocket() != this)) { if (route_back_again) - log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str()); + Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str()); return true; } @@ -2751,7 +2975,7 @@ class TreeSocket : public InspSocket * When there is activity on the socket, reset the ping counter so * that we're not wasting bandwidth pinging an active server. */ - route_back_again->SetNextPingTime(time(NULL) + 120); + route_back_again->SetNextPingTime(time(NULL) + 60); route_back_again->SetPingFlag(); } @@ -2779,6 +3003,14 @@ class TreeSocket : public InspSocket { return this->Stats(prefix, params); } + else if (command == "MOTD") + { + return this->Motd(prefix, params); + } + else if (command == "ADMIN") + { + return this->Admin(prefix, params); + } else if (command == "SERVER") { return this->RemoteServer(prefix,params); @@ -2811,6 +3043,10 @@ class TreeSocket : public InspSocket { return this->MetaData(prefix,params); } + else if (command == "REMSTATUS") + { + return this->RemoveStatus(prefix,params); + } else if (command == "PING") { /* @@ -2821,7 +3057,7 @@ class TreeSocket : public InspSocket if (this->bursting) { this->bursting = false; - apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); + Instance->XLines->apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); } if (prefix == "") { @@ -2839,7 +3075,7 @@ class TreeSocket : public InspSocket if (this->bursting) { this->bursting = false; - apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); + Instance->XLines->apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); } if (prefix == "") { @@ -2888,8 +3124,8 @@ class TreeSocket : public InspSocket std::string sourceserv = this->myhost; if (params.size() == 3) { - userrec* user = Srv->FindNick(params[1]); - chanrec* chan = Srv->FindChannel(params[0]); + userrec* user = this->Instance->FindNick(params[1]); + chanrec* chan = this->Instance->FindChan(params[0]); if (user && chan) { if (!chan->ServerKickUser(user, params[2].c_str(), false)) @@ -2922,13 +3158,13 @@ class TreeSocket : public InspSocket else if (command == "ENDBURST") { this->bursting = false; - apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); + Instance->XLines->apply_lines(APPLY_ZLINES|APPLY_GLINES|APPLY_QLINES); std::string sourceserv = this->myhost; if (this->InboundServerName != "") { sourceserv = this->InboundServerName; } - WriteOpers("*** Received end of netburst from \2%s\2",sourceserv.c_str()); + this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str()); return true; } else @@ -2936,7 +3172,7 @@ class TreeSocket : public InspSocket // not a special inter-server command. // Emulate the actual user doing the command, // this saves us having a huge ugly parser. - userrec* who = Srv->FindNick(prefix); + userrec* who = this->Instance->FindNick(prefix); std::string sourceserv = this->myhost; if (this->InboundServerName != "") { @@ -2950,19 +3186,19 @@ class TreeSocket : public InspSocket * already exist here. If it does, kill their copy, * and our copy. */ - userrec* x = Srv->FindNick(params[0]); + userrec* x = this->Instance->FindNick(params[0]); if ((x) && (x != who)) { std::deque p; p.push_back(params[0]); p.push_back("Nickname collision ("+prefix+" -> "+params[0]+")"); - DoOneToMany(Srv->GetServerName(),"KILL",p); + DoOneToMany(this->Instance->Config->ServerName,"KILL",p); p.clear(); p.push_back(prefix); p.push_back("Nickname collision"); - DoOneToMany(Srv->GetServerName(),"KILL",p); + DoOneToMany(this->Instance->Config->ServerName,"KILL",p); userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")"); - userrec* y = Srv->FindNick(prefix); + userrec* y = this->Instance->FindNick(prefix); if (y) { userrec::QuitUser(this->Instance,y,"Nickname collision"); @@ -2977,10 +3213,18 @@ class TreeSocket : public InspSocket { strparams[q] = params[q].c_str(); } - if (!Srv->CallCommandHandler(command.c_str(), strparams, params.size(), who)) + switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who)) { - this->WriteLine("ERROR :Unrecognised command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules"); - return false; + case CMD_INVALID: + this->WriteLine("ERROR :Unrecognised command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules"); + return false; + break; + case CMD_FAILURE: + return true; + break; + default: + /* CMD_SUCCESS and CMD_USER_DELETED fall through here */ + break; } } else @@ -2988,11 +3232,11 @@ class TreeSocket : public InspSocket // its not a user. Its either a server, or somethings screwed up. if (IsServer(prefix)) { - target = Srv->GetServerName(); + target = this->Instance->Config->ServerName; } else { - log(DEBUG,"Command with unknown origin '%s'",prefix.c_str()); + Instance->Log(DEBUG,"Command with unknown origin '%s'",prefix.c_str()); return true; } } @@ -3019,7 +3263,10 @@ class TreeSocket : public InspSocket { if (this->LinkState == CONNECTING) { - Srv->SendOpers("*** CONNECT: Connection to \002"+myhost+"\002 timed out."); + this->Instance->SNO->WriteToSnoMask('l',"CONNECT: Connection to \002"+myhost+"\002 timed out."); + Link* MyLink = FindLink(myhost); + if (MyLink) + DoFailOver(MyLink); } } @@ -3038,7 +3285,7 @@ class TreeSocket : public InspSocket { Squit(s,"Remote host closed the connection"); } - WriteOpers("Server '\2%s\2' closed the connection.",quitserver.c_str()); + this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str()); } virtual int OnIncomingConnection(int newsock, char* ip) @@ -3058,13 +3305,13 @@ class TreeSocket : public InspSocket if (!found) { - WriteOpers("Server connection from %s denied (no link blocks with that IP address)", ip); + this->Instance->SNO->WriteToSnoMask('l',"Server connection from %s denied (no link blocks with that IP address)", ip); close(newsock); return false; } } TreeSocket* s = new TreeSocket(this->Instance, newsock, ip); - Srv->AddSocket(s); + s = s; /* Whinge whinge whinge, thats all GCC ever does. */ return true; } }; @@ -3083,12 +3330,12 @@ class ServernameResolver : public Resolver * admin takes the tag away and rehashes while the domain is resolving. */ Link MyLink; - public: + public: ServernameResolver(InspIRCd* Instance, const std::string &hostname, Link x) : Resolver(Instance, hostname, DNS_QUERY_FORWARD), MyLink(x) { /* Nothing in here, folks */ } - + void OnLookupComplete(const std::string &result) { /* Initiate the connection, now that we have an IP to use. @@ -3102,13 +3349,13 @@ class ServernameResolver : public Resolver if (newsocket->GetFd() > -1) { /* We're all OK */ - Srv->AddSocket(newsocket); } else { /* Something barfed, show the opers */ - WriteOpers("*** CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno)); + ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno)); delete newsocket; + DoFailOver(&MyLink); } } } @@ -3116,7 +3363,8 @@ class ServernameResolver : public Resolver void OnError(ResolverError e, const std::string &errormessage) { /* Ooops! */ - WriteOpers("*** CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s",MyLink.Name.c_str(),errormessage.c_str()); + ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s",MyLink.Name.c_str(),errormessage.c_str()); + DoFailOver(&MyLink); } }; @@ -3131,13 +3379,13 @@ class SecurityIPResolver : public Resolver void OnLookupComplete(const std::string &result) { - log(DEBUG,"Security IP cache: Adding IP address '%s' for Link '%s'",result.c_str(),MyLink.Name.c_str()); + ServerInstance->Log(DEBUG,"Security IP cache: Adding IP address '%s' for Link '%s'",result.c_str(),MyLink.Name.c_str()); ValidIPs.push_back(result); } void OnError(ResolverError e, const std::string &errormessage) { - log(DEBUG,"Could not resolve IP associated with Link '%s': %s",MyLink.Name.c_str(),errormessage.c_str()); + ServerInstance->Log(DEBUG,"Could not resolve IP associated with Link '%s': %s",MyLink.Name.c_str(),errormessage.c_str()); } }; @@ -3153,13 +3401,13 @@ void AddThisServer(TreeServer* server, std::deque &list) list.push_back(server); } -// returns a list of DIRECT servernames for a specific channel +/** returns a list of DIRECT servernames for a specific channel */ void GetListOfServersForChannel(chanrec* c, std::deque &list) { CUList *ulist = c->GetUsers(); for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) { - if (i->second->fd < 0) + if (i->second->GetFd() < 0) { TreeServer* best = BestRouteTo(i->second->server); if (best) @@ -3184,7 +3432,7 @@ bool DoOneToAllButSenderRaw(std::string data, std::string omit, std::string pref if ((*(params[0].c_str()) != '#') && (*(params[0].c_str()) != '$')) { // special routing for private messages/notices - userrec* d = Srv->FindNick(params[0]); + userrec* d = ServerInstance->FindNick(params[0]); if (d) { std::deque par; @@ -3204,20 +3452,20 @@ bool DoOneToAllButSenderRaw(std::string data, std::string omit, std::string pref } else { - log(DEBUG,"Channel privmsg going to chan %s",params[0].c_str()); - chanrec* c = Srv->FindChannel(params[0]); + ServerInstance->Log(DEBUG,"Channel privmsg going to chan %s",params[0].c_str()); + chanrec* c = ServerInstance->FindChan(params[0]); if (c) { std::deque list; GetListOfServersForChannel(c,list); - log(DEBUG,"Got a list of %d servers",list.size()); + ServerInstance->Log(DEBUG,"Got a list of %d servers",list.size()); unsigned int lsize = list.size(); for (unsigned int i = 0; i < lsize; i++) { TreeSocket* Sock = list[i]->GetSocket(); if ((Sock) && (list[i]->GetName() != omit) && (omitroute != list[i])) { - log(DEBUG,"Writing privmsg to server %s",list[i]->GetName().c_str()); + ServerInstance->Log(DEBUG,"Writing privmsg to server %s",list[i]->GetName().c_str()); Sock->WriteLine(data); } } @@ -3230,10 +3478,11 @@ bool DoOneToAllButSenderRaw(std::string data, std::string omit, std::string pref for (unsigned int x = 0; x < items; x++) { TreeServer* Route = TreeRoot->GetChild(x); - if ((Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route)) + if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route)) { TreeSocket* Sock = Route->GetSocket(); - Sock->WriteLine(data); + if (Sock) + Sock->WriteLine(data); } } return true; @@ -3256,10 +3505,11 @@ bool DoOneToAllButSender(std::string prefix, std::string command, std::dequeGetSocket()) && (Route->GetName() != omit) && (omitroute != Route)) + if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route)) { TreeSocket* Sock = Route->GetSocket(); - Sock->WriteLine(FullLine); + if (Sock) + Sock->WriteLine(FullLine); } } return true; @@ -3277,15 +3527,30 @@ bool DoOneToMany(std::string prefix, std::string command, std::dequeGetChild(x); - if (Route->GetSocket()) + if (Route && Route->GetSocket()) { TreeSocket* Sock = Route->GetSocket(); - Sock->WriteLine(FullLine); + if (Sock) + Sock->WriteLine(FullLine); } } return true; } +bool DoOneToMany(const char* prefix, const char* command, std::deque ¶ms) +{ + std::string spfx = prefix; + std::string scmd = command; + return DoOneToMany(spfx, scmd, params); +} + +bool DoOneToAllButSender(const char* prefix, const char* command, std::deque ¶ms, std::string omit) +{ + std::string spfx = prefix; + std::string scmd = command; + return DoOneToAllButSender(spfx, scmd, params, omit); +} + bool DoOneToOne(std::string prefix, std::string command, std::deque ¶ms, std::string target) { TreeServer* Route = BestRouteTo(target); @@ -3297,16 +3562,17 @@ bool DoOneToOne(std::string prefix, std::string command, std::deque { FullLine = FullLine + " " + params[x]; } - if (Route->GetSocket()) + if (Route && Route->GetSocket()) { TreeSocket* Sock = Route->GetSocket(); - Sock->WriteLine(FullLine); + if (Sock) + Sock->WriteLine(FullLine); } return true; } else { - return true; + return false; } } @@ -3314,7 +3580,7 @@ std::vector Bindings; void ReadConfiguration(bool rebind) { - Conf = new ConfigReader; + Conf = new ConfigReader(ServerInstance); if (rebind) { for (int j =0; j < Conf->Enumerate("bind"); j++) @@ -3331,12 +3597,11 @@ void ReadConfiguration(bool rebind) TreeSocket* listener = new TreeSocket(ServerInstance, IP.c_str(),Port,true,10); if (listener->GetState() == I_LISTENING) { - Srv->AddSocket(listener); Bindings.push_back(listener); } else { - log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port %d",Port); + ServerInstance->Log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port %d",Port); listener->Close(); DELETE(listener); } @@ -3353,6 +3618,7 @@ void ReadConfiguration(bool rebind) std::string Allow = Conf->ReadValue("link","allowmask",j); L.Name = (Conf->ReadValue("link","name",j)).c_str(); L.IPAddr = Conf->ReadValue("link","ipaddr",j); + L.FailOver = Conf->ReadValue("link","failover",j).c_str(); L.Port = Conf->ReadInteger("link","port",j,true); L.SendPass = Conf->ReadValue("link","sendpass",j); L.RecvPass = Conf->ReadValue("link","recvpass",j); @@ -3361,53 +3627,60 @@ void ReadConfiguration(bool rebind) L.HiddenFromStats = Conf->ReadFlag("link","hidden",j); L.NextConnectTime = time(NULL) + L.AutoConnect; /* Bugfix by brain, do not allow people to enter bad configurations */ - if ((L.IPAddr != "") && (L.RecvPass != "") && (L.SendPass != "") && (L.Name != "") && (L.Port)) + if (L.Name != ServerInstance->Config->ServerName) { - ValidIPs.push_back(L.IPAddr); + if ((L.IPAddr != "") && (L.RecvPass != "") && (L.SendPass != "") && (L.Name != "") && (L.Port)) + { + ValidIPs.push_back(L.IPAddr); + + if (Allow.length()) + ValidIPs.push_back(Allow); - if (Allow.length()) - ValidIPs.push_back(Allow); + /* Needs resolving */ + insp_inaddr binip; + if (insp_aton(L.IPAddr.c_str(), &binip) < 1) + { + try + { + SecurityIPResolver* sr = new SecurityIPResolver(ServerInstance, L.IPAddr, L); + ServerInstance->AddResolver(sr); + } + catch (ModuleException& e) + { + ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason()); + } + } - /* Needs resolving */ - insp_inaddr binip; - if (insp_aton(L.IPAddr.c_str(), &binip) < 1) + LinkBlocks.push_back(L); + ServerInstance->Log(DEBUG,"m_spanningtree: Read server %s with host %s:%d",L.Name.c_str(),L.IPAddr.c_str(),L.Port); + } + else { - try + if (L.IPAddr == "") { - SecurityIPResolver* sr = new SecurityIPResolver(ServerInstance, L.IPAddr, L); - Srv->AddResolver(sr); + ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', IP address not defined!",L.Name.c_str()); } - catch (ModuleException& e) + else if (L.RecvPass == "") { - log(DEBUG,"Error in resolver: %s",e.GetReason()); + ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', recvpass not defined!",L.Name.c_str()); + } + else if (L.SendPass == "") + { + ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', sendpass not defined!",L.Name.c_str()); + } + else if (L.Name == "") + { + ServerInstance->Log(DEFAULT,"Invalid configuration, link tag without a name!"); + } + else if (!L.Port) + { + ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', no port specified!",L.Name.c_str()); } } - - LinkBlocks.push_back(L); - log(DEBUG,"m_spanningtree: Read server %s with host %s:%d",L.Name.c_str(),L.IPAddr.c_str(),L.Port); } else { - if (L.IPAddr == "") - { - log(DEFAULT,"Invalid configuration for server '%s', IP address not defined!",L.Name.c_str()); - } - else if (L.RecvPass == "") - { - log(DEFAULT,"Invalid configuration for server '%s', recvpass not defined!",L.Name.c_str()); - } - else if (L.SendPass == "") - { - log(DEFAULT,"Invalid configuration for server '%s', sendpass not defined!",L.Name.c_str()); - } - else if (L.Name == "") - { - log(DEFAULT,"Invalid configuration, link tag without a name!"); - } - else if (!L.Port) - { - log(DEFAULT,"Invalid configuration for server '%s', no port specified!",L.Name.c_str()); - } + ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', link tag has the same server name as the local server!",L.Name.c_str()); } } DELETE(Conf); @@ -3425,19 +3698,21 @@ class ModuleSpanningTree : public Module public: - ModuleSpanningTree(Server* Me) + ModuleSpanningTree(InspIRCd* Me) : Module::Module(Me), max_local(0), max_global(0) { - Srv = Me; + Bindings.clear(); + ::ServerInstance = Me; + // Create the root of the tree - TreeRoot = new TreeServer(Srv->GetServerName(),Srv->GetServerDescription()); + TreeRoot = new TreeServer(ServerInstance, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc); ReadConfiguration(true); - command_rconnect = new cmd_rconnect(this); - Srv->AddCommand(command_rconnect); + command_rconnect = new cmd_rconnect(ServerInstance, this); + ServerInstance->AddCommand(command_rconnect); } void ShowLinks(TreeServer* Current, userrec* user, int hops) @@ -3449,7 +3724,7 @@ class ModuleSpanningTree : public Module } for (unsigned int q = 0; q < Current->ChildCount(); q++) { - if ((HideULines) && (Srv->IsUlined(Current->GetChild(q)->GetName()))) + if ((HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))) { if (*user->oper) { @@ -3462,9 +3737,9 @@ class ModuleSpanningTree : public Module } } /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */ - if ((HideULines) && (Srv->IsUlined(Current->GetName())) && (!*user->oper)) + if ((HideULines) && (ServerInstance->ULine(Current->GetName().c_str())) && (!*user->oper)) return; - user->WriteServ("364 %s %s %s :%d %s",user->nick,Current->GetName().c_str(),(FlatLinks && (!*user->oper)) ? Srv->GetServerName().c_str() : Parent.c_str(),(FlatLinks && (!*user->oper)) ? 0 : hops,Current->GetDesc().c_str()); + user->WriteServ("364 %s %s %s :%d %s",user->nick,Current->GetName().c_str(),(FlatLinks && (!*user->oper)) ? ServerInstance->Config->ServerName : Parent.c_str(),(FlatLinks && (!*user->oper)) ? 0 : hops,Current->GetDesc().c_str()); } int CountLocalServs() @@ -3486,23 +3761,23 @@ class ModuleSpanningTree : public Module void HandleLusers(const char** parameters, int pcnt, userrec* user) { - unsigned int n_users = ServerInstance->usercnt(); + unsigned int n_users = ServerInstance->UserCount(); /* Only update these when someone wants to see them, more efficient */ - if ((unsigned int)ServerInstance->local_count() > max_local) - max_local = ServerInstance->local_count(); + if ((unsigned int)ServerInstance->LocalUserCount() > max_local) + max_local = ServerInstance->LocalUserCount(); if (n_users > max_global) max_global = n_users; - user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->usercount_invisible(),ServerInstance->usercount_invisible(),this->CountServs()); - if (ServerInstance->usercount_opers()) - user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->usercount_opers()); - if (ServerInstance->usercount_unknown()) - user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->usercount_unknown()); - if (ServerInstance->chancount()) - user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->chancount()); - user->WriteServ("254 %s :I have %d clients and %d servers",user->nick,ServerInstance->local_count(),this->CountLocalServs()); - user->WriteServ("265 %s :Current Local Users: %d Max: %d",user->nick,ServerInstance->local_count(),max_local); + user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount(),this->CountServs()); + if (ServerInstance->OperCount()) + user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount()); + if (ServerInstance->UnregisteredUserCount()) + user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount()); + if (ServerInstance->ChannelCount()) + user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount()); + user->WriteServ("254 %s :I have %d clients and %d servers",user->nick,ServerInstance->LocalUserCount(),this->CountLocalServs()); + user->WriteServ("265 %s :Current Local Users: %d Max: %d",user->nick,ServerInstance->LocalUserCount(),max_local); user->WriteServ("266 %s :Current Global Users: %d Max: %d",user->nick,n_users,max_global); return; } @@ -3548,7 +3823,7 @@ class ModuleSpanningTree : public Module line++; for (unsigned int q = 0; q < Current->ChildCount(); q++) { - if ((HideULines) && (Srv->IsUlined(Current->GetChild(q)->GetName()))) + if ((HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))) { if (*user->oper) { @@ -3563,6 +3838,52 @@ class ModuleSpanningTree : public Module } } + int HandleMotd(const char** parameters, int pcnt, userrec* user) + { + if (pcnt > 0) + { + /* Remote MOTD, the server is within the 1st parameter */ + std::deque params; + params.push_back(parameters[0]); + + /* Send it out remotely, generate no reply yet */ + TreeServer* s = FindServerMask(parameters[0]); + if (s) + { + DoOneToOne(user->nick, "MOTD", params, s->GetName()); + } + else + { + user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); + } + return 1; + } + return 0; + } + + int HandleAdmin(const char** parameters, int pcnt, userrec* user) + { + if (pcnt > 0) + { + /* Remote ADMIN, the server is within the 1st parameter */ + std::deque params; + params.push_back(parameters[0]); + + /* Send it out remotely, generate no reply yet */ + TreeServer* s = FindServerMask(parameters[0]); + if (s) + { + DoOneToOne(user->nick, "ADMIN", params, s->GetName()); + } + else + { + user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); + } + return 1; + } + return 0; + } + int HandleStats(const char** parameters, int pcnt, userrec* user) { if (pcnt > 1) @@ -3665,10 +3986,12 @@ class ModuleSpanningTree : public Module TreeSocket* sock = s->GetSocket(); if (sock) { - log(DEBUG,"Splitting server %s",s->GetName().c_str()); - WriteOpers("*** SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); + ServerInstance->Log(DEBUG,"Splitting server %s",s->GetName().c_str()); + ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); sock->Squit(s,"Server quit by "+std::string(user->nick)+"!"+std::string(user->ident)+"@"+std::string(user->host)); - Srv->RemoveSocket(sock); + ServerInstance->SE->DelFd(sock); + sock->Close(); + delete sock; } else { @@ -3696,7 +4019,7 @@ class ModuleSpanningTree : public Module std::deque params; params.push_back(found->GetName()); params.push_back(user->nick); - DoOneToOne(Srv->GetServerName(),"TIME",params,found->GetName()); + DoOneToOne(ServerInstance->Config->ServerName,"TIME",params,found->GetName()); } else { @@ -3710,8 +4033,8 @@ class ModuleSpanningTree : public Module { if ((IS_LOCAL(user)) && (pcnt > 1)) { - userrec* remote = Srv->FindNick(parameters[1]); - if ((remote) && (remote->fd < 0)) + userrec* remote = ServerInstance->FindNick(parameters[1]); + if ((remote) && (remote->GetFd() < 0)) { std::deque params; params.push_back(parameters[1]); @@ -3740,15 +4063,17 @@ class ModuleSpanningTree : public Module { if (serv->AnsweredLastPing()) { - sock->WriteLine(":"+Srv->GetServerName()+" PING "+serv->GetName()); - serv->SetNextPingTime(curtime + 120); + sock->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" PING "+serv->GetName()); + serv->SetNextPingTime(curtime + 60); } else { // they didnt answer, boot them - WriteOpers("*** Server \002%s\002 pinged out",serv->GetName().c_str()); + ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 pinged out",serv->GetName().c_str()); sock->Squit(serv,"Ping timeout"); - Srv->RemoveSocket(sock); + ServerInstance->SE->DelFd(sock); + sock->Close(); + delete sock; return; } } @@ -3756,49 +4081,100 @@ class ModuleSpanningTree : public Module } } + void ConnectServer(Link* x) + { + insp_inaddr binip; + + /* Do we already have an IP? If so, no need to resolve it. */ + if (insp_aton(x->IPAddr.c_str(), &binip) > 0) + { + TreeSocket* newsocket = new TreeSocket(ServerInstance, x->IPAddr,x->Port,false,10,x->Name.c_str()); + if (newsocket->GetFd() > -1) + { + /* Handled automatically on success */ + } + else + { + ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno)); + delete newsocket; + this->DoFailOver(x); + } + } + else + { + try + { + ServernameResolver* snr = new ServernameResolver(ServerInstance,x->IPAddr, *x); + ServerInstance->AddResolver(snr); + } + catch (ModuleException& e) + { + ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason()); + this->DoFailOver(x); + } + } + } + + void DoFailOver(Link* x) + { + if (x->FailOver.length()) + { + if (x->FailOver == x->Name) + { + ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Some muppet configured the failover for server \002%s\002 to point at itself. Not following it!", x->Name.c_str()); + return; + } + Link* TryThisOne = this->FindLink(x->FailOver.c_str()); + if (TryThisOne) + { + ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Name.c_str(), TryThisOne->Name.c_str()); + ConnectServer(TryThisOne); + } + else + { + ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Name.c_str()); + } + } + } + + Link* FindLink(const std::string& name) + { + for (std::vector::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++) + { + if (ServerInstance->MatchText(x->Name.c_str(), name.c_str())) + { + return &(*x); + } + } + return NULL; + } + void AutoConnectServers(time_t curtime) { for (std::vector::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++) { if ((x->AutoConnect) && (curtime >= x->NextConnectTime)) { - log(DEBUG,"Auto-Connecting %s",x->Name.c_str()); + ServerInstance->Log(DEBUG,"Auto-Connecting %s",x->Name.c_str()); x->NextConnectTime = curtime + x->AutoConnect; TreeServer* CheckDupe = FindServer(x->Name.c_str()); - if (!CheckDupe) + if (x->FailOver.length()) { - // an autoconnected server is not connected. Check if its time to connect it - WriteOpers("*** AUTOCONNECT: Auto-connecting server \002%s\002 (%lu seconds until next attempt)",x->Name.c_str(),x->AutoConnect); - - insp_inaddr binip; - - /* Do we already have an IP? If so, no need to resolve it. */ - if (insp_aton(x->IPAddr.c_str(), &binip) > 0) + TreeServer* CheckFailOver = FindServer(x->FailOver.c_str()); + if (CheckFailOver) { - TreeSocket* newsocket = new TreeSocket(ServerInstance, x->IPAddr,x->Port,false,10,x->Name.c_str()); - if (newsocket->GetFd() > -1) - { - Srv->AddSocket(newsocket); - } - else - { - WriteOpers("*** AUTOCONNECT: Error autoconnecting \002%s\002: %s.",x->Name.c_str(),strerror(errno)); - delete newsocket; - } - } - else - { - try - { - ServernameResolver* snr = new ServernameResolver(ServerInstance,x->IPAddr, *x); - Srv->AddResolver(snr); - } - catch (ModuleException& e) - { - log(DEBUG,"Error in resolver: %s",e.GetReason()); - } + /* The failover for this server is currently a member of the network. + * The failover probably succeeded, where the main link did not. + * Don't try the main link until the failover is gone again. + */ + continue; } - + } + if (!CheckDupe) + { + // an autoconnected server is not connected. Check if its time to connect it + ServerInstance->SNO->WriteToSnoMask('l',"AUTOCONNECT: Auto-connecting server \002%s\002 (%lu seconds until next attempt)",x->Name.c_str(),x->AutoConnect); + this->ConnectServer(&(*x)); } } } @@ -3845,40 +4221,13 @@ class ModuleSpanningTree : public Module { for (std::vector::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++) { - if (Srv->MatchText(x->Name.c_str(),parameters[0])) + if (ServerInstance->MatchText(x->Name.c_str(),parameters[0])) { TreeServer* CheckDupe = FindServer(x->Name.c_str()); if (!CheckDupe) { user->WriteServ("NOTICE %s :*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",user->nick,x->Name.c_str(),(x->HiddenFromStats ? "" : x->IPAddr.c_str()),x->Port); - insp_inaddr binip; - - /* Do we already have an IP? If so, no need to resolve it. */ - if (insp_aton(x->IPAddr.c_str(), &binip) > 0) - { - TreeSocket* newsocket = new TreeSocket(ServerInstance,x->IPAddr,x->Port,false,10,x->Name.c_str()); - if (newsocket->GetFd() > -1) - { - Srv->AddSocket(newsocket); - } - else - { - WriteOpers("*** CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno)); - delete newsocket; - } - } - else - { - try - { - ServernameResolver* snr = new ServernameResolver(ServerInstance, x->IPAddr, *x); - Srv->AddResolver(snr); - } - catch (ModuleException& e) - { - log(DEBUG,"Error in resolver: %s",e.GetReason()); - } - } + ConnectServer(&(*x)); return 1; } else @@ -3898,17 +4247,17 @@ class ModuleSpanningTree : public Module { for (unsigned int i = 0; i < LinkBlocks.size(); i++) { - results.push_back(Srv->GetServerName()+" 213 "+user->nick+" C *@"+(LinkBlocks[i].HiddenFromStats ? "" : LinkBlocks[i].IPAddr)+" * "+LinkBlocks[i].Name.c_str()+" "+ConvToStr(LinkBlocks[i].Port)+" "+(LinkBlocks[i].EncryptionKey != "" ? 'e' : '-')+(LinkBlocks[i].AutoConnect ? 'a' : '-')+'s'); - results.push_back(Srv->GetServerName()+" 244 "+user->nick+" H * * "+LinkBlocks[i].Name.c_str()); + results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" C *@"+(LinkBlocks[i].HiddenFromStats ? "" : LinkBlocks[i].IPAddr)+" * "+LinkBlocks[i].Name.c_str()+" "+ConvToStr(LinkBlocks[i].Port)+" "+(LinkBlocks[i].EncryptionKey != "" ? 'e' : '-')+(LinkBlocks[i].AutoConnect ? 'a' : '-')+'s'); + results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+LinkBlocks[i].Name.c_str()); } - results.push_back(Srv->GetServerName()+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); - WriteOpers("*** Notice: %s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host); + results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); + ServerInstance->SNO->WriteToSnoMask('t',"Notice: %s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host); return 1; } return 0; } - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated) + virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) { /* If the command doesnt appear to be valid, we dont want to mess with it. */ if (!validated) @@ -3922,6 +4271,14 @@ class ModuleSpanningTree : public Module { return this->HandleStats(parameters,pcnt,user); } + else if (command == "MOTD") + { + return this->HandleMotd(parameters,pcnt,user); + } + else if (command == "ADMIN") + { + return this->HandleAdmin(parameters,pcnt,user); + } else if (command == "SQUIT") { return this->HandleSquit(parameters,pcnt,user); @@ -3958,7 +4315,13 @@ class ModuleSpanningTree : public Module this->HandleVersion(parameters,pcnt,user); return 1; } - else if (Srv->IsValidModuleCommand(command, pcnt, user)) + + return 0; + } + + virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line) + { + if ((result == CMD_SUCCESS) && (ServerInstance->IsValidModuleCommand(command, pcnt, user))) { // this bit of code cleverly routes all module commands // to all remote severs *automatically* so that modules @@ -3978,10 +4341,9 @@ class ModuleSpanningTree : public Module params.push_back(std::string(parameters[j])); } } - log(DEBUG,"Globally route '%s'",command.c_str()); + ServerInstance->Log(DEBUG,"Globally route '%s'",command.c_str()); DoOneToMany(user->nick,command,params); } - return 0; } virtual void OnGetServerDescription(const std::string &servername,std::string &description) @@ -4027,7 +4389,7 @@ class ModuleSpanningTree : public Module if (target_type == TYPE_USER) { userrec* d = (userrec*)dest; - if ((d->fd < 0) && (IS_LOCAL(user))) + if ((d->GetFd() < 0) && (IS_LOCAL(user))) { std::deque params; params.clear(); @@ -4041,17 +4403,20 @@ class ModuleSpanningTree : public Module if (IS_LOCAL(user)) { chanrec *c = (chanrec*)dest; - std::string cname = c->name; - if (status) - cname = status + cname; - std::deque list; - GetListOfServersForChannel(c,list); - unsigned int ucount = list.size(); - for (unsigned int i = 0; i < ucount; i++) + if (c) { - TreeSocket* Sock = list[i]->GetSocket(); - if (Sock) - Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text); + std::string cname = c->name; + if (status) + cname = status + cname; + std::deque list; + GetListOfServersForChannel(c,list); + unsigned int ucount = list.size(); + for (unsigned int i = 0; i < ucount; i++) + { + TreeSocket* Sock = list[i]->GetSocket(); + if (Sock) + Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text); + } } } } @@ -4075,7 +4440,7 @@ class ModuleSpanningTree : public Module // route private messages which are targetted at clients only to the server // which needs to receive them userrec* d = (userrec*)dest; - if ((d->fd < 0) && (IS_LOCAL(user))) + if ((d->GetFd() < 0) && (IS_LOCAL(user))) { std::deque params; params.clear(); @@ -4089,17 +4454,20 @@ class ModuleSpanningTree : public Module if (IS_LOCAL(user)) { chanrec *c = (chanrec*)dest; - std::string cname = c->name; - if (status) - cname = status + cname; - std::deque list; - GetListOfServersForChannel(c,list); - unsigned int ucount = list.size(); - for (unsigned int i = 0; i < ucount; i++) + if (c) { - TreeSocket* Sock = list[i]->GetSocket(); - if (Sock) - Sock->WriteLine(":"+std::string(user->nick)+" PRIVMSG "+cname+" :"+text); + std::string cname = c->name; + if (status) + cname = status + cname; + std::deque list; + GetListOfServersForChannel(c,list); + unsigned int ucount = list.size(); + for (unsigned int i = 0; i < ucount; i++) + { + TreeSocket* Sock = list[i]->GetSocket(); + if (Sock) + Sock->WriteLine(":"+std::string(user->nick)+" PRIVMSG "+cname+" :"+text); + } } } } @@ -4130,24 +4498,14 @@ class ModuleSpanningTree : public Module std::deque params; params.clear(); params.push_back(channel->name); - - if (channel->GetUserCounter() > 1) - { - // not the first in the channel - DoOneToMany(user->nick,"JOIN",params); - } - else - { - // first in the channel, set up their permissions - // and the channel TS with FJOIN. - char ts[24]; - snprintf(ts,24,"%lu",(unsigned long)channel->age); - params.clear(); - params.push_back(channel->name); - params.push_back(ts); - params.push_back("@"+std::string(user->nick)); - DoOneToMany(Srv->GetServerName(),"FJOIN",params); - } + // set up their permissions and the channel TS with FJOIN. + // All users are FJOINed now, because a module may specify + // new joining permissions for the user. + params.clear(); + params.push_back(channel->name); + params.push_back(ConvToStr(channel->age)); + params.push_back(std::string(channel->GetAllPrefixChars(user))+","+std::string(user->nick)); + DoOneToMany(ServerInstance->Config->ServerName,"FJOIN",params); } } @@ -4198,7 +4556,7 @@ class ModuleSpanningTree : public Module params.push_back("+"+std::string(user->FormatModes())); params.push_back(user->GetIPString()); params.push_back(":"+std::string(user->fullname)); - DoOneToMany(Srv->GetServerName(),"NICK",params); + DoOneToMany(ServerInstance->Config->ServerName,"NICK",params); // User is Local, change needs to be reflected! TreeServer* SourceServer = FindServer(user->server); @@ -4253,7 +4611,7 @@ class ModuleSpanningTree : public Module params.push_back(chan->name); params.push_back(user->nick); params.push_back(":"+reason); - DoOneToMany(Srv->GetServerName(),"KICK",params); + DoOneToMany(ServerInstance->Config->ServerName,"KICK",params); } } @@ -4271,12 +4629,12 @@ class ModuleSpanningTree : public Module { std::deque params; params.push_back(parameter); - DoOneToMany(Srv->GetServerName(),"REHASH",params); + DoOneToMany(ServerInstance->Config->ServerName,"REHASH",params); // check for self - if (Srv->MatchText(Srv->GetServerName(),parameter)) + if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameter)) { - Srv->SendOpers("*** Remote rehash initiated from server \002"+Srv->GetServerName()+"\002."); - Srv->RehashServer(); + ServerInstance->WriteOpers("*** Remote rehash initiated from server \002%s\002",ServerInstance->Config->ServerName); + ServerInstance->RehashServer(); } } ReadConfiguration(false); @@ -4412,12 +4770,12 @@ class ModuleSpanningTree : public Module if (target_type == TYPE_USER) { userrec* u = (userrec*)target; - s->WriteLine(":"+Srv->GetServerName()+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline); + s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline); } else { chanrec* c = (chanrec*)target; - s->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline); + s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline); } } } @@ -4430,52 +4788,61 @@ class ModuleSpanningTree : public Module if (target_type == TYPE_USER) { userrec* u = (userrec*)target; - s->WriteLine(":"+Srv->GetServerName()+" METADATA "+u->nick+" "+extname+" :"+extdata); + s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+u->nick+" "+extname+" :"+extdata); } else if (target_type == TYPE_OTHER) { - s->WriteLine(":"+Srv->GetServerName()+" METADATA * "+extname+" :"+extdata); + s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA * "+extname+" :"+extdata); } else if (target_type == TYPE_CHANNEL) { chanrec* c = (chanrec*)target; - s->WriteLine(":"+Srv->GetServerName()+" METADATA "+c->name+" "+extname+" :"+extdata); + s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+c->name+" "+extname+" :"+extdata); } } } virtual void OnEvent(Event* event) { + std::deque* params = (std::deque*)event->GetData(); + if (event->GetEventID() == "send_metadata") { - std::deque* params = (std::deque*)event->GetData(); if (params->size() < 3) return; (*params)[2] = ":" + (*params)[2]; - DoOneToMany(Srv->GetServerName(),"METADATA",*params); + DoOneToMany(ServerInstance->Config->ServerName,"METADATA",*params); + } + else if (event->GetEventID() == "send_topic") + { + if (params->size() < 2) + return; + (*params)[1] = ":" + (*params)[1]; + params->insert(params->begin() + 1,ServerInstance->Config->ServerName); + params->insert(params->begin() + 1,ConvToStr(ServerInstance->Time())); + DoOneToMany(ServerInstance->Config->ServerName,"FTOPIC",*params); } else if (event->GetEventID() == "send_mode") { - std::deque* params = (std::deque*)event->GetData(); if (params->size() < 2) return; // Insert the TS value of the object, either userrec or chanrec time_t ourTS = 0; - userrec* a = Srv->FindNick((*params)[0]); + userrec* a = ServerInstance->FindNick((*params)[0]); if (a) { ourTS = a->age; } else { - chanrec* a = Srv->FindChannel((*params)[0]); + chanrec* a = ServerInstance->FindChan((*params)[0]); if (a) { ourTS = a->age; } } params->insert(params->begin() + 1,ConvToStr(ourTS)); - DoOneToMany(Srv->GetServerName(),"FMODE",*params); + DoOneToMany(ServerInstance->Config->ServerName,"FMODE",*params); } } @@ -4496,7 +4863,7 @@ class ModuleSpanningTree : public Module List[I_OnUserQuit] = List[I_OnUserPostNick] = List[I_OnUserKick] = List[I_OnRemoteKill] = List[I_OnRehash] = 1; List[I_OnOper] = List[I_OnAddGLine] = List[I_OnAddZLine] = List[I_OnAddQLine] = List[I_OnAddELine] = 1; List[I_OnDelGLine] = List[I_OnDelZLine] = List[I_OnDelQLine] = List[I_OnDelELine] = List[I_ProtoSendMode] = List[I_OnMode] = 1; - List[I_OnStats] = List[I_ProtoSendMetaData] = List[I_OnEvent] = List[I_OnSetAway] = List[I_OnCancelAway] = 1; + List[I_OnStats] = List[I_ProtoSendMetaData] = List[I_OnEvent] = List[I_OnSetAway] = List[I_OnCancelAway] = List[I_OnPostCommand] = 1; } /* It is IMPORTANT that m_spanningtree is the last module in the chain @@ -4512,6 +4879,15 @@ class ModuleSpanningTree : public Module } }; +void DoFailOver(Link* x) +{ + TreeProtocolModule->DoFailOver(x); +} + +Link* FindLink(const std::string& name) +{ + return TreeProtocolModule->FindLink(name); +} class ModuleSpanningTreeFactory : public ModuleFactory { @@ -4524,7 +4900,7 @@ class ModuleSpanningTreeFactory : public ModuleFactory { } - virtual Module * CreateModule(Server* Me) + virtual Module * CreateModule(InspIRCd* Me) { TreeProtocolModule = new ModuleSpanningTree(Me); return TreeProtocolModule;