+ return MOD_RES_DENY;
+ }
+ }
+ return MOD_RES_PASSTHRU;
+}
+
+void ModuleFilter::OnRehash(User* user)
+{
+ ConfigTagList tags = ServerInstance->Config->ConfTags("exemptfromfilter");
+ exemptfromfilter.clear();
+ for (ConfigIter i = tags.first; i != tags.second; ++i)
+ {
+ std::string chan = i->second->getString("channel");
+ if (!chan.empty())
+ exemptfromfilter.insert(chan);
+ }
+
+ std::string newrxengine = ServerInstance->Config->ConfValue("filteropts")->getString("engine");
+
+ factory = RegexEngine ? (RegexEngine.operator->()) : NULL;
+
+ if (newrxengine.empty())
+ RegexEngine.SetProvider("regex");
+ else
+ RegexEngine.SetProvider("regex/" + newrxengine);
+
+ if (!RegexEngine)
+ {
+ if (newrxengine.empty())
+ ServerInstance->SNO->WriteGlobalSno('a', "WARNING: No regex engine loaded - Filter functionality disabled until this is corrected.");
+ else
+ ServerInstance->SNO->WriteGlobalSno('a', "WARNING: Regex engine '%s' is not loaded - Filter functionality disabled until this is corrected.", newrxengine.c_str());
+
+ initing = false;
+ FreeFilters();
+ return;
+ }
+
+ if ((!initing) && (RegexEngine.operator->() != factory))
+ {
+ ServerInstance->SNO->WriteGlobalSno('a', "Dumping all filters due to regex engine change");
+ FreeFilters();
+ }
+
+ initing = false;
+ ReadFilters();
+}
+
+Version ModuleFilter::GetVersion()
+{
+ return Version("Text (spam) filtering", VF_VENDOR | VF_COMMON, RegexEngine ? RegexEngine->name : "");
+}
+
+std::string ModuleFilter::EncodeFilter(FilterResult* filter)
+{
+ std::ostringstream stream;
+ std::string x = filter->freeform;
+
+ /* Hax to allow spaces in the freeform without changing the design of the irc protocol */
+ for (std::string::iterator n = x.begin(); n != x.end(); n++)
+ if (*n == ' ')
+ *n = '\7';
+
+ stream << x << " " << FilterActionToString(filter->action) << " " << filter->GetFlags() << " " << filter->gline_time << " :" << filter->reason;
+ return stream.str();
+}
+
+FilterResult ModuleFilter::DecodeFilter(const std::string &data)
+{
+ std::string filteraction;
+ FilterResult res;
+ irc::tokenstream tokens(data);
+ tokens.GetToken(res.freeform);
+ tokens.GetToken(filteraction);
+ if (!StringToFilterAction(filteraction, res.action))
+ throw ModuleException("Invalid action: " + filteraction);
+
+ std::string filterflags;
+ tokens.GetToken(filterflags);
+ char c = res.FillFlags(filterflags);
+ if (c != 0)
+ throw ModuleException("Invalid flag: '" + std::string(1, c) + "'");
+
+ tokens.GetToken(res.gline_time);
+ tokens.GetToken(res.reason);
+
+ /* Hax to allow spaces in the freeform without changing the design of the irc protocol */
+ for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++)
+ if (*n == '\7')
+ *n = ' ';
+
+ return res;
+}
+
+void ModuleFilter::OnSyncNetwork(Module* proto, void* opaque)
+{
+ for (std::vector<ImplFilter>::iterator i = filters.begin(); i != filters.end(); ++i)
+ {
+ proto->ProtoSendMetaData(opaque, NULL, "filter", EncodeFilter(&(*i)));
+ }
+}
+
+void ModuleFilter::OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata)
+{
+ if ((target == NULL) && (extname == "filter"))
+ {
+ try
+ {
+ FilterResult data = DecodeFilter(extdata);
+ this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.GetFlags());
+ }
+ catch (ModuleException& e)
+ {
+ ServerInstance->Logs->Log("m_filter", LOG_DEBUG, "Error when unserializing filter: " + std::string(e.GetReason()));