From a1f29e2b87cc865c6cdeefd5ba49b663c1c31e43 Mon Sep 17 00:00:00 2001 From: JustinAJ Date: Tue, 30 Jun 2015 23:24:49 -0400 Subject: [PATCH] IRCCommand: * Added static member selected_server. * Added static member active_server. ExtraCommands: * Converted all existing console/IRC commands to Generic commands. * Added SelectGenericCommand. * Added DeselectGenericCommand. --- Bot/IRC_Bot.cpp | 15 +- Bot/IRC_Command.cpp | 3 + Bot/IRC_Command.h | 5 + ExtraCommands/ExtraCommands.cpp | 395 ++++++++++++++++++++------------ ExtraCommands/ExtraCommands.h | 20 +- Release/Bot.lib | Bin 25088 -> 25566 bytes Release/Plugins/RenX.Core.lib | Bin 129390 -> 129390 bytes 7 files changed, 282 insertions(+), 156 deletions(-) diff --git a/Bot/IRC_Bot.cpp b/Bot/IRC_Bot.cpp index d091203..6c3c895 100644 --- a/Bot/IRC_Bot.cpp +++ b/Bot/IRC_Bot.cpp @@ -47,7 +47,12 @@ IRC_Bot::IRC_Bot(const Jupiter::ReadableString &configSection) : Client(configSe IRC_Bot::~IRC_Bot() { - while (IRC_Bot::commands.size()) delete IRC_Bot::commands.remove(0); + if (IRCCommand::selected_server == this) + IRCCommand::selected_server = nullptr; + if (IRCCommand::active_server == this) + IRCCommand::active_server = IRCCommand::selected_server; + + IRC_Bot::commands.emptyAndDelete(); } void IRC_Bot::addCommand(IRCCommand *cmd) @@ -193,9 +198,13 @@ void IRC_Bot::OnChat(const Jupiter::ReadableString &channel, const Jupiter::Read IRCCommand *cmd = IRC_Bot::getCommand(command); if (cmd != nullptr) { + IRCCommand::active_server = this; int cAccess = cmd->getAccessLevel(chan); - if (cAccess >= 0 && Jupiter::IRC::Client::getAccessLevel(channel, nick) >= cAccess) cmd->trigger(this, channel, nick, parameters); - else this->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Access Denied.")); + if (cAccess >= 0 && Jupiter::IRC::Client::getAccessLevel(channel, nick) >= cAccess) + cmd->trigger(this, channel, nick, parameters); + else + this->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Access Denied.")); + IRCCommand::active_server = IRCCommand::selected_server; } } } diff --git a/Bot/IRC_Command.cpp b/Bot/IRC_Command.cpp index 09ad1ba..5be6158 100644 --- a/Bot/IRC_Command.cpp +++ b/Bot/IRC_Command.cpp @@ -53,6 +53,9 @@ IRCCommand::~IRCCommand() IRCCommand::types.emptyAndDelete(); } +IRC_Bot *IRCCommand::active_server = nullptr; +IRC_Bot *IRCCommand::selected_server = nullptr; + // IRC Command Functions int IRCCommand::getAccessLevel() diff --git a/Bot/IRC_Command.h b/Bot/IRC_Command.h index e590de7..9fc8972 100644 --- a/Bot/IRC_Command.h +++ b/Bot/IRC_Command.h @@ -145,6 +145,11 @@ public: */ virtual ~IRCCommand(); + /** Public members */ + + static IRC_Bot *active_server; /** Currently active IRC server */ + static IRC_Bot *selected_server; /** Currently selected IRC server */ + /** Private members */ private: int access; /** Default access level */ diff --git a/ExtraCommands/ExtraCommands.cpp b/ExtraCommands/ExtraCommands.cpp index fa476ce..1cf4da6 100644 --- a/ExtraCommands/ExtraCommands.cpp +++ b/ExtraCommands/ExtraCommands.cpp @@ -20,267 +20,374 @@ #include "ExtraCommands.h" #include "IRC_Bot.h" -// Raw Console Command +using namespace Jupiter::literals; -RawConsoleCommand::RawConsoleCommand() +// Select Command + +SelectGenericCommand::SelectGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("raw")); - this->addTrigger(STRING_LITERAL_AS_REFERENCE("sendraw")); + this->addTrigger("select"_jrs); + this->addTrigger("ircselect"_jrs); } -void RawConsoleCommand::trigger(const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *SelectGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - if (parameters.wordCount(WHITESPACE) < 2) - puts("Error: Too few parameters."); - else + if (parameters.isEmpty()) { - Jupiter::ReferenceString network = Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE); - Jupiter::ReferenceString message = Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE); - size_t total = 0; - for (size_t i = 0; i < serverManager->size(); i++) - { - IRC_Bot *server = serverManager->getServer(i); - if (server->getConfigSection().matchi(network)) - { - server->send(message); - total++; - } - } - printf("%u packets sent." ENDL, total); + if (IRCCommand::selected_server == nullptr) + return new GenericCommand::ResponseLine("No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicSuccess); + return new GenericCommand::ResponseLine(IRCCommand::selected_server->getConfigSection() + " is currently selected."_jrs, GenericCommand::DisplayType::PublicSuccess); } + if (IRCCommand::active_server == IRCCommand::selected_server) + IRCCommand::active_server = nullptr; + + IRCCommand::selected_server = serverManager->getServer(parameters); + if (IRCCommand::selected_server == nullptr) + return new GenericCommand::ResponseLine("Error: IRC server \""_jrs + parameters + "\" not found. No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); + + if (IRCCommand::active_server == nullptr) + IRCCommand::active_server = IRCCommand::selected_server; + return new GenericCommand::ResponseLine(IRCCommand::selected_server->getConfigSection() + " is now selected."_jrs, GenericCommand::DisplayType::PublicSuccess); } -const Jupiter::ReadableString &RawConsoleCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &SelectGenericCommand::getHelp(const Jupiter::ReadableString &) { - static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Syntax: raw "); + static Jupiter::ReferenceString defaultHelp = "Selects an IRC server if specified, responds with the currently selected server otherwise. Syntax: select [server]"_jrs; return defaultHelp; } -CONSOLE_COMMAND_INIT(RawConsoleCommand) +GENERIC_COMMAND_INIT(SelectGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(SelectGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(SelectGenericCommand, 4) -// Message Console Command +// Deselect Command -MessageConsoleCommand::MessageConsoleCommand() +DeselectGenericCommand::DeselectGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("ircmsg")); - this->addTrigger(STRING_LITERAL_AS_REFERENCE("message")); - this->addTrigger(STRING_LITERAL_AS_REFERENCE("privmsg")); + this->addTrigger("deselect"_jrs); + this->addTrigger("ircdeselect"_jrs); + this->addTrigger("dselect"_jrs); + this->addTrigger("ircdselect"_jrs); + this->addTrigger("unselect"_jrs); + this->addTrigger("ircunselect"_jrs); } -void MessageConsoleCommand::trigger(const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *DeselectGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - if (parameters.wordCount(WHITESPACE) < 3) - puts("Error: Too few parameters."); + if (IRCCommand::selected_server == nullptr) + return new GenericCommand::ResponseLine("No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicSuccess); + + GenericCommand::ResponseLine *ret = new GenericCommand::ResponseLine(IRCCommand::selected_server->getConfigSection() + " has been deselected."_jrs, GenericCommand::DisplayType::PublicSuccess); + IRCCommand::selected_server = nullptr; + IRCCommand::active_server = IRCCommand::selected_server; + return ret; +} + +const Jupiter::ReadableString &DeselectGenericCommand::getHelp(const Jupiter::ReadableString &) +{ + static Jupiter::ReferenceString defaultHelp = "Deselects the currently selected IRC server. Syntax: deselect"_jrs; + return defaultHelp; +} + +GENERIC_COMMAND_INIT(DeselectGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(DeselectGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(DeselectGenericCommand, 4) + +// Raw Command + +RawGenericCommand::RawGenericCommand() +{ + this->addTrigger("raw"_jrs); + this->addTrigger("sendraw"_jrs); +} + +GenericCommand::ResponseLine *RawGenericCommand::trigger(const Jupiter::ReadableString ¶meters) +{ + IRC_Bot *server; + if (IRCCommand::selected_server != nullptr) + server = IRCCommand::selected_server; + else if (IRCCommand::active_server != nullptr) + server = IRCCommand::active_server; else - { - Jupiter::ReferenceString network = Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE); - Jupiter::ReferenceString channel = Jupiter::ReferenceString::getWord(parameters, 1, WHITESPACE); - Jupiter::ReferenceString message = Jupiter::ReferenceString::gotoWord(parameters, 2, WHITESPACE); + return new GenericCommand::ResponseLine("Error: No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); - size_t total = 0; - for (size_t i = 0; i < serverManager->size(); i++) - { - IRC_Bot *server = serverManager->getServer(i); - if (server->getConfigSection().matchi(network)) - { - server->sendMessage(channel, message); - total++; - } - } - printf("%u messages sent." ENDL, total); - } + if (parameters.isEmpty()) + return new GenericCommand::ResponseLine("Error: Too few parameters. Syntax: raw "_jrs, GenericCommand::DisplayType::PrivateError); + + server->send(parameters); + return new GenericCommand::ResponseLine("Data has been successfully sent to server."_jrs, GenericCommand::DisplayType::PublicSuccess); } -const Jupiter::ReadableString &MessageConsoleCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &RawGenericCommand::getHelp(const Jupiter::ReadableString &) { - static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Sends a message to an IRC user/channel, on a specified network (accepts wildcards). Syntax: msg "); + static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Sends a line of data to the selected IRC server. Syntax: raw "); return defaultHelp; } -CONSOLE_COMMAND_INIT(MessageConsoleCommand) +GENERIC_COMMAND_INIT(RawGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(RawGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(RawGenericCommand, 5) + +// Message Command + +IRCMessageGenericCommand::IRCMessageGenericCommand() +{ + this->addTrigger("ircmsg"_jrs); + this->addTrigger("ircmessage"_jrs); + this->addTrigger("privmsg"_jrs); +} + +GenericCommand::ResponseLine *IRCMessageGenericCommand::trigger(const Jupiter::ReadableString ¶meters) +{ + IRC_Bot *server; + if (IRCCommand::selected_server != nullptr) + server = IRCCommand::selected_server; + else if (IRCCommand::active_server != nullptr) + server = IRCCommand::active_server; + else + return new GenericCommand::ResponseLine("Error: No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); + + if (parameters.wordCount(WHITESPACE) < 3) + return new GenericCommand::ResponseLine("Error: Too few parameters. Syntax: ircmsg "_jrs, GenericCommand::DisplayType::PrivateError); + + server->sendMessage(Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE), Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE)); + return new GenericCommand::ResponseLine("Message successfully sent."_jrs, GenericCommand::DisplayType::PublicSuccess); +} + +const Jupiter::ReadableString &IRCMessageGenericCommand::getHelp(const Jupiter::ReadableString &) +{ + static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Sends a message to an IRC user or channel on the selected IRC server. Syntax: ircmsg "); + return defaultHelp; +} + +GENERIC_COMMAND_INIT(IRCMessageGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(IRCMessageGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(IRCMessageGenericCommand, 5) // Join Command -void JoinIRCCommand::create() +JoinGenericCommand::JoinGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("Join")); - this->setAccessLevel(3); + this->addTrigger("Join"_jrs); } -void JoinIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *JoinGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - if (parameters.isNotEmpty()) - { - if (parameters.wordCount(WHITESPACE) == 1) - source->joinChannel(parameters); - else source->joinChannel(Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE), Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE)); - } - else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Too Few Parameters. Syntax: join [password]")); + IRC_Bot *server; + if (IRCCommand::selected_server != nullptr) + server = IRCCommand::selected_server; + else if (IRCCommand::active_server != nullptr) + server = IRCCommand::active_server; + else + return new GenericCommand::ResponseLine("Error: No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); + + if (parameters.isEmpty()) + return new GenericCommand::ResponseLine("Error: Too Few Parameters. Syntax: join [password]"_jrs, GenericCommand::DisplayType::PublicError); + + if (parameters.wordCount(WHITESPACE) == 1) + server->joinChannel(parameters); + else + server->joinChannel(Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE), Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE)); + + return new GenericCommand::ResponseLine("Request to join channel has been sent."_jrs, GenericCommand::DisplayType::PublicSuccess); } -const Jupiter::ReadableString &JoinIRCCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &JoinGenericCommand::getHelp(const Jupiter::ReadableString &) { - static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Joins a channel. Syntax: join "); + static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Joins a channel. Syntax: join [password]"); return defaultHelp; } -IRC_COMMAND_INIT(JoinIRCCommand) +GENERIC_COMMAND_INIT(JoinGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(JoinGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(JoinGenericCommand, 3) // Part Command -void PartIRCCommand::create() +PartGenericCommand::PartGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("Part")); - this->setAccessLevel(3); + this->addTrigger("Part"_jrs); } -void PartIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *PartGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - if (parameters.isNotEmpty()) - { - if (parameters.wordCount(WHITESPACE) == 1) - source->partChannel(parameters); - else source->partChannel(Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE), Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE)); - } - else source->partChannel(channel); + IRC_Bot *server; + if (IRCCommand::selected_server != nullptr) + server = IRCCommand::selected_server; + else if (IRCCommand::active_server != nullptr) + server = IRCCommand::active_server; + else + return new GenericCommand::ResponseLine("Error: No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); + + if (parameters.isEmpty()) + return new GenericCommand::ResponseLine("Error: Too few parameters. Syntax: part [message]"_jrs, GenericCommand::DisplayType::PublicError); + + if (parameters.wordCount(WHITESPACE) == 1) + server->partChannel(parameters); + else + server->partChannel(Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE), Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE)); + + return new GenericCommand::ResponseLine("Part command successfuly sent."_jrs, GenericCommand::DisplayType::PublicSuccess); } -const Jupiter::ReadableString &PartIRCCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &PartGenericCommand::getHelp(const Jupiter::ReadableString &) { - static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Parts from a channel. Syntax: part [channel=here] [message=empty]"); + static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Parts from a channel. Syntax: part [message]"); return defaultHelp; } -IRC_COMMAND_INIT(PartIRCCommand) +GENERIC_COMMAND_INIT(PartGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(PartGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(PartGenericCommand, 3) -// Info Command +// DebugInfo Command -void InfoIRCCommand::create() +DebugInfoGenericCommand::DebugInfoGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("info")); - this->setAccessLevel(4); + this->addTrigger("debuginfo"_jrs); } -void InfoIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *DebugInfoGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - Jupiter::String msg; - msg.format("Prefixes: %.*s", source->getPrefixes().size(), source->getPrefixes().ptr()); - source->sendMessage(channel, msg); - msg.format("Prefix Modes: %.*s", source->getPrefixModes().size(), source->getPrefixModes().ptr()); - source->sendMessage(channel, msg); - msg.format("Outputing data for %u channels...", source->getChannelCount()); - source->sendMessage(channel, msg); - for (unsigned int a = 0; a < source->getChannelCount(); a++) + IRC_Bot *server; + if (IRCCommand::selected_server != nullptr) + server = IRCCommand::selected_server; + else if (IRCCommand::active_server != nullptr) + server = IRCCommand::active_server; + else + return new GenericCommand::ResponseLine("Error: No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); + + Jupiter::IRC::Client::Channel *chan; + Jupiter::IRC::Client::User *user; + GenericCommand::ResponseLine *ret = new GenericCommand::ResponseLine("Prefixes: "_jrs + server->getPrefixes(), GenericCommand::DisplayType::PublicSuccess); + GenericCommand::ResponseLine *line = new GenericCommand::ResponseLine("Prefix Modes: "_jrs + server->getPrefixModes(), GenericCommand::DisplayType::PublicSuccess); + ret->next = line; + line->next = new GenericCommand::ResponseLine(Jupiter::StringS::Format("Outputting data for %u channels...", server->getChannelCount()), GenericCommand::DisplayType::PublicSuccess); + line = line->next; + for (unsigned int index = 0; index < server->getChannelCount(); ++index) { - Jupiter::IRC::Client::Channel *chan = source->getChannel(a); + chan = server->getChannel(index); if (chan != nullptr) { - msg.format("Channel %.*s - Type: %d", chan->getName().size(), chan->getName().ptr(), chan->getType()); - source->sendMessage(channel, msg); - for (unsigned int b = 0; b < chan->getUserCount(); b++) + line->next = new GenericCommand::ResponseLine(Jupiter::StringS::Format("Channel %.*s - Type: %d", chan->getName().size(), chan->getName().ptr(), chan->getType()), GenericCommand::DisplayType::PublicSuccess); + line = line->next; + for (unsigned int j = 0; j != chan->getUserCount(); ++j) { - Jupiter::IRC::Client::Channel::User *chanUser = chan->getUser(b); - Jupiter::IRC::Client::User *user = chanUser->getUser(); - msg.format("PRIVMSG %.*s :User %.*s!%.*s@%.*s (prefix: %c) of channel %.*s (of %u shared)" ENDL, channel.size(), channel.ptr(), user->getNickname().size(), user->getNickname().ptr(), user->getUsername().size(), user->getUsername().ptr(), user->getHostname().size(), user->getHostname().ptr(), chan->getUserPrefix(b) ? chan->getUserPrefix(b) : ' ', chan->getName().size(), chan->getName().ptr(), user->getChannelCount()); - source->send(msg); + user = chan->getUser(j)->getUser(); + line->next = new GenericCommand::ResponseLine(Jupiter::StringS::Format("User %.*s!%.*s@%.*s (prefix: %c) of channel %.*s (of %u shared)", user->getNickname().size(), user->getNickname().ptr(), user->getUsername().size(), user->getUsername().ptr(), user->getHostname().size(), user->getHostname().ptr(), chan->getUserPrefix(j) ? chan->getUserPrefix(j) : ' ', chan->getName().size(), chan->getName().ptr(), user->getChannelCount()), GenericCommand::DisplayType::PublicSuccess); + line = line->next; } } } + return ret; } -const Jupiter::ReadableString &InfoIRCCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &DebugInfoGenericCommand::getHelp(const Jupiter::ReadableString &) { - static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "TEMPORARY COMMAND - Spits out some info about channels. Syntax: info"); + static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "DEBUG COMMAND - Spits out some information about channels. Syntax: debuginfo"); return defaultHelp; } -IRC_COMMAND_INIT(InfoIRCCommand) +GENERIC_COMMAND_INIT(DebugInfoGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(DebugInfoGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(DebugInfoGenericCommand, 4) // Exit command -void ExitIRCCommand::create() +ExitGenericCommand::ExitGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("exit")); - this->setAccessLevel(5); + this->addTrigger("exit"_jrs); } -void ExitIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *ExitGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("Bye!")); exit(0); } -const Jupiter::ReadableString &ExitIRCCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &ExitGenericCommand::getHelp(const Jupiter::ReadableString &) { static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Closes the bot's application process. Syntax: exit"); return defaultHelp; } -IRC_COMMAND_INIT(ExitIRCCommand) +GENERIC_COMMAND_INIT(ExitGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(ExitGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(ExitGenericCommand, 5) // IRC Connect command -void IRCConnectIRCCommand::create() +IRCConnectGenericCommand::IRCConnectGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("IRCConnect")); - this->addTrigger(STRING_LITERAL_AS_REFERENCE("IRCReconnect")); - this->setAccessLevel(5); + this->addTrigger("IRCConnect"_jrs); + this->addTrigger("IRCReconnect"_jrs); } -void IRCConnectIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *IRCConnectGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - if (parameters == nullptr) - source->disconnect(STRING_LITERAL_AS_REFERENCE("Connect command used; reconnecting..."), false); - else + if (parameters.isEmpty()) { - IRC_Bot *server = serverManager->getServer(parameters); - if (server != nullptr) - { - source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("Warning: Server already exists. Severing connection...")); - server->disconnect(true); - } - if (serverManager->addServer(parameters)) - source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("Connection successfully established; server added to server list.")); - else source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("Error: Unable to find configuration settings for server, or connection refused.")); + IRC_Bot *server; + if (IRCCommand::selected_server != nullptr) + server = IRCCommand::selected_server; + else if (IRCCommand::active_server != nullptr) + server = IRCCommand::active_server; + else + return new GenericCommand::ResponseLine("Error: No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); + + server->disconnect("Connect command used; reconnecting..."_jrs, false); + return new GenericCommand::ResponseLine("Disconnected from IRC server."_jrs, GenericCommand::DisplayType::PublicSuccess); + } + IRC_Bot *server = serverManager->getServer(parameters); + if (server != nullptr) + { + server->disconnect("Connect command used; reconnecting..."_jrs, false); + return new GenericCommand::ResponseLine("Disconnected from IRC server."_jrs, GenericCommand::DisplayType::PublicSuccess); } + if (serverManager->addServer(parameters)) + return new GenericCommand::ResponseLine("Connection successfully established; server added to server list."_jrs, GenericCommand::DisplayType::PublicSuccess); + return new GenericCommand::ResponseLine("Error: Unable to find configuration settings for server, or connection refused."_jrs, GenericCommand::DisplayType::PublicError); } -const Jupiter::ReadableString &IRCConnectIRCCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &IRCConnectGenericCommand::getHelp(const Jupiter::ReadableString &) { static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Connects/reconnects to an IRC server, based on config entry. Syntax: IRCConnect [server=here]"); return defaultHelp; } -IRC_COMMAND_INIT(IRCConnectIRCCommand) +GENERIC_COMMAND_INIT(IRCConnectGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(IRCConnectGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(IRCConnectGenericCommand, 5) // IRC Disconnect command -void IRCDisconnectIRCCommand::create() +IRCDisconnectGenericCommand::IRCDisconnectGenericCommand() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("IRCDisconnect")); - this->setAccessLevel(5); + this->addTrigger("IRCDisconnect"_jrs); } -void IRCDisconnectIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) +GenericCommand::ResponseLine *IRCDisconnectGenericCommand::trigger(const Jupiter::ReadableString ¶meters) { - if (parameters.isEmpty()) - source->disconnect(STRING_LITERAL_AS_REFERENCE("Disconnect command used"), true); + IRC_Bot *server; + if (IRCCommand::selected_server != nullptr) + server = IRCCommand::selected_server; + else if (IRCCommand::active_server != nullptr) + server = IRCCommand::active_server; else - { - IRC_Bot *server = serverManager->getServer(parameters); - if (server == nullptr) - source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Server not found.")); - else server->disconnect(STRING_LITERAL_AS_REFERENCE("Disconnect command used remotely"), true); - } + return new GenericCommand::ResponseLine("Error: No IRC server is currently selected."_jrs, GenericCommand::DisplayType::PublicError); + + server->disconnect("Disconnect command used."_jrs, true); + return new GenericCommand::ResponseLine("Disconnected from server."_jrs, GenericCommand::DisplayType::PublicSuccess); } -const Jupiter::ReadableString &IRCDisconnectIRCCommand::getHelp(const Jupiter::ReadableString &) +const Jupiter::ReadableString &IRCDisconnectGenericCommand::getHelp(const Jupiter::ReadableString &) { - static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Disconnects from an IRC server, based on config entry. Syntax: IRCDisconnect [server=here]"); + static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Disconnects from an IRC server, based on config entry. Syntax: IRCDisconnect"); return defaultHelp; } -IRC_COMMAND_INIT(IRCDisconnectIRCCommand) +GENERIC_COMMAND_INIT(IRCDisconnectGenericCommand) +GENERIC_COMMAND_AS_CONSOLE_COMMAND(IRCDisconnectGenericCommand) +GENERIC_COMMAND_AS_IRC_COMMAND_ACCESS_CREATE(IRCDisconnectGenericCommand, 5) // Plugin instantiation and entry point. FunCommandsPlugin pluginInstance; diff --git a/ExtraCommands/ExtraCommands.h b/ExtraCommands/ExtraCommands.h index 08a80d2..b75f512 100644 --- a/ExtraCommands/ExtraCommands.h +++ b/ExtraCommands/ExtraCommands.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2014 Justin James. + * Copyright (C) 2014-2015 Justin James. * * This license must be preserved. * Any applications, libraries, or code which make any use of any @@ -31,13 +31,15 @@ private: STRING_LITERAL_AS_NAMED_REFERENCE(name, "ExtraCommands"); }; -GENERIC_CONSOLE_COMMAND(RawConsoleCommand) -GENERIC_CONSOLE_COMMAND(MessageConsoleCommand) -GENERIC_IRC_COMMAND(JoinIRCCommand) -GENERIC_IRC_COMMAND(PartIRCCommand) -GENERIC_IRC_COMMAND(InfoIRCCommand) -GENERIC_IRC_COMMAND(ExitIRCCommand) -GENERIC_IRC_COMMAND(IRCConnectIRCCommand) -GENERIC_IRC_COMMAND(IRCDisconnectIRCCommand) +GENERIC_GENERIC_COMMAND(SelectGenericCommand) +GENERIC_GENERIC_COMMAND(DeselectGenericCommand) +GENERIC_GENERIC_COMMAND(RawGenericCommand) +GENERIC_GENERIC_COMMAND(IRCMessageGenericCommand) +GENERIC_GENERIC_COMMAND(JoinGenericCommand) +GENERIC_GENERIC_COMMAND(PartGenericCommand) +GENERIC_GENERIC_COMMAND(DebugInfoGenericCommand) +GENERIC_GENERIC_COMMAND(ExitGenericCommand) +GENERIC_GENERIC_COMMAND(IRCConnectGenericCommand) +GENERIC_GENERIC_COMMAND(IRCDisconnectGenericCommand) #endif // _EXTRACOMMANDS_H_HEADER \ No newline at end of file diff --git a/Release/Bot.lib b/Release/Bot.lib index 71c83c17432e91d5d6b17a7fce687047aab805b6..a164183470e8ac12a5f1e2fb84a77fba5ff19a52 100644 GIT binary patch delta 3416 zcmbVOT}+$T8GeXNn}qz3km3ZWaS{>;Az(Yg@wx;FE0Y2Zw&mO z0SY7U0O@N6{yNHt37bK1nZb$fj}4;Ki&X*rL16kSkl?)kJs{c$WM&MqF98Y}#!(pC zVvzb0NGOZ?A&r|HiJ{X5gN=YfhzTfo-!w>5*7LH# z%mSb=%nB-uuv!Ykmoz*`GJwKl)L?=YP?%XWm|6l9rkR<-;IhH&JTN;iw~qF#EUyc% zKX!KR%p7A;g23G_ z;C>G<&+%k0bMB^InClUs!UtR?z6k-J`GI#vfNN=>j=yaaz%uPWrv5e7sEWaY{oJ{$ z(-b6t_c&?f!b}EuDN83Dw~PT_rhtp1z!m6hi+_#4;!%w z4QRv`Y()zeU1&uc4&o4+(S;~_;6?x;1aTDmupc$3MF%?ZH0%hY7wzanKc2yE?8P2D z2R|Z+p$O~#KLXQu3N}=s8ctN85`}ae7NO!tly>}AQqRKsZDK3mbzIt3`=lLu>zNiQ zt$bR3Q0Y?R%7W|N;<_h24=cOc9u%3r&UBVbeS7J;FNRj!?f-lvv`eUCYw;IDGV-Ck z(OE4E9e>a1?^n97b~3@5hwf@^aWP&`1BrL}EeA$l$$r-r zE>vmnE>QVNcbQVT+8xZBeLtvW4o`PZrd|KY<2Ca;9zFlsGnt#)<*ZlRyy_jx%l>6# zrM{GrImhjC-e*!^SF`PGlC9n+;|CAR1D{DlyrFuXV-pohEQL-_i7fi<#!H5Yz3ei^FQb2iZ=I8`AGGe{SYPlV@Atv_vSW$p&P!pUP2|`>Z6- z^y?%Y{c+>Nn!lBsE5gN59j78{`SDKL<$FfC0`k)?`UnI)Jm9P#6qseOtlj>2ruUDy_uWXiq zM6RP*pns&wHYfsows26I24}50ap_ls#+VNWFX3XyM=p<)Bnyl~Nn^}c0EZ--Oy`Yn zjTln>^5dae`RmTT(v-3+GehPeHPEVwP2{WDEx#TrNQg&Pb9#;nF4;Ofn0H&qsabKl z-(0{+o#V0*V|;?fEz&gdO5Qln>3phIsy9E*N!PGJ{>`N;DT|G2p~4EaO3|oQA#S)P zd6041DBdeKMlCDn_)htHbh|#rd<^;Uu<}cX`&feY5+5zkGkSZ>l$dWYA1i9z-Qmj@ z$~kTd#YdHIiB0PE#~yb<1O(Q37>xeu%`DojX@0e_!Iv}Sj3TtRC2<=y05FXh!HDdfSWUuwn z|Lx8{LQSvg{3raH%lAI-03GWPJ^1A9sos1J52s9e-{F#9DyJ9ClG@G>r_B;SpAe8g zP0yJnHl=o^nlec7Ub&FAwzDu!NH1;5)L0IA%KJ0s;ozq_KS*ri+J2zmzBU)BZiN~u v^s0hZ*{kHKZ0^1(2ppD)Y{=q6!{26&=Y2Gc(DVD1jt%^tZJb+}!^ZyrmG*sn delta 3272 zcmbVOTWnO<6cR$zO``mNx7k?_aaJyi&-f^t6`>6bLyn3b6)78HVD1~DD;;YL}~$rzEy+BdweGPUpI&{hQi=Q1AhR}xWjdYKjCHr%At^o z0rQ_342%K_)7K4xpEEhp|HNSU9uN-!v1Q@`Fgyt?ylJrbKA_RSm6-h0AWgZ#WEZfa zex{NJp*W!6J)HvsdWmGlAnIf#MDo5tlocuX*eQkhLxYiVKw+rDAaH?&DLgeuqyUY_ zSV7`3kgYSAJqIYH)(xiE9fb_5Qy6y{jIe5j&`ks14H6*c*{Sd~gX|T?B*xh}g^61^ zM7R>8%rUy&1Uf=1PpR3kpk@6y)pHcDdhEwRW>`uw?D@mhv68 zJ=NZx-&4Z?o^=AQ9`1@>;Q0`6ehherYw+5`e9tAEAvR{7S z4$&NDpa6%=-hDPtCIi5A`hQOUC$zuEL~3@+G4}L9jMJsy%?057MWBKBbdvw4fiAAe zDYI)%dw~Z;hGjdM@IKdzTq8cSHn zzeoFi~Ur+Q238;1;R(S6fC&zlqX7BX(Mn&Ykj>-#W|X zcYaOro`24Ail?KcW;GkJ;}-bWtXuHs_)+qdoABvVJ&+Q?z3b$VxfqQ7)dDK z+YwuihNzZxMB|n(W!q_&ewk#eI1QigxQrE5%J27WlP{yTndFAsHfS5}>Y%B#iOw~w z)al$qrxJPhg*h$gtaU@SF{}=`N>x^#g4ikhh7L(zaj9g6Y}2cYX*W+SW|8H{RZ-Vt z{!OyFVVmsiu(rE2Y-`dZBYQfWw0v{2vvHg3VO;w@iRa_hNFq_WRng@E%%hZa?9J>+~is!AEfdX z*@^k44oG1pPfYhqbB@Vhsrq(nqg>78yHzb5pXRN`cS0wqoz8n#OKRGvd0(PKemwmH z!~4RjX#Zs$0fpUsUN4Dz6?joTU?SYdHKw z79N+nq7(AXtVjMh=eFV&&YP6H>d_~A=YO)Hs*z9T&CvO|zzbaMeRyXW0EqwCEV$@PSTr`vXE>(VZ<)mJFTvKeq|>xruT5gL5hy8lIk%cqRNei}q+aJRL-H1MOdZD-D%LD_!+XC@!9 diff --git a/Release/Plugins/RenX.Core.lib b/Release/Plugins/RenX.Core.lib index 1160e05b388619ae6487c7d967c1faf388771274..3d2f4a44fb8b30955eb4346fbde0c0c9d6a0aad1 100644 GIT binary patch delta 7527 zcmZ`;dsJ3c7U#4awT47AfgwW7EEnPe%Z$(j6ciB^e4$8)kIaw|%*+rK)9f)Wqi8rr zKFBFUM-gp$Xo{qkR)qLS$r!^Pq(%CrnYNZSv-dvtce(eQnLpXze*X6JTrOPdaN$yi zlF)Y11Nz^qJwsK%j_Adf>` zvC3CD=>6kV=RaK;S32R8_K#KF^&f-Ot$KN!`pM!+RN*A1E8VRjT2Wo;Y9iYsI|ydbbm z6r#KzDfiXglL(%gAu7r!u5L6Q1tr;vhZ@S7B$pbF`p@iRA5!Dz)2_6^FI3mXt4?}M zf(kUsC~CoB^$0c0P@1(0(w-5ji+C`OME&*lWEEK2_-H>p`jSh!`Azb+G}&NQnXG16 zp>q(xeDFwb%y*B3n>OZRt0&p&rau^|y6Myu)!Wi#K~$LnA%Tds`ysYKpLRa6vHeO5 zE(GiCBai@FITytGQAntVvf#^-QDp8fBw5<;mfKmZlTID30@|z!Q#dgNGt=C=LiFBI zZYB$M-!X6vXs#RsG(oxUqy%cNGjX3|4mIxU_!M=YF)t9xzZm3HoSqi&d}?l8I-Z>d7YyEj!~+_s+jelNJK&bV`;qoe~h!q_ws zVc5V(!Q4w4`{*6%>J}ZFt_B)=wOb7&Thgr&P&UaBA||OMM|j-9Tp6!VvcTkEm=G}; zBgO7?CRb1P;)~7zUrC0M+>@c=#6sB=OVt!r==SR56bz=~&4y=ECi+7HPwZkyfaJ9^CAmUX{79aT`*O3Els_8k3*m5 zBcm^8sx3IxP<*r13Ir3R8y+zRYO~c-ZPcu3ma|hx{{!S~@xakKat54@%coH?=%SGf zovxm3lT3ZaP)|-*ON_(S1vE6~&M-+?F+=4Ua&|81=rq%^vzY9}lbxz@`TEtFu+zN3 zxa^s!${bP~A2K%Hc}T4>mWvGEl38k%;Y;0NC@~Mi4N%V66c@l{vn`w`#X*|mXV{}3 zv9cjl#!671M&6Flv2#?nvK-7tTbrGiWN?J)>?{>+9CJ<9=sA!kM5RXS=cv_oq(WJh zt11j7>QTd!`KYQg6v;z#p7Av%Pd)EN7FTk}*;E~$ry_KAk&1T=!-_%*HGjSlubKanU>!F(|zs110KBYqU%yztU;6=-3-nUtK*< z-R)Rkwreu1^N4kl#hR^)AHxXZoC-r0F-+z$HFrwiQcu604jx+*JMVei84|KwwE)h+ z-HazdVRu=w{X$i2f)s@ZORN%Hs7eeujP42XC6#=c%DxoL7@~jN@7gSqurmjYY(Sw} zX{!_?b%p9>Ly@Lgw8%6~$s(02yUNSKY z6n88)3G?BH=@l*BQgwyh<%F_&3vj z5t}o}W)ay8i=OCZQ#V(cWW=miGmR8Fu6{K-&aPcnU-$wl-JY*vgZExB+3(ysnkt~b1>vUEw2@^71vf)P)BvB^_^1=&nHG~O#NyLcp@*~IrW zcSw&|sc-9Eat)&SFT)j1m56bwo?)?)kq`er{S3*qzqyJN;Z~L*-0C_5@@%cxR>)=CCV9AbYFRV-CM{D=v4z5MJhOgO|>iS6LNaEW(Tz){-i`urT3#w_6hq zuaAoDs0Hp%foeQ?x>FyiR=sp;HQq2hM%k^y)z+D=ak&=lK#gOkh3~}WB|g5r(*XR* zPB`gGf6`la`uTpx8Pf0;&JaoehF0t2!YJ}?7vb1^B2FLqC+f^~a_#2&uXs}Sn>95A z7JiRPE@DZ?`=sOIlXvTz-+>Np5Bd2X`gsriT=DsxI^(G85U`gYW6|;sCRy!OgU<8s zVu7HBLf=CTxv(gI?|)(uw9AFXs$FKNRqO)jwtaDwm+t{`bg=I*UHgH{QDo=ZZe)i< zO?c@f^&v^Ucq&;R`3%uhP9(vj_rQh!UTud+>TF(uw=Dtp)#E113-_YQU2WU325oDn zf+5^g18!I04%mmn<)p}j;iS}YV*MBQ(g%jaZ836Bt+Aa{t8z>W3)!#Unodb1ThG&} zzL$z&@2#p3uHTOs;ldAG!u&K8kVlhn0|kC$QM^Occ2{_K{2e8p$kS1L7MjUvZ!-=w z?f~8=GEce6rP*eYmCXU7??oxsag5vfT(q>WjZq30(XQ z?j(mC*<0PF`+NkvN?J^si$AiiLyb!+0`J>K$)@|L>@KK&qtdgb?(>p&-nbuAYJ$v4aLJqkmX@?hNPA)9_~P2V#UYT0iW8F z5<63%m8@ntuGzx>UaQ1 zTJf!^>Pt*Q?8}rUSYu5bYikp}{==gM{{j!L&44qwHnH3r&tUr?vfQr_8M?gnD|9)e zRyRY6lO%BQvD99*EA{`bm*ZBkt4Da^iKm0`^l%3&V}kEd4rIXBb|BWj5o*7NOM*(D zZwzDHH~8j+U3&5x_$7=JzBPCq|@I+19TRi0|mEf@Oj*(@Z^*8-kzlV04a1* z>ksH8*BlI@@b;Y>?g&pHz@!dph5th4i%C`iUrfP@R>9Q!RIK;wfrA(PQi$tTGO+Bt z@R$whdK6vw36COsg>j0@FJQt68Q))1FIwMU`5$_1-_|>NFrH-UocEZluJmBYxX6Fl zWKtraFZkK&I@fmf{EY3&SB|8Pubew{+GYA!zxR@Q(4-E}`sB+91$XVQmvLgDQ?~qq zPQj6$as@}aYZW$LLAHd9|6^qTif00D!Iocf3)(#*(DR!uf}oH3sjpsh6&nP7(0Ubp mKo|t*oNMY9hQ0WjiZMY6`GiIO;hO62AV>dZxJUn{!u|ug@|QIL delta 7527 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