]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_chanfilter.cpp
Fix the cloaking module on C++98 compilers.
[user/henk/code/inspircd.git] / src / modules / m_chanfilter.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2019 linuxdaemon <linuxdaemon.irc@gmail.com>
5  *   Copyright (C) 2013, 2017-2020 Sadie Powell <sadie@witchery.services>
6  *   Copyright (C) 2012-2014 Attila Molnar <attilamolnar@hush.com>
7  *   Copyright (C) 2012, 2018 Robby <robby@chatbelgie.be>
8  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
9  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
10  *   Copyright (C) 2006 Oliver Lupton <om@inspircd.org>
11  *   Copyright (C) 2005-2006, 2008-2010 Craig Edwards <brain@inspircd.org>
12  *
13  * This file is part of InspIRCd.  InspIRCd is free software: you can
14  * redistribute it and/or modify it under the terms of the GNU General Public
15  * License as published by the Free Software Foundation, version 2.
16  *
17  * This program is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
20  * details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25
26
27 #include "inspircd.h"
28 #include "listmode.h"
29 #include "modules/exemption.h"
30
31 enum
32 {
33         // InspIRCd-specific.
34         RPL_ENDOFSPAMFILTER = 940,
35         RPL_SPAMFILTER = 941
36 };
37
38 class ChanFilter : public ListModeBase
39 {
40  public:
41         unsigned long maxlen;
42
43         ChanFilter(Module* Creator)
44                 : ListModeBase(Creator, "filter", 'g', "End of channel spamfilter list", RPL_SPAMFILTER, RPL_ENDOFSPAMFILTER, false)
45         {
46                 syntax = "<pattern>";
47         }
48
49         bool ValidateParam(User* user, Channel* chan, std::string& word) CXX11_OVERRIDE
50         {
51                 if (word.length() > maxlen)
52                 {
53                         user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word, "Word is too long for the spamfilter list."));
54                         return false;
55                 }
56
57                 return true;
58         }
59 };
60
61 class ModuleChanFilter : public Module
62 {
63         CheckExemption::EventProvider exemptionprov;
64         ChanFilter cf;
65         bool hidemask;
66         bool notifyuser;
67
68         ChanFilter::ListItem* Match(User* user, Channel* chan, const std::string& text)
69         {
70                 ModResult res = CheckExemption::Call(exemptionprov, user, chan, "filter");
71                 if (!IS_LOCAL(user) || res == MOD_RES_ALLOW)
72                         return NULL;
73
74                 ListModeBase::ModeList* list = cf.GetList(chan);
75                 if (!list)
76                         return NULL;
77
78                 for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); i++)
79                 {
80                         if (InspIRCd::Match(text, i->mask))
81                                 return &*i;
82                 }
83
84                 return NULL;
85         }
86
87  public:
88
89         ModuleChanFilter()
90                 : exemptionprov(this)
91                 , cf(this)
92         {
93         }
94
95         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
96         {
97                 ConfigTag* tag = ServerInstance->Config->ConfValue("chanfilter");
98                 hidemask = tag->getBool("hidemask");
99                 cf.maxlen = tag->getUInt("maxlen", 35, 10, ModeParser::MODE_PARAM_MAX);
100                 notifyuser = tag->getBool("notifyuser", true);
101                 cf.DoRehash();
102         }
103
104         void OnUserPart(Membership* memb, std::string& partmessage, CUList& except_list) CXX11_OVERRIDE
105         {
106                 if (!memb)
107                         return;
108
109                 User* user = memb->user;
110                 Channel* chan = memb->chan;
111                 ChanFilter::ListItem* match = Match(user, chan, partmessage);
112                 if (!match)
113                         return;
114
115                 // Match() checks the user is local, we can assume from here
116                 LocalUser* luser = IS_LOCAL(user);
117
118                 std::string oldreason(partmessage);
119                 partmessage = "Reason filtered";
120                 if (!notifyuser)
121                 {
122                         // Send fake part
123                         ClientProtocol::Messages::Part partmsg(memb, oldreason);
124                         ClientProtocol::Event ev(ServerInstance->GetRFCEvents().part, partmsg);
125                         luser->Send(ev);
126
127                         // Don't send the user the changed message
128                         except_list.insert(user);
129                         return;
130                 }
131
132                 if (hidemask)
133                         user->WriteNumeric(Numerics::CannotSendTo(chan, "Your part message contained a banned phrase and was blocked."));
134                 else
135                         user->WriteNumeric(Numerics::CannotSendTo(chan, InspIRCd::Format("Your part message contained a banned phrase (%s) and was blocked.",
136                                 match->mask.c_str())));
137         }
138
139         ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE
140         {
141                 if (target.type != MessageTarget::TYPE_CHANNEL)
142                         return MOD_RES_PASSTHRU;
143
144                 Channel* chan = target.Get<Channel>();
145                 ChanFilter::ListItem* match = Match(user, chan, details.text);
146                 if (match)
147                 {
148                         if (!notifyuser)
149                         {
150                                 details.echo_original = true;
151                                 return MOD_RES_DENY;
152                         }
153
154                         if (hidemask)
155                                 user->WriteNumeric(Numerics::CannotSendTo(chan, "Your message to this channel contained a banned phrase and was blocked."));
156                         else
157                                 user->WriteNumeric(Numerics::CannotSendTo(chan, InspIRCd::Format("Your message to this channel contained a banned phrase (%s) and was blocked.",
158                                         match->mask.c_str())));
159
160                         return MOD_RES_DENY;
161                 }
162                 return MOD_RES_PASSTHRU;
163         }
164
165         Version GetVersion() CXX11_OVERRIDE
166         {
167                 // We don't send any link data if the length is 35 for compatibility with the 2.0 branch.
168                 std::string maxfilterlen;
169                 if (cf.maxlen != 35)
170                         maxfilterlen.assign(ConvToStr(cf.maxlen));
171
172                 return Version("Adds channel mode g (filter) which allows channel operators to define glob patterns for inappropriate phrases that are not allowed to be used in the channel.", VF_VENDOR, maxfilterlen);
173         }
174 };
175
176 MODULE_INIT(ModuleChanFilter)