diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2005-04-07 17:04:04 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2005-04-07 17:04:04 +0000 |
commit | 211b24ba8cf6e21f435f145b0366adc8a3b62460 (patch) | |
tree | 8119f965d57ad163f57c220ff8e11ca772184419 | |
parent | e4a08d44617d8b46f58a0e110ffcf7f8df29a56f (diff) |
Started work on /UNLOADMODULE, resource tracking and flags in Version class
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@999 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r-- | include/commands.h | 1 | ||||
-rw-r--r-- | include/ctables.h | 3 | ||||
-rw-r--r-- | include/inspircd.h | 1 | ||||
-rw-r--r-- | include/modules.h | 11 | ||||
-rw-r--r-- | src/commands.cpp | 13 | ||||
-rw-r--r-- | src/inspircd.cpp | 171 | ||||
-rw-r--r-- | src/modules.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_chghost.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_globops.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_helpop.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_knock.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_opermotd.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_randquote.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_remove.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_sajoin.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_samode.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_sanick.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_sapart.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_saquit.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_sethost.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_setname.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_silence.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_testcommand.cpp | 2 |
23 files changed, 163 insertions, 77 deletions
diff --git a/include/commands.h b/include/commands.h index aa6fcf206..589168409 100644 --- a/include/commands.h +++ b/include/commands.h @@ -80,6 +80,7 @@ void handle_qline(char **parameters, int pcnt, userrec *user); void handle_eline(char **parameters, int pcnt, userrec *user); void handle_server(char **parameters, int pcnt, userrec *user); void handle_loadmodule(char **parameters, int pcnt, userrec *user); +void handle_unloadmodule(char **parameters, int pcnt, userrec *user); /** Special functions for processing server to server traffic */ diff --git a/include/ctables.h b/include/ctables.h index fb96b9ef6..5926f3a2a 100644 --- a/include/ctables.h +++ b/include/ctables.h @@ -44,6 +44,9 @@ class command_t : public Extensible /** used by /stats m */ long total_bytes; + /** used for resource tracking between modules + */ + char source[MAXBUF]; }; #endif diff --git a/include/inspircd.h b/include/inspircd.h index e54da779b..b7a5b7104 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -159,6 +159,7 @@ long map_count(const char* s); userrec* ReHashNick(char* Old, char* New); long GetMaxBans(char* name); bool LoadModule(const char* filename); +bool UnloadModule(const char* filename); char* ModuleError(); // mesh network functions diff --git a/include/modules.h b/include/modules.h index 9b2118472..b1f505e29 100644 --- a/include/modules.h +++ b/include/modules.h @@ -96,7 +96,7 @@ typedef std::deque<userrec*> chanuserlist; // ********************************************************************************************* -extern void createcommand(char* cmd, handlerfunc f, char flags, int minparams); +extern void createcommand(char* cmd, handlerfunc f, char flags, int minparams, char* source); extern void server_mode(char **parameters, int pcnt, userrec *user); // class Version holds the version information of a Module, returned @@ -109,8 +109,8 @@ extern void server_mode(char **parameters, int pcnt, userrec *user); class Version : public classbase { public: - const int Major, Minor, Revision, Build; - Version(int major, int minor, int revision, int build); + const int Major, Minor, Revision, Build, Flags; + Version(int major, int minor, int revision, int build, int flags); }; /** Holds /ADMIN data @@ -545,8 +545,11 @@ class Server : public classbase * than the 'minparams' value you specified when creating the command. The *user parameter is the class of * the user which caused the command to trigger, who will always have the flag you specified in 'flags' when * creating the initial command. For example to create an oper only command create the commands with flags='o'. + * The source parameter is used for resource tracking, and should contain the name of your module (with file + * extension) e.g. "m_blarp.so". If you place the wrong identifier here, you can cause crashes if your module + * is unloaded. */ - virtual void AddCommand(char* cmd, handlerfunc f, char flags, int minparams); + virtual void AddCommand(char* cmd, handlerfunc f, char flags, int minparams, char* source); /** Sends a servermode. * you must format the parameters array with the target, modes and parameters for those modes. diff --git a/src/commands.cpp b/src/commands.cpp index 5d8f94316..19dd9f200 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -283,6 +283,19 @@ void handle_loadmodule(char **parameters, int pcnt, userrec *user) } } +void handle_unloadmodule(char **parameters, int pcnt, userrec *user) +{ + if (UnloadModule(parameters[0])) + { + WriteOpers("*** MODULE UNLOADED: %s",parameters[0]); + WriteServ(user->fd,"973 %s %s :Module successfully unloaded.",user->nick, parameters[0]); + } + else + { + WriteServ(user->fd,"972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ModuleError()); + } +} + void handle_die(char **parameters, int pcnt, userrec *user) { log(DEBUG,"die: %s",user->nick); diff --git a/src/inspircd.cpp b/src/inspircd.cpp index d3c9e9ed4..f0d007cb9 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -2920,11 +2920,12 @@ void process_command(userrec *user, char* cmd) } -void createcommand(char* cmd, handlerfunc f, char flags, int minparams) +void createcommand(char* cmd, handlerfunc f, char flags, int minparams,char* source) { command_t comm; /* create the command and push it onto the table */ strlcpy(comm.command,cmd,MAXBUF); + strlcpy(comm.source,source,MAXBUF); comm.handler_function = f; comm.flags_needed = flags; comm.min_params = minparams; @@ -2934,59 +2935,80 @@ void createcommand(char* cmd, handlerfunc f, char flags, int minparams) log(DEBUG,"Added command %s (%d parameters)",cmd,minparams); } +bool removecommands(const char* source) +{ + bool go_again = true; + while (go_again) + { + go_again = false; + for (std::deque<command_t>::iterator i = cmdlist.begin(); i != cmdlist.end(); i++) + { + if (!strcmp(i->source,source)) + { + log(DEBUG,"removecommands(%s) Removing dependent command: %s",i->source,i->command); + cmdlist.erase(i); + go_again = true; + break; + } + } + } + return true; +} + void SetupCommandTable(void) { - createcommand("USER",handle_user,0,4); - createcommand("NICK",handle_nick,0,1); - createcommand("QUIT",handle_quit,0,0); - createcommand("VERSION",handle_version,0,0); - createcommand("PING",handle_ping,0,1); - createcommand("PONG",handle_pong,0,1); - createcommand("ADMIN",handle_admin,0,0); - createcommand("PRIVMSG",handle_privmsg,0,2); - createcommand("INFO",handle_info,0,0); - createcommand("TIME",handle_time,0,0); - createcommand("WHOIS",handle_whois,0,1); - createcommand("WALLOPS",handle_wallops,'o',1); - createcommand("NOTICE",handle_notice,0,2); - createcommand("JOIN",handle_join,0,1); - createcommand("NAMES",handle_names,0,1); - createcommand("PART",handle_part,0,1); - createcommand("KICK",handle_kick,0,2); - createcommand("MODE",handle_mode,0,1); - createcommand("TOPIC",handle_topic,0,1); - createcommand("WHO",handle_who,0,1); - createcommand("MOTD",handle_motd,0,0); - createcommand("RULES",handle_rules,0,0); - createcommand("OPER",handle_oper,0,2); - createcommand("LIST",handle_list,0,0); - createcommand("DIE",handle_die,'o',1); - createcommand("RESTART",handle_restart,'o',1); - createcommand("KILL",handle_kill,'o',2); - createcommand("REHASH",handle_rehash,'o',0); - createcommand("LUSERS",handle_lusers,0,0); - createcommand("STATS",handle_stats,0,1); - createcommand("USERHOST",handle_userhost,0,1); - createcommand("AWAY",handle_away,0,0); - createcommand("ISON",handle_ison,0,0); - createcommand("SUMMON",handle_summon,0,0); - createcommand("USERS",handle_users,0,0); - createcommand("INVITE",handle_invite,0,2); - createcommand("PASS",handle_pass,0,1); - createcommand("TRACE",handle_trace,'o',0); - createcommand("WHOWAS",handle_whowas,0,1); - createcommand("CONNECT",handle_connect,'o',1); - createcommand("SQUIT",handle_squit,'o',0); - createcommand("MODULES",handle_modules,'o',0); - createcommand("LINKS",handle_links,0,0); - createcommand("MAP",handle_map,0,0); - createcommand("KLINE",handle_kline,'o',1); - createcommand("GLINE",handle_gline,'o',1); - createcommand("ZLINE",handle_zline,'o',1); - createcommand("QLINE",handle_qline,'o',1); - createcommand("ELINE",handle_eline,'o',1); - createcommand("LOADMODULE",handle_loadmodule,'o',1); - createcommand("SERVER",handle_server,0,0); + createcommand("USER",handle_user,0,4,"<core>"); + createcommand("NICK",handle_nick,0,1,"<core>"); + createcommand("QUIT",handle_quit,0,0,"<core>"); + createcommand("VERSION",handle_version,0,0,"<core>"); + createcommand("PING",handle_ping,0,1,"<core>"); + createcommand("PONG",handle_pong,0,1,"<core>"); + createcommand("ADMIN",handle_admin,0,0,"<core>"); + createcommand("PRIVMSG",handle_privmsg,0,2,"<core>"); + createcommand("INFO",handle_info,0,0,"<core>"); + createcommand("TIME",handle_time,0,0,"<core>"); + createcommand("WHOIS",handle_whois,0,1,"<core>"); + createcommand("WALLOPS",handle_wallops,'o',1,"<core>"); + createcommand("NOTICE",handle_notice,0,2,"<core>"); + createcommand("JOIN",handle_join,0,1,"<core>"); + createcommand("NAMES",handle_names,0,1,"<core>"); + createcommand("PART",handle_part,0,1,"<core>"); + createcommand("KICK",handle_kick,0,2,"<core>"); + createcommand("MODE",handle_mode,0,1,"<core>"); + createcommand("TOPIC",handle_topic,0,1,"<core>"); + createcommand("WHO",handle_who,0,1,"<core>"); + createcommand("MOTD",handle_motd,0,0,"<core>"); + createcommand("RULES",handle_rules,0,0,"<core>"); + createcommand("OPER",handle_oper,0,2,"<core>"); + createcommand("LIST",handle_list,0,0,"<core>"); + createcommand("DIE",handle_die,'o',1,"<core>"); + createcommand("RESTART",handle_restart,'o',1,"<core>"); + createcommand("KILL",handle_kill,'o',2,"<core>"); + createcommand("REHASH",handle_rehash,'o',0,"<core>"); + createcommand("LUSERS",handle_lusers,0,0,"<core>"); + createcommand("STATS",handle_stats,0,1,"<core>"); + createcommand("USERHOST",handle_userhost,0,1,"<core>"); + createcommand("AWAY",handle_away,0,0,"<core>"); + createcommand("ISON",handle_ison,0,0,"<core>"); + createcommand("SUMMON",handle_summon,0,0,"<core>"); + createcommand("USERS",handle_users,0,0,"<core>"); + createcommand("INVITE",handle_invite,0,2,"<core>"); + createcommand("PASS",handle_pass,0,1,"<core>"); + createcommand("TRACE",handle_trace,'o',0,"<core>"); + createcommand("WHOWAS",handle_whowas,0,1,"<core>"); + createcommand("CONNECT",handle_connect,'o',1,"<core>"); + createcommand("SQUIT",handle_squit,'o',0,"<core>"); + createcommand("MODULES",handle_modules,'o',0,"<core>"); + createcommand("LINKS",handle_links,0,0,"<core>"); + createcommand("MAP",handle_map,0,0,"<core>"); + createcommand("KLINE",handle_kline,'o',1,"<core>"); + createcommand("GLINE",handle_gline,'o',1,"<core>"); + createcommand("ZLINE",handle_zline,'o',1,"<core>"); + createcommand("QLINE",handle_qline,'o',1,"<core>"); + createcommand("ELINE",handle_eline,'o',1,"<core>"); + createcommand("LOADMODULE",handle_loadmodule,'o',1,"<core>"); + createcommand("UNLOADMODULE",handle_unloadmodule,'o',1,"<core>"); + createcommand("SERVER",handle_server,0,0,"<core>"); } void process_buffer(const char* cmdbuf,userrec *user) @@ -3241,6 +3263,51 @@ char* ModuleError() return MODERR; } +bool UnloadModule(const char* filename) +{ + for (int j = 0; j != module_names.size(); j++) + { + if (module_names[j] == std::string(filename)) + { + // found the module + log(DEBUG,"Deleting module..."); + delete factory[j]->factory; + log(DEBUG,"Deleting module factory..."); + delete factory[j]; + log(DEBUG,"Erasing module entry..."); + factory[j] = NULL; + // here we should locate ALL resources claimed by this module... and release them + // for example commands + log(DEBUG,"Erasing module vector..."); + for (std::vector<ircd_module*>::iterator t = factory.begin(); t != factory.end(); t++) + { + if (*t == NULL) + { + factory.erase(t); + break; + } + } + log(DEBUG,"Erasing module name vector..."); + for (std::vector<std::string>::iterator v = module_names.begin(); v != module_names.end(); v++) + { + if (*v == std::string(filename)) + { + module_names.erase(v); + break; + } + } + log(DEBUG,"Removing dependent commands..."); + removecommands(filename); + log(DEFAULT,"Module %s unloaded",filename); + MODCOUNT--; + return true; + } + } + log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename); + snprintf(MODERR,MAXBUF,"Module not loaded"); + return false; +} + bool LoadModule(const char* filename) { char modfile[MAXBUF]; diff --git a/src/modules.cpp b/src/modules.cpp index ec1d20560..7242ae92e 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -297,7 +297,7 @@ void ModeMakeList(char modechar) // version is a simple class for holding a modules version number -Version::Version(int major, int minor, int revision, int build) : Major(major), Minor(minor), Revision(revision), Build(build) { }; +Version::Version(int major, int minor, int revision, int build, int flags) : Major(major), Minor(minor), Revision(revision), Build(build), Flags(flags) { }; // admin is a simple class for holding a server's administrative info @@ -417,9 +417,9 @@ void Server::Log(int level, std::string s) log(level,"%s",s.c_str()); } -void Server::AddCommand(char* cmd, handlerfunc f, char flags, int minparams) +void Server::AddCommand(char* cmd, handlerfunc f, char flags, int minparams, char* source) { - createcommand(cmd,f,flags,minparams); + createcommand(cmd,f,flags,minparams,source); } void Server::SendMode(char **parameters, int pcnt, userrec *user) diff --git a/src/modules/m_chghost.cpp b/src/modules/m_chghost.cpp index c1ba262f1..366166e4c 100644 --- a/src/modules/m_chghost.cpp +++ b/src/modules/m_chghost.cpp @@ -51,7 +51,7 @@ class ModuleChgHost : public Module ModuleChgHost() { Srv = new Server; - Srv->AddCommand("CHGHOST",handle_chghost,'o',2); + Srv->AddCommand("CHGHOST",handle_chghost,'o',2,"m_chghost.so"); } virtual ~ModuleChgHost() diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp index 03c49ca10..5a1a8f7b3 100644 --- a/src/modules/m_globops.cpp +++ b/src/modules/m_globops.cpp @@ -50,7 +50,7 @@ class ModuleGlobops : public Module printf("Could not claim usermode +g for this module!"); exit(0); } - Srv->AddCommand("GLOBOPS",handle_globops,'o',1); + Srv->AddCommand("GLOBOPS",handle_globops,'o',1,"m_globops.so"); } virtual ~ModuleGlobops() diff --git a/src/modules/m_helpop.cpp b/src/modules/m_helpop.cpp index 71b9013e4..dc4f6f614 100644 --- a/src/modules/m_helpop.cpp +++ b/src/modules/m_helpop.cpp @@ -163,7 +163,7 @@ class ModuleHelpop : public Module } // Loads of comments, untill supported properly. - Srv->AddCommand("HELPOP",handle_helpop,0,0); + Srv->AddCommand("HELPOP",handle_helpop,0,0,"m_helpop.so"); } diff --git a/src/modules/m_knock.cpp b/src/modules/m_knock.cpp index fb07bcafc..3940a61a6 100644 --- a/src/modules/m_knock.cpp +++ b/src/modules/m_knock.cpp @@ -62,7 +62,7 @@ class ModuleKnock : public Module Srv = new Server; Srv->AddExtendedMode('K',MT_CHANNEL,false,0,0); - Srv->AddCommand("KNOCK",handle_knock,0,2); + Srv->AddCommand("KNOCK",handle_knock,0,2,"m_knock.so"); } virtual void On005Numeric(std::string &output) diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index ef2ad89e7..06b994c91 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -58,7 +58,7 @@ class ModuleOpermotd : public Module { Srv = new Server; - Srv->AddCommand("OPERMOTD",do_opermotd,'o',0); + Srv->AddCommand("OPERMOTD",do_opermotd,'o',0,"m_opermotd.so"); opermotd = new FileReader(); LoadOperMOTD(); diff --git a/src/modules/m_randquote.cpp b/src/modules/m_randquote.cpp index d3dfc5a45..1a875e527 100644 --- a/src/modules/m_randquote.cpp +++ b/src/modules/m_randquote.cpp @@ -80,7 +80,7 @@ class ModuleRandQuote : public Module exit(0); } /* Hidden Command -- Mode clients assume /quote sends raw data to an IRCd >:D */ - Srv->AddCommand("QUOTE",handle_randquote,0,0); + Srv->AddCommand("QUOTE",handle_randquote,0,0,"m_randquote.so"); } virtual ~ModuleRandQuote() diff --git a/src/modules/m_remove.cpp b/src/modules/m_remove.cpp index 873bdb25e..d4735081f 100644 --- a/src/modules/m_remove.cpp +++ b/src/modules/m_remove.cpp @@ -113,7 +113,7 @@ class ModuleRemove : public Module ModuleRemove() { Srv = new Server; - Srv->AddCommand("REMOVE", handle_remove, 0, 3); + Srv->AddCommand("REMOVE", handle_remove, 0, 3, "m_remove.so"); } virtual void On005Numeric(std::string &output) diff --git a/src/modules/m_sajoin.cpp b/src/modules/m_sajoin.cpp index 5b461362b..b3ca5fef2 100644 --- a/src/modules/m_sajoin.cpp +++ b/src/modules/m_sajoin.cpp @@ -51,7 +51,7 @@ class ModuleSajoin : public Module ModuleSajoin() { Srv = new Server; - Srv->AddCommand("SAJOIN",handle_sajoin,'o',2); + Srv->AddCommand("SAJOIN",handle_sajoin,'o',2,"m_sajoin.so"); } virtual ~ModuleSajoin() diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp index 6a2499f12..624f0483b 100644 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@ -62,9 +62,7 @@ class ModuleSaMode : public Module ModuleSaMode() { Srv = new Server; - Srv->Log(DEBUG,"SAMODE: Pre-add cmd"); - Srv->AddCommand("SAMODE",handle_samode,'o',2); - Srv->Log(DEBUG,"SAMODE: Post-add cmd"); + Srv->AddCommand("SAMODE",handle_samode,'o',2,"m_samode.so"); } virtual ~ModuleSaMode() diff --git a/src/modules/m_sanick.cpp b/src/modules/m_sanick.cpp index 053f59828..65de14250 100644 --- a/src/modules/m_sanick.cpp +++ b/src/modules/m_sanick.cpp @@ -46,7 +46,7 @@ class ModuleSanick : public Module ModuleSanick() { Srv = new Server; - Srv->AddCommand("SANICK",handle_sanick,'o',2); + Srv->AddCommand("SANICK",handle_sanick,'o',2,"m_sanick.so"); } virtual ~ModuleSanick() diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp index fb15d2cf8..e4b36b035 100644 --- a/src/modules/m_sapart.cpp +++ b/src/modules/m_sapart.cpp @@ -50,7 +50,7 @@ class ModuleSapart : public Module ModuleSapart() { Srv = new Server; - Srv->AddCommand("SAPART",handle_sapart,'o',2); + Srv->AddCommand("SAPART",handle_sapart,'o',2,"m_sapart.so"); } virtual ~ModuleSapart() diff --git a/src/modules/m_saquit.cpp b/src/modules/m_saquit.cpp index 9996f2044..5221f38ea 100644 --- a/src/modules/m_saquit.cpp +++ b/src/modules/m_saquit.cpp @@ -58,7 +58,7 @@ class ModuleSaquit : public Module ModuleSaquit() { Srv = new Server; - Srv->AddCommand("SAQUIT",handle_saquit,'o',2); + Srv->AddCommand("SAQUIT",handle_saquit,'o',2,"m_saquit.so"); } virtual ~ModuleSaquit() diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp index ba5e3319b..dd60e5766 100644 --- a/src/modules/m_sethost.cpp +++ b/src/modules/m_sethost.cpp @@ -48,7 +48,7 @@ class ModuleSetHost : public Module ModuleSetHost() { Srv = new Server; - Srv->AddCommand("SETHOST",handle_sethost,'o',1); + Srv->AddCommand("SETHOST",handle_sethost,'o',1,"m_sethost.so"); } virtual ~ModuleSetHost() diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp index 110afbe51..c1489876f 100644 --- a/src/modules/m_setname.cpp +++ b/src/modules/m_setname.cpp @@ -42,7 +42,7 @@ class ModuleSetName : public Module ModuleSetName() { Srv = new Server; - Srv->AddCommand("SETNAME",handle_setname,0,1); + Srv->AddCommand("SETNAME",handle_setname,0,1,"m_setname.so"); } virtual ~ModuleSetName() diff --git a/src/modules/m_silence.cpp b/src/modules/m_silence.cpp index e6cd730ac..a73ec757d 100644 --- a/src/modules/m_silence.cpp +++ b/src/modules/m_silence.cpp @@ -120,7 +120,7 @@ class ModuleSilence : public Module ModuleSilence() { Srv = new Server; - Srv->AddCommand("SILENCE",handle_silence,0,0); + Srv->AddCommand("SILENCE",handle_silence,0,0,"m_silence.so"); } virtual void OnUserQuit(userrec* user) diff --git a/src/modules/m_testcommand.cpp b/src/modules/m_testcommand.cpp index 452160dd0..984283fc3 100644 --- a/src/modules/m_testcommand.cpp +++ b/src/modules/m_testcommand.cpp @@ -55,7 +55,7 @@ class ModuleTestCommand : public Module // 0 in the modes parameter signifies that // anyone can issue the command, and the // command takes only one parameter. - Srv->AddCommand("WOOT",handle_woot,0,0); + Srv->AddCommand("WOOT",handle_woot,0,0,"m_testcommand.so"); // Add a mode +Z for channels with no parameters Srv->AddExtendedMode('Z',MT_CHANNEL,false,1,0); |