From 889d521e05f2e922683d48c74eb00290e7a2f548 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 17 Jul 2024 00:06:50 +0100 Subject: Shuffle the modules about a bit. --- modules/remove.cpp | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 modules/remove.cpp (limited to 'modules/remove.cpp') diff --git a/modules/remove.cpp b/modules/remove.cpp new file mode 100644 index 000000000..f8b583e31 --- /dev/null +++ b/modules/remove.cpp @@ -0,0 +1,182 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2017 B00mX0r + * Copyright (C) 2013, 2018-2023 Sadie Powell + * Copyright (C) 2012-2014 Attila Molnar + * Copyright (C) 2012 Robby + * Copyright (C) 2012 Justin Crawford + * Copyright (C) 2009 Uli Schlachter + * Copyright (C) 2009 Daniel De Graaf + * Copyright (C) 2008 Thomas Stagner + * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2006 Oliver Lupton + * Copyright (C) 2005-2006, 2010 Craig Edwards + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "inspircd.h" +#include "modules/isupport.h" +#include "numerichelper.h" + +class CommandRemove final + : public Command +{ +private: + ChanModeReference nokicksmode; + UserModeReference servprotectmode; + +public: + ModeHandler::Rank protectedrank; + bool supportnokicks; + + CommandRemove(Module* Creator) + : Command(Creator, "REMOVE", 2, 3) + , nokicksmode(Creator, "nokick") + , servprotectmode(Creator, "servprotect") + { + syntax = { " [:]" }; + translation = { TR_TEXT, TR_NICK, TR_TEXT }; + } + + CmdResult Handle(User* user, const CommandBase::Params& parameters) override + { + // Keep compatibility with v3 servers by allowing them to send removes with the old order. + bool neworder = !IS_LOCAL(user) && ServerInstance->Channels.IsPrefix(parameters[0][0]); + const std::string& channame = parameters[neworder ? 0 : 1]; + const std::string& username = parameters[neworder ? 1 : 0]; + + /* Look up the user we're meant to be removing from the channel */ + User* target; + if (IS_LOCAL(user)) + target = ServerInstance->Users.FindNick(username, true); + else + target = ServerInstance->Users.Find(username, true); + + /* And the channel we're meant to be removing them from */ + auto* channel = ServerInstance->Channels.Find(channame); + + /* Fix by brain - someone needs to learn to validate their input! */ + if (!channel) + { + user->WriteNumeric(Numerics::NoSuchChannel(channame)); + return CmdResult::FAILURE; + } + if (!target) + { + user->WriteNumeric(Numerics::NoSuchNick(username)); + return CmdResult::FAILURE; + } + + if (!channel->HasUser(target)) + { + user->WriteNotice(fmt::format("*** User {} is not on channel {}", target->nick, channel->name)); + return CmdResult::FAILURE; + } + + if (target->IsModeSet(servprotectmode)) + { + user->WriteNumeric(ERR_RESTRICTED, channame, "Only a service may remove a service from a channel."); + return CmdResult::FAILURE; + } + + /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */ + if ((!IS_LOCAL(user)) || (!supportnokicks) || (!channel->IsModeSet(nokicksmode))) + { + /* We'll let everyone remove their level and below, eg: + * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1) + * a services target will get a higher level than it's possible for a /remover to get..so they're safe. + * Nobody may remove people with >= protectedrank rank. + */ + ModeHandler::Rank ulevel = channel->GetPrefixValue(user); + ModeHandler::Rank tlevel = channel->GetPrefixValue(target); + if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && ((protectedrank == 0) || (tlevel < protectedrank)))) + { + // REMOVE will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command) + if (!IS_LOCAL(target)) + { + CommandBase::Params p; + p.push_back(channel->name); + p.push_back(target->uuid); + if (parameters.size() > 2) + p.push_back(":" + parameters[2]); + ServerInstance->PI->SendEncapsulatedData(target->server->GetName(), "REMOVE", p, user); + + return CmdResult::SUCCESS; + } + + std::string reasonparam; + + /* If a reason is given, use it */ + if(parameters.size() > 2) + reasonparam = parameters[2]; + else + reasonparam = "No reason given"; + + /* Build up the part reason string. */ + std::string reason = "Removed by " + user->nick + ": " + reasonparam; + + channel->WriteRemoteNotice(fmt::format("{} removed {} from the channel", user->nick, target->nick)); + target->WriteNotice("*** " + user->nick + " removed you from " + channel->name + " with the message: " + reasonparam); + + channel->PartUser(target, reason); + } + else + { + user->WriteNotice(fmt::format("*** You do not have access to /REMOVE {} from {}", target->nick, channel->name)); + return CmdResult::FAILURE; + } + } + else + { + /* m_nokicks.so was loaded and +Q was set, block! */ + user->WriteNumeric(ERR_RESTRICTED, channel->name, fmt::format("Can't remove user {} from channel (+{} is set)", + target->nick, servprotectmode->GetModeChar())); + return CmdResult::FAILURE; + } + + return CmdResult::SUCCESS; + } +}; + +class ModuleRemove final + : public Module + , public ISupport::EventListener +{ +private: + CommandRemove cmd; + +public: + ModuleRemove() + : Module(VF_VENDOR | VF_OPTCOMMON, "Adds the /REMOVE command which allows channel operators to force part users from a channel.") + , ISupport::EventListener(this) + , cmd(this) + { + } + + void OnBuildISupport(ISupport::TokenMap& tokens) override + { + tokens["REMOVE"]; + } + + void ReadConfig(ConfigStatus& status) override + { + const auto& tag = ServerInstance->Config->ConfValue("remove"); + cmd.supportnokicks = tag->getBool("supportnokicks"); + cmd.protectedrank = tag->getNum("protectedrank", 50000, 1); + } +}; + +MODULE_INIT(ModuleRemove) -- cgit v1.3.1-10-gc9f91