From 2468fc2582a2f8ac0b69b7d9e2cfb511e700f2eb Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Tue, 22 Mar 2022 17:05:30 +0000 Subject: Fix our WHO oplevels being incompatible with the WHOX spec. Unlike in InspIRCd where 0 is an unprivileged member and higher levels grant more privileges the WHOX spec defines the oplevel field as using n/a for unprivileged users and the lower an oplevel is the more privileges it grants. InspIRCd also uses values between 0 and UINT_MAX whereas WHOX only uses values between 0 and 999. In order to work around this we now lazily build dummy oplevels for the InspIRCd member ranks. --- src/coremods/core_who.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/coremods/core_who.cpp b/src/coremods/core_who.cpp index b853ef4b1..a459b49d3 100644 --- a/src/coremods/core_who.cpp +++ b/src/coremods/core_who.cpp @@ -120,6 +120,33 @@ class CommandWho : public SplitCommand UserModeReference invisiblemode; Events::ModuleEventProvider whoevprov; + void BuildOpLevels() + { + // Build a map of prefixes ordered descending by their rank. + std::multimap > ranks; + const ModeParser::PrefixModeList& modes = ServerInstance->Modes.GetPrefixModes(); + for (ModeParser::PrefixModeList::const_iterator iter = modes.begin(); iter != modes.end(); ++iter) + { + const PrefixMode* pm = *iter; + ranks.insert(std::make_pair(pm->GetPrefixRank(), pm)); + } + + // Now we have the ranks ordered we can assign them levels. + unsigned int lastrank; + unsigned int oplevel = 0; + for (std::multimap::const_iterator iter = ranks.begin(); iter != ranks.end(); ++iter) + { + const PrefixMode* pm = iter->second; + if (iter != ranks.begin() && pm->GetPrefixRank() != lastrank) + oplevel++; // Keep the same op level for modes with the same prefix rank. + + lastrank = pm->GetPrefixRank(); + oplevels[pm->GetModeChar()] = ConvToStr(oplevel); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Assigned oplevel %u to the %c (%s) prefix mode.", + oplevel, pm->GetModeChar(), pm->name.c_str()); + } + } + /** Determines whether a user can view the users of a channel. */ bool CanView(Channel* chan, User* user) { @@ -168,6 +195,8 @@ class CommandWho : public SplitCommand void WhoUsers(LocalUser* source, const std::vector& parameters, const T& users, WhoData& data); public: + insp::flat_map oplevels; + CommandWho(Module* parent) : SplitCommand(parent, "WHO", 1, 3) , secretmode(parent, "secret") @@ -496,7 +525,14 @@ void CommandWho::SendWhoLine(LocalUser* source, const std::vector& // Include the user's operator rank level. if (data.whox_fields['o']) - wholine.push(memb ? ConvToStr(memb->getRank()) : "0"); + { + // If we haven't built a table to convert from InspIRCd member + // ranks to WHOX oplevels yet we need to do that here. + if (oplevels.empty()) + BuildOpLevels(); + + wholine.push(memb && memb->getRank() ? oplevels[memb->GetPrefixChar()] : "n/a"); + } // Include the user's real name. if (data.whox_fields['r']) @@ -598,6 +634,18 @@ class CoreModWho : public Module tokens["WHOX"]; } + void OnServiceAdd(ServiceProvider& provider) CXX11_OVERRIDE + { + // If the service is a prefix mode we need to rebuild the oplevel map. + if (provider.service == SERVICE_MODE && static_cast(provider).IsPrefixMode()) + cmd.oplevels.clear(); + } + + void OnServiceDel(ServiceProvider& provider) CXX11_OVERRIDE + { + this->OnServiceAdd(provider); + } + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the WHO command", VF_VENDOR|VF_CORE); -- cgit v1.3.1-10-gc9f91