+ }
+ else
+ {
+ reasonindex = 3;
+ }
+
+ Module *me = creator;
+ std::pair<bool, std::string> result = static_cast<ModuleFilter *>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags);
+ if (result.first)
+ {
+ user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick.c_str(), freeform.c_str(),
+ parameters[1].c_str(), (duration ? ", duration " : ""), (duration ? parameters[3].c_str() : ""),
+ flags.c_str(), parameters[reasonindex].c_str());
+
+ ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'a' : 'A', "FILTER: "+user->nick+" added filter '"+freeform+"', type '"+parameters[1]+"', "+(duration ? "duration "+parameters[3]+", " : "")+"flags '"+flags+"', reason: "+parameters[reasonindex]);
+
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick.c_str(), freeform.c_str(), result.second.c_str());
+ return CMD_FAILURE;
+ }
+ }
+ else
+ {
+ user->WriteServ("NOTICE %s :*** Not enough parameters.", user->nick.c_str());
+ return CMD_FAILURE;
+ }
+
+ }
+}
+
+bool ModuleFilter::AppliesToMe(User* user, FilterResult* filter, int iflags)
+{
+ if ((filter->flag_no_opers) && IS_OPER(user))
+ return false;
+ if ((iflags & FLAG_PRIVMSG) && (!filter->flag_privmsg))
+ return false;
+ if ((iflags & FLAG_NOTICE) && (!filter->flag_notice))
+ return false;
+ if ((iflags & FLAG_QUIT) && (!filter->flag_quit_message))
+ return false;
+ if ((iflags & FLAG_PART) && (!filter->flag_part_message))
+ return false;
+ return true;
+}
+
+ModuleFilter::ModuleFilter() : filtcommand(this), RegexEngine(this, "regex")
+{
+}
+
+void ModuleFilter::init()
+{
+ ServerInstance->Modules->AddService(filtcommand);
+ Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncNetwork, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash };
+ ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+ OnRehash(NULL);
+}
+
+ModResult ModuleFilter::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+{
+ if (!IS_LOCAL(user))
+ return MOD_RES_PASSTHRU;
+
+ flags = FLAG_PRIVMSG;
+ return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
+}
+
+ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+{
+ /* Leave ulines alone */
+ if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user)))
+ return MOD_RES_PASSTHRU;
+
+ if (!flags)
+ flags = FLAG_NOTICE;
+
+ FilterResult* f = this->FilterMatch(user, text, flags);
+ if (f)
+ {
+ std::string target;
+ if (target_type == TYPE_USER)
+ {
+ User* t = (User*)dest;
+ target = t->nick;
+ }
+ else if (target_type == TYPE_CHANNEL)
+ {
+ Channel* t = (Channel*)dest;
+ if (exemptfromfilter.find(t->name) != exemptfromfilter.end())
+ return MOD_RES_PASSTHRU;
+
+ target = t->name;
+ }
+ 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(404, "%s %s :Message to channel blocked and opers notified (%s)",user->nick.c_str(), target.c_str(), f->reason.c_str());
+ else
+ user->WriteServ("NOTICE "+user->nick+" :Your message to "+target+" was blocked and opers notified: "+f->reason);
+ }
+ else if (f->action == FA_SILENT)
+ {
+ if (target_type == TYPE_CHANNEL)
+ user->WriteNumeric(404, "%s %s :Message to channel blocked (%s)",user->nick.c_str(), target.c_str(), f->reason.c_str());
+ else
+ user->WriteServ("NOTICE "+user->nick+" :Your message to "+target+" was blocked: "+f->reason);
+ }
+ else if (f->action == FA_KILL)
+ {
+ ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason);
+ }
+ 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());
+ if (ServerInstance->XLines->AddLine(gl,NULL))
+ {
+ ServerInstance->XLines->ApplyLines();
+ }
+ else
+ delete gl;
+ }
+
+ ServerInstance->Logs->Log("FILTER",DEFAULT,"FILTER: "+ user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + ModuleFilter::FilterActionToString(f->action));
+ return MOD_RES_DENY;
+ }
+ return MOD_RES_PASSTHRU;
+}
+
+ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line)
+{
+ if (validated && IS_LOCAL(user))
+ {
+ flags = 0;
+ bool parting;
+
+ if (command == "QUIT")
+ {
+ /* QUIT with no reason: nothing to do */
+ if (parameters.size() < 1)
+ return MOD_RES_PASSTHRU;
+
+ parting = false;
+ flags = FLAG_QUIT;
+ }
+ else if (command == "PART")
+ {
+ /* PART with no reason: nothing to do */
+ if (parameters.size() < 2)
+ return MOD_RES_PASSTHRU;
+
+ if (exemptfromfilter.find(parameters[0]) != exemptfromfilter.end())
+ return MOD_RES_PASSTHRU;
+
+ parting = true;
+ flags = FLAG_PART;
+ }
+ else
+ /* We're only messing with PART and QUIT */
+ return MOD_RES_PASSTHRU;
+
+ FilterResult* f = this->FilterMatch(user, parameters[parting ? 1 : 0], flags);
+ if (!f)
+ /* PART or QUIT reason doesnt match a filter */
+ return MOD_RES_PASSTHRU;