2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2019 linuxdaemon <linuxdaemon.irc@gmail.com>
5 * Copyright (C) 2019 Robby <robby@chatbelgie.be>
6 * Copyright (C) 2018-2019 Sadie Powell <sadie@witchery.services>
7 * Copyright (C) 2017 B00mX0r <b00mx0r@aureus.pw>
8 * Copyright (C) 2014-2016 Attila Molnar <attilamolnar@hush.com>
10 * This file is part of InspIRCd. InspIRCd is free software: you can
11 * redistribute it and/or modify it under the terms of the GNU General Public
12 * License as published by the Free Software Foundation, version 2.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 class CommandMode : public Command
29 unsigned int sent[256];
31 ChanModeReference secretmode;
32 ChanModeReference privatemode;
34 /** Show the list of one or more list modes to a user.
35 * @param user User to send to.
36 * @param chan Channel whose lists to show.
37 * @param mode_sequence Mode letters to show the lists of.
39 void DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence);
41 /** Show the current modes of a channel or a user to a user.
42 * @param user User to show the modes to.
43 * @param targetuser User whose modes to show. NULL if showing the modes of a channel.
44 * @param targetchannel Channel whose modes to show. NULL if showing the modes of a user.
46 void DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel);
48 bool CanSeeChan(User* user, Channel* chan)
50 // A user can always see the channel modes if they are:
51 // (1) In the channel.
52 // (2) An oper with the channels/auspex privilege.
53 if (chan->HasUser(user) || user->HasPrivPermission("channels/auspex"))
56 // Otherwise, they can only see the modes when the channel is not +p or +s.
57 return !chan->IsModeSet(secretmode) && !chan->IsModeSet(privatemode);
61 /** Constructor for mode.
63 CommandMode(Module* parent);
66 * @param parameters The parameters to the command
67 * @param user The user issuing the command
68 * @return A value from CmdResult to indicate command success or failure.
70 CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
72 RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE;
75 CommandMode::CommandMode(Module* parent)
76 : Command(parent, "MODE", 1)
78 , secretmode(creator, "secret")
79 , privatemode(creator, "private")
81 syntax = "<target> [[(+|-)]<modes> [<mode-parameters>]]";
82 memset(&sent, 0, sizeof(sent));
85 CmdResult CommandMode::Handle(User* user, const Params& parameters)
87 const std::string& target = parameters[0];
88 Channel* targetchannel = ServerInstance->FindChan(target);
89 User* targetuser = NULL;
93 targetuser = ServerInstance->FindNickOnly(target);
95 targetuser = ServerInstance->FindNick(target);
98 if ((!targetchannel || !CanSeeChan(user, targetchannel)) && (!targetuser))
100 if (target[0] == '#')
101 user->WriteNumeric(Numerics::NoSuchChannel(target));
103 user->WriteNumeric(Numerics::NoSuchNick(target));
106 if (parameters.size() == 1)
108 this->DisplayCurrentModes(user, targetuser, targetchannel);
112 // Populate a temporary Modes::ChangeList with the parameters
113 Modes::ChangeList changelist;
114 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
115 ServerInstance->Modes.ModeParamsToChangeList(user, type, parameters, changelist);
117 ModResult MOD_RESULT;
118 FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist));
120 ModeParser::ModeProcessFlag flags = ModeParser::MODE_NONE;
123 if (MOD_RESULT == MOD_RES_PASSTHRU)
125 if ((targetuser) && (user != targetuser))
127 // Local users may only change the modes of other users if a module explicitly allows it
128 user->WriteNumeric(ERR_USERSDONTMATCH, "Can't change mode for other users");
132 // This is a mode change by a local user and modules didn't explicitly allow/deny.
133 // Ensure access checks will happen for each mode being changed.
134 flags |= ModeParser::MODE_CHECKACCESS;
136 else if (MOD_RESULT == MOD_RES_DENY)
137 return CMD_FAILURE; // Entire mode change denied by a module
140 flags |= ModeParser::MODE_LOCALONLY;
143 ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags);
145 ServerInstance->Modes->Process(user, targetchannel, targetuser, changelist, flags);
147 if ((ServerInstance->Modes.GetLastChangeList().empty()) && (targetchannel) && (parameters.size() == 2))
149 /* Special case for displaying the list for listmodes,
150 * e.g. MODE #chan b, or MODE #chan +b without a parameter
152 this->DisplayListModes(user, targetchannel, parameters[1]);
158 RouteDescriptor CommandMode::GetRouting(User* user, const Params& parameters)
160 return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
163 void CommandMode::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence)
167 for (std::string::const_iterator i = mode_sequence.begin(); i != mode_sequence.end(); ++i)
169 unsigned char mletter = *i;
173 ModeHandler* mh = ServerInstance->Modes->FindMode(mletter, MODETYPE_CHANNEL);
174 if (!mh || !mh->IsListMode())
177 /* Ensure the user doesnt request the same mode twice,
178 * so they can't flood themselves off out of idiocy.
180 if (sent[mletter] == seq)
184 ServerInstance->Modes.ShowListModeList(user, chan, mh);
188 static std::string GetSnomasks(const User* user)
190 ModeHandler* const snomask = ServerInstance->Modes.FindMode('s', MODETYPE_USER);
191 std::string snomaskstr = snomask->GetUserParameter(user);
192 // snomaskstr is empty if the snomask mode isn't set, otherwise it begins with a '+'.
193 // In the former case output a "+", not an empty string.
194 if (snomaskstr.empty())
195 snomaskstr.push_back('+');
201 void GetModeList(Numeric::Numeric& num, Channel* chan, User* user)
203 // We should only show the value of secret parameters (i.e. key) if
204 // the user is a member of the channel.
205 bool show_secret = chan->HasUser(user);
207 size_t modepos = num.push("+").GetParams().size() - 1;
210 for (unsigned char chr = 65; chr < 123; ++chr)
212 // Check that the mode exists and is set.
213 ModeHandler* mh = ServerInstance->Modes->FindMode(chr, MODETYPE_CHANNEL);
214 if (!mh || !chan->IsModeSet(mh))
217 // Add the mode to the set list.
218 modes.push_back(mh->GetModeChar());
220 // If the mode has a parameter we need to include that too.
221 ParamModeBase* pm = mh->IsParameterMode();
225 // If a mode has a secret parameter and the user is not privy to
226 // the value of it then we use <name> instead of the value.
227 if (pm->IsParameterSecret() && !show_secret)
229 num.push("<" + pm->name + ">");
233 // Retrieve the parameter and add it to the mode list.
234 pm->GetParameter(chan, param);
238 num.GetParams()[modepos].append(modes);
242 void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
246 // Display channel's current mode string
247 Numeric::Numeric modenum(RPL_CHANNELMODEIS);
248 modenum.push(targetchannel->name);
249 GetModeList(modenum, targetchannel, user);
250 user->WriteNumeric(modenum);
251 user->WriteNumeric(RPL_CHANNELCREATED, targetchannel->name, (unsigned long)targetchannel->age);
255 if (targetuser == user)
257 // Display user's current mode string
258 user->WriteNumeric(RPL_UMODEIS, targetuser->GetModeLetters());
259 if (targetuser->IsOper())
260 user->WriteNumeric(RPL_SNOMASKIS, GetSnomasks(targetuser), "Server notice mask");
262 else if (user->HasPrivPermission("users/auspex"))
264 // Querying the modes of another user.
265 // We cannot use RPL_UMODEIS because that's only for showing the user's own modes.
266 user->WriteNumeric(RPL_OTHERUMODEIS, targetuser->nick, targetuser->GetModeLetters());
267 if (targetuser->IsOper())
268 user->WriteNumeric(RPL_OTHERSNOMASKIS, targetuser->nick, GetSnomasks(targetuser), "Server notice mask");
272 user->WriteNumeric(ERR_USERSDONTMATCH, "Can't view modes for other users");
277 class CoreModMode : public Module
288 void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
290 tokens["CHANMODES"] = ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL);
291 tokens["USERMODES"] = ServerInstance->Modes->GiveModeList(MODETYPE_USER);
294 Version GetVersion() CXX11_OVERRIDE
296 return Version("Provides the MODE command", VF_VENDOR|VF_CORE);
300 MODULE_INIT(CoreModMode)