2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
5 * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
6 * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
7 * Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc>
9 * This file is part of InspIRCd. InspIRCd is free software: you can
10 * redistribute it and/or modify it under the terms of the GNU General Public
11 * License as published by the Free Software Foundation, version 2.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 class CommandMode : public Command
27 unsigned int sent[256];
30 /** Show the list of one or more list modes to a user.
31 * @param user User to send to.
32 * @param chan Channel whose lists to show.
33 * @param mode_sequence Mode letters to show the lists of.
35 void DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence);
37 /** Show the current modes of a channel or a user to a user.
38 * @param user User to show the modes to.
39 * @param targetuser User whose modes to show. NULL if showing the modes of a channel.
40 * @param targetchannel Channel whose modes to show. NULL if showing the modes of a user.
42 void DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel);
45 /** Constructor for mode.
47 CommandMode(Module* parent);
50 * @param parameters The parameters to the command
51 * @param user The user issuing the command
52 * @return A value from CmdResult to indicate command success or failure.
54 CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
56 RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE;
59 CommandMode::CommandMode(Module* parent)
60 : Command(parent, "MODE", 1)
63 syntax = "<target> [[(+|-)]<modes> [<mode-parameters>]]";
64 memset(&sent, 0, sizeof(sent));
67 CmdResult CommandMode::Handle(User* user, const Params& parameters)
69 const std::string& target = parameters[0];
70 Channel* targetchannel = ServerInstance->FindChan(target);
71 User* targetuser = NULL;
75 targetuser = ServerInstance->FindNickOnly(target);
77 targetuser = ServerInstance->FindNick(target);
80 if ((!targetchannel) && (!targetuser))
83 user->WriteNumeric(Numerics::NoSuchChannel(target));
85 user->WriteNumeric(Numerics::NoSuchNick(target));
88 if (parameters.size() == 1)
90 this->DisplayCurrentModes(user, targetuser, targetchannel);
94 // Populate a temporary Modes::ChangeList with the parameters
95 Modes::ChangeList changelist;
96 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
97 ServerInstance->Modes.ModeParamsToChangeList(user, type, parameters, changelist);
100 FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist));
102 ModeParser::ModeProcessFlag flags = ModeParser::MODE_NONE;
105 if (MOD_RESULT == MOD_RES_PASSTHRU)
107 if ((targetuser) && (user != targetuser))
109 // Local users may only change the modes of other users if a module explicitly allows it
110 user->WriteNumeric(ERR_USERSDONTMATCH, "Can't change mode for other users");
114 // This is a mode change by a local user and modules didn't explicitly allow/deny.
115 // Ensure access checks will happen for each mode being changed.
116 flags |= ModeParser::MODE_CHECKACCESS;
118 else if (MOD_RESULT == MOD_RES_DENY)
119 return CMD_FAILURE; // Entire mode change denied by a module
122 flags |= ModeParser::MODE_LOCALONLY;
125 ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags);
127 ServerInstance->Modes->Process(user, targetchannel, targetuser, changelist, flags);
129 if ((ServerInstance->Modes.GetLastChangeList().empty()) && (targetchannel) && (parameters.size() == 2))
131 /* Special case for displaying the list for listmodes,
132 * e.g. MODE #chan b, or MODE #chan +b without a parameter
134 this->DisplayListModes(user, targetchannel, parameters[1]);
140 RouteDescriptor CommandMode::GetRouting(User* user, const Params& parameters)
142 return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
145 void CommandMode::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence)
149 for (std::string::const_iterator i = mode_sequence.begin(); i != mode_sequence.end(); ++i)
151 unsigned char mletter = *i;
155 ModeHandler* mh = ServerInstance->Modes->FindMode(mletter, MODETYPE_CHANNEL);
156 if (!mh || !mh->IsListMode())
159 /* Ensure the user doesnt request the same mode twice,
160 * so they can't flood themselves off out of idiocy.
162 if (sent[mletter] == seq)
166 ServerInstance->Modes.ShowListModeList(user, chan, mh);
170 static std::string GetSnomasks(const User* user)
172 ModeHandler* const snomask = ServerInstance->Modes.FindMode('s', MODETYPE_USER);
173 std::string snomaskstr = snomask->GetUserParameter(user);
174 // snomaskstr is empty if the snomask mode isn't set, otherwise it begins with a '+'.
175 // In the former case output a "+", not an empty string.
176 if (snomaskstr.empty())
177 snomaskstr.push_back('+');
183 void GetModeList(Numeric::Numeric& num, Channel* chan, User* user)
185 // We should only show the value of secret parameters (i.e. key) if
186 // the user is a member of the channel.
187 bool show_secret = chan->HasUser(user);
189 size_t modepos = num.push("+").GetParams().size() - 1;
192 for (unsigned char chr = 65; chr < 123; ++chr)
194 // Check that the mode exists and is set.
195 ModeHandler* mh = ServerInstance->Modes->FindMode(chr, MODETYPE_CHANNEL);
196 if (!mh || !chan->IsModeSet(mh))
199 // Add the mode to the set list.
200 modes.push_back(mh->GetModeChar());
202 // If the mode has a parameter we need to include that too.
203 ParamModeBase* pm = mh->IsParameterMode();
207 // If a mode has a secret parameter and the user is not privy to
208 // the value of it then we use <name> instead of the value.
209 if (pm->IsParameterSecret() && !show_secret)
211 num.push("<" + pm->name + ">");
215 // Retrieve the parameter and add it to the mode list.
216 pm->GetParameter(chan, param);
220 num.GetParams()[modepos].append(modes);
224 void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
228 // Display channel's current mode string
229 Numeric::Numeric modenum(RPL_CHANNELMODEIS);
230 modenum.push(targetchannel->name);
231 GetModeList(modenum, targetchannel, user);
232 user->WriteNumeric(modenum);
233 user->WriteNumeric(RPL_CHANNELCREATED, targetchannel->name, (unsigned long)targetchannel->age);
237 if (targetuser == user)
239 // Display user's current mode string
240 user->WriteNumeric(RPL_UMODEIS, targetuser->GetModeLetters());
241 if (targetuser->IsOper())
242 user->WriteNumeric(RPL_SNOMASKIS, GetSnomasks(targetuser), "Server notice mask");
244 else if (user->HasPrivPermission("users/auspex"))
246 // Querying the modes of another user.
247 // We cannot use RPL_UMODEIS because that's only for showing the user's own modes.
248 user->WriteNumeric(RPL_OTHERUMODEIS, targetuser->nick, targetuser->GetModeLetters());
249 if (targetuser->IsOper())
250 user->WriteNumeric(RPL_OTHERSNOMASKIS, targetuser->nick, GetSnomasks(targetuser), "Server notice mask");
254 user->WriteNumeric(ERR_USERSDONTMATCH, "Can't view modes for other users");
259 class CoreModMode : public Module
270 Version GetVersion() CXX11_OVERRIDE
272 return Version("Provides the MODE command", VF_VENDOR|VF_CORE);
276 MODULE_INIT(CoreModMode)