]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_mode.cpp
Update my name and email address.
[user/henk/code/inspircd.git] / src / coremods / core_mode.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
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>
8  *
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.
12  *
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
16  * details.
17  *
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/>.
20  */
21
22
23 #include "inspircd.h"
24
25 class CommandMode : public Command
26 {
27         unsigned int sent[256];
28         unsigned int seq;
29
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.
34          */
35         void DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence);
36
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.
41          */
42         void DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel);
43
44  public:
45         /** Constructor for mode.
46          */
47         CommandMode(Module* parent);
48
49         /** Handle command.
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.
53          */
54         CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
55
56         RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE;
57 };
58
59 CommandMode::CommandMode(Module* parent)
60         : Command(parent, "MODE", 1)
61         , seq(0)
62 {
63         syntax = "<target> [[(+|-)]<modes> [<mode-parameters>]]";
64         memset(&sent, 0, sizeof(sent));
65 }
66
67 CmdResult CommandMode::Handle(User* user, const Params& parameters)
68 {
69         const std::string& target = parameters[0];
70         Channel* targetchannel = ServerInstance->FindChan(target);
71         User* targetuser = NULL;
72         if (!targetchannel)
73         {
74                 if (IS_LOCAL(user))
75                         targetuser = ServerInstance->FindNickOnly(target);
76                 else
77                         targetuser = ServerInstance->FindNick(target);
78         }
79
80         if ((!targetchannel) && (!targetuser))
81         {
82                 if (target[0] == '#')
83                         user->WriteNumeric(Numerics::NoSuchChannel(target));
84                 else
85                         user->WriteNumeric(Numerics::NoSuchNick(target));
86                 return CMD_FAILURE;
87         }
88         if (parameters.size() == 1)
89         {
90                 this->DisplayCurrentModes(user, targetuser, targetchannel);
91                 return CMD_SUCCESS;
92         }
93
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);
98
99         ModResult MOD_RESULT;
100         FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist));
101
102         ModeParser::ModeProcessFlag flags = ModeParser::MODE_NONE;
103         if (IS_LOCAL(user))
104         {
105                 if (MOD_RESULT == MOD_RES_PASSTHRU)
106                 {
107                         if ((targetuser) && (user != targetuser))
108                         {
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");
111                                 return CMD_FAILURE;
112                         }
113
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;
117                 }
118                 else if (MOD_RESULT == MOD_RES_DENY)
119                         return CMD_FAILURE; // Entire mode change denied by a module
120         }
121         else
122                 flags |= ModeParser::MODE_LOCALONLY;
123
124         if (IS_LOCAL(user))
125                 ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags);
126         else
127                 ServerInstance->Modes->Process(user, targetchannel, targetuser, changelist, flags);
128
129         if ((ServerInstance->Modes.GetLastChangeList().empty()) && (targetchannel) && (parameters.size() == 2))
130         {
131                 /* Special case for displaying the list for listmodes,
132                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
133                  */
134                 this->DisplayListModes(user, targetchannel, parameters[1]);
135         }
136
137         return CMD_SUCCESS;
138 }
139
140 RouteDescriptor CommandMode::GetRouting(User* user, const Params& parameters)
141 {
142         return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
143 }
144
145 void CommandMode::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence)
146 {
147         seq++;
148
149         for (std::string::const_iterator i = mode_sequence.begin(); i != mode_sequence.end(); ++i)
150         {
151                 unsigned char mletter = *i;
152                 if (mletter == '+')
153                         continue;
154
155                 ModeHandler* mh = ServerInstance->Modes->FindMode(mletter, MODETYPE_CHANNEL);
156                 if (!mh || !mh->IsListMode())
157                         return;
158
159                 /* Ensure the user doesnt request the same mode twice,
160                  * so they can't flood themselves off out of idiocy.
161                  */
162                 if (sent[mletter] == seq)
163                         continue;
164
165                 sent[mletter] = seq;
166                 ServerInstance->Modes.ShowListModeList(user, chan, mh);
167         }
168 }
169
170 static std::string GetSnomasks(const User* user)
171 {
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('+');
178         return snomaskstr;
179 }
180
181 namespace
182 {
183         void GetModeList(Numeric::Numeric& num, Channel* chan, User* user)
184         {
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);
188
189                 size_t modepos = num.push("+").GetParams().size() - 1;
190                 std::string modes;
191                 std::string param;
192                 for (unsigned char chr = 65; chr < 123; ++chr)
193                 {
194                         // Check that the mode exists and is set.
195                         ModeHandler* mh = ServerInstance->Modes->FindMode(chr, MODETYPE_CHANNEL);
196                         if (!mh || !chan->IsModeSet(mh))
197                                 continue;
198
199                         // Add the mode to the set list.
200                         modes.push_back(mh->GetModeChar());
201
202                         // If the mode has a parameter we need to include that too.
203                         ParamModeBase* pm = mh->IsParameterMode();
204                         if (!pm)
205                                 continue;
206
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)
210                         {
211                                 num.push("<" + pm->name + ">");
212                                 continue;
213                         }
214
215                         // Retrieve the parameter and add it to the mode list.
216                         pm->GetParameter(chan, param);
217                         num.push(param);
218                         param.clear();
219                 }
220                 num.GetParams()[modepos].append(modes);
221         }
222 }
223
224 void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
225 {
226         if (targetchannel)
227         {
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);
234         }
235         else
236         {
237                 if (targetuser == user)
238                 {
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");
243                 }
244                 else if (user->HasPrivPermission("users/auspex"))
245                 {
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");
251                 }
252                 else
253                 {
254                         user->WriteNumeric(ERR_USERSDONTMATCH, "Can't view modes for other users");
255                 }
256         }
257 }
258
259 class CoreModMode : public Module
260 {
261  private:
262         CommandMode cmdmode;
263
264  public:
265         CoreModMode()
266                 : cmdmode(this)
267         {
268         }
269
270         Version GetVersion() CXX11_OVERRIDE
271         {
272                 return Version("Provides the MODE command", VF_VENDOR|VF_CORE);
273         }
274 };
275
276 MODULE_INIT(CoreModMode)