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/>.
23 #include "core_user.h"
25 CommandMode::CommandMode(Module* parent)
26 : Command(parent, "MODE", 1)
29 syntax = "<target> <modes> {<mode-parameters>}";
30 memset(&sent, 0, sizeof(sent));
33 CmdResult CommandMode::Handle(User* user, const Params& parameters)
35 const std::string& target = parameters[0];
36 Channel* targetchannel = ServerInstance->FindChan(target);
37 User* targetuser = NULL;
41 targetuser = ServerInstance->FindNickOnly(target);
43 targetuser = ServerInstance->FindNick(target);
46 if ((!targetchannel) && (!targetuser))
49 user->WriteNumeric(Numerics::NoSuchChannel(target));
51 user->WriteNumeric(Numerics::NoSuchNick(target));
54 if (parameters.size() == 1)
56 this->DisplayCurrentModes(user, targetuser, targetchannel);
60 // Populate a temporary Modes::ChangeList with the parameters
61 Modes::ChangeList changelist;
62 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
63 ServerInstance->Modes.ModeParamsToChangeList(user, type, parameters, changelist);
66 FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist));
68 ModeParser::ModeProcessFlag flags = ModeParser::MODE_NONE;
71 if (MOD_RESULT == MOD_RES_PASSTHRU)
73 if ((targetuser) && (user != targetuser))
75 // Local users may only change the modes of other users if a module explicitly allows it
76 user->WriteNumeric(ERR_USERSDONTMATCH, "Can't change mode for other users");
80 // This is a mode change by a local user and modules didn't explicitly allow/deny.
81 // Ensure access checks will happen for each mode being changed.
82 flags |= ModeParser::MODE_CHECKACCESS;
84 else if (MOD_RESULT == MOD_RES_DENY)
85 return CMD_FAILURE; // Entire mode change denied by a module
88 flags |= ModeParser::MODE_LOCALONLY;
91 ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags);
93 ServerInstance->Modes->Process(user, targetchannel, targetuser, changelist, flags);
95 if ((ServerInstance->Modes.GetLastChangeList().empty()) && (targetchannel) && (parameters.size() == 2))
97 /* Special case for displaying the list for listmodes,
98 * e.g. MODE #chan b, or MODE #chan +b without a parameter
100 this->DisplayListModes(user, targetchannel, parameters[1]);
106 RouteDescriptor CommandMode::GetRouting(User* user, const Params& parameters)
108 return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
111 void CommandMode::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence)
115 for (std::string::const_iterator i = mode_sequence.begin(); i != mode_sequence.end(); ++i)
117 unsigned char mletter = *i;
121 ModeHandler* mh = ServerInstance->Modes->FindMode(mletter, MODETYPE_CHANNEL);
122 if (!mh || !mh->IsListMode())
125 /* Ensure the user doesnt request the same mode twice,
126 * so they can't flood themselves off out of idiocy.
128 if (sent[mletter] == seq)
132 ServerInstance->Modes.ShowListModeList(user, chan, mh);
136 static std::string GetSnomasks(const User* user)
138 ModeHandler* const snomask = ServerInstance->Modes.FindMode('s', MODETYPE_USER);
139 std::string snomaskstr = snomask->GetUserParameter(user);
140 // snomaskstr is empty if the snomask mode isn't set, otherwise it begins with a '+'.
141 // In the former case output a "+", not an empty string.
142 if (snomaskstr.empty())
143 snomaskstr.push_back('+');
147 void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
151 // Display channel's current mode string
152 user->WriteNumeric(RPL_CHANNELMODEIS, targetchannel->name, (std::string("+") + targetchannel->ChanModes(targetchannel->HasUser(user))));
153 user->WriteNumeric(RPL_CHANNELCREATED, targetchannel->name, (unsigned long)targetchannel->age);
157 if (targetuser == user)
159 // Display user's current mode string
160 user->WriteNumeric(RPL_UMODEIS, targetuser->GetModeLetters());
161 if (targetuser->IsOper())
162 user->WriteNumeric(RPL_SNOMASKIS, GetSnomasks(targetuser), "Server notice mask");
164 else if (user->HasPrivPermission("users/auspex"))
166 // Querying the modes of another user.
167 // We cannot use RPL_UMODEIS because that's only for showing the user's own modes.
168 user->WriteNumeric(RPL_OTHERUMODEIS, targetuser->nick, targetuser->GetModeLetters());
169 if (targetuser->IsOper())
170 user->WriteNumeric(RPL_OTHERSNOMASKIS, targetuser->nick, GetSnomasks(targetuser), "Server notice mask");
174 user->WriteNumeric(ERR_USERSDONTMATCH, "Can't view modes for other users");