]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_namedmodes.cpp
Add support for blocking tag messages with the deaf mode.
[user/henk/code/inspircd.git] / src / modules / m_namedmodes.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2017 B00mX0r <b00mx0r@aureus.pw>
5  *   Copyright (C) 2013-2016 Attila Molnar <attilamolnar@hush.com>
6  *   Copyright (C) 2013, 2017-2019 Sadie Powell <sadie@witchery.services>
7  *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
8  *   Copyright (C) 2010 Craig Edwards <brain@inspircd.org>
9  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
10  *
11  * This file is part of InspIRCd.  InspIRCd is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation, version 2.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 #include "inspircd.h"
26
27 enum
28 {
29         // InspIRCd-specific.
30         RPL_ENDOFPROPLIST = 960,
31         RPL_PROPLIST = 961
32 };
33
34 static void DisplayList(LocalUser* user, Channel* channel)
35 {
36         Numeric::ParamBuilder<1> numeric(user, RPL_PROPLIST);
37         numeric.AddStatic(channel->name);
38
39         const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL);
40         for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i)
41         {
42                 ModeHandler* mh = i->second;
43                 if (!channel->IsModeSet(mh))
44                         continue;
45                 numeric.Add("+" + mh->name);
46                 ParamModeBase* pm = mh->IsParameterMode();
47                 if (pm)
48                 {
49                         if ((pm->IsParameterSecret()) && (!channel->HasUser(user)) && (!user->HasPrivPermission("channels/auspex")))
50                                 numeric.Add("<" + mh->name + ">");
51                         else
52                                 numeric.Add(channel->GetModeParameter(mh));
53                 }
54         }
55         numeric.Flush();
56         user->WriteNumeric(RPL_ENDOFPROPLIST, channel->name, "End of mode list");
57 }
58
59 class CommandProp : public SplitCommand
60 {
61  public:
62         CommandProp(Module* parent)
63                 : SplitCommand(parent, "PROP", 1)
64         {
65                 syntax = "<channel> [[(+|-)]<mode> [<value>]]";
66         }
67
68         CmdResult HandleLocal(LocalUser* src, const Params& parameters) CXX11_OVERRIDE
69         {
70                 Channel* const chan = ServerInstance->FindChan(parameters[0]);
71                 if (!chan)
72                 {
73                         src->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
74                         return CMD_FAILURE;
75                 }
76
77                 if (parameters.size() == 1)
78                 {
79                         DisplayList(src, chan);
80                         return CMD_SUCCESS;
81                 }
82                 unsigned int i = 1;
83                 Modes::ChangeList modes;
84                 while (i < parameters.size())
85                 {
86                         std::string prop = parameters[i++];
87                         if (prop.empty())
88                                 continue;
89                         bool plus = prop[0] != '-';
90                         if (prop[0] == '+' || prop[0] == '-')
91                                 prop.erase(prop.begin());
92
93                         ModeHandler* mh = ServerInstance->Modes->FindMode(prop, MODETYPE_CHANNEL);
94                         if (mh)
95                         {
96                                 if (mh->NeedsParam(plus))
97                                 {
98                                         if (i != parameters.size())
99                                                 modes.push(mh, plus, parameters[i++]);
100                                 }
101                                 else
102                                         modes.push(mh, plus);
103                         }
104                 }
105                 ServerInstance->Modes->ProcessSingle(src, chan, NULL, modes, ModeParser::MODE_CHECKACCESS);
106                 return CMD_SUCCESS;
107         }
108 };
109
110 class DummyZ : public ModeHandler
111 {
112  public:
113         DummyZ(Module* parent) : ModeHandler(parent, "namebase", 'Z', PARAM_ALWAYS, MODETYPE_CHANNEL)
114         {
115                 list = true;
116         }
117
118         // Handle /MODE #chan Z
119         void DisplayList(User* user, Channel* chan) CXX11_OVERRIDE
120         {
121                 LocalUser* luser = IS_LOCAL(user);
122                 if (luser)
123                         ::DisplayList(luser, chan);
124         }
125 };
126
127 class ModuleNamedModes : public Module
128 {
129         CommandProp cmd;
130         DummyZ dummyZ;
131  public:
132         ModuleNamedModes() : cmd(this), dummyZ(this)
133         {
134         }
135
136         Version GetVersion() CXX11_OVERRIDE
137         {
138                 return Version("Provides support for adding and removing modes via their long names.", VF_VENDOR);
139         }
140
141         void Prioritize() CXX11_OVERRIDE
142         {
143                 ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST);
144         }
145
146         ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) CXX11_OVERRIDE
147         {
148                 if (!channel)
149                         return MOD_RES_PASSTHRU;
150
151                 Modes::ChangeList::List& list = modes.getlist();
152                 for (Modes::ChangeList::List::iterator i = list.begin(); i != list.end(); )
153                 {
154                         Modes::Change& curr = *i;
155                         // Replace all namebase (dummyZ) modes being changed with the actual
156                         // mode handler and parameter. The parameter format of the namebase mode is
157                         // <modename>[=<parameter>].
158                         if (curr.mh == &dummyZ)
159                         {
160                                 std::string name = curr.param;
161                                 std::string value;
162                                 std::string::size_type eq = name.find('=');
163                                 if (eq != std::string::npos)
164                                 {
165                                         value.assign(name, eq + 1, std::string::npos);
166                                         name.erase(eq);
167                                 }
168
169                                 ModeHandler* mh = ServerInstance->Modes->FindMode(name, MODETYPE_CHANNEL);
170                                 if (!mh)
171                                 {
172                                         // Mode handler not found
173                                         i = list.erase(i);
174                                         continue;
175                                 }
176
177                                 curr.param.clear();
178                                 if (mh->NeedsParam(curr.adding))
179                                 {
180                                         if (value.empty())
181                                         {
182                                                 // Mode needs a parameter but there wasn't one
183                                                 i = list.erase(i);
184                                                 continue;
185                                         }
186
187                                         // Change parameter to the text after the '='
188                                         curr.param = value;
189                                 }
190
191                                 // Put the actual ModeHandler in place of the namebase handler
192                                 curr.mh = mh;
193                         }
194
195                         ++i;
196                 }
197
198                 return MOD_RES_PASSTHRU;
199         }
200 };
201
202 MODULE_INIT(ModuleNamedModes)