diff options
Diffstat (limited to 'modules/commands/bs_kick.cpp')
-rw-r--r-- | modules/commands/bs_kick.cpp | 1474 |
1 files changed, 0 insertions, 1474 deletions
diff --git a/modules/commands/bs_kick.cpp b/modules/commands/bs_kick.cpp deleted file mode 100644 index 3a52878c1..000000000 --- a/modules/commands/bs_kick.cpp +++ /dev/null @@ -1,1474 +0,0 @@ -/* BotServ core functions - * - * (C) 2003-2017 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - */ - -#include "module.h" -#include "modules/bs_kick.h" -#include "modules/bs_badwords.h" - -static Module *me; - -struct KickerDataImpl : KickerData -{ - KickerDataImpl(Extensible *obj) - { - amsgs = badwords = bolds = caps = colors = flood = italics = repeat = reverses = underlines = false; - for (int16_t i = 0; i < TTB_SIZE; ++i) - ttb[i] = 0; - capsmin = capspercent = 0; - floodlines = floodsecs = 0; - repeattimes = 0; - - dontkickops = dontkickvoices = false; - } - - void Check(ChannelInfo *ci) anope_override - { - if (amsgs || badwords || bolds || caps || colors || flood || italics || repeat || reverses || underlines) - return; - - ci->Shrink<KickerData>("kickerdata"); - } - - struct ExtensibleItem : ::ExtensibleItem<KickerDataImpl> - { - ExtensibleItem(Module *m, const Anope::string &ename) : ::ExtensibleItem<KickerDataImpl>(m, ename) { } - - void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override - { - if (s->GetSerializableType()->GetName() != "ChannelInfo") - return; - - const ChannelInfo *ci = anope_dynamic_static_cast<const ChannelInfo *>(e); - KickerData *kd = this->Get(ci); - if (kd == NULL) - return; - - data["kickerdata:amsgs"] << kd->amsgs; - data["kickerdata:badwords"] << kd->badwords; - data["kickerdata:bolds"] << kd->bolds; - data["kickerdata:caps"] << kd->caps; - data["kickerdata:colors"] << kd->colors; - data["kickerdata:flood"] << kd->flood; - data["kickerdata:italics"] << kd->italics; - data["kickerdata:repeat"] << kd->repeat; - data["kickerdata:reverses"] << kd->reverses; - data["kickerdata:underlines"] << kd->underlines; - - data.SetType("capsmin", Serialize::Data::DT_INT); data["capsmin"] << kd->capsmin; - data.SetType("capspercent", Serialize::Data::DT_INT); data["capspercent"] << kd->capspercent; - data.SetType("floodlines", Serialize::Data::DT_INT); data["floodlines"] << kd->floodlines; - data.SetType("floodsecs", Serialize::Data::DT_INT); data["floodsecs"] << kd->floodsecs; - data.SetType("repeattimes", Serialize::Data::DT_INT); data["repeattimes"] << kd->repeattimes; - for (int16_t i = 0; i < TTB_SIZE; ++i) - data["ttb"] << kd->ttb[i] << " "; - } - - void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override - { - if (s->GetSerializableType()->GetName() != "ChannelInfo") - return; - - ChannelInfo *ci = anope_dynamic_static_cast<ChannelInfo *>(e); - KickerData *kd = ci->Require<KickerData>("kickerdata"); - - data["kickerdata:amsgs"] >> kd->amsgs; - data["kickerdata:badwords"] >> kd->badwords; - data["kickerdata:bolds"] >> kd->bolds; - data["kickerdata:caps"] >> kd->caps; - data["kickerdata:colors"] >> kd->colors; - data["kickerdata:flood"] >> kd->flood; - data["kickerdata:italics"] >> kd->italics; - data["kickerdata:repeat"] >> kd->repeat; - data["kickerdata:reverses"] >> kd->reverses; - data["kickerdata:underlines"] >> kd->underlines; - - data["capsmin"] >> kd->capsmin; - data["capspercent"] >> kd->capspercent; - data["floodlines"] >> kd->floodlines; - data["floodsecs"] >> kd->floodsecs; - data["repeattimes"] >> kd->repeattimes; - - Anope::string ttb, tok; - data["ttb"] >> ttb; - spacesepstream sep(ttb); - for (int i = 0; sep.GetToken(tok) && i < TTB_SIZE; ++i) - try - { - kd->ttb[i] = convertTo<int16_t>(tok); - } - catch (const ConvertException &) { } - - kd->Check(ci); - } - }; -}; - -class CommandBSKick : public Command -{ - public: - CommandBSKick(Module *creator) : Command(creator, "botserv/kick", 0) - { - this->SetDesc(_("Configures kickers")); - this->SetSyntax(_("\037option\037 \037channel\037 {\037ON|OFF\037} [\037settings\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - this->OnSyntaxError(source, ""); - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Configures bot kickers. \037option\037 can be one of:")); - - Anope::string this_name = source.command; - for (CommandInfo::map::const_iterator it = source.service->commands.begin(), it_end = source.service->commands.end(); it != it_end; ++it) - { - const Anope::string &c_name = it->first; - const CommandInfo &info = it->second; - - if (c_name.find_ci(this_name + " ") == 0) - { - ServiceReference<Command> command("Command", info.name); - if (command) - { - source.command = c_name; - command->OnServHelp(source); - } - } - } - - source.Reply(_("Type \002%s%s HELP %s \037option\037\002 for more information\n" - "on a specific option.\n" - " \n" - "Note: access to this command is controlled by the\n" - "level SET."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), this_name.c_str()); - - return true; - } -}; - -class CommandBSKickBase : public Command -{ - public: - CommandBSKickBase(Module *creator, const Anope::string &cname, int minarg, int maxarg) : Command(creator, cname, minarg, maxarg) - { - } - - virtual void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override = 0; - - virtual bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override = 0; - - protected: - bool CheckArguments(CommandSource &source, const std::vector<Anope::string> ¶ms, ChannelInfo* &ci) - { - const Anope::string &chan = params[0]; - const Anope::string &option = params[1]; - - ci = ChannelInfo::Find(chan); - - if (Anope::ReadOnly) - source.Reply(_("Sorry, kicker configuration is temporarily disabled.")); - else if (ci == NULL) - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - else if (option.empty()) - this->OnSyntaxError(source, ""); - else if (!option.equals_ci("ON") && !option.equals_ci("OFF")) - this->OnSyntaxError(source, ""); - else if (!source.AccessFor(ci).HasPriv("SET") && !source.HasPriv("botserv/administration")) - source.Reply(ACCESS_DENIED); - else if (!ci->bi) - source.Reply(BOT_NOT_ASSIGNED); - else - return true; - - return false; - } - - void Process(CommandSource &source, ChannelInfo *ci, const Anope::string ¶m, const Anope::string &ttb, size_t ttb_idx, const Anope::string &optname, KickerData *kd, bool &val) - { - if (param.equals_ci("ON")) - { - if (!ttb.empty()) - { - int16_t i; - - try - { - i = convertTo<int16_t>(ttb); - if (i < 0) - throw ConvertException(); - } - catch (const ConvertException &) - { - source.Reply(_("\002%s\002 cannot be taken as times to ban."), ttb.c_str()); - return; - } - - kd->ttb[ttb_idx] = i; - } - else - kd->ttb[ttb_idx] = 0; - - val = true; - if (kd->ttb[ttb_idx]) - source.Reply(_("Bot will now kick for \002%s\002, and will place a ban\n" - "after %d kicks for the same user."), optname.c_str(), kd->ttb[ttb_idx]); - else - source.Reply(_("Bot will now kick for \002%s\002."), optname.c_str()); - - bool override = !source.AccessFor(ci).HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable the " << optname << " kicker"; - } - else if (param.equals_ci("OFF")) - { - bool override = !source.AccessFor(ci).HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable the " << optname << " kicker"; - - val = false; - source.Reply(_("Bot won't kick for \002%s\002 anymore."), optname.c_str()); - } - else - this->OnSyntaxError(source, ""); - } -}; - -class CommandBSKickAMSG : public CommandBSKickBase -{ - public: - CommandBSKickAMSG(Module *creator) : CommandBSKickBase(creator, "botserv/kick/amsg", 2, 3) - { - this->SetDesc(_("Configures AMSG kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (CheckArguments(source, params, ci)) - { - KickerData *kd = ci->Require<KickerData>("kickerdata"); - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_AMSGS, "AMSG", kd, kd->amsgs); - kd->Check(ci); - } - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - BotInfo *bi = Config->GetClient("BotServ"); - source.Reply(_("Sets the AMSG kicker on or off. When enabled, the bot will\n" - "kick users who send the same message to multiple channels\n" - "where %s bots are.\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before they get banned. Don't give ttb to disable\n" - "the ban system once activated."), bi ? bi->nick.c_str() : "BotServ"); - return true; - } -}; - -class CommandBSKickBadwords : public CommandBSKickBase -{ - public: - CommandBSKickBadwords(Module *creator) : CommandBSKickBase(creator, "botserv/kick/badwords", 2, 3) - { - this->SetDesc(_("Configures badwords kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (CheckArguments(source, params, ci)) - { - KickerData *kd = ci->Require<KickerData>("kickerdata"); - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BADWORDS, "badwords", kd, kd->badwords); - kd->Check(ci); - } - - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the bad words kicker on or off. When enabled, this\n" - "option tells the bot to kick users who say certain words\n" - "on the channels.\n" - "You can define bad words for your channel using the\n" - "\002BADWORDS\002 command. Type \002%s%s HELP BADWORDS\002 for\n" - "more information.\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str()); - return true; - } -}; - -class CommandBSKickBolds : public CommandBSKickBase -{ - public: - CommandBSKickBolds(Module *creator) : CommandBSKickBase(creator, "botserv/kick/bolds", 2, 3) - { - this->SetDesc(_("Configures bolds kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (CheckArguments(source, params, ci)) - { - KickerData *kd = ci->Require<KickerData>("kickerdata"); - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BOLDS, "bolds", kd, kd->bolds); - kd->Check(ci); - } - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the bolds kicker on or off. When enabled, this\n" - "option tells the bot to kick users who use bolds.\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSKickCaps : public CommandBSKickBase -{ - public: - CommandBSKickCaps(Module *creator) : CommandBSKickBase(creator, "botserv/kick/caps", 2, 5) - { - this->SetDesc(_("Configures caps kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037 [\037min\037 [\037percent\037]]]\002")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (!CheckArguments(source, params, ci)) - return; - - KickerData *kd = ci->Require<KickerData>("kickerdata"); - - if (params[1].equals_ci("ON")) - { - const Anope::string &ttb = params.size() > 2 ? params[2] : "", - &min = params.size() > 3 ? params[3] : "", - &percent = params.size() > 4 ? params[4] : ""; - - if (!ttb.empty()) - { - try - { - kd->ttb[TTB_CAPS] = convertTo<int16_t>(ttb); - if (kd->ttb[TTB_CAPS] < 0) - throw ConvertException(); - } - catch (const ConvertException &) - { - kd->ttb[TTB_CAPS] = 0; - source.Reply(_("\002%s\002 cannot be taken as times to ban."), ttb.c_str()); - return; - } - } - else - kd->ttb[TTB_CAPS] = 0; - - kd->capsmin = 10; - try - { - kd->capsmin = convertTo<int16_t>(min); - } - catch (const ConvertException &) { } - if (kd->capsmin < 1) - kd->capsmin = 10; - - kd->capspercent = 25; - try - { - kd->capspercent = convertTo<int16_t>(percent); - } - catch (const ConvertException &) { } - if (kd->capspercent < 1 || kd->capspercent > 100) - kd->capspercent = 25; - - kd->caps = true; - if (kd->ttb[TTB_CAPS]) - source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n" - "%d characters and %d%% of the entire message), and will\n" - "place a ban after %d kicks for the same user."), kd->capsmin, kd->capspercent, kd->ttb[TTB_CAPS]); - else - source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n" - "%d characters and %d%% of the entire message)."), kd->capsmin, kd->capspercent); - } - else - { - kd->caps = false; - source.Reply(_("Bot won't kick for \002caps\002 anymore.")); - } - - kd->Check(ci); - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the caps kicker on or off. When enabled, this\n" - "option tells the bot to kick users who are talking in\n" - "CAPS.\n" - "The bot kicks only if there are at least \002min\002 caps\n" - "and they constitute at least \002percent\002%% of the total\n" - "text line (if not given, it defaults to 10 characters\n" - "and 25%%).\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSKickColors : public CommandBSKickBase -{ - public: - CommandBSKickColors(Module *creator) : CommandBSKickBase(creator, "botserv/kick/colors", 2, 3) - { - this->SetDesc(_("Configures color kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (CheckArguments(source, params, ci)) - { - KickerData *kd = ci->Require<KickerData>("kickerdata"); - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_COLORS, "colors", kd, kd->colors); - kd->Check(ci); - } - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the colors kicker on or off. When enabled, this\n" - "option tells the bot to kick users who use colors.\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSKickFlood : public CommandBSKickBase -{ - public: - CommandBSKickFlood(Module *creator) : CommandBSKickBase(creator, "botserv/kick/flood", 2, 5) - { - this->SetDesc(_("Configures flood kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037 [\037ln\037 [\037secs\037]]]\002")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (!CheckArguments(source, params, ci)) - return; - - KickerData *kd = ci->Require<KickerData>("kickerdata"); - - if (params[1].equals_ci("ON")) - { - const Anope::string &ttb = params.size() > 2 ? params[2] : "", - &lines = params.size() > 3 ? params[3] : "", - &secs = params.size() > 4 ? params[4] : ""; - - if (!ttb.empty()) - { - int16_t i; - - try - { - i = convertTo<int16_t>(ttb); - if (i < 0) - throw ConvertException(); - } - catch (const ConvertException &) - { - source.Reply(_("\002%s\002 cannot be taken as times to ban."), ttb.c_str()); - return; - } - - kd->ttb[TTB_FLOOD] = i; - } - else - kd->ttb[TTB_FLOOD] = 0; - - kd->floodlines = 6; - try - { - kd->floodlines = convertTo<int16_t>(lines); - } - catch (const ConvertException &) { } - if (kd->floodlines < 2) - kd->floodlines = 6; - - kd->floodsecs = 10; - try - { - kd->floodsecs = convertTo<int16_t>(secs); - } - catch (const ConvertException &) { } - if (kd->floodsecs < 1) - kd->floodsecs = 10; - if (kd->floodsecs > Config->GetModule(me)->Get<time_t>("keepdata")) - kd->floodsecs = Config->GetModule(me)->Get<time_t>("keepdata"); - - kd->flood = true; - if (kd->ttb[TTB_FLOOD]) - source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds\n" - "and will place a ban after %d kicks for the same user."), kd->floodlines, kd->floodsecs, kd->ttb[TTB_FLOOD]); - else - source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds)."), kd->floodlines, kd->floodsecs); - } - else if (params[1].equals_ci("OFF")) - { - kd->flood = false; - source.Reply(_("Bot won't kick for \002flood\002 anymore.")); - } - else - this->OnSyntaxError(source, params[1]); - - kd->Check(ci); - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the flood kicker on or off. When enabled, this\n" - "option tells the bot to kick users who are flooding\n" - "the channel using at least \002ln\002 lines in \002secs\002 seconds\n" - "(if not given, it defaults to 6 lines in 10 seconds).\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSKickItalics : public CommandBSKickBase -{ - public: - CommandBSKickItalics(Module *creator) : CommandBSKickBase(creator, "botserv/kick/italics", 2, 3) - { - this->SetDesc(_("Configures italics kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (CheckArguments(source, params, ci)) - { - KickerData *kd = ci->Require<KickerData>("kickerdata"); - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", kd, kd->italics); - kd->Check(ci); - } - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the italics kicker on or off. When enabled, this\n" - "option tells the bot to kick users who use italics.\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSKickRepeat : public CommandBSKickBase -{ - public: - CommandBSKickRepeat(Module *creator) : CommandBSKickBase(creator, "botserv/kick/repeat", 2, 4) - { - this->SetDesc(_("Configures repeat kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037 [\037num\037]]\002")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (!CheckArguments(source, params, ci)) - return; - - KickerData *kd = ci->Require<KickerData>("kickerdata"); - - if (params[1].equals_ci("ON")) - { - const Anope::string &ttb = params.size() > 2 ? params[2] : "", - × = params.size() > 3 ? params[3] : ""; - - if (!ttb.empty()) - { - int16_t i; - - try - { - i = convertTo<int16_t>(ttb); - if (i < 0) - throw ConvertException(); - } - catch (const ConvertException &) - { - source.Reply(_("\002%s\002 cannot be taken as times to ban."), ttb.c_str()); - return; - } - - kd->ttb[TTB_REPEAT] = i; - } - else - kd->ttb[TTB_REPEAT] = 0; - - kd->repeattimes = 3; - try - { - kd->repeattimes = convertTo<int16_t>(times); - } - catch (const ConvertException &) { } - if (kd->repeattimes < 1) - kd->repeattimes = 3; - - kd->repeat = true; - if (kd->ttb[TTB_REPEAT]) - { - if (kd->repeattimes != 1) - source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n" - "same message %d times), and will place a ban after %d\n" - "kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]); - else - source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n" - "same message %d time), and will place a ban after %d\n" - "kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]); - } - else - { - if (kd->repeattimes != 1) - source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n" - "same message %d times)."), kd->repeattimes); - else - source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n" - "same message %d time)."), kd->repeattimes); - } - } - else if (params[1].equals_ci("OFF")) - { - kd->repeat = false; - source.Reply(_("Bot won't kick for \002repeats\002 anymore.")); - } - else - this->OnSyntaxError(source, params[1]); - - kd->Check(ci); - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the repeat kicker on or off. When enabled, this\n" - "option tells the bot to kick users who are repeating\n" - "themselves \002num\002 times (if num is not given, it\n" - "defaults to 3).\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSKickReverses : public CommandBSKickBase -{ - public: - CommandBSKickReverses(Module *creator) : CommandBSKickBase(creator, "botserv/kick/reverses", 2, 3) - { - this->SetDesc(_("Configures reverses kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (CheckArguments(source, params, ci)) - { - KickerData *kd = ci->Require<KickerData>("kickerdata"); - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_REVERSES, "reverses", kd, kd->reverses); - kd->Check(ci); - } - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the reverses kicker on or off. When enabled, this\n" - "option tells the bot to kick users who use reverses.\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSKickUnderlines : public CommandBSKickBase -{ - public: - CommandBSKickUnderlines(Module *creator) : CommandBSKickBase(creator, "botserv/kick/underlines", 2, 3) - { - this->SetDesc(_("Configures underlines kicker")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037} [\037ttb\037]")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci; - if (CheckArguments(source, params, ci)) - { - KickerData *kd = ci->Require<KickerData>("kickerdata"); - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_UNDERLINES, "underlines", kd, kd->underlines); - kd->Check(ci); - } - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Sets the underlines kicker on or off. When enabled, this\n" - "option tells the bot to kick users who use underlines.\n" - " \n" - "\037ttb\037 is the number of times a user can be kicked\n" - "before it gets banned. Don't give ttb to disable\n" - "the ban system once activated.")); - return true; - } -}; - -class CommandBSSetDontKickOps : public Command -{ - public: - CommandBSSetDontKickOps(Module *creator, const Anope::string &sname = "botserv/set/dontkickops") : Command(creator, sname, 2, 2) - { - this->SetDesc(_("To protect ops against bot kicks")); - this->SetSyntax(_("\037channel\037 {ON | OFF}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - AccessGroup access = source.AccessFor(ci); - if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot option setting is temporarily disabled.")); - return; - } - - KickerData *kd = ci->Require<KickerData>("kickerdata"); - if (params[1].equals_ci("ON")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickops"; - - kd->dontkickops = true; - source.Reply(_("Bot \002won't kick ops\002 on channel %s."), ci->name.c_str()); - } - else if (params[1].equals_ci("OFF")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickops"; - - kd->dontkickops = false; - source.Reply(_("Bot \002will kick ops\002 on channel %s."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, source.command); - - kd->Check(ci); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(_(" \n" - "Enables or disables \002ops protection\002 mode on a channel.\n" - "When it is enabled, ops won't be kicked by the bot\n" - "even if they don't match the NOKICK level.")); - return true; - } -}; - -class CommandBSSetDontKickVoices : public Command -{ - public: - CommandBSSetDontKickVoices(Module *creator, const Anope::string &sname = "botserv/set/dontkickvoices") : Command(creator, sname, 2, 2) - { - this->SetDesc(_("To protect voices against bot kicks")); - this->SetSyntax(_("\037channel\037 {ON | OFF}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - AccessGroup access = source.AccessFor(ci); - if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot option setting is temporarily disabled.")); - return; - } - - KickerData *kd = ci->Require<KickerData>("kickerdata"); - if (params[1].equals_ci("ON")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickvoices"; - - kd->dontkickvoices = true; - source.Reply(_("Bot \002won't kick voices\002 on channel %s."), ci->name.c_str()); - } - else if (params[1].equals_ci("OFF")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickvoices"; - - kd->dontkickvoices = false; - source.Reply(_("Bot \002will kick voices\002 on channel %s."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, source.command); - - kd->Check(ci); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(_(" \n" - "Enables or disables \002voices protection\002 mode on a channel.\n" - "When it is enabled, voices won't be kicked by the bot\n" - "even if they don't match the NOKICK level.")); - return true; - } -}; - -struct BanData -{ - struct Data - { - Anope::string mask; - time_t last_use; - int16_t ttb[TTB_SIZE]; - - Data() - { - last_use = 0; - for (int i = 0; i < TTB_SIZE; ++i) - this->ttb[i] = 0; - } - }; - - private: - typedef Anope::map<Data> data_type; - data_type data_map; - - public: - BanData(Extensible *) { } - - Data &get(const Anope::string &key) - { - return this->data_map[key]; - } - - bool empty() const - { - return this->data_map.empty(); - } - - void purge() - { - time_t keepdata = Config->GetModule(me)->Get<time_t>("keepdata"); - for (data_type::iterator it = data_map.begin(), it_end = data_map.end(); it != it_end;) - { - const Anope::string &user = it->first; - Data &bd = it->second; - ++it; - - if (Anope::CurTime - bd.last_use > keepdata) - data_map.erase(user); - } - } -}; - -struct UserData -{ - UserData(Extensible *) - { - last_use = last_start = Anope::CurTime; - lines = times = 0; - lastline.clear(); - } - - /* Data validity */ - time_t last_use; - - /* for flood kicker */ - int16_t lines; - time_t last_start; - - /* for repeat kicker */ - Anope::string lasttarget; - int16_t times; - - Anope::string lastline; -}; - -class BanDataPurger : public Timer -{ - public: - BanDataPurger(Module *o) : Timer(o, 300, Anope::CurTime, true) { } - - void Tick(time_t) anope_override - { - Log(LOG_DEBUG) << "bs_main: Running bandata purger"; - - for (channel_map::iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it) - { - Channel *c = it->second; - - BanData *bd = c->GetExt<BanData>("bandata"); - if (bd != NULL) - { - bd->purge(); - if (bd->empty()) - c->Shrink<BanData>("bandata"); - } - } - } -}; - -class BSKick : public Module -{ - ExtensibleItem<BanData> bandata; - ExtensibleItem<UserData> userdata; - KickerDataImpl::ExtensibleItem kickerdata; - - CommandBSKick commandbskick; - CommandBSKickAMSG commandbskickamsg; - CommandBSKickBadwords commandbskickbadwords; - CommandBSKickBolds commandbskickbolds; - CommandBSKickCaps commandbskickcaps; - CommandBSKickColors commandbskickcolors; - CommandBSKickFlood commandbskickflood; - CommandBSKickItalics commandbskickitalics; - CommandBSKickRepeat commandbskickrepeat; - CommandBSKickReverses commandbskickreverse; - CommandBSKickUnderlines commandbskickunderlines; - - CommandBSSetDontKickOps commandbssetdontkickops; - CommandBSSetDontKickVoices commandbssetdontkickvoices; - - BanDataPurger purger; - - BanData::Data &GetBanData(User *u, Channel *c) - { - BanData *bd = bandata.Require(c); - return bd->get(u->GetMask()); - } - - UserData *GetUserData(User *u, Channel *c) - { - ChanUserContainer *uc = c->FindUser(u); - if (uc == NULL) - return NULL; - - UserData *ud = userdata.Require(uc); - return ud; - } - - void check_ban(ChannelInfo *ci, User *u, KickerData *kd, int ttbtype) - { - /* Don't ban ulines or protected users */ - if (u->IsProtected()) - return; - - BanData::Data &bd = this->GetBanData(u, ci->c); - - ++bd.ttb[ttbtype]; - if (kd->ttb[ttbtype] && bd.ttb[ttbtype] >= kd->ttb[ttbtype]) - { - /* Should not use == here because bd.ttb[ttbtype] could possibly be > kd->ttb[ttbtype] - * if the TTB was changed after it was not set (0) before and the user had already been - * kicked a few times. Bug #1056 - Adam */ - - bd.ttb[ttbtype] = 0; - - Anope::string mask = ci->GetIdealBan(u); - - ci->c->SetMode(NULL, "BAN", mask); - FOREACH_MOD(OnBotBan, (u, ci, mask)); - } - } - - void bot_kick(ChannelInfo *ci, User *u, const char *message, ...) - { - va_list args; - char buf[1024]; - - if (!ci || !ci->bi || !ci->c || !u || u->IsProtected() || !ci->c->FindUser(u)) - return; - - Anope::string fmt = Language::Translate(u, message); - va_start(args, message); - vsnprintf(buf, sizeof(buf), fmt.c_str(), args); - va_end(args); - - ci->c->Kick(ci->bi, u, "%s", buf); - } - - public: - BSKick(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - bandata(this, "bandata"), - userdata(this, "userdata"), - kickerdata(this, "kickerdata"), - - commandbskick(this), - commandbskickamsg(this), commandbskickbadwords(this), commandbskickbolds(this), commandbskickcaps(this), - commandbskickcolors(this), commandbskickflood(this), commandbskickitalics(this), commandbskickrepeat(this), - commandbskickreverse(this), commandbskickunderlines(this), - - commandbssetdontkickops(this), commandbssetdontkickvoices(this), - - purger(this) - { - me = this; - - } - - void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override - { - if (!ci) - return; - - Anope::string enabled = Language::Translate(source.nc, _("Enabled")); - Anope::string disabled = Language::Translate(source.nc, _("Disabled")); - KickerData *kd = kickerdata.Get(ci); - - if (kd && kd->badwords) - { - if (kd->ttb[TTB_BADWORDS]) - info[_("Bad words kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BADWORDS]); - else - info[_("Bad words kicker")] = enabled; - } - else - info[_("Bad words kicker")] = disabled; - - if (kd && kd->bolds) - { - if (kd->ttb[TTB_BOLDS]) - info[_("Bolds kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BOLDS]); - else - info[_("Bolds kicker")] = enabled; - } - else - info[_("Bolds kicker")] = disabled; - - if (kd && kd->caps) - { - if (kd->ttb[TTB_CAPS]) - info[_("Caps kicker")] = Anope::printf(_("%s (%d kick(s) to ban; minimum %d/%d%%)"), enabled.c_str(), kd->ttb[TTB_CAPS], kd->capsmin, kd->capspercent); - else - info[_("Caps kicker")] = Anope::printf(_("%s (minimum %d/%d%%)"), enabled.c_str(), kd->capsmin, kd->capspercent); - } - else - info[_("Caps kicker")] = disabled; - - if (kd && kd->colors) - { - if (kd->ttb[TTB_COLORS]) - info[_("Colors kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_COLORS]); - else - info[_("Colors kicker")] = enabled; - } - else - info[_("Colors kicker")] = disabled; - - if (kd && kd->flood) - { - if (kd->ttb[TTB_FLOOD]) - info[_("Flood kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d lines in %ds)"), enabled.c_str(), kd->ttb[TTB_FLOOD], kd->floodlines, kd->floodsecs); - else - info[_("Flood kicker")] = Anope::printf(_("%s (%d lines in %ds)"), enabled.c_str(), kd->floodlines, kd->floodsecs); - } - else - info[_("Flood kicker")] = disabled; - - if (kd && kd->repeat) - { - if (kd->ttb[TTB_REPEAT]) - info[_("Repeat kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), kd->ttb[TTB_REPEAT], kd->repeattimes); - else - info[_("Repeat kicker")] = Anope::printf(_("%s (%d times)"), enabled.c_str(), kd->repeattimes); - } - else - info[_("Repeat kicker")] = disabled; - - if (kd && kd->reverses) - { - if (kd->ttb[TTB_REVERSES]) - info[_("Reverses kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_REVERSES]); - else - info[_("Reverses kicker")] = enabled; - } - else - info[_("Reverses kicker")] = disabled; - - if (kd && kd->underlines) - { - if (kd->ttb[TTB_UNDERLINES]) - info[_("Underlines kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_UNDERLINES]); - else - info[_("Underlines kicker")] = enabled; - } - else - info[_("Underlines kicker")] = disabled; - - if (kd && kd->italics) - { - if (kd->ttb[TTB_ITALICS]) - info[_("Italics kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_ITALICS]); - else - info[_("Italics kicker")] = enabled; - } - else - info[_("Italics kicker")] = disabled; - - if (kd && kd->amsgs) - { - if (kd->ttb[TTB_AMSGS]) - info[_("AMSG kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_AMSGS]); - else - info[_("AMSG kicker")] = enabled; - } - else - info[_("AMSG kicker")] = disabled; - - if (kd && kd->dontkickops) - info.AddOption(_("Ops protection")); - if (kd && kd->dontkickvoices) - info.AddOption(_("Voices protection")); - } - - void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override - { - /* Now we can make kicker stuff. We try to order the checks - * from the fastest one to the slowest one, since there's - * no need to process other kickers if a user is kicked before - * the last kicker check. - * - * But FIRST we check whether the user is protected in any - * way. - */ - ChannelInfo *ci = c->ci; - if (ci == NULL) - return; - KickerData *kd = kickerdata.Get(ci); - if (kd == NULL) - return; - - if (ci->AccessFor(u).HasPriv("NOKICK")) - return; - else if (kd->dontkickops && (c->HasUserStatus(u, "HALFOP") || c->HasUserStatus(u, "OP") || c->HasUserStatus(u, "PROTECT") || c->HasUserStatus(u, "OWNER"))) - return; - else if (kd->dontkickvoices && c->HasUserStatus(u, "VOICE")) - return; - - Anope::string realbuf = msg; - - /* If it's a /me, cut the CTCP part because the ACTION will cause - * problems with the caps or badwords kicker - */ - if (realbuf.substr(0, 8).equals_ci("\1ACTION ") && realbuf[realbuf.length() - 1] == '\1') - { - realbuf.erase(0, 8); - realbuf.erase(realbuf.length() - 1); - } - - if (realbuf.empty()) - return; - - /* Bolds kicker */ - if (kd->bolds && realbuf.find(2) != Anope::string::npos) - { - check_ban(ci, u, kd, TTB_BOLDS); - bot_kick(ci, u, _("Don't use bolds on this channel!")); - return; - } - - /* Color kicker */ - if (kd->colors && realbuf.find(3) != Anope::string::npos) - { - check_ban(ci, u, kd, TTB_COLORS); - bot_kick(ci, u, _("Don't use colors on this channel!")); - return; - } - - /* Reverses kicker */ - if (kd->reverses && realbuf.find(22) != Anope::string::npos) - { - check_ban(ci, u, kd, TTB_REVERSES); - bot_kick(ci, u, _("Don't use reverses on this channel!")); - return; - } - - /* Italics kicker */ - if (kd->italics && realbuf.find(29) != Anope::string::npos) - { - check_ban(ci, u, kd, TTB_ITALICS); - bot_kick(ci, u, _("Don't use italics on this channel!")); - return; - } - - /* Underlines kicker */ - if (kd->underlines && realbuf.find(31) != Anope::string::npos) - { - check_ban(ci, u, kd, TTB_UNDERLINES); - bot_kick(ci, u, _("Don't use underlines on this channel!")); - return; - } - - /* Caps kicker */ - if (kd->caps && realbuf.length() >= static_cast<unsigned>(kd->capsmin)) - { - int i = 0, l = 0; - - for (unsigned j = 0, end = realbuf.length(); j < end; ++j) - { - if (isupper(realbuf[j])) - ++i; - else if (islower(realbuf[j])) - ++l; - } - - /* i counts uppercase chars, l counts lowercase chars. Only - * alphabetic chars (so islower || isupper) qualify for the - * percentage of caps to kick for; the rest is ignored. -GD - */ - - if ((i || l) && i >= kd->capsmin && i * 100 / (i + l) >= kd->capspercent) - { - check_ban(ci, u, kd, TTB_CAPS); - bot_kick(ci, u, _("Turn caps lock OFF!")); - return; - } - } - - /* Bad words kicker */ - if (kd->badwords) - { - bool mustkick = false; - BadWords *badwords = ci->GetExt<BadWords>("badwords"); - - /* Normalize the buffer */ - Anope::string nbuf = Anope::NormalizeBuffer(realbuf); - bool casesensitive = Config->GetModule("botserv")->Get<bool>("casesensitive"); - - /* Normalize can return an empty string if this only conains control codes etc */ - if (badwords && !nbuf.empty()) - for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i) - { - const BadWord *bw = badwords->GetBadWord(i); - - if (bw->word.empty()) - continue; // Shouldn't happen - - if (bw->word.length() > nbuf.length()) - continue; // This can't ever match - - if (bw->type == BW_ANY && ((casesensitive && nbuf.find(bw->word) != Anope::string::npos) || (!casesensitive && nbuf.find_ci(bw->word) != Anope::string::npos))) - mustkick = true; - else if (bw->type == BW_SINGLE) - { - size_t len = bw->word.length(); - - if ((casesensitive && bw->word.equals_cs(nbuf)) || (!casesensitive && bw->word.equals_ci(nbuf))) - mustkick = true; - else if (nbuf.find(' ') == len && ((casesensitive && bw->word.equals_cs(nbuf.substr(0, len))) || (!casesensitive && bw->word.equals_ci(nbuf.substr(0, len))))) - mustkick = true; - else - { - if (len < nbuf.length() && nbuf.rfind(' ') == nbuf.length() - len - 1 && ((casesensitive && nbuf.find(bw->word) == nbuf.length() - len) || (!casesensitive && nbuf.find_ci(bw->word) == nbuf.length() - len))) - mustkick = true; - else - { - Anope::string wordbuf = " " + bw->word + " "; - - if ((casesensitive && nbuf.find(wordbuf) != Anope::string::npos) || (!casesensitive && nbuf.find_ci(wordbuf) != Anope::string::npos)) - mustkick = true; - } - } - } - else if (bw->type == BW_START) - { - size_t len = bw->word.length(); - - if ((casesensitive && nbuf.substr(0, len).equals_cs(bw->word)) || (!casesensitive && nbuf.substr(0, len).equals_ci(bw->word))) - mustkick = true; - else - { - Anope::string wordbuf = " " + bw->word; - - if ((casesensitive && nbuf.find(wordbuf) != Anope::string::npos) || (!casesensitive && nbuf.find_ci(wordbuf) != Anope::string::npos)) - mustkick = true; - } - } - else if (bw->type == BW_END) - { - size_t len = bw->word.length(); - - if ((casesensitive && nbuf.substr(nbuf.length() - len).equals_cs(bw->word)) || (!casesensitive && nbuf.substr(nbuf.length() - len).equals_ci(bw->word))) - mustkick = true; - else - { - Anope::string wordbuf = bw->word + " "; - - if ((casesensitive && nbuf.find(wordbuf) != Anope::string::npos) || (!casesensitive && nbuf.find_ci(wordbuf) != Anope::string::npos)) - mustkick = true; - } - } - - if (mustkick) - { - check_ban(ci, u, kd, TTB_BADWORDS); - if (Config->GetModule(me)->Get<bool>("gentlebadwordreason")) - bot_kick(ci, u, _("Watch your language!")); - else - bot_kick(ci, u, _("Don't use the word \"%s\" on this channel!"), bw->word.c_str()); - - return; - } - } /* for */ - } /* if badwords */ - - UserData *ud = GetUserData(u, c); - - if (ud) - { - /* Flood kicker */ - if (kd->flood) - { - if (Anope::CurTime - ud->last_start > kd->floodsecs) - { - ud->last_start = Anope::CurTime; - ud->lines = 0; - } - - ++ud->lines; - if (ud->lines >= kd->floodlines) - { - check_ban(ci, u, kd, TTB_FLOOD); - bot_kick(ci, u, _("Stop flooding!")); - return; - } - } - - /* Repeat kicker */ - if (kd->repeat) - { - if (!ud->lastline.equals_ci(realbuf)) - ud->times = 0; - else - ++ud->times; - - if (ud->times >= kd->repeattimes) - { - check_ban(ci, u, kd, TTB_REPEAT); - bot_kick(ci, u, _("Stop repeating yourself!")); - return; - } - } - - if (ud->lastline.equals_ci(realbuf) && !ud->lasttarget.empty() && !ud->lasttarget.equals_ci(ci->name)) - { - for (User::ChanUserList::iterator it = u->chans.begin(); it != u->chans.end();) - { - Channel *chan = it->second->chan; - ++it; - - if (chan->ci && kd->amsgs && !chan->ci->AccessFor(u).HasPriv("NOKICK")) - { - check_ban(chan->ci, u, kd, TTB_AMSGS); - bot_kick(chan->ci, u, _("Don't use AMSGs!")); - } - } - } - - ud->lasttarget = ci->name; - ud->lastline = realbuf; - } - } -}; - -MODULE_INIT(BSKick) |