2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2019 Robby <robby@chatbelgie.be>
5 * Copyright (C) 2017-2018 Sadie Powell <sadie@witchery.services>
6 * Copyright (C) 2014, 2016 Attila Molnar <attilamolnar@hush.com>
8 * This file is part of InspIRCd. InspIRCd is free software: you can
9 * redistribute it and/or modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation, version 2.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 class CommandClearChan : public Command
30 CommandClearChan(Module* Creator)
31 : Command(Creator, "CLEARCHAN", 1, 3)
33 syntax = "<channel> [KILL|KICK|G|Z] [:<reason>]";
36 // Stop the linking mod from forwarding ENCAP'd CLEARCHAN commands, see below why
37 force_manual_route = true;
40 CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE
42 Channel* chan = activechan = ServerInstance->FindChan(parameters[0]);
45 user->WriteNotice("The channel " + parameters[0] + " does not exist.");
49 // See what method the oper wants to use, default to KILL
50 std::string method("KILL");
51 if (parameters.size() > 1)
53 method = parameters[1];
54 std::transform(method.begin(), method.end(), method.begin(), ::toupper);
57 XLineFactory* xlf = NULL;
58 bool kick = (method == "KICK");
59 if ((!kick) && (method != "KILL"))
61 if ((method != "Z") && (method != "G"))
63 user->WriteNotice("Invalid method for clearing " + chan->name);
67 xlf = ServerInstance->XLines->GetFactory(method);
72 const std::string reason = parameters.size() > 2 ? parameters.back() : "Clearing " + chan->name;
74 if (!user->server->IsSilentULine())
75 ServerInstance->SNO->WriteToSnoMask((IS_LOCAL(user) ? 'a' : 'A'), user->nick + " has cleared \002" + chan->name + "\002 (" + method + "): " + reason);
77 user->WriteNotice("Clearing \002" + chan->name + "\002 (" + method + "): " + reason);
80 // Route this command manually so it is sent before the QUITs we are about to generate.
81 // The idea is that by the time our QUITs reach the next hop, it has already removed all their
82 // clients from the channel, meaning victims on other servers won't see the victims on this
84 CommandBase::Params eparams;
85 eparams.push_back(chan->name);
86 eparams.push_back(method);
87 eparams.push_back(":");
88 eparams.back().append(reason);
89 ServerInstance->PI->BroadcastEncap(this->name, eparams, user, user);
92 // Attach to the appropriate hook so we're able to hide the QUIT/KICK messages
93 Implementation hook = (kick ? I_OnUserKick : I_OnBuildNeighborList);
94 ServerInstance->Modules->Attach(hook, creator);
97 // Now remove all local non-opers from the channel
98 Channel::MemberMap& users = chan->userlist;
99 for (Channel::MemberMap::iterator i = users.begin(); i != users.end(); )
101 User* curr = i->first;
102 const Channel::MemberMap::iterator currit = i;
105 if (!IS_LOCAL(curr) || curr->IsOper())
108 // If kicking users, remove them and skip the QuitUser()
111 chan->KickUser(ServerInstance->FakeClient, currit, reason);
115 // If we are banning users then create the XLine and add it
121 mask = ((method[0] == 'Z') ? curr->GetIPString() : "*@" + curr->GetRealHost());
122 xline = xlf->Generate(ServerInstance->Time(), 60*60, user->nick, reason, mask);
124 catch (ModuleException&)
126 // Nothing, move on to the next user
130 if (!ServerInstance->XLines->AddLine(xline, user))
134 ServerInstance->Users->QuitUser(curr, reason);
137 ServerInstance->Modules->Detach(hook, creator);
139 ServerInstance->XLines->ApplyLines();
145 class ModuleClearChan : public Module
147 CommandClearChan cmd;
155 void init() CXX11_OVERRIDE
157 // Only attached while we are working; don't react to events otherwise
158 ServerInstance->Modules->DetachAll(this);
161 void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE
164 for (IncludeChanList::iterator i = include.begin(); i != include.end(); ++i)
166 if ((*i)->chan == cmd.activechan)
168 // Don't show the QUIT to anyone in the channel by default
175 const Channel::MemberMap& users = cmd.activechan->GetUsers();
176 for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
178 LocalUser* curr = IS_LOCAL(i->first);
184 // If another module has removed the channel we're working on from the list of channels
185 // to consider for sending the QUIT to then don't add exceptions for opers, because the
186 // module before us doesn't want them to see it or added the exceptions already.
187 // If there is a value for this oper in excepts already, this won't overwrite it.
189 exception.insert(std::make_pair(curr, true));
192 else if (!include.empty() && curr->chans.size() > 1)
194 // This is a victim and potentially has another common channel with the user quitting,
195 // add a negative exception overwriting the previous value, if any.
196 exception[curr] = false;
201 void OnUserKick(User* source, Membership* memb, const std::string& reason, CUList& excepts) CXX11_OVERRIDE
203 // Hide the KICK from all non-opers
204 User* leaving = memb->user;
205 const Channel::MemberMap& users = memb->chan->GetUsers();
206 for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
208 User* curr = i->first;
209 if ((IS_LOCAL(curr)) && (!curr->IsOper()) && (curr != leaving))
210 excepts.insert(curr);
214 Version GetVersion() CXX11_OVERRIDE
216 return Version("Provides the CLEARCHAN command that allows opers to masskick, masskill or mass G/Z-line users on a channel", VF_VENDOR|VF_OPTCOMMON);
220 MODULE_INIT(ModuleClearChan)