summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/botserv.example.conf52
-rw-r--r--data/chanserv.example.conf2
-rw-r--r--include/config.h4
-rw-r--r--include/modules.h14
-rw-r--r--modules/pseudoclients/botserv.cpp106
-rw-r--r--src/command.cpp1
-rw-r--r--src/config.cpp31
7 files changed, 162 insertions, 48 deletions
diff --git a/data/botserv.example.conf b/data/botserv.example.conf
index e4605f1ab..fd3d2dc1e 100644
--- a/data/botserv.example.conf
+++ b/data/botserv.example.conf
@@ -308,3 +308,55 @@ command { service = "BotServ"; name = "SET NOBOT"; command = "botserv/set/nobot"
module { name = "bs_set_private" }
command { service = "BotServ"; name = "SET PRIVATE"; command = "botserv/set/private"; }
+/* Fantasy commands
+ *
+ * Fantasy commands can be executed in channels that have a BotServ bot by prefixing the
+ * command with one of the fantasy characters configured in botserv:fantasycharacter.
+ *
+ * Sane defaults are provided below that do not need to be edited unless you wish to change the default behavior.
+ */
+
+fantasy { name = "ACCESS"; command = "chanserv/access"; }
+fantasy { name = "AKICK"; command = "chanserv/akick"; }
+fantasy { name = "AOP"; command = "chanserv/aop"; }
+fantasy { name = "APPENDTOPIC"; command = "chanserv/appendtopic"; }
+fantasy { name = "BAN"; command = "chanserv/ban"; }
+fantasy { name = "CLEARUSERS"; command = "chanserv/clearusers"; }
+fantasy { name = "CLONE"; command = "chanserv/clone"; }
+fantasy { name = "DEHALFOP"; command = "chanserv/dehalfop"; }
+fantasy { name = "DEOP"; command = "chanserv/deop"; }
+fantasy { name = "DEOWNER"; command = "chanserv/deowner"; }
+fantasy { name = "DEPROTECT"; command = "chanserv/deprotect"; }
+fantasy { name = "DEVOICE"; command = "chanserv/devoice"; }
+fantasy { name = "DOWN"; command = "chanserv/down"; }
+fantasy { name = "ENFORCE"; command = "chanserv/enforce"; }
+fantasy { name = "ENTRYMSG"; command = "chanserv/entrymsg"; }
+fantasy { name = "FLAGS"; command = "chanserv/flags"; }
+fantasy { name = "HALFOP"; command = "chanserv/halfop"; }
+fantasy { name = "HELP"; command = "chanserv/help"; }
+fantasy { name = "HOP"; command = "chanserv/hop"; }
+fantasy { name = "INFO"; command = "chanserv/info"; }
+fantasy { name = "INVITE"; command = "chanserv/invite"; }
+fantasy { name = "K"; command = "chanserv/kick"; }
+fantasy { name = "KB"; command = "chanserv/ban"; }
+fantasy { name = "KICK"; command = "chanserv/kick"; }
+fantasy { name = "LEVELS"; command = "chanserv/levels"; }
+fantasy { name = "LIST"; command = "chanserv/list"; }
+fantasy { name = "LOG"; command = "chanserv/log"; }
+fantasy { name = "MODE"; command = "chanserv/mode"; }
+fantasy { name = "OP"; command = "chanserv/op"; }
+fantasy { name = "OWNER"; command = "chanserv/owner"; }
+fantasy { name = "PROTECT"; command = "chanserv/protect"; }
+fantasy { name = "QOP"; command = "chanserv/qop"; }
+fantasy { name = "SEEN"; command = "chanserv/seen"; }
+fantasy { name = "SOP"; command = "chanserv/sop"; }
+fantasy { name = "SUSPEND"; command = "chanserv/suspend"; }
+fantasy { name = "SYNC"; command = "chanserv/sync"; }
+fantasy { name = "TOPIC"; command = "chanserv/topic"; }
+fantasy { name = "UNBAN"; command = "chanserv/unban"; }
+fantasy { name = "UNBAN"; command = "chanserv/unban"; }
+fantasy { name = "UNSUSPEND"; command = "chanserv/unsuspend"; }
+fantasy { name = "UP"; command = "chanserv/up"; }
+fantasy { name = "VOICE"; command = "chanserv/voice"; }
+fantasy { name = "VOP"; command = "chanserv/vop"; }
+
diff --git a/data/chanserv.example.conf b/data/chanserv.example.conf
index f507c5cab..e6e21dba3 100644
--- a/data/chanserv.example.conf
+++ b/data/chanserv.example.conf
@@ -882,7 +882,6 @@ command { service = "ChanServ"; name = "APPENDTOPIC"; command = "chanserv/append
*/
module { name = "cs_ban" }
command { service = "ChanServ"; name = "BAN"; command = "chanserv/ban"; }
-command { service = "ChanServ"; name = "KB"; command = "chanserv/ban"; }
/*
* cs_tban
@@ -999,7 +998,6 @@ command { service = "ChanServ"; name = "INVITE"; command = "chanserv/invite"; }
*/
module { name = "cs_kick" }
command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; }
-command { service = "ChanServ"; name = "K"; command = "chanserv/kick"; }
/*
* cs_list
diff --git a/include/config.h b/include/config.h
index de68d3105..f4f164b37 100644
--- a/include/config.h
+++ b/include/config.h
@@ -688,6 +688,10 @@ class CoreExport ServerConfig
std::list<OperType *> MyOperTypes;
/* List of pairs of opers and their opertype from the config */
std::vector<Oper *> Opers;
+
+ /* Map of fantasy commands */
+ typedef Anope::insensitive_map<CommandInfo> fantasy_map;
+ fantasy_map Fantasy;
};
/** This class can be used on its own to represent an exception, or derived to represent a module-specific exception.
diff --git a/include/modules.h b/include/modules.h
index 14fdff066..627bbab59 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -348,20 +348,22 @@ class CoreExport Module : public Extensible
virtual EventReturn OnDecrypt(const Anope::string &hashm, const Anope::string &src, Anope::string &dest) { return EVENT_CONTINUE; }
/** Called on fantasy command
- * @param command The command
- * @param u The user using the command
+ * @param source The source of the command
+ * @param c The command
* @param ci The channel it's being used in
* @param params The params
+ * @return EVENT_STOP to halt processing and not run the command, EVENT_ALLOW to allow the command to be executed
*/
- virtual void OnBotFantasy(const Anope::string &command, User *u, ChannelInfo *ci, const Anope::string &params) { }
+ virtual EventReturn OnBotFantasy(CommandSource &source, Command *c, ChannelInfo *ci, const std::vector<Anope::string> &params) { return EVENT_CONTINUE; }
/** Called on fantasy command without access
- * @param command The command
- * @param u The user using the command
+ * @param source The source of the command
+ * @param c The command
* @param ci The channel it's being used in
* @param params The params
+ * @return EVENT_STOP to halt processing and not run the command, EVENT_ALLOW to allow the command to be executed
*/
- virtual void OnBotNoFantasyAccess(const Anope::string &command, User *u, ChannelInfo *ci, const Anope::string &params) { }
+ virtual EventReturn OnBotNoFantasyAccess(CommandSource &source, Command *c, ChannelInfo *ci, const std::vector<Anope::string> &params) { return EVENT_CONTINUE; }
/** Called after a bot joins a channel
* @param c The channel
diff --git a/modules/pseudoclients/botserv.cpp b/modules/pseudoclients/botserv.cpp
index d792f74da..ec4bac11d 100644
--- a/modules/pseudoclients/botserv.cpp
+++ b/modules/pseudoclients/botserv.cpp
@@ -15,9 +15,8 @@
class BotServCore : public Module
{
- Channel *fantasy_channel;
public:
- BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), fantasy_channel(NULL)
+ BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE)
{
this->SetAuthor("Anope");
@@ -25,7 +24,7 @@ class BotServCore : public Module
if (BotServ == NULL)
throw ModuleException("No bot named " + Config->BotServ);
- Implementation i[] = { I_OnPrivmsg, I_OnPreCommand, I_OnJoinChannel, I_OnLeaveChannel,
+ Implementation i[] = { I_OnPrivmsg, I_OnJoinChannel, I_OnLeaveChannel,
I_OnPreHelp, I_OnPostHelp, I_OnChannelModeSet };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
@@ -45,7 +44,6 @@ class BotServCore : public Module
ircdproto->SendCTCP(c->ci->bi, u->nick, "%s", ctcp.c_str());
}
-
Anope::string realbuf = msg;
bool was_action = false;
@@ -66,58 +64,88 @@ class BotServCore : public Module
if (!Config->BSFantasyCharacter.empty())
realbuf.erase(realbuf.begin());
- size_t space = realbuf.find(' ');
- Anope::string command, rest;
- if (space == Anope::string::npos)
- command = realbuf;
- else
+ std::vector<Anope::string> params = BuildStringVector(realbuf);
+
+ ServerConfig::fantasy_map::const_iterator it = Config->Fantasy.end();
+ unsigned count = 0;
+ for (unsigned max = params.size(); it == Config->Fantasy.end() && max > 0; --max)
{
- command = realbuf.substr(0, space);
- rest = realbuf.substr(space + 1);
+ Anope::string full_command;
+ for (unsigned i = 0; i < max; ++i)
+ full_command += " " + params[i];
+ full_command.erase(full_command.begin());
+
+ ++count;
+ it = Config->Fantasy.find(full_command);
}
- if (c->ci->AccessFor(u).HasPriv("FANTASIA"))
+ if (it == Config->Fantasy.end())
+ return;
+
+ const CommandInfo &info = it->second;
+ service_reference<Command> cmd("Command", info.name);
+ if (!cmd)
{
- FOREACH_MOD(I_OnBotFantasy, OnBotFantasy(command, u, c->ci, rest));
+ Log(LOG_DEBUG) << "Fantasy command " << it->first << " exists for nonexistant service " << info.name << "!";
+ return;
}
- else
+
+ for (unsigned i = 0, j = params.size() - (count - 1); i < j; ++i)
+ params.erase(params.begin());
+
+ while (cmd->MaxParams > 0 && params.size() > cmd->MaxParams)
{
- FOREACH_MOD(I_OnBotNoFantasyAccess, OnBotNoFantasyAccess(command, u, c->ci, rest));
+ params[cmd->MaxParams - 1] += " " + params[cmd->MaxParams];
+ params.erase(params.begin() + cmd->MaxParams);
}
- BotInfo *bi = findbot(Config->ChanServ);
- if (bi == NULL)
- bi = findbot(Config->BotServ);
- if (bi == NULL || !bi->commands.count(command))
+ /* All ChanServ commands take the channel as a first parameter */
+ if (cmd->name.find("chanserv/") == 0)
+ params.insert(params.begin(), c->ci->name);
+
+ // Command requires registered users only
+ if (!cmd->HasFlag(CFLAG_ALLOW_UNREGISTERED) && !u->Account())
return;
+ if (params.size() < cmd->MinParams)
+ return;
+
+ CommandSource source(u->nick, u, u->Account(), u);
+ source.c = c;
+ source.owner = c->ci->bi;
+ source.service = c->ci->bi;
+ source.command = it->first;
+ source.permission = info.permission;
+
+ EventReturn MOD_RESULT;
if (c->ci->AccessFor(u).HasPriv("FANTASIA"))
{
- this->fantasy_channel = c;
- bi->OnMessage(u, realbuf);
- this->fantasy_channel = NULL;
+ FOREACH_RESULT(I_OnBotFantasy, OnBotFantasy(source, cmd, c->ci, params));
+ }
+ else
+ {
+ FOREACH_RESULT(I_OnBotNoFantasyAccess, OnBotNoFantasyAccess(source, cmd, c->ci, params));
}
- }
- }
- EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) anope_override
- {
- if (this->fantasy_channel != NULL)
- {
- if (!command->HasFlag(CFLAG_STRIP_CHANNEL))
+ if (MOD_RESULT == EVENT_STOP || !c->ci->AccessFor(u).HasPriv("FANTASIA"))
+ return;
+
+ if (MOD_RESULT != EVENT_ALLOW && !info.permission.empty() && !source.HasCommand(info.permission))
+ return;
+
+ FOREACH_RESULT(I_OnPreCommand, OnPreCommand(source, cmd, params));
+ if (MOD_RESULT == EVENT_STOP)
+ return;
+
+ dynamic_reference<User> user_reference(u);
+ dynamic_reference<NickCore> nc_reference(u->Account());
+ cmd->Execute(source, params);
+
+ if (user_reference && nc_reference)
{
- params.insert(params.begin(), this->fantasy_channel->name);
- if (command->MaxParams && params.size() > command->MaxParams)
- {
- params[params.size() - 2] += " " + params[params.size() - 1];
- params.erase(params.end() - 1);
- }
+ FOREACH_MOD(I_OnPostCommand, OnPostCommand(source, cmd, params));
}
- source.c = this->fantasy_channel;
- source.service = this->fantasy_channel->ci->WhoSends();
}
-
- return EVENT_CONTINUE;
}
void OnJoinChannel(User *user, Channel *c) anope_override
diff --git a/src/command.cpp b/src/command.cpp
index 9f1b26fa4..976f89de7 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -239,7 +239,6 @@ void RunCommand(CommandSource &source, const Anope::string &message)
if (MOD_RESULT == EVENT_STOP)
return;
-
if (params.size() < c->MinParams)
{
c->OnSyntaxError(source, !params.empty() ? params[params.size() - 1] : "");
diff --git a/src/config.cpp b/src/config.cpp
index e0cd21b68..b90c8598a 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -890,6 +890,8 @@ static bool DoneCommands(ServerConfig *config, const Anope::string &)
return true;
}
+/*************************************************************************/
+
static bool InitPrivileges(ServerConfig *config, const Anope::string &)
{
PrivilegeManager::ClearPrivileges();
@@ -1040,6 +1042,30 @@ static bool DoneServices(ServerConfig *config, const Anope::string &)
/*************************************************************************/
+static bool InitFantasy(ServerConfig *config, const Anope::string &)
+{
+ config->Fantasy.clear();
+ return true;
+}
+
+static bool DoFantasy(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *)
+{
+ Anope::string name = values[0].GetValue();
+ Anope::string service = values[1].GetValue();
+ Anope::string permission = values[2].GetValue();
+
+ config->Fantasy[name].name = service;
+ config->Fantasy[name].permission = permission;
+ return true;
+}
+
+static bool DoneFantasy(ServerConfig *config, const Anope::string &)
+{
+ return true;
+}
+
+/*************************************************************************/
+
ConfigurationFile::ConfigurationFile(const Anope::string &n, bool e) : name(n), executable(e), fp(NULL)
{
}
@@ -1359,6 +1385,11 @@ ConfigItems::ConfigItems(ServerConfig *conf)
{"", "", "", ""},
{DT_STRING, DT_STRING, DT_INTEGER, DT_STRING},
InitPrivileges, DoPrivileges, DonePrivileges},
+ {"fantasy",
+ {"name", "command", "permission", ""},
+ {"", "", "", ""},
+ {DT_STRING, DT_STRING, DT_STRING},
+ InitFantasy, DoFantasy, DoneFantasy},
{"",
{""},
{""},