diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2007-10-14 19:18:04 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2007-10-14 19:18:04 +0000 |
commit | f087d825a88760d251b8f80b5d50bc98b40fa2ae (patch) | |
tree | bbd5e06dc1d62bc5e338d1eeaa9ca47e45c95707 /src | |
parent | af8692ea3b8ad6bf602ad4cee669a6d9d217c7a2 (diff) |
Split up spanningtree some more, the filenames should be more intuitive so that developers know where to find stuff (more of this is coming soon)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@8187 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src')
-rw-r--r-- | src/modules/m_spanningtree/main.cpp | 447 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_admin.cpp | 59 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_map.cpp | 162 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_modules.cpp | 57 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_motd.cpp | 59 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_squit.cpp | 66 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_stats.cpp | 99 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_time.cpp | 59 | ||||
-rw-r--r-- | src/modules/m_spanningtree/override_whois.cpp | 57 | ||||
-rw-r--r-- | src/modules/m_spanningtree/postcommand.cpp | 80 | ||||
-rw-r--r-- | src/modules/m_spanningtree/precommand.cpp | 100 |
11 files changed, 798 insertions, 447 deletions
diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index fdd57c4ef..4a31d7007 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -167,307 +167,6 @@ std::string ModuleSpanningTree::TimeToStr(time_t secs) + ConvToStr(secs) + "s"); } -const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current) -{ - time_t secs_up = ServerInstance->Time() - Current->age; - return (" [Up: " + TimeToStr(secs_up) + " Lag: "+ConvToStr(Current->rtt)+"ms]"); -} - -// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS. -void ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers) -{ - if (line < 128) - { - for (int t = 0; t < depth; t++) - { - matrix[line][t] = ' '; - } - // For Aligning, we need to work out exactly how deep this thing is, and produce - // a 'Spacer' String to compensate. - char spacer[40]; - memset(spacer,' ',40); - if ((40 - Current->GetName().length() - depth) > 1) { - spacer[40 - Current->GetName().length() - depth] = '\0'; - } - else - { - spacer[5] = '\0'; - } - float percent; - char text[128]; - /* Neat and tidy default values, as we're dealing with a matrix not a simple string */ - memset(text, 0, 128); - - if (ServerInstance->clientlist->size() == 0) { - // If there are no users, WHO THE HELL DID THE /MAP?!?!?! - percent = 0; - } - else - { - percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100; - } - const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : ""; - snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str()); - totusers += Current->GetUserCount(); - totservers++; - strlcpy(&matrix[line][depth],text,126); - line++; - for (unsigned int q = 0; q < Current->ChildCount(); q++) - { - if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str())))) - { - if (*user->oper) - { - ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); - } - } - else - { - ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); - } - } - } -} - -int ModuleSpanningTree::HandleMotd(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - /* Remote MOTD, the server is within the 1st parameter */ - std::deque<std::string> params; - params.push_back(parameters[0]); - /* Send it out remotely, generate no reply yet */ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->uuid, "MOTD", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleAdmin(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - /* Remote ADMIN, the server is within the 1st parameter */ - std::deque<std::string> params; - params.push_back(parameters[0]); - /* Send it out remotely, generate no reply yet */ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->uuid, "ADMIN", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleModules(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - std::deque<std::string> params; - params.push_back(parameters[0]); - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->uuid, "MODULES", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 1) - { - if (match(ServerInstance->Config->ServerName, parameters[1])) - return 0; - - /* Remote STATS, the server is within the 2nd parameter */ - std::deque<std::string> params; - params.push_back(parameters[0]); - params.push_back(parameters[1]); - /* Send it out remotely, generate no reply yet */ - - TreeServer* s = Utils->FindServerMask(parameters[1]); - if (s) - { - params[1] = s->GetName(); - Utils->DoOneToOne(user->uuid, "STATS", params, s->GetName()); - } - else - { - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]); - } - return 1; - } - return 0; -} - -// Ok, prepare to be confused. -// After much mulling over how to approach this, it struck me that -// the 'usual' way of doing a /MAP isnt the best way. Instead of -// keeping track of a ton of ascii characters, and line by line -// under recursion working out where to place them using multiplications -// and divisons, we instead render the map onto a backplane of characters -// (a character matrix), then draw the branches as a series of "L" shapes -// from the nodes. This is not only friendlier on CPU it uses less stack. -void ModuleSpanningTree::HandleMap(const char** parameters, int pcnt, userrec* user) -{ - // This array represents a virtual screen which we will - // "scratch" draw to, as the console device of an irc - // client does not provide for a proper terminal. - float totusers = 0; - float totservers = 0; - char matrix[128][128]; - for (unsigned int t = 0; t < 128; t++) - { - matrix[t][0] = '\0'; - } - line = 0; - // The only recursive bit is called here. - ShowMap(Utils->TreeRoot,user,0,matrix,totusers,totservers); - // Process each line one by one. The algorithm has a limit of - // 128 servers (which is far more than a spanning tree should have - // anyway, so we're ok). This limit can be raised simply by making - // the character matrix deeper, 128 rows taking 10k of memory. - for (int l = 1; l < line; l++) - { - // scan across the line looking for the start of the - // servername (the recursive part of the algorithm has placed - // the servers at indented positions depending on what they - // are related to) - int first_nonspace = 0; - while (matrix[l][first_nonspace] == ' ') - { - first_nonspace++; - } - first_nonspace--; - // Draw the `- (corner) section: this may be overwritten by - // another L shape passing along the same vertical pane, becoming - // a |- (branch) section instead. - matrix[l][first_nonspace] = '-'; - matrix[l][first_nonspace-1] = '`'; - int l2 = l - 1; - // Draw upwards until we hit the parent server, causing possibly - // other corners (`-) to become branches (|-) - while ((matrix[l2][first_nonspace-1] == ' ') || (matrix[l2][first_nonspace-1] == '`')) - { - matrix[l2][first_nonspace-1] = '|'; - l2--; - } - } - // dump the whole lot to the user. This is the easy bit, honest. - for (int t = 0; t < line; t++) - { - user->WriteServ("006 %s :%s",user->nick,&matrix[t][0]); - } - float avg_users = totusers / totservers; - user->WriteServ("270 %s :%.0f server%s and %.0f user%s, average %.2f users per server",user->nick,totservers,(totservers > 1 ? "s" : ""),totusers,(totusers > 1 ? "s" : ""),avg_users); - user->WriteServ("007 %s :End of /MAP",user->nick); - return; -} - -int ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user) -{ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - if (s == Utils->TreeRoot) - { - user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]); - return 1; - } - TreeSocket* sock = s->GetSocket(); - if (sock) - { - ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); - sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost()); - ServerInstance->SE->DelFd(sock); - sock->Close(); - } - else - { - if (IS_LOCAL(user)) - user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick); - } - } - else - { - user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]); - } - return 1; -} - -int ModuleSpanningTree::HandleTime(const char** parameters, int pcnt, userrec* user) -{ - if ((IS_LOCAL(user)) && (pcnt)) - { - TreeServer* found = Utils->FindServerMask(parameters[0]); - if (found) - { - // we dont' override for local server - if (found == Utils->TreeRoot) - return 0; - - std::deque<std::string> params; - params.push_back(found->GetName()); - params.push_back(user->uuid); - Utils->DoOneToOne(ServerInstance->Config->GetSID(),"TIME",params,found->GetName()); - } - else - { - user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]); - } - } - return 1; -} - -int ModuleSpanningTree::HandleRemoteWhois(const char** parameters, int pcnt, userrec* user) -{ - if ((IS_LOCAL(user)) && (pcnt > 1)) - { - userrec* remote = ServerInstance->FindNick(parameters[1]); - if ((remote) && (remote->GetFd() < 0)) - { - std::deque<std::string> params; - params.push_back(parameters[1]); - Utils->DoOneToOne(user->uuid,"IDLE",params,remote->server); - return 1; - } - else if (!remote) - { - user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]); - user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, parameters[1]); - return 1; - } - } - return 0; -} - void ModuleSpanningTree::DoPingChecks(time_t curtime) { for (unsigned int j = 0; j < Utils->TreeRoot->ChildCount(); j++) @@ -705,152 +404,6 @@ void ModuleSpanningTree::BroadcastTimeSync() } } -int ModuleSpanningTree::OnStats(char statschar, userrec* user, string_list &results) -{ - if ((statschar == 'c') || (statschar == 'n')) - { - for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++) - { - results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].Hook.empty() ? "plaintext" : Utils->LinkBlocks[i].Hook)+" "+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s'); - if (statschar == 'c') - results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str()); - } - results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); - ServerInstance->SNO->WriteToSnoMask('t',"%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; - } - - if (statschar == 'p') - { - /* show all server ports, after showing client ports. -- w00t */ - - for (unsigned int i = 0; i < Utils->Bindings.size(); i++) - { - std::string ip = Utils->Bindings[i]->IP; - if (ip.empty()) - ip = "*"; - - std::string transport("plaintext"); - if (Utils->Bindings[i]->GetHook()) - transport = InspSocketNameRequest(this, Utils->Bindings[i]->GetHook()).Send(); - - results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->port)+ - " (server, " + transport + ")"); - } - } - return 0; -} - -int ModuleSpanningTree::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) - return 0; - - if (command == "CONNECT") - { - return this->HandleConnect(parameters,pcnt,user); - } - else if (command == "STATS") - { - 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); - } - else if (command == "MAP") - { - this->HandleMap(parameters,pcnt,user); - return 1; - } - else if ((command == "TIME") && (pcnt > 0)) - { - return this->HandleTime(parameters,pcnt,user); - } - else if (command == "LUSERS") - { - this->HandleLusers(parameters,pcnt,user); - return 1; - } - else if (command == "LINKS") - { - this->HandleLinks(parameters,pcnt,user); - return 1; - } - else if (command == "WHOIS") - { - if (pcnt > 1) - { - // remote whois - return this->HandleRemoteWhois(parameters,pcnt,user); - } - } - else if ((command == "VERSION") && (pcnt > 0)) - { - this->HandleVersion(parameters,pcnt,user); - return 1; - } - else if ((command == "MODULES") && (pcnt > 0)) - { - return this->HandleModules(parameters,pcnt,user); - } - return 0; -} - -void ModuleSpanningTree::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))) - { - /* Safe, we know its non-null because IsValidModuleCommand returned true */ - command_t* thiscmd = ServerInstance->Parser->GetHandler(command); - // this bit of code cleverly routes all module commands - // to all remote severs *automatically* so that modules - // can just handle commands locally, without having - // to have any special provision in place for remote - // commands and linking protocols. - std::deque<std::string> params; - params.clear(); - int n_translate = thiscmd->translation.size(); - TranslateType translate_to; - - /* To make sure that parameters with spaces, or empty - * parameters, etc, are always sent properly, *always* - * prefix the last parameter with a :. This also removes - * an extra strchr() */ - for (int j = 0; j < pcnt; j++) - { - std::string target; - - /* Map all items to UUIDs where neccessary */ - if (j < n_translate) - { - /* We have a translation mapping for this index */ - translate_to = thiscmd->translation[j] != TR_END ? thiscmd->translation[j] : TR_TEXT; - } - else - translate_to = TR_TEXT; - - ServerInstance->Log(DEBUG,"TRANSLATION: %s - type is %d", parameters[j], translate_to); - ServerInstance->Parser->TranslateUIDs(translate_to, parameters[j], target); - - if (j == (pcnt - 1)) - params.push_back(":" + target); - else - params.push_back(target); - } - Utils->DoOneToMany(user->uuid, command, params); - } -} - void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description) { TreeServer* s = Utils->FindServer(servername); diff --git a/src/modules/m_spanningtree/override_admin.cpp b/src/modules/m_spanningtree/override_admin.cpp new file mode 100644 index 000000000..86ea216f2 --- /dev/null +++ b/src/modules/m_spanningtree/override_admin.cpp @@ -0,0 +1,59 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::HandleAdmin(const char** parameters, int pcnt, userrec* user) +{ + if (pcnt > 0) + { + if (match(ServerInstance->Config->ServerName, parameters[0])) + return 0; + + /* Remote ADMIN, the server is within the 1st parameter */ + std::deque<std::string> params; + params.push_back(parameters[0]); + /* Send it out remotely, generate no reply yet */ + TreeServer* s = Utils->FindServerMask(parameters[0]); + if (s) + { + params[0] = s->GetName(); + Utils->DoOneToOne(user->uuid, "ADMIN", params, s->GetName()); + } + else + user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); + return 1; + } + return 0; +} + diff --git a/src/modules/m_spanningtree/override_map.cpp b/src/modules/m_spanningtree/override_map.cpp new file mode 100644 index 000000000..a6bff8aba --- /dev/null +++ b/src/modules/m_spanningtree/override_map.cpp @@ -0,0 +1,162 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current) +{ + time_t secs_up = ServerInstance->Time() - Current->age; + return (" [Up: " + TimeToStr(secs_up) + " Lag: "+ConvToStr(Current->rtt)+"ms]"); +} + +// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS. +void ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers) +{ + if (line < 128) + { + for (int t = 0; t < depth; t++) + { + matrix[line][t] = ' '; + } + // For Aligning, we need to work out exactly how deep this thing is, and produce + // a 'Spacer' String to compensate. + char spacer[40]; + memset(spacer,' ',40); + if ((40 - Current->GetName().length() - depth) > 1) { + spacer[40 - Current->GetName().length() - depth] = '\0'; + } + else + { + spacer[5] = '\0'; + } + float percent; + char text[128]; + /* Neat and tidy default values, as we're dealing with a matrix not a simple string */ + memset(text, 0, 128); + + if (ServerInstance->clientlist->size() == 0) { + // If there are no users, WHO THE HELL DID THE /MAP?!?!?! + percent = 0; + } + else + { + percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100; + } + const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : ""; + snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str()); + totusers += Current->GetUserCount(); + totservers++; + strlcpy(&matrix[line][depth],text,126); + line++; + for (unsigned int q = 0; q < Current->ChildCount(); q++) + { + if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str())))) + { + if (*user->oper) + { + ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); + } + } + else + { + ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); + } + } + } +} + + +// Ok, prepare to be confused. +// After much mulling over how to approach this, it struck me that +// the 'usual' way of doing a /MAP isnt the best way. Instead of +// keeping track of a ton of ascii characters, and line by line +// under recursion working out where to place them using multiplications +// and divisons, we instead render the map onto a backplane of characters +// (a character matrix), then draw the branches as a series of "L" shapes +// from the nodes. This is not only friendlier on CPU it uses less stack. +void ModuleSpanningTree::HandleMap(const char** parameters, int pcnt, userrec* user) +{ + // This array represents a virtual screen which we will + // "scratch" draw to, as the console device of an irc + // client does not provide for a proper terminal. + float totusers = 0; + float totservers = 0; + char matrix[128][128]; + for (unsigned int t = 0; t < 128; t++) + { + matrix[t][0] = '\0'; + } + line = 0; + // The only recursive bit is called here. + ShowMap(Utils->TreeRoot,user,0,matrix,totusers,totservers); + // Process each line one by one. The algorithm has a limit of + // 128 servers (which is far more than a spanning tree should have + // anyway, so we're ok). This limit can be raised simply by making + // the character matrix deeper, 128 rows taking 10k of memory. + for (int l = 1; l < line; l++) + { + // scan across the line looking for the start of the + // servername (the recursive part of the algorithm has placed + // the servers at indented positions depending on what they + // are related to) + int first_nonspace = 0; + while (matrix[l][first_nonspace] == ' ') + { + first_nonspace++; + } + first_nonspace--; + // Draw the `- (corner) section: this may be overwritten by + // another L shape passing along the same vertical pane, becoming + // a |- (branch) section instead. + matrix[l][first_nonspace] = '-'; + matrix[l][first_nonspace-1] = '`'; + int l2 = l - 1; + // Draw upwards until we hit the parent server, causing possibly + // other corners (`-) to become branches (|-) + while ((matrix[l2][first_nonspace-1] == ' ') || (matrix[l2][first_nonspace-1] == '`')) + { + matrix[l2][first_nonspace-1] = '|'; + l2--; + } + } + // dump the whole lot to the user. This is the easy bit, honest. + for (int t = 0; t < line; t++) + { + user->WriteServ("006 %s :%s",user->nick,&matrix[t][0]); + } + float avg_users = totusers / totservers; + user->WriteServ("270 %s :%.0f server%s and %.0f user%s, average %.2f users per server",user->nick,totservers,(totservers > 1 ? "s" : ""),totusers,(totusers > 1 ? "s" : ""),avg_users); + user->WriteServ("007 %s :End of /MAP",user->nick); + return; +} + diff --git a/src/modules/m_spanningtree/override_modules.cpp b/src/modules/m_spanningtree/override_modules.cpp new file mode 100644 index 000000000..2e2a4dd86 --- /dev/null +++ b/src/modules/m_spanningtree/override_modules.cpp @@ -0,0 +1,57 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::HandleModules(const char** parameters, int pcnt, userrec* user) +{ + if (pcnt > 0) + { + if (match(ServerInstance->Config->ServerName, parameters[0])) + return 0; + + std::deque<std::string> params; + params.push_back(parameters[0]); + TreeServer* s = Utils->FindServerMask(parameters[0]); + if (s) + { + params[0] = s->GetName(); + Utils->DoOneToOne(user->uuid, "MODULES", params, s->GetName()); + } + else + user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); + return 1; + } + return 0; +} + diff --git a/src/modules/m_spanningtree/override_motd.cpp b/src/modules/m_spanningtree/override_motd.cpp new file mode 100644 index 000000000..ce9f5b5e1 --- /dev/null +++ b/src/modules/m_spanningtree/override_motd.cpp @@ -0,0 +1,59 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::HandleMotd(const char** parameters, int pcnt, userrec* user) +{ + if (pcnt > 0) + { + if (match(ServerInstance->Config->ServerName, parameters[0])) + return 0; + + /* Remote MOTD, the server is within the 1st parameter */ + std::deque<std::string> params; + params.push_back(parameters[0]); + /* Send it out remotely, generate no reply yet */ + TreeServer* s = Utils->FindServerMask(parameters[0]); + if (s) + { + params[0] = s->GetName(); + Utils->DoOneToOne(user->uuid, "MOTD", params, s->GetName()); + } + else + user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); + return 1; + } + return 0; +} + diff --git a/src/modules/m_spanningtree/override_squit.cpp b/src/modules/m_spanningtree/override_squit.cpp new file mode 100644 index 000000000..11f5be135 --- /dev/null +++ b/src/modules/m_spanningtree/override_squit.cpp @@ -0,0 +1,66 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user) +{ + TreeServer* s = Utils->FindServerMask(parameters[0]); + if (s) + { + if (s == Utils->TreeRoot) + { + user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]); + return 1; + } + TreeSocket* sock = s->GetSocket(); + if (sock) + { + ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); + sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost()); + ServerInstance->SE->DelFd(sock); + sock->Close(); + } + else + { + if (IS_LOCAL(user)) + user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick); + } + } + else + { + user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]); + } + return 1; +} + diff --git a/src/modules/m_spanningtree/override_stats.cpp b/src/modules/m_spanningtree/override_stats.cpp new file mode 100644 index 000000000..2e32cc72e --- /dev/null +++ b/src/modules/m_spanningtree/override_stats.cpp @@ -0,0 +1,99 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user) +{ + if (pcnt > 1) + { + if (match(ServerInstance->Config->ServerName, parameters[1])) + return 0; + + /* Remote STATS, the server is within the 2nd parameter */ + std::deque<std::string> params; + params.push_back(parameters[0]); + params.push_back(parameters[1]); + /* Send it out remotely, generate no reply yet */ + + TreeServer* s = Utils->FindServerMask(parameters[1]); + if (s) + { + params[1] = s->GetName(); + Utils->DoOneToOne(user->uuid, "STATS", params, s->GetName()); + } + else + { + user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]); + } + return 1; + } + return 0; +} + +int ModuleSpanningTree::OnStats(char statschar, userrec* user, string_list &results) +{ + if ((statschar == 'c') || (statschar == 'n')) + { + for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++) + { + results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].Hook.empty() ? "plaintext" : Utils->LinkBlocks[i].Hook)+" "+(Utils->LinkBlocks[i].AutoConnect ? 'a': '-')+'s'); + if (statschar == 'c') + results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str()); + } + results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); + ServerInstance->SNO->WriteToSnoMask('t',"%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; + } + + if (statschar == 'p') + { + /* show all server ports, after showing client ports. -- w00t */ + + for (unsigned int i = 0; i < Utils->Bindings.size(); i++) + { + std::string ip = Utils->Bindings[i]->IP; + if (ip.empty()) + ip = "*"; + + std::string transport("plaintext"); + if (Utils->Bindings[i]->GetHook()) + transport = InspSocketNameRequest(this, Utils->Bindings[i]->GetHook()).Send(); + + results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->port)+ + " (server, " + transport + ")"); + } + } + return 0; +} + diff --git a/src/modules/m_spanningtree/override_time.cpp b/src/modules/m_spanningtree/override_time.cpp new file mode 100644 index 000000000..9fa4b15b6 --- /dev/null +++ b/src/modules/m_spanningtree/override_time.cpp @@ -0,0 +1,59 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::HandleTime(const char** parameters, int pcnt, userrec* user) +{ + if ((IS_LOCAL(user)) && (pcnt)) + { + TreeServer* found = Utils->FindServerMask(parameters[0]); + if (found) + { + // we dont' override for local server + if (found == Utils->TreeRoot) + return 0; + + std::deque<std::string> params; + params.push_back(found->GetName()); + params.push_back(user->uuid); + Utils->DoOneToOne(ServerInstance->Config->GetSID(),"TIME",params,found->GetName()); + } + else + { + user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]); + } + } + return 1; +} + diff --git a/src/modules/m_spanningtree/override_whois.cpp b/src/modules/m_spanningtree/override_whois.cpp new file mode 100644 index 000000000..15488e71c --- /dev/null +++ b/src/modules/m_spanningtree/override_whois.cpp @@ -0,0 +1,57 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::HandleRemoteWhois(const char** parameters, int pcnt, userrec* user) +{ + if ((IS_LOCAL(user)) && (pcnt > 1)) + { + userrec* remote = ServerInstance->FindNick(parameters[1]); + if ((remote) && (remote->GetFd() < 0)) + { + std::deque<std::string> params; + params.push_back(parameters[1]); + Utils->DoOneToOne(user->uuid,"IDLE",params,remote->server); + return 1; + } + else if (!remote) + { + user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]); + user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, parameters[1]); + return 1; + } + } + return 0; +} + diff --git a/src/modules/m_spanningtree/postcommand.cpp b/src/modules/m_spanningtree/postcommand.cpp new file mode 100644 index 000000000..44476c8c7 --- /dev/null +++ b/src/modules/m_spanningtree/postcommand.cpp @@ -0,0 +1,80 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +void ModuleSpanningTree::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))) + { + /* Safe, we know its non-null because IsValidModuleCommand returned true */ + command_t* thiscmd = ServerInstance->Parser->GetHandler(command); + // this bit of code cleverly routes all module commands + // to all remote severs *automatically* so that modules + // can just handle commands locally, without having + // to have any special provision in place for remote + // commands and linking protocols. + std::deque<std::string> params; + params.clear(); + int n_translate = thiscmd->translation.size(); + TranslateType translate_to; + + /* To make sure that parameters with spaces, or empty + * parameters, etc, are always sent properly, *always* + * prefix the last parameter with a :. This also removes + * an extra strchr() */ + for (int j = 0; j < pcnt; j++) + { + std::string target; + + /* Map all items to UUIDs where neccessary */ + if (j < n_translate) + { + /* We have a translation mapping for this index */ + translate_to = thiscmd->translation[j] != TR_END ? thiscmd->translation[j] : TR_TEXT; + } + else + translate_to = TR_TEXT; + + ServerInstance->Log(DEBUG,"TRANSLATION: %s - type is %d", parameters[j], translate_to); + ServerInstance->Parser->TranslateUIDs(translate_to, parameters[j], target); + + if (j == (pcnt - 1)) + params.push_back(":" + target); + else + params.push_back(target); + } + Utils->DoOneToMany(user->uuid, command, params); + } +} + diff --git a/src/modules/m_spanningtree/precommand.cpp b/src/modules/m_spanningtree/precommand.cpp new file mode 100644 index 000000000..3fc8febc0 --- /dev/null +++ b/src/modules/m_spanningtree/precommand.cpp @@ -0,0 +1,100 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +/* $ModDesc: Provides a spanning tree server link protocol */ + +#include "inspircd.h" +#include "commands/cmd_whois.h" +#include "commands/cmd_stats.h" +#include "socket.h" +#include "wildcard.h" +#include "xline.h" +#include "transport.h" + +#include "m_spanningtree/timesynctimer.h" +#include "m_spanningtree/resolvers.h" +#include "m_spanningtree/main.h" +#include "m_spanningtree/utils.h" +#include "m_spanningtree/treeserver.h" +#include "m_spanningtree/link.h" +#include "m_spanningtree/treesocket.h" +#include "m_spanningtree/rconnect.h" +#include "m_spanningtree/rsquit.h" + +/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ + +int ModuleSpanningTree::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) + return 0; + + if (command == "CONNECT") + { + return this->HandleConnect(parameters,pcnt,user); + } + else if (command == "STATS") + { + 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); + } + else if (command == "MAP") + { + this->HandleMap(parameters,pcnt,user); + return 1; + } + else if ((command == "TIME") && (pcnt > 0)) + { + return this->HandleTime(parameters,pcnt,user); + } + else if (command == "LUSERS") + { + this->HandleLusers(parameters,pcnt,user); + return 1; + } + else if (command == "LINKS") + { + this->HandleLinks(parameters,pcnt,user); + return 1; + } + else if (command == "WHOIS") + { + if (pcnt > 1) + { + // remote whois + return this->HandleRemoteWhois(parameters,pcnt,user); + } + } + else if ((command == "VERSION") && (pcnt > 0)) + { + this->HandleVersion(parameters,pcnt,user); + return 1; + } + else if ((command == "MODULES") && (pcnt > 0)) + { + return this->HandleModules(parameters,pcnt,user); + } + return 0; +} + |