/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019 linuxdaemon * Copyright (C) 2013, 2018-2021 Sadie Powell * Copyright (C) 2012-2016 Attila Molnar * Copyright (C) 2012, 2019 Robby * Copyright (C) 2009-2010 Daniel De Graaf * Copyright (C) 2007 Dennis Friis * Copyright (C) 2006, 2008 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/cap.h" #include "modules/names.h" #include "modules/who.h" #include "modules/whois.h" class ModuleNamesX final : public Module , public Names::EventListener , public Who::EventListener , public Whois::LineEventListener { private: Cap::Capability cap; public: ModuleNamesX() : Module(VF_VENDOR, "Provides the IRCv3 multi-prefix client capability.") , Names::EventListener(this) , Who::EventListener(this) , Whois::LineEventListener(this) , cap(this, "multi-prefix") { } ModResult OnNamesListItem(LocalUser* issuer, Membership* memb, std::string& prefixes, std::string& nick) override { if (cap.IsEnabled(issuer)) prefixes = memb->GetAllPrefixChars(); return MOD_RES_PASSTHRU; } ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) override { if ((!memb) || (!cap.IsEnabled(source))) return MOD_RES_PASSTHRU; // Don't do anything if the user has only one prefix if (memb->modes.size() <= 1) return MOD_RES_PASSTHRU; size_t flag_index; if (!request.GetFieldIndex('f', flag_index)) return MOD_RES_PASSTHRU; // #chan ident localhost insp22.test nick H@ :0 Attila if (numeric.GetParams().size() <= flag_index) return MOD_RES_PASSTHRU; numeric.GetParams()[flag_index].append(memb->GetAllPrefixChars(), 1, std::string::npos); return MOD_RES_PASSTHRU; } ModResult OnWhoisLine(Whois::Context& whois, Numeric::Numeric& numeric) override { if (numeric.GetNumeric() != RPL_WHOISCHANNELS || !cap.IsEnabled(whois.GetSource())) return MOD_RES_PASSTHRU; // :testnet.inspircd.org 319 test Sadie :#test ~#inspircd if (numeric.GetParams().size() < 2 || numeric.GetParams().back().empty()) return MOD_RES_PASSTHRU; std::stringstream newchannels; irc::spacesepstream channelstream(numeric.GetParams().back()); for (std::string channel; channelstream.GetToken(channel); ) { size_t hashpos = channel.find('#'); if (!hashpos || hashpos == std::string::npos) { // The entry is malformed or the user has no privs. newchannels << channel << ' '; continue; } auto* chan = ServerInstance->Channels.Find(channel.substr(hashpos)); if (!chan) { // Should never happen. newchannels << channel << ' '; continue; } Membership* memb = chan->GetUser(whois.GetTarget()); if (!memb) { // Should never happen. newchannels << channel << ' '; continue; } newchannels << memb->GetAllPrefixChars() << chan->name << ' '; } numeric.GetParams().back() = newchannels.str(); return MOD_RES_PASSTHRU; } }; MODULE_INIT(ModuleNamesX)