From d43acc2381c7aef91f1557d9380243961be9496c Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Mon, 16 Feb 2026 23:17:40 +0000 Subject: [PATCH] Store modes as their object form in ModeStatus. This has the side effect of preventing users from putting nonsense modes in {botserv}:botmodes and other related fields. --- include/modes.h | 12 ++++++--- modules/chanserv/chanserv.cpp | 2 +- modules/chanserv/cs_updown.cpp | 4 +-- modules/nickserv/ns_recover.cpp | 2 +- modules/operserv/os_mode.cpp | 4 +-- modules/protocol/hybrid.cpp | 4 +-- modules/protocol/inspircd.cpp | 6 ++--- modules/protocol/ngircd.cpp | 4 +-- modules/protocol/plexus.cpp | 4 +-- modules/protocol/ratbox.cpp | 2 +- modules/protocol/unrealircd.cpp | 6 ++--- src/channels.cpp | 10 +++---- src/config.cpp | 2 +- src/modes.cpp | 46 +++++++++++++++++++-------------- 14 files changed, 60 insertions(+), 48 deletions(-) diff --git a/include/modes.h b/include/modes.h index 4113f63ae..f5a3f920e 100644 --- a/include/modes.h +++ b/include/modes.h @@ -263,16 +263,20 @@ public: /* The status a user has on a channel (+v, +h, +o) etc */ class CoreExport ChannelStatus final { - Anope::string modes; +private: + std::set modes; + static bool IsValidMode(ChannelMode *cm); + public: ChannelStatus() = default; ChannelStatus(const Anope::string &modes); void AddMode(char c); - void DelMode(char c); - bool HasMode(char c) const; + void AddMode(ChannelMode *cm); + void DelMode(ChannelMode *cm); + bool HasMode(ChannelMode *cm) const; bool Empty() const; void Clear(); - const Anope::string &Modes() const; + const auto &Modes() const { return modes; } Anope::string BuildModePrefixList() const; }; diff --git a/modules/chanserv/chanserv.cpp b/modules/chanserv/chanserv.cpp index 2bfafc31f..608066143 100644 --- a/modules/chanserv/chanserv.cpp +++ b/modules/chanserv/chanserv.cpp @@ -464,7 +464,7 @@ public: { auto *memb = c->FindUser(setter.GetUser()); ChannelMode *cm = ModeManager::FindChannelModeByName("OP"); - if (memb && cm && !memb->status.HasMode(cm->mchar)) + if (memb && cm && !memb->status.HasMode(cm)) { /* Our -o and their mode change crossing, bounce their mode */ c->RemoveMode(c->ci->WhoSends(), mode, data.value); diff --git a/modules/chanserv/cs_updown.cpp b/modules/chanserv/cs_updown.cpp index 023ad988d..717d8a6e2 100644 --- a/modules/chanserv/cs_updown.cpp +++ b/modules/chanserv/cs_updown.cpp @@ -143,8 +143,8 @@ class CommandCSDown final auto *memb = c->FindUser(u); if (memb != NULL) { - for (size_t i = memb->status.Modes().length(); i > 0;) - c->RemoveMode(NULL, ModeManager::FindChannelModeByChar(memb->status.Modes()[--i]), u->GetUID()); + for (auto *mode : memb->status.Modes()) + c->RemoveMode(NULL, mode, u->GetUID()); } } diff --git a/modules/nickserv/ns_recover.cpp b/modules/nickserv/ns_recover.cpp index c74ed6338..e5f93a547 100644 --- a/modules/nickserv/ns_recover.cpp +++ b/modules/nickserv/ns_recover.cpp @@ -292,7 +292,7 @@ public: if (it != ei->end()) { for (auto mode : it->second.Modes()) - c->SetMode(c->WhoSends(), ModeManager::FindChannelModeByChar(mode), u->GetUID()); + c->SetMode(c->WhoSends(), mode, u->GetUID()); ei->erase(it); if (ei->empty()) diff --git a/modules/operserv/os_mode.cpp b/modules/operserv/os_mode.cpp index 5414c8dbe..dc846ae5e 100644 --- a/modules/operserv/os_mode.cpp +++ b/modules/operserv/os_mode.cpp @@ -55,8 +55,8 @@ public: if (uc->user->HasMode("OPER")) continue; - for (size_t i = uc->status.Modes().length(); i > 0; --i) - c->RemoveMode(c->WhoSends(), ModeManager::FindChannelModeByChar(uc->status.Modes()[i - 1]), uc->user->GetUID(), false); + for (auto *mode : uc->status.Modes()) + c->RemoveMode(c->WhoSends(), mode, uc->user->GetUID(), false); } source.Reply(_("All modes cleared on %s."), c->name.c_str()); diff --git a/modules/protocol/hybrid.cpp b/modules/protocol/hybrid.cpp index 9fb47f785..41130aa1c 100644 --- a/modules/protocol/hybrid.cpp +++ b/modules/protocol/hybrid.cpp @@ -122,8 +122,8 @@ public: memb->status.Clear(); BotInfo *setter = BotInfo::Find(u->GetUID()); - for (auto mode : cs.Modes()) - c->SetMode(setter, ModeManager::FindChannelModeByChar(mode), u->GetUID(), false); + for (auto *mode : cs.Modes()) + c->SetMode(setter, mode, u->GetUID(), false); if (memb) memb->status = cs; diff --git a/modules/protocol/inspircd.cpp b/modules/protocol/inspircd.cpp index 20cb434c8..557d544fd 100644 --- a/modules/protocol/inspircd.cpp +++ b/modules/protocol/inspircd.cpp @@ -516,8 +516,8 @@ public: memb->status.Clear(); BotInfo *setter = BotInfo::Find(user->GetUID()); - for (auto mode : cs.Modes()) - c->SetMode(setter, ModeManager::FindChannelModeByChar(mode), user->GetUID(), false); + for (auto *mode : cs.Modes()) + c->SetMode(setter, mode, user->GetUID(), false); if (memb != NULL) memb->status = cs; @@ -845,7 +845,7 @@ namespace InspIRCdExtBan { auto *memb = c->FindUser(u); if (memb != NULL) - if (cm == NULL || memb->status.HasMode(cm->mchar)) + if (cm == NULL || memb->status.HasMode(cm)) return true; } diff --git a/modules/protocol/ngircd.cpp b/modules/protocol/ngircd.cpp index d36614cb6..cb046f677 100644 --- a/modules/protocol/ngircd.cpp +++ b/modules/protocol/ngircd.cpp @@ -105,8 +105,8 @@ public: memb->status.Clear(); BotInfo *setter = BotInfo::Find(user->GetUID()); - for (auto mode : cs.Modes()) - c->SetMode(setter, ModeManager::FindChannelModeByChar(mode), user->GetUID(), false); + for (auto *mode : cs.Modes()) + c->SetMode(setter, mode, user->GetUID(), false); if (memb != NULL) memb->status = cs; diff --git a/modules/protocol/plexus.cpp b/modules/protocol/plexus.cpp index 8aa3479eb..270ff0294 100644 --- a/modules/protocol/plexus.cpp +++ b/modules/protocol/plexus.cpp @@ -77,8 +77,8 @@ public: memb->status.Clear(); BotInfo *setter = BotInfo::Find(user->GetUID()); - for (auto mode : cs.Modes()) - c->SetMode(setter, ModeManager::FindChannelModeByChar(mode), user->GetUID(), false); + for (auto *mode : cs.Modes()) + c->SetMode(setter, mode, user->GetUID(), false); if (memb != NULL) memb->status = cs; diff --git a/modules/protocol/ratbox.cpp b/modules/protocol/ratbox.cpp index 9e5ed1347..cae567c27 100644 --- a/modules/protocol/ratbox.cpp +++ b/modules/protocol/ratbox.cpp @@ -134,7 +134,7 @@ public: { ChannelStatus status; - status.AddMode('o'); + status.AddMode(ModeManager::FindChannelModeByName("OP")); bi->Join(c, &status); } diff --git a/modules/protocol/unrealircd.cpp b/modules/protocol/unrealircd.cpp index 2629823ed..1c3030255 100644 --- a/modules/protocol/unrealircd.cpp +++ b/modules/protocol/unrealircd.cpp @@ -200,8 +200,8 @@ private: memb->status.Clear(); BotInfo *setter = BotInfo::Find(user->GetUID()); - for (auto mode : cs.Modes()) - c->SetMode(setter, ModeManager::FindChannelModeByChar(mode), user->GetUID(), false); + for (auto *mode : cs.Modes()) + c->SetMode(setter, mode, user->GetUID(), false); if (memb != NULL) memb->status = cs; @@ -554,7 +554,7 @@ namespace UnrealExtBan { auto *memb = c->FindUser(u); if (memb != NULL) - if (cm == NULL || memb->status.HasMode(cm->mchar)) + if (cm == NULL || memb->status.HasMode(cm)) return true; } diff --git a/src/channels.cpp b/src/channels.cpp index dbba66636..1bdd1dae9 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -77,8 +77,8 @@ void Channel::Reset() /* reset modes for my clients */ if (uc->user->server == Me) { - for (auto mode : f.Modes()) - this->SetMode(NULL, ModeManager::FindChannelModeByChar(mode), uc->user->GetUID(), false); + for (auto *mode : f.Modes()) + this->SetMode(NULL, mode, uc->user->GetUID(), false); /* Modes might not exist yet, so be sure the status is really reset */ uc->status = f; } @@ -182,7 +182,7 @@ bool Channel::HasUserStatus(User *u, ChannelModeStatus *cms) if (memb) { if (cms) - return memb->status.HasMode(cms->mchar); + return memb->status.HasMode(cms); else return memb->status.Empty(); } @@ -283,7 +283,7 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Mod /* Set the status on the user */ auto *memb = u->FindChannel(this); if (memb) - memb->status.AddMode(cm->mchar); + memb->status.AddMode(cm); FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, data)); @@ -354,7 +354,7 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const /* Remove the status on the user */ auto *memb = u->FindChannel(this); if (memb) - memb->status.DelMode(cm->mchar); + memb->status.DelMode(cm); FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm, param)); diff --git a/src/config.cpp b/src/config.cpp index b7ca41060..3ab46b1ec 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -386,7 +386,7 @@ Conf::Conf() : Block("") if (memb != NULL) { for (auto mode : memb->status.Modes()) - c->RemoveMode(bi, ModeManager::FindChannelModeByChar(mode), bi->GetUID()); + c->RemoveMode(bi, mode, bi->GetUID()); } /* Set the new modes */ for (char want_mode : want_modes) diff --git a/src/modes.cpp b/src/modes.cpp index 96212529a..698844fe6 100644 --- a/src/modes.cpp +++ b/src/modes.cpp @@ -64,24 +64,41 @@ struct StackerInfo final void AddMode(Mode *mode, bool set, const ModeData &data); }; -ChannelStatus::ChannelStatus(const Anope::string &m) : modes(m) +ChannelStatus::ChannelStatus(const Anope::string &m) { + for (const auto mc : m) + { + auto *cm = ModeManager::FindChannelModeByChar(mc); + if (IsValidMode(cm)) + AddMode(cm); + } +} + +bool ChannelStatus::IsValidMode(ChannelMode *cm) +{ + return cm && cm->type == MODE_STATUS; } void ChannelStatus::AddMode(char c) { - if (modes.find(c) == Anope::string::npos) - modes.append(c); + AddMode(ModeManager::FindChannelModeByChar(c)); } -void ChannelStatus::DelMode(char c) +void ChannelStatus::AddMode(ChannelMode *cm) { - modes = modes.replace_all_cs(c, ""); + if (IsValidMode(cm)) + modes.insert(cm); } -bool ChannelStatus::HasMode(char c) const +void ChannelStatus::DelMode(ChannelMode *cm) { - return modes.find(c) != Anope::string::npos; + if (IsValidMode(cm)) + modes.erase(cm); +} + +bool ChannelStatus::HasMode(ChannelMode *cm) const +{ + return IsValidMode(cm) && modes.find(cm) != modes.end(); } bool ChannelStatus::Empty() const @@ -94,23 +111,14 @@ void ChannelStatus::Clear() modes.clear(); } -const Anope::string &ChannelStatus::Modes() const -{ - return modes; -} - Anope::string ChannelStatus::BuildModePrefixList() const { Anope::string ret; - for (auto mode : modes) + for (const auto *cm : modes) { - ChannelMode *cm = ModeManager::FindChannelModeByChar(mode); - if (cm != NULL && cm->type == MODE_STATUS) - { - ChannelModeStatus *cms = anope_dynamic_static_cast(cm); - ret += cms->symbol; - } + const auto *cms = anope_dynamic_static_cast(cm); + ret += cms->symbol; } return ret;