+ if (flags)
+ f = this->FilterMatch(user, checkline, flags);
+
+ if (!f)
+ /* PART or QUIT reason doesnt match a filter */
+ return 0;
+
+ /* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */
+ Command* c = ServerInstance->Parser->GetHandler(command);
+ if (c)
+ {
+ std::vector<std::string> params;
+ for (int item = 0; item < (int)parameters.size(); item++)
+ params.push_back(parameters[item]);
+ params[replacepoint] = "Reason filtered";
+
+ /* We're blocking, OR theyre quitting and its a KILL action
+ * (we cant kill someone whos already quitting, so filter them anyway)
+ */
+ if ((f->action == "block") || (((!parting) && (f->action == "kill"))) || (f->action == "silent"))
+ {
+ c->Handle(params, user);
+ return 1;
+ }
+ else
+ {
+ /* Are they parting, if so, kill is applicable */
+ if ((parting) && (f->action == "kill"))
+ {
+ user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick.c_str(), f->reason.c_str());
+ ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason);
+ }
+ if (f->action == "gline")
+ {
+ /* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */
+ GLine* gl = new GLine(ServerInstance, ServerInstance->Time(), f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), "*", user->GetIPString());
+ if (ServerInstance->XLines->AddLine(gl,NULL))
+ {
+ ServerInstance->XLines->ApplyLines();
+ }
+ else
+ delete gl;
+ }
+ return 1;
+ }
+ }
+ return 0;
+ }
+ return 0;
+}
+
+void FilterBase::OnRehash(User* user, const std::string ¶meter)
+{
+ ConfigReader* MyConf = new ConfigReader(ServerInstance);
+ std::vector<std::string>().swap(exemptfromfilter);
+ for (int index = 0; index < MyConf->Enumerate("exemptfromfilter"); ++index)
+ {
+ std::string chan = MyConf->ReadValue("exemptfromfilter", "channel", index);
+ if (!chan.empty()) {
+ exemptfromfilter.push_back(chan);
+ }
+ }
+ std::string newrxengine = MyConf->ReadValue("filteropts", "engine", 0);
+ if (!RegexEngine.empty())
+ {
+ if (RegexEngine == newrxengine)
+ return;
+
+ ServerInstance->SNO->WriteToSnoMask('A', "Dumping all filters due to regex engine change (was '%s', now '%s')", RegexEngine.c_str(), newrxengine.c_str());
+ //ServerInstance->XLines->DelAll("R");
+ }
+ rxengine = NULL;
+
+ RegexEngine = newrxengine;
+ modulelist* ml = ServerInstance->Modules->FindInterface("RegularExpression");
+ if (ml)
+ {
+ for (modulelist::iterator i = ml->begin(); i != ml->end(); ++i)
+ {
+ if (RegexNameRequest(this, *i).Send() == newrxengine)
+ {
+ ServerInstance->SNO->WriteToSnoMask('A', "Filter now using engine '%s'", RegexEngine.c_str());
+ rxengine = *i;
+ }
+ }
+ }
+ if (!rxengine)
+ {
+ ServerInstance->SNO->WriteToSnoMask('A', "WARNING: Regex engine '%s' is not loaded - Filter functionality disabled until this is corrected.", RegexEngine.c_str());
+ }
+
+ delete MyConf;
+}
+
+void FilterBase::OnLoadModule(Module* mod, const std::string& name)
+{
+ if (ServerInstance->Modules->ModuleHasInterface(mod, "RegularExpression"))
+ {
+ std::string rxname = RegexNameRequest(this, mod).Send();
+ if (rxname == RegexEngine)
+ {
+ rxengine = mod;
+ /* Force a rehash to make sure that any filters that couldnt be applied from the conf
+ * on startup or on load are applied right now.
+ */
+ ConfigReader Config(ServerInstance);
+ ServerInstance->SNO->WriteToSnoMask('A', "Found and activated regex module '%s' for m_filter.so.", RegexEngine.c_str());
+ ReadFilters(Config);
+ }
+ }
+}
+
+
+Version FilterBase::GetVersion()
+{
+ return Version("$Id$", VF_VENDOR | VF_COMMON, API_VERSION);
+}
+
+
+std::string FilterBase::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 << " " << filter->action << " " << (filter->flags.empty() ? "-" : filter->flags) << " " << filter->gline_time << " :" << filter->reason;
+ return stream.str();
+}
+
+FilterResult FilterBase::DecodeFilter(const std::string &data)
+{
+ FilterResult res;
+ irc::tokenstream tokens(data);
+ tokens.GetToken(res.freeform);
+ tokens.GetToken(res.action);
+ tokens.GetToken(res.flags);
+ if (res.flags == "-")
+ res.flags = "";
+ res.FillFlags(res.flags);
+ 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 FilterBase::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
+{
+ this->SyncFilters(proto, opaque);
+}
+
+void FilterBase::SendFilter(Module* proto, void* opaque, FilterResult* iter)
+{
+ proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "filter", EncodeFilter(iter));
+}
+
+void FilterBase::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+{
+ if ((target_type == TYPE_OTHER) && (extname == "filter"))
+ {
+ FilterResult data = DecodeFilter(extdata);
+ this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.flags);
+ }
+}
+
+class ImplFilter : public FilterResult
+{
+ public:
+ Regex* regex;
+
+ ImplFilter(Module* mymodule, const std::string &rea, const std::string &act, long glinetime, const std::string &pat, const std::string &flgs)
+ : FilterResult(pat, rea, act, glinetime, flgs)
+ {
+ if (!rxengine)
+ throw ModuleException("Regex module implementing '"+RegexEngine+"' is not loaded!");
+
+ regex = RegexFactoryRequest(mymodule, rxengine, pat).Create();
+ }
+
+ ImplFilter()
+ {
+ }
+};