]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_user/cmd_mode.cpp
Convert WriteNumeric() calls to pass the parameters of the numeric as method parameters
[user/henk/code/inspircd.git] / src / coremods / core_user / cmd_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 #include "inspircd.h"
23 #include "core_user.h"
24
25 CommandMode::CommandMode(Module* parent)
26         : Command(parent, "MODE", 1)
27         , seq(0)
28 {
29         syntax = "<target> <modes> {<mode-parameters>}";
30         memset(&sent, 0, sizeof(sent));
31 }
32
33 CmdResult CommandMode::Handle(const std::vector<std::string>& parameters, User* user)
34 {
35         const std::string& target = parameters[0];
36         Channel* targetchannel = ServerInstance->FindChan(target);
37         User* targetuser = NULL;
38         if (!targetchannel)
39         {
40                 if (IS_LOCAL(user))
41                         targetuser = ServerInstance->FindNickOnly(target);
42                 else
43                         targetuser = ServerInstance->FindNick(target);
44         }
45
46         if ((!targetchannel) && (!targetuser))
47         {
48                 user->WriteNumeric(Numerics::NoSuchNick(target));
49                 return CMD_FAILURE;
50         }
51         if (parameters.size() == 1)
52         {
53                 this->DisplayCurrentModes(user, targetuser, targetchannel);
54                 return CMD_SUCCESS;
55         }
56
57         // Populate a temporary Modes::ChangeList with the parameters
58         Modes::ChangeList changelist;
59         ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
60         ServerInstance->Modes.ModeParamsToChangeList(user, type, parameters, changelist);
61
62         ModResult MOD_RESULT;
63         FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist));
64
65         ModeParser::ModeProcessFlag flags = ModeParser::MODE_NONE;
66         if (IS_LOCAL(user))
67         {
68                 if (MOD_RESULT == MOD_RES_PASSTHRU)
69                 {
70                         if ((targetuser) && (user != targetuser))
71                         {
72                                 // Local users may only change the modes of other users if a module explicitly allows it
73                                 user->WriteNumeric(ERR_USERSDONTMATCH, "Can't change mode for other users");
74                                 return CMD_FAILURE;
75                         }
76
77                         // This is a mode change by a local user and modules didn't explicitly allow/deny.
78                         // Ensure access checks will happen for each mode being changed.
79                         flags |= ModeParser::MODE_CHECKACCESS;
80                 }
81                 else if (MOD_RESULT == MOD_RES_DENY)
82                         return CMD_FAILURE; // Entire mode change denied by a module
83         }
84         else
85                 flags |= ModeParser::MODE_LOCALONLY;
86
87         if (IS_LOCAL(user))
88                 ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags);
89         else
90                 ServerInstance->Modes->Process(user, targetchannel, targetuser, changelist, flags);
91
92         if ((ServerInstance->Modes.GetLastParse().empty()) && (targetchannel) && (parameters.size() == 2))
93         {
94                 /* Special case for displaying the list for listmodes,
95                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
96                  */
97                 this->DisplayListModes(user, targetchannel, parameters[1]);
98         }
99
100         return CMD_SUCCESS;
101 }
102
103 RouteDescriptor CommandMode::GetRouting(User* user, const std::vector<std::string>& parameters)
104 {
105         return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
106 }
107
108 void CommandMode::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence)
109 {
110         seq++;
111
112         for (std::string::const_iterator i = mode_sequence.begin(); i != mode_sequence.end(); ++i)
113         {
114                 unsigned char mletter = *i;
115                 if (mletter == '+')
116                         continue;
117
118                 ModeHandler* mh = ServerInstance->Modes->FindMode(mletter, MODETYPE_CHANNEL);
119                 if (!mh || !mh->IsListMode())
120                         return;
121
122                 /* Ensure the user doesnt request the same mode twice,
123                  * so they can't flood themselves off out of idiocy.
124                  */
125                 if (sent[mletter] == seq)
126                         continue;
127
128                 sent[mletter] = seq;
129                 ServerInstance->Modes.ShowListModeList(user, chan, mh);
130         }
131 }
132
133 void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
134 {
135         if (targetchannel)
136         {
137                 // Display channel's current mode string
138                 user->WriteNumeric(RPL_CHANNELMODEIS, targetchannel->name, (std::string("+") + targetchannel->ChanModes(targetchannel->HasUser(user))));
139                 user->WriteNumeric(RPL_CHANNELCREATED, targetchannel->name, (unsigned long)targetchannel->age);
140         }
141         else
142         {
143                 if (targetuser == user || user->HasPrivPermission("users/auspex"))
144                 {
145                         // Display user's current mode string
146                         // XXX: Use WriteServ() because WriteNumeric() assumes the target (i.e. next word after the number)
147                         // is 'user' and puts his nick there which is not what we want
148                         user->WriteServ("%03d %s :+%s", RPL_UMODEIS, targetuser->nick.c_str(), targetuser->FormatModes());
149                         if (targetuser->IsOper())
150                         {
151                                 ModeHandler* snomask = ServerInstance->Modes->FindMode('s', MODETYPE_USER);
152                                 std::string snomaskstr = snomask->GetUserParameter(user);
153                                 // snomaskstr is empty if the snomask mode isn't set, otherwise it begins with a '+'.
154                                 // In the former case output a "+", not an empty string.
155                                 user->WriteServ("%03d %s %s%s :Server notice mask", RPL_SNOMASKIS, targetuser->nick.c_str(), (snomaskstr.empty() ? "+" : ""), snomaskstr.c_str());
156                         }
157                 }
158                 else
159                 {
160                         user->WriteNumeric(ERR_USERSDONTMATCH, "Can't view modes for other users");
161                 }
162         }
163 }