]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_chanfilter.cpp
Add enum constants for list mode numerics.
[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-2019 Sadie Powell <sadie@witchery.services>
6  *   Copyright (C) 2012-2014, 2016 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(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your part message contained a censored word)");
133                 else
134                         user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your part message contained a censored word: " + match->mask + ")");
135         }
136
137         ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE
138         {
139                 if (target.type != MessageTarget::TYPE_CHANNEL)
140                         return MOD_RES_PASSTHRU;
141
142                 Channel* chan = target.Get<Channel>();
143                 ChanFilter::ListItem* match = Match(user, chan, details.text);
144                 if (match)
145                 {
146                         if (!notifyuser)
147                         {
148                                 details.echo_original = true;
149                                 return MOD_RES_DENY;
150                         }
151
152                         if (hidemask)
153                                 user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your message contained a censored word)");
154                         else
155                                 user->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (your message contained a censored word: " + match->mask + ")");
156
157                         return MOD_RES_DENY;
158                 }
159                 return MOD_RES_PASSTHRU;
160         }
161
162         Version GetVersion() CXX11_OVERRIDE
163         {
164                 // We don't send any link data if the length is 35 for compatibility with the 2.0 branch.
165                 std::string maxfilterlen;
166                 if (cf.maxlen != 35)
167                         maxfilterlen.assign(ConvToStr(cf.maxlen));
168
169                 return Version("Provides channel-specific censor lists (like mode +G but varies from channel to channel)", VF_VENDOR, maxfilterlen);
170         }
171 };
172
173 MODULE_INIT(ModuleChanFilter)