]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_channel/cmd_kick.cpp
Merge tag 'v2.0.26' into master.
[user/henk/code/inspircd.git] / src / coremods / core_channel / cmd_kick.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #include "inspircd.h"
22 #include "core_channel.h"
23
24 CommandKick::CommandKick(Module* parent)
25         : Command(parent, "KICK", 2, 3)
26 {
27         syntax = "<channel> <nick>{,<nick>} [<reason>]";
28 }
29
30 /** Handle /KICK
31  */
32 CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User *user)
33 {
34         Channel* c = ServerInstance->FindChan(parameters[0]);
35         User* u;
36
37         if (CommandParser::LoopCall(user, this, parameters, 1))
38                 return CMD_SUCCESS;
39
40         if (IS_LOCAL(user))
41                 u = ServerInstance->FindNickOnly(parameters[1]);
42         else
43                 u = ServerInstance->FindNick(parameters[1]);
44
45         if (!c)
46         {
47                 user->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
48                 return CMD_FAILURE;
49         }
50         if ((!u) || (u->registered != REG_ALL))
51         {
52                 user->WriteNumeric(Numerics::NoSuchNick(parameters[1]));
53                 return CMD_FAILURE;
54         }
55
56         Membership* srcmemb = NULL;
57         if (IS_LOCAL(user))
58         {
59                 srcmemb = c->GetUser(user);
60                 if (!srcmemb)
61                 {
62                         user->WriteNumeric(ERR_NOTONCHANNEL, parameters[0], "You're not on that channel!");
63                         return CMD_FAILURE;
64                 }
65
66                 if (u->server->IsULine())
67                 {
68                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, "You may not kick a u-lined client");
69                         return CMD_FAILURE;
70                 }
71         }
72
73         const Channel::MemberMap::iterator victimiter = c->userlist.find(u);
74         if (victimiter == c->userlist.end())
75         {
76                 user->WriteNumeric(ERR_USERNOTINCHANNEL, u->nick, c->name, "They are not on that channel");
77                 return CMD_FAILURE;
78         }
79         Membership* const memb = victimiter->second;
80
81         // KICKs coming from servers can carry a membership id
82         if ((!IS_LOCAL(user)) && (parameters.size() > 3))
83         {
84                 // If the current membership id is not equal to the one in the message then the user rejoined
85                 if (memb->id != Membership::IdFromString(parameters[2]))
86                 {
87                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Dropped KICK due to membership id mismatch: " + ConvToStr(memb->id) + " != " + parameters[2]);
88                         return CMD_FAILURE;
89                 }
90         }
91
92         const bool has_reason = (parameters.size() > 2);
93         const std::string reason((has_reason ? parameters.back() : user->nick), 0, ServerInstance->Config->Limits.MaxKick);
94
95         // Do the following checks only if the KICK is done by a local user;
96         // each server enforces its own rules.
97         if (srcmemb)
98         {
99                 // Modules are allowed to explicitly allow or deny kicks done by local users
100                 ModResult res;
101                 FIRST_MOD_RESULT(OnUserPreKick, res, (user, memb, reason));
102                 if (res == MOD_RES_DENY)
103                         return CMD_FAILURE;
104
105                 if (res == MOD_RES_PASSTHRU)
106                 {
107                         unsigned int them = srcmemb->getRank();
108                         unsigned int req = HALFOP_VALUE;
109                         for (std::string::size_type i = 0; i < memb->modes.length(); i++)
110                         {
111                                 ModeHandler* mh = ServerInstance->Modes->FindMode(memb->modes[i], MODETYPE_CHANNEL);
112                                 if (mh && mh->GetLevelRequired(true) > req)
113                                         req = mh->GetLevelRequired(true);
114                         }
115
116                         if (them < req)
117                         {
118                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, InspIRCd::Format("You must be a channel %soperator",
119                                         req > HALFOP_VALUE ? "" : "half-"));
120                                 return CMD_FAILURE;
121                         }
122                 }
123         }
124
125         c->KickUser(user, victimiter, reason);
126
127         return CMD_SUCCESS;
128 }
129
130 RouteDescriptor CommandKick::GetRouting(User* user, const std::vector<std::string>& parameters)
131 {
132         return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
133 }