]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_filter.cpp
Use CommandBase::Params instead of std::vector<std::string>.
[user/henk/code/inspircd.git] / src / modules / m_filter.cpp
index bd1022a0824a291340dd53cb36820c62095d589c..343a62a8d0c2f8167131f4f1a4a37dcd393ef5dc 100644 (file)
@@ -23,6 +23,9 @@
 #include "inspircd.h"
 #include "xline.h"
 #include "modules/regex.h"
+#include "modules/server.h"
+#include "modules/shun.h"
+#include "modules/stats.h"
 
 enum FilterFlags
 {
@@ -38,6 +41,7 @@ enum FilterAction
        FA_BLOCK,
        FA_SILENT,
        FA_KILL,
+       FA_SHUN,
        FA_NONE
 };
 
@@ -48,7 +52,7 @@ class FilterResult
        std::string freeform;
        std::string reason;
        FilterAction action;
-       long gline_time;
+       long duration;
 
        bool flag_no_opers;
        bool flag_part_message;
@@ -58,7 +62,10 @@ class FilterResult
        bool flag_strip_color;
 
        FilterResult(dynamic_reference<RegexFactory>& RegexEngine, const std::string& free, const std::string& rea, FilterAction act, long gt, const std::string& fla)
-               : freeform(free), reason(rea), action(act), gline_time(gt)
+               : freeform(free)
+               , reason(rea)
+               , action(act)
+               , duration(gt)
        {
                if (!RegexEngine)
                        throw ModuleException("Regex module implementing '"+RegexEngine.GetProvider()+"' is not loaded!");
@@ -144,21 +151,22 @@ class CommandFilter : public Command
                : Command(f, "FILTER", 1, 5)
        {
                flags_needed = 'o';
-               this->syntax = "<filter-definition> <action> <flags> [<gline-duration>] :<reason>";
+               this->syntax = "<filter-definition> <action> <flags> [<duration>] :<reason>";
        }
-       CmdResult Handle(const std::vector<std::string>&, User*);
+       CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
 
-       RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
+       RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE
        {
                return ROUTE_BROADCAST;
        }
 };
 
-class ModuleFilter : public Module
+class ModuleFilter : public Module, public ServerEventListener, public Stats::EventListener
 {
        typedef insp::flat_set<std::string, irc::insensitive_swo> ExemptTargetSet;
 
        bool initing;
+       bool notifyuser;
        RegexFactory* factory;
        void FreeFilters();
 
@@ -176,8 +184,8 @@ class ModuleFilter : public Module
        ExemptTargetSet exemptednicks;
 
        ModuleFilter();
-       CullResult cull();
-       ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE;
+       CullResult cull() CXX11_OVERRIDE;
+       ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE;
        FilterResult* FilterMatch(User* user, const std::string &text, int flags);
        bool DeleteFilter(const std::string &freeform);
        std::pair<bool, std::string> AddFilter(const std::string &freeform, FilterAction type, const std::string &reason, long duration, const std::string &flags);
@@ -187,8 +195,8 @@ class ModuleFilter : public Module
        FilterResult DecodeFilter(const std::string &data);
        void OnSyncNetwork(ProtocolInterface::Server& server) CXX11_OVERRIDE;
        void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata) CXX11_OVERRIDE;
-       ModResult OnStats(char symbol, User* user, string_list &results) CXX11_OVERRIDE;
-       ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE;
+       ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE;
+       ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated, const std::string& original_line) CXX11_OVERRIDE;
        void OnUnloadModule(Module* mod) CXX11_OVERRIDE;
        bool AppliesToMe(User* user, FilterResult* filter, int flags);
        void ReadFilters();
@@ -196,7 +204,7 @@ class ModuleFilter : public Module
        static std::string FilterActionToString(FilterAction fa);
 };
 
-CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User *user)
+CmdResult CommandFilter::Handle(User* user, const Params& parameters)
 {
        if (parameters.size() == 1)
        {
@@ -227,11 +235,14 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
 
                        if (!ModuleFilter::StringToFilterAction(parameters[1], type))
                        {
-                               user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.");
+                               if (ServerInstance->XLines->GetFactory("SHUN"))
+                                       user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'none', 'block', 'silent', 'kill', and 'shun'.");
+                               else
+                                       user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'none', 'block', 'silent', and 'kill'.");
                                return CMD_FAILURE;
                        }
 
-                       if (type == FA_GLINE)
+                       if (type == FA_GLINE || type == FA_SHUN)
                        {
                                if (parameters.size() >= 5)
                                {
@@ -240,7 +251,7 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> &parameters, User
                                }
                                else
                                {
-                                       user->WriteNotice("*** Not enough parameters: When setting a gline type filter, a gline duration must be specified as the third parameter.");
+                                       user->WriteNotice("*** Not enough parameters: When setting a gline or shun type filter, a duration must be specified as the third parameter.");
                                        return CMD_FAILURE;
                                }
                        }
@@ -292,7 +303,11 @@ bool ModuleFilter::AppliesToMe(User* user, FilterResult* filter, int iflags)
 }
 
 ModuleFilter::ModuleFilter()
-       : initing(true), filtcommand(this), RegexEngine(this, "regex")
+       : ServerEventListener(this)
+       , Stats::EventListener(this)
+       , initing(true)
+       , filtcommand(this)
+       , RegexEngine(this, "regex")
 {
 }
 
@@ -310,30 +325,30 @@ void ModuleFilter::FreeFilters()
        filters.clear();
 }
 
-ModResult ModuleFilter::OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype)
+ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtarget, MessageDetails& details)
 {
        // Leave remote users and servers alone
        if (!IS_LOCAL(user))
                return MOD_RES_PASSTHRU;
 
-       flags = (msgtype == MSG_PRIVMSG) ? FLAG_PRIVMSG : FLAG_NOTICE;
+       flags = (details.type == MSG_PRIVMSG) ? FLAG_PRIVMSG : FLAG_NOTICE;
 
-       FilterResult* f = this->FilterMatch(user, text, flags);
+       FilterResult* f = this->FilterMatch(user, details.text, flags);
        if (f)
        {
                std::string target;
-               if (target_type == TYPE_USER)
+               if (msgtarget.type == MessageTarget::TYPE_USER)
                {
-                       User* t = (User*)dest;
+                       User* t = msgtarget.Get<User>();
                        // Check if the target nick is exempted, if yes, ignore this message
                        if (exemptednicks.count(t->nick))
                                return MOD_RES_PASSTHRU;
 
                        target = t->nick;
                }
-               else if (target_type == TYPE_CHANNEL)
+               else if (msgtarget.type == MessageTarget::TYPE_CHANNEL)
                {
-                       Channel* t = (Channel*)dest;
+                       Channel* t = msgtarget.Get<Channel>();
                        if (exemptedchans.count(t->name))
                                return MOD_RES_PASSTHRU;
 
@@ -342,25 +357,48 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, void* dest, int target_type
                if (f->action == FA_BLOCK)
                {
                        ServerInstance->SNO->WriteGlobalSno('a', "FILTER: "+user->nick+" had their message filtered, target was "+target+": "+f->reason);
-                       if (target_type == TYPE_CHANNEL)
-                               user->WriteNumeric(ERR_CANNOTSENDTOCHAN, target, InspIRCd::Format("Message to channel blocked and opers notified (%s)", f->reason.c_str()));
+                       if (notifyuser)
+                       {
+                               if (msgtarget.type == MessageTarget::TYPE_CHANNEL)
+                                       user->WriteNumeric(ERR_CANNOTSENDTOCHAN, target, InspIRCd::Format("Message to channel blocked and opers notified (%s)", f->reason.c_str()));
+                               else
+                                       user->WriteNotice("Your message to "+target+" was blocked and opers notified: "+f->reason);
+                       }
                        else
-                               user->WriteNotice("Your message to "+target+" was blocked and opers notified: "+f->reason);
+                               details.echooriginal = true;
                }
                else if (f->action == FA_SILENT)
                {
-                       if (target_type == TYPE_CHANNEL)
-                               user->WriteNumeric(ERR_CANNOTSENDTOCHAN, target, InspIRCd::Format("Message to channel blocked (%s)", f->reason.c_str()));
+                       if (notifyuser)
+                       {
+                               if (msgtarget.type == MessageTarget::TYPE_CHANNEL)
+                                       user->WriteNumeric(ERR_CANNOTSENDTOCHAN, target, InspIRCd::Format("Message to channel blocked (%s)", f->reason.c_str()));
+                               else
+                                       user->WriteNotice("Your message to "+target+" was blocked: "+f->reason);
+                       }
                        else
-                               user->WriteNotice("Your message to "+target+" was blocked: "+f->reason);
+                               details.echooriginal = true;
                }
                else if (f->action == FA_KILL)
                {
+                       ServerInstance->SNO->WriteGlobalSno('a', "FILTER: " + user->nick + " had their message filtered and was killed, target was " + target + ": " + f->reason);
                        ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason);
                }
+               else if (f->action == FA_SHUN && (ServerInstance->XLines->GetFactory("SHUN")))
+               {
+                       Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
+                       ServerInstance->SNO->WriteGlobalSno('a', "FILTER: " + user->nick + " had their message filtered and was shunned, target was " + target + ": " + f->reason);
+                       if (ServerInstance->XLines->AddLine(sh, NULL))
+                       {
+                               ServerInstance->XLines->ApplyLines();
+                       }
+                       else
+                               delete sh;
+               }
                else if (f->action == FA_GLINE)
                {
-                       GLine* gl = new GLine(ServerInstance->Time(), f->gline_time, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
+                       GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
+                       ServerInstance->SNO->WriteGlobalSno('a', "FILTER: " + user->nick + " had their message filtered and was G-Lined, target was " + target + ": " + f->reason);
                        if (ServerInstance->XLines->AddLine(gl,NULL))
                        {
                                ServerInstance->XLines->ApplyLines();
@@ -375,7 +413,7 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, void* dest, int target_type
        return MOD_RES_PASSTHRU;
 }
 
-ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
+ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated, const std::string& original_line)
 {
        if (validated)
        {
@@ -433,7 +471,8 @@ ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::stri
                        if (f->action == FA_GLINE)
                        {
                                /* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */
-                               GLine* gl = new GLine(ServerInstance->Time(), f->gline_time, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
+                               GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
+                               ServerInstance->SNO->WriteGlobalSno('a', "FILTER: " + user->nick + " had their " + command + " message filtered and was G-Lined: " + f->reason);
                                if (ServerInstance->XLines->AddLine(gl,NULL))
                                {
                                        ServerInstance->XLines->ApplyLines();
@@ -441,6 +480,18 @@ ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::stri
                                else
                                        delete gl;
                        }
+                       else if (f->action == FA_SHUN && (ServerInstance->XLines->GetFactory("SHUN")))
+                       {
+                               /* Note: We shun *!*@IP so that if their host doesnt resolve the shun still applies. */
+                               Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
+                               ServerInstance->SNO->WriteGlobalSno('a', "FILTER: " + user->nick + " had their " + command + " message filtered and was shunned: " + f->reason);
+                               if (ServerInstance->XLines->AddLine(sh, NULL))
+                               {
+                                       ServerInstance->XLines->ApplyLines();
+                               }
+                               else
+                                       delete sh;
+                       }
                        return MOD_RES_DENY;
                }
        }
@@ -468,7 +519,9 @@ void ModuleFilter::ReadConfig(ConfigStatus& status)
                }
        }
 
-       std::string newrxengine = ServerInstance->Config->ConfValue("filteropts")->getString("engine");
+       ConfigTag* tag = ServerInstance->Config->ConfValue("filteropts");
+       std::string newrxengine = tag->getString("engine");
+       notifyuser = tag->getBool("notifyuser", true);
 
        factory = RegexEngine ? (RegexEngine.operator->()) : NULL;
 
@@ -514,7 +567,7 @@ std::string ModuleFilter::EncodeFilter(FilterResult* filter)
                if (*n == ' ')
                        *n = '\7';
 
-       stream << x << " " << FilterActionToString(filter->action) << " " << filter->GetFlags() << " " << filter->gline_time << " :" << filter->reason;
+       stream << x << " " << FilterActionToString(filter->action) << " " << filter->GetFlags() << " " << filter->duration << " :" << filter->reason;
        return stream.str();
 }
 
@@ -534,7 +587,7 @@ FilterResult ModuleFilter::DecodeFilter(const std::string &data)
        if (c != 0)
                throw ModuleException("Invalid flag: '" + std::string(1, c) + "'");
 
-       tokens.GetToken(res.gline_time);
+       tokens.GetToken(res.duration);
        tokens.GetToken(res.reason);
 
        /* Hax to allow spaces in the freeform without changing the design of the irc protocol */
@@ -560,7 +613,7 @@ void ModuleFilter::OnDecodeMetaData(Extensible* target, const std::string &extna
                try
                {
                        FilterResult data = DecodeFilter(extdata);
-                       this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.GetFlags());
+                       this->AddFilter(data.freeform, data.action, data.reason, data.duration, data.GetFlags());
                }
                catch (ModuleException& e)
                {
@@ -632,17 +685,17 @@ std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string &freeform
 
 bool ModuleFilter::StringToFilterAction(const std::string& str, FilterAction& fa)
 {
-       irc::string s(str.c_str());
-
-       if (s == "gline")
+       if (stdalgo::string::equalsci(str, "gline"))
                fa = FA_GLINE;
-       else if (s == "block")
+       else if (stdalgo::string::equalsci(str, "block"))
                fa = FA_BLOCK;
-       else if (s == "silent")
+       else if (stdalgo::string::equalsci(str, "silent"))
                fa = FA_SILENT;
-       else if (s == "kill")
+       else if (stdalgo::string::equalsci(str, "kill"))
                fa = FA_KILL;
-       else if (s == "none")
+       else if (stdalgo::string::equalsci(str, "shun") && (ServerInstance->XLines->GetFactory("SHUN")))
+               fa = FA_SHUN;
+       else if (stdalgo::string::equalsci(str, "none"))
                fa = FA_NONE;
        else
                return false;
@@ -658,6 +711,7 @@ std::string ModuleFilter::FilterActionToString(FilterAction fa)
                case FA_BLOCK:  return "block";
                case FA_SILENT: return "silent";
                case FA_KILL:   return "kill";
+               case FA_SHUN:   return "shun";
                default:                return "none";
        }
 }
@@ -673,7 +727,7 @@ void ModuleFilter::ReadFilters()
                std::string reason = i->second->getString("reason");
                std::string action = i->second->getString("action");
                std::string flgs = i->second->getString("flags");
-               unsigned long gline_time = i->second->getDuration("duration", 10*60, 1);
+               unsigned long duration = i->second->getDuration("duration", 10*60, 1);
                if (flgs.empty())
                        flgs = "*";
 
@@ -683,7 +737,7 @@ void ModuleFilter::ReadFilters()
 
                try
                {
-                       filters.push_back(FilterResult(RegexEngine, pattern, reason, fa, gline_time, flgs));
+                       filters.push_back(FilterResult(RegexEngine, pattern, reason, fa, duration, flgs));
                        ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Regular expression %s loaded.", pattern.c_str());
                }
                catch (ModuleException &e)
@@ -693,21 +747,21 @@ void ModuleFilter::ReadFilters()
        }
 }
 
-ModResult ModuleFilter::OnStats(char symbol, User* user, string_list &results)
+ModResult ModuleFilter::OnStats(Stats::Context& stats)
 {
-       if (symbol == 's')
+       if (stats.GetSymbol() == 's')
        {
                for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++)
                {
-                       results.push_back("223 "+user->nick+" :"+RegexEngine.GetProvider()+":"+i->freeform+" "+i->GetFlags()+" "+FilterActionToString(i->action)+" "+ConvToStr(i->gline_time)+" :"+i->reason);
+                       stats.AddRow(223, RegexEngine.GetProvider()+":"+i->freeform+" "+i->GetFlags()+" "+FilterActionToString(i->action)+" "+ConvToStr(i->duration)+" :"+i->reason);
                }
                for (ExemptTargetSet::const_iterator i = exemptedchans.begin(); i != exemptedchans.end(); ++i)
                {
-                       results.push_back("223 "+user->nick+" :EXEMPT "+(*i));
+                       stats.AddRow(223, "EXEMPT "+(*i));
                }
                for (ExemptTargetSet::const_iterator i = exemptednicks.begin(); i != exemptednicks.end(); ++i)
                {
-                       results.push_back("223 "+user->nick+" :EXEMPT "+(*i));
+                       stats.AddRow(223, "EXEMPT "+(*i));
                }
        }
        return MOD_RES_PASSTHRU;