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