summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/commands.h1
-rw-r--r--include/ctables.h3
-rw-r--r--include/inspircd.h1
-rw-r--r--include/modules.h11
-rw-r--r--src/commands.cpp13
-rw-r--r--src/inspircd.cpp171
-rw-r--r--src/modules.cpp6
-rw-r--r--src/modules/m_chghost.cpp2
-rw-r--r--src/modules/m_globops.cpp2
-rw-r--r--src/modules/m_helpop.cpp2
-rw-r--r--src/modules/m_knock.cpp2
-rw-r--r--src/modules/m_opermotd.cpp2
-rw-r--r--src/modules/m_randquote.cpp2
-rw-r--r--src/modules/m_remove.cpp2
-rw-r--r--src/modules/m_sajoin.cpp2
-rw-r--r--src/modules/m_samode.cpp4
-rw-r--r--src/modules/m_sanick.cpp2
-rw-r--r--src/modules/m_sapart.cpp2
-rw-r--r--src/modules/m_saquit.cpp2
-rw-r--r--src/modules/m_sethost.cpp2
-rw-r--r--src/modules/m_setname.cpp2
-rw-r--r--src/modules/m_silence.cpp2
-rw-r--r--src/modules/m_testcommand.cpp2
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);