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
DisplayList(LocalUser * user,Channel * channel)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:
CommandProp(Module * parent)62 CommandProp(Module* parent)
63 : SplitCommand(parent, "PROP", 1)
64 {
65 syntax = "<channel> [[(+|-)]<mode> [<value>]]";
66 }
67
HandleLocal(LocalUser * src,const Params & parameters)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:
DummyZ(Module * parent)113 DummyZ(Module* parent) : ModeHandler(parent, "namebase", 'Z', PARAM_ALWAYS, MODETYPE_CHANNEL)
114 {
115 list = true;
116 }
117
118 // Handle /MODE #chan Z
DisplayList(User * user,Channel * chan)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:
ModuleNamedModes()132 ModuleNamedModes() : cmd(this), dummyZ(this)
133 {
134 }
135
GetVersion()136 Version GetVersion() CXX11_OVERRIDE
137 {
138 return Version("Provides support for adding and removing modes via their long names.", VF_VENDOR);
139 }
140
Prioritize()141 void Prioritize() CXX11_OVERRIDE
142 {
143 ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST);
144 }
145
OnPreMode(User * source,User * dest,Channel * channel,Modes::ChangeList & modes)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)
203