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/namedmodes.cpp | 207 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 modules/namedmodes.cpp (limited to 'modules/namedmodes.cpp') diff --git a/modules/namedmodes.cpp b/modules/namedmodes.cpp new file mode 100644 index 000000000..31a82a1c4 --- /dev/null +++ b/modules/namedmodes.cpp @@ -0,0 +1,207 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2021 Herman + * Copyright (C) 2018-2023 Sadie Powell + * Copyright (C) 2017 B00mX0r + * Copyright (C) 2013-2016 Attila Molnar + * Copyright (C) 2012 Robby + * Copyright (C) 2009-2010 Daniel De Graaf + * + * 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 "numericbuilder.h" +#include "numerichelper.h" + +enum +{ + // InspIRCd-specific. + RPL_ENDOFPROPLIST = 960, + RPL_PROPLIST = 961 +}; + +static void DisplayList(LocalUser* user, Channel* channel) +{ + Numeric::ParamBuilder<1> numeric(user, RPL_PROPLIST); + numeric.AddStatic(channel->name); + + for (const auto& [_, mh] : ServerInstance->Modes.GetModes(MODETYPE_CHANNEL)) + { + if (!channel->IsModeSet(mh)) + continue; + + numeric.Add("+" + mh->name); + ParamModeBase* pm = mh->IsParameterMode(); + if (pm) + { + if ((pm->IsParameterSecret()) && (!channel->HasUser(user)) && (!user->HasPrivPermission("channels/auspex"))) + numeric.Add("<" + mh->name + ">"); + else + numeric.Add(channel->GetModeParameter(mh)); + } + } + numeric.Flush(); + user->WriteNumeric(RPL_ENDOFPROPLIST, channel->name, "End of mode list"); +} + +class CommandProp final + : public SplitCommand +{ +public: + CommandProp(Module* parent) + : SplitCommand(parent, "PROP", 1) + { + syntax = { " [[(+|-)] []]" }; + } + + CmdResult HandleLocal(LocalUser* src, const Params& parameters) override + { + Channel* const chan = ServerInstance->Channels.Find(parameters[0]); + if (!chan) + { + src->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); + return CmdResult::FAILURE; + } + + if (parameters.size() == 1) + { + DisplayList(src, chan); + return CmdResult::SUCCESS; + } + unsigned int i = 1; + Modes::ChangeList modes; + while (i < parameters.size()) + { + std::string prop = parameters[i++]; + if (prop.empty()) + continue; + bool plus = prop[0] != '-'; + if (prop[0] == '+' || prop[0] == '-') + prop.erase(prop.begin()); + + ModeHandler* mh = ServerInstance->Modes.FindMode(prop, MODETYPE_CHANNEL); + if (mh) + { + if (mh->NeedsParam(plus)) + { + if (i != parameters.size()) + modes.push(mh, plus, parameters[i++]); + } + else + modes.push(mh, plus); + } + } + ServerInstance->Modes.ProcessSingle(src, chan, nullptr, modes, ModeParser::MODE_CHECKACCESS); + return CmdResult::SUCCESS; + } +}; + +class DummyZ final + : public ModeHandler +{ +public: + DummyZ(Module* parent) + : ModeHandler(parent, "namebase", 'Z', PARAM_ALWAYS, MODETYPE_CHANNEL) + { + list = true; + } + + // Handle /MODE #chan Z + void DisplayList(User* user, Channel* chan) override + { + LocalUser* luser = IS_LOCAL(user); + if (luser) + ::DisplayList(luser, chan); + } +}; + +class ModuleNamedModes final + : public Module +{ +private: + CommandProp cmd; + DummyZ dummyZ; + +public: + ModuleNamedModes() + : Module(VF_VENDOR, "Provides support for adding and removing modes via their long names.") + , cmd(this) + , dummyZ(this) + { + } + + void Prioritize() override + { + ServerInstance->Modules.SetPriority(this, I_OnPreMode, PRIORITY_FIRST); + } + + ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) override + { + if (!channel) + return MOD_RES_PASSTHRU; + + Modes::ChangeList::List& list = modes.getlist(); + for (Modes::ChangeList::List::iterator i = list.begin(); i != list.end(); ) + { + Modes::Change& curr = *i; + // Replace all namebase (dummyZ) modes being changed with the actual + // mode handler and parameter. The parameter format of the namebase mode is + // [=]. + if (curr.mh == &dummyZ) + { + std::string name = curr.param; + std::string value; + std::string::size_type eq = name.find('='); + if (eq != std::string::npos) + { + value.assign(name, eq + 1, std::string::npos); + name.erase(eq); + } + + ModeHandler* mh = ServerInstance->Modes.FindMode(name, MODETYPE_CHANNEL); + if (!mh) + { + // Mode handler not found + i = list.erase(i); + continue; + } + + curr.param.clear(); + if (mh->NeedsParam(curr.adding)) + { + if (value.empty()) + { + // Mode needs a parameter but there wasn't one + i = list.erase(i); + continue; + } + + // Change parameter to the text after the '=' + curr.param = std::move(value); + } + + // Put the actual ModeHandler in place of the namebase handler + curr.mh = mh; + } + + ++i; + } + + return MOD_RES_PASSTHRU; + } +}; + +MODULE_INIT(ModuleNamedModes) -- cgit v1.3.1-10-gc9f91