]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_filter.cpp
Improve support for wildcards in <link:name>.
[user/henk/code/inspircd.git] / src / modules / m_filter.cpp
index 2d0657c997c1ecc820d01d50eaae60e8a74fdfbc..849f9908617404f978107e413811f423cf28d855 100644 (file)
@@ -38,6 +38,8 @@ enum FilterFlags
 enum FilterAction
 {
        FA_GLINE,
+       FA_ZLINE,
+       FA_WARN,
        FA_BLOCK,
        FA_SILENT,
        FA_KILL,
@@ -52,7 +54,8 @@ class FilterResult
        std::string freeform;
        std::string reason;
        FilterAction action;
-       long duration;
+       unsigned long duration;
+       bool from_config;
 
        bool flag_no_opers;
        bool flag_part_message;
@@ -61,11 +64,12 @@ class FilterResult
        bool flag_notice;
        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)
+       FilterResult(dynamic_reference<RegexFactory>& RegexEngine, const std::string& free, const std::string& rea, FilterAction act, unsigned long gt, const std::string& fla, bool cfg)
                : freeform(free)
                , reason(rea)
                , action(act)
                , duration(gt)
+               , from_config(cfg)
        {
                if (!RegexEngine)
                        throw ModuleException("Regex module implementing '"+RegexEngine.GetProvider()+"' is not loaded!");
@@ -189,7 +193,7 @@ class ModuleFilter : public Module, public ServerEventListener, public Stats::Ev
        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);
+       std::pair<bool, std::string> AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flags);
        void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE;
        Version GetVersion() CXX11_OVERRIDE;
        std::string EncodeFilter(FilterResult* filter);
@@ -232,27 +236,31 @@ CmdResult CommandFilter::Handle(User* user, const Params& parameters)
                        FilterAction type;
                        const std::string& flags = parameters[2];
                        unsigned int reasonindex;
-                       long duration = 0;
+                       unsigned long duration = 0;
 
                        if (!ModuleFilter::StringToFilterAction(parameters[1], type))
                        {
                                if (ServerInstance->XLines->GetFactory("SHUN"))
-                                       user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'none', 'block', 'silent', 'kill', and 'shun'.");
+                                       user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'zline', 'none', 'warn', 'block', 'silent', 'kill', and 'shun'.");
                                else
-                                       user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'none', 'block', 'silent', and 'kill'.");
+                                       user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'zline', 'none', 'warn', 'block', 'silent', and 'kill'.");
                                return CMD_FAILURE;
                        }
 
-                       if (type == FA_GLINE || type == FA_SHUN)
+                       if (type == FA_GLINE || type == FA_ZLINE || type == FA_SHUN)
                        {
                                if (parameters.size() >= 5)
                                {
-                                       duration = InspIRCd::Duration(parameters[3]);
+                                       if (!InspIRCd::Duration(parameters[3], duration))
+                                       {
+                                               user->WriteNotice("*** Invalid duration for filter");
+                                               return CMD_FAILURE;
+                                       }
                                        reasonindex = 4;
                                }
                                else
                                {
-                                       user->WriteNotice("*** Not enough parameters: When setting a gline or shun type filter, a duration must be specified as the third parameter.");
+                                       user->WriteNotice("*** Not enough parameters: When setting a '" + parameters[1] + "' type filter, a duration must be specified as the third parameter.");
                                        return CMD_FAILURE;
                                }
                        }
@@ -360,6 +368,12 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar
 
                        target = t->name;
                }
+               if (f->action == FA_WARN)
+               {
+                       ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("WARNING: %s's message to %s matched %s (%s)",
+                               user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str()));
+                       return MOD_RES_PASSTHRU;
+               }
                if (f->action == FA_BLOCK)
                {
                        ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s had their message to %s filtered as it matched %s (%s)",
@@ -407,7 +421,7 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar
                else if (f->action == FA_GLINE)
                {
                        GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
-                       ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s was glined because their message to %s matched %s (%s)",
+                       ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s was G-lined because their message to %s matched %s (%s)",
                                user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str()));
                        if (ServerInstance->XLines->AddLine(gl,NULL))
                        {
@@ -416,6 +430,18 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar
                        else
                                delete gl;
                }
+               else if (f->action == FA_ZLINE)
+               {
+                       ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
+                       ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s was Z-lined because their message to %s matched %s (%s)",
+                               user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str()));
+                       if (ServerInstance->XLines->AddLine(zl,NULL))
+                       {
+                               ServerInstance->XLines->ApplyLines();
+                       }
+                       else
+                               delete zl;
+               }
 
                ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + ModuleFilter::FilterActionToString(f->action));
                return MOD_RES_DENY;
@@ -463,10 +489,10 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
                /* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */
                parameters[parting ? 1 : 0] = "Reason filtered";
 
-               /* We're blocking, OR theyre quitting and its a KILL action
+               /* We're warning or blocking, OR theyre quitting and its a KILL action
                 * (we cant kill someone whos already quitting, so filter them anyway)
                 */
-               if ((f->action == FA_BLOCK) || (((!parting) && (f->action == FA_KILL))) || (f->action == FA_SILENT))
+               if ((f->action == FA_WARN) || (f->action == FA_BLOCK) || (((!parting) && (f->action == FA_KILL))) || (f->action == FA_SILENT))
                {
                        return MOD_RES_PASSTHRU;
                }
@@ -480,9 +506,9 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
                        }
                        if (f->action == FA_GLINE)
                        {
-                               /* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */
+                               /* Note: We G-line *@IP so that if their host doesn't resolve the G-line still applies. */
                                GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
-                               ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s was glined because their %s message matched %s (%s)",
+                               ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s was G-lined because their %s message matched %s (%s)",
                                        user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str()));
 
                                if (ServerInstance->XLines->AddLine(gl,NULL))
@@ -492,6 +518,19 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
                                else
                                        delete gl;
                        }
+                       if (f->action == FA_ZLINE)
+                       {
+                               ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
+                               ServerInstance->SNO->WriteGlobalSno('f', InspIRCd::Format("%s was Z-lined because their %s message matched %s (%s)",
+                                       user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str()));
+
+                               if (ServerInstance->XLines->AddLine(zl,NULL))
+                               {
+                                       ServerInstance->XLines->ApplyLines();
+                               }
+                               else
+                                       delete zl;
+                       }
                        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. */
@@ -602,7 +641,7 @@ FilterResult ModuleFilter::DecodeFilter(const std::string &data)
 
        std::string duration;
        tokens.GetMiddle(duration);
-       res.duration = ConvToInt(duration);
+       res.duration = ConvToNum<unsigned long>(duration);
 
        tokens.GetTrailing(res.reason);
 
@@ -618,7 +657,11 @@ void ModuleFilter::OnSyncNetwork(ProtocolInterface::Server& server)
 {
        for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); ++i)
        {
-               server.SendMetaData("filter", EncodeFilter(&(*i)));
+               FilterResult& filter = *i;
+               if (filter.from_config)
+                       continue;
+
+               server.SendMetaData("filter", EncodeFilter(&filter));
        }
 }
 
@@ -677,7 +720,7 @@ bool ModuleFilter::DeleteFilter(const std::string &freeform)
        return false;
 }
 
-std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string &freeform, FilterAction type, const std::string &reason, long duration, const std::string &flgs)
+std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flgs)
 {
        for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++)
        {
@@ -689,7 +732,7 @@ std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string &freeform
 
        try
        {
-               filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs));
+               filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs, false));
        }
        catch (ModuleException &e)
        {
@@ -703,6 +746,10 @@ bool ModuleFilter::StringToFilterAction(const std::string& str, FilterAction& fa
 {
        if (stdalgo::string::equalsci(str, "gline"))
                fa = FA_GLINE;
+       else if (stdalgo::string::equalsci(str, "zline"))
+               fa = FA_ZLINE;
+       else if (stdalgo::string::equalsci(str, "warn"))
+               fa = FA_WARN;
        else if (stdalgo::string::equalsci(str, "block"))
                fa = FA_BLOCK;
        else if (stdalgo::string::equalsci(str, "silent"))
@@ -724,6 +771,8 @@ std::string ModuleFilter::FilterActionToString(FilterAction fa)
        switch (fa)
        {
                case FA_GLINE:  return "gline";
+               case FA_ZLINE:  return "zline";
+               case FA_WARN:   return "warn";
                case FA_BLOCK:  return "block";
                case FA_SILENT: return "silent";
                case FA_KILL:   return "kill";
@@ -734,12 +783,24 @@ std::string ModuleFilter::FilterActionToString(FilterAction fa)
 
 void ModuleFilter::ReadFilters()
 {
+       for (std::vector<FilterResult>::iterator filter = filters.begin(); filter != filters.end(); )
+       {
+               if (filter->from_config)
+               {
+                       ServerInstance->SNO->WriteGlobalSno('f', "FILTER: removing filter '" + filter->freeform + "' due to config rehash.");
+                       delete filter->regex;
+                       filter = filters.erase(filter);
+                       continue;
+               }
+
+               // The filter is not from the config.
+               filter++;
+       }
+
        ConfigTagList tags = ServerInstance->Config->ConfTags("keyword");
        for (ConfigIter i = tags.first; i != tags.second; ++i)
        {
                std::string pattern = i->second->getString("pattern");
-               this->DeleteFilter(pattern);
-
                std::string reason = i->second->getString("reason");
                std::string action = i->second->getString("action");
                std::string flgs = i->second->getString("flags");
@@ -753,7 +814,7 @@ void ModuleFilter::ReadFilters()
 
                try
                {
-                       filters.push_back(FilterResult(RegexEngine, pattern, reason, fa, duration, flgs));
+                       filters.push_back(FilterResult(RegexEngine, pattern, reason, fa, duration, flgs, true));
                        ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Regular expression %s loaded.", pattern.c_str());
                }
                catch (ModuleException &e)