diff options
author | Sadie Powell <sadie@witchery.services> | 2025-05-03 17:07:07 +0100 |
---|---|---|
committer | Sadie Powell <sadie@witchery.services> | 2025-05-03 21:28:56 +0100 |
commit | 010beb52b1f3c697a07f9a130d2ed9335fe1cd98 (patch) | |
tree | 734750a5677afff443f2117dc34ba14d3351fb28 | |
parent | c95594141346ef6fb65a5af177bed35ed865234d (diff) |
Store the setter and ts for all modes and try to restore them.
This is mostly for preserving channel list mode info.
-rw-r--r-- | include/account.h | 2 | ||||
-rw-r--r-- | include/channels.h | 14 | ||||
-rw-r--r-- | include/defs.h | 1 | ||||
-rw-r--r-- | include/modes.h | 23 | ||||
-rw-r--r-- | include/modules.h | 4 | ||||
-rw-r--r-- | include/protocol.h | 2 | ||||
-rw-r--r-- | include/users.h | 14 | ||||
-rw-r--r-- | modules/botserv/botserv.cpp | 6 | ||||
-rw-r--r-- | modules/chanserv/chanserv.cpp | 6 | ||||
-rw-r--r-- | modules/chanserv/cs_mode.cpp | 2 | ||||
-rw-r--r-- | modules/chanserv/cs_set.cpp | 47 | ||||
-rw-r--r-- | modules/chanstats.cpp | 2 | ||||
-rw-r--r-- | modules/database/db_atheme.cpp | 8 | ||||
-rw-r--r-- | modules/helpchan.cpp | 4 | ||||
-rw-r--r-- | modules/irc2sql/irc2sql.cpp | 4 | ||||
-rw-r--r-- | modules/irc2sql/irc2sql.h | 2 | ||||
-rw-r--r-- | modules/nickserv/ns_set_keepmodes.cpp | 45 | ||||
-rw-r--r-- | modules/operserv/os_defcon.cpp | 4 | ||||
-rw-r--r-- | modules/operserv/os_mode.cpp | 4 | ||||
-rw-r--r-- | modules/protocol/inspircd.cpp | 47 | ||||
-rw-r--r-- | modules/rpc/rpc_data.cpp | 12 | ||||
-rw-r--r-- | src/channels.cpp | 97 | ||||
-rw-r--r-- | src/modes.cpp | 124 | ||||
-rw-r--r-- | src/protocol.cpp | 61 | ||||
-rw-r--r-- | src/servers.cpp | 4 | ||||
-rw-r--r-- | src/users.cpp | 20 |
26 files changed, 341 insertions, 218 deletions
diff --git a/include/account.h b/include/account.h index be130ea95..947daeff6 100644 --- a/include/account.h +++ b/include/account.h @@ -151,7 +151,7 @@ public: /* The time this account was registered */ time_t registered = Anope::CurTime; MemoInfo memos; - std::map<Anope::string, Anope::string> last_modes; + std::map<Anope::string, ModeData> last_modes; /* Nicknames registered that are grouped to this account. * for n in aliases, n->nc == this. diff --git a/include/channels.h b/include/channels.h index 9d1c5b738..155feadb2 100644 --- a/include/channels.h +++ b/include/channels.h @@ -36,7 +36,7 @@ class CoreExport Channel final static std::vector<Channel *> deleting; public: - typedef std::multimap<Anope::string, Anope::string> ModeList; + typedef std::multimap<Anope::string, ModeData> ModeList; private: /** A map of channel modes with their parameters set on this channel */ @@ -148,10 +148,10 @@ public: /** Set a mode internally on a channel, this is not sent out to the IRCd * @param setter The setter * @param cm The mode - * @param param The param + * @param data Data about the mode. * @param enforce_mlock true if mlocks should be enforced, false to override mlock */ - void SetModeInternal(MessageSource &source, ChannelMode *cm, const Anope::string ¶m = "", bool enforce_mlock = true); + void SetModeInternal(MessageSource &source, ChannelMode *cm, const ModeData &data = {}, bool enforce_mlock = true); /** Remove a mode internally on a channel, this is not sent out to the IRCd * @param setter The Setter @@ -164,19 +164,19 @@ public: /** Set a mode on a channel * @param bi The client setting the modes * @param cm The mode - * @param param Optional param arg for the mode + * @param data Data about the mode * @param enforce_mlock true if mlocks should be enforced, false to override mlock */ - void SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m = "", bool enforce_mlock = true); + void SetMode(BotInfo *bi, ChannelMode *cm, const ModeData &data = {}, bool enforce_mlock = true); /** * Set a mode on a channel * @param bi The client setting the modes * @param name The mode name - * @param param Optional param arg for the mode + * @param data Data about the mode * @param enforce_mlock true if mlocks should be enforced, false to override mlock */ - void SetMode(BotInfo *bi, const Anope::string &name, const Anope::string ¶m = "", bool enforce_mlock = true); + void SetMode(BotInfo *bi, const Anope::string &name, const ModeData &data = {}, bool enforce_mlock = true); /** Remove a mode from a channel * @param bi The client setting the modes diff --git a/include/defs.h b/include/defs.h index 2286a8e41..31de70c60 100644 --- a/include/defs.h +++ b/include/defs.h @@ -19,6 +19,7 @@ class ChanAccess; class Channel; class ChannelInfo; class ChannelStatus; +struct ModeData; struct ChanUserContainer; class ClientSocket; class Command; diff --git a/include/modes.h b/include/modes.h index db84a64fe..3052ab00b 100644 --- a/include/modes.h +++ b/include/modes.h @@ -33,6 +33,20 @@ enum ModeClass MC_USER }; +struct ModeData final +{ + Anope::string value; + Anope::string set_by; + time_t set_at; + + ModeData(const Anope::string &v = "", const Anope::string &s = "", time_t t = 0) + : value(v) + , set_by(s) + , set_at(t) + { + } +}; + /** This class is the basis of all modes in Anope */ class CoreExport Mode @@ -311,6 +325,7 @@ public: class CoreExport ModeManager final { public: + using Change = std::multimap<Mode *, std::pair<bool, ModeData>>; /* Number of generic channel and user modes we are tracking */ static unsigned GenericChannelModes; @@ -378,18 +393,18 @@ public: * @param c The channel * @param cm The channel mode * @param set true for setting, false for removing - * @param param The param, if there is one + * @param data Data about the mode. */ - static void StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool set, const Anope::string ¶m = ""); + static void StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool set, const ModeData &data = {}); /** Add a mode to the stacker to be set on a user * @param bi The client to set the modes from * @param u The user * @param um The user mode * @param set true for setting, false for removing - * @param param The param, if there is one + * @param data Data about the mode. */ - static void StackerAdd(BotInfo *bi, User *u, UserMode *um, bool set, const Anope::string ¶m = ""); + static void StackerAdd(BotInfo *bi, User *u, UserMode *um, bool set, const ModeData &data = {}); /** Process all of the modes in the stacker and send them to the IRCd to be set on channels/users */ diff --git a/include/modules.h b/include/modules.h index 7aaf5e2ab..03f5fe837 100644 --- a/include/modules.h +++ b/include/modules.h @@ -871,10 +871,10 @@ public: * @param c The channel * @param setter The user or server that is setting the mode * @param mode The mode - * @param param The mode param, if there is one + * @param data Data about the mode. * @return EVENT_STOP to make mlock/secureops etc checks not happen */ - virtual EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) ATTR_NOT_NULL(2, 4) { throw NotImplementedException(); } + virtual EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) ATTR_NOT_NULL(2, 4) { throw NotImplementedException(); } /** Called when a mode is unset on a channel * @param c The channel diff --git a/include/protocol.h b/include/protocol.h index ec090090a..40312874d 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -195,8 +195,10 @@ public: */ virtual void SendSVSKill(const MessageSource &source, User *user, const Anope::string &msg); + virtual void SendMode(const MessageSource &source, Channel *chan, const ModeManager::Change &change); virtual void SendModeInternal(const MessageSource &source, Channel *chan, const Anope::string &modes, const std::vector<Anope::string> &values); + virtual void SendMode(const MessageSource &source, User *u, const ModeManager::Change &change); virtual void SendModeInternal(const MessageSource &source, User *u, const Anope::string &modes, const std::vector<Anope::string> &values); /** Introduces a client to the rest of the network diff --git a/include/users.h b/include/users.h index 2a5823cc5..08fa339b2 100644 --- a/include/users.h +++ b/include/users.h @@ -39,7 +39,7 @@ class CoreExport User static std::list<User *> quitting_users; public: - typedef std::map<Anope::string, Anope::string> ModeList; + typedef std::map<Anope::string, ModeData> ModeList; protected: Anope::string vident; Anope::string ident; @@ -261,9 +261,9 @@ public: /** Set a mode internally on the user, the IRCd is not informed * @param setter who/what is setting the mode * @param um The user mode - * @param Param The param, if there is one + * @param data Data about the mode. */ - void SetModeInternal(const MessageSource &setter, UserMode *um, const Anope::string ¶m = ""); + void SetModeInternal(const MessageSource &setter, UserMode *um, const ModeData &data = {}); /** Remove a mode internally on the user, the IRCd is not informed * @param setter who/what is setting the mode @@ -274,16 +274,16 @@ public: /** Set a mode on the user * @param bi The client setting the mode * @param um The user mode - * @param Param Optional param for the mode + * @param data Data about the mode */ - void SetMode(BotInfo *bi, UserMode *um, const Anope::string ¶m = ""); + void SetMode(BotInfo *bi, UserMode *um, const ModeData &data = {}); /** Set a mode on the user * @param bi The client setting the mode * @param name The mode name - * @param Param Optional param for the mode + * @param data Data about the mode */ - void SetMode(BotInfo *bi, const Anope::string &name, const Anope::string ¶m = ""); + void SetMode(BotInfo *bi, const Anope::string &name, const ModeData &data = {}); /** Remove a mode on the user * @param bi The client setting the mode diff --git a/modules/botserv/botserv.cpp b/modules/botserv/botserv.cpp index 99e2c9134..2b251b67b 100644 --- a/modules/botserv/botserv.cpp +++ b/modules/botserv/botserv.cpp @@ -196,15 +196,15 @@ public: } } - EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string ¶m) override + EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const ModeData &data) override { if (source.GetUser() && !source.GetBot() && Config->GetModule(this).Get<bool>("smartjoin") && mode->name == "BAN" && c->ci && c->ci->bi && c->FindUser(c->ci->bi)) { BotInfo *bi = c->ci->bi; - Entry ban("BAN", param); + Entry ban("BAN", data.value); if (ban.Matches(bi)) - c->RemoveMode(bi, "BAN", param); + c->RemoveMode(bi, "BAN", data.value); } return EVENT_CONTINUE; diff --git a/modules/chanserv/chanserv.cpp b/modules/chanserv/chanserv.cpp index 8f3ec68e4..259a92842 100644 --- a/modules/chanserv/chanserv.cpp +++ b/modules/chanserv/chanserv.cpp @@ -309,7 +309,7 @@ public: return; if (c->ci) - c->SetMode(c->ci->WhoSends(), "REGISTERED", "", false); + c->SetMode(c->ci->WhoSends(), "REGISTERED", {}, false); else c->RemoveMode(c->WhoSends(), "REGISTERED", "", false); @@ -461,7 +461,7 @@ public: } } - EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) override + EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override { if (!always_lower && Anope::CurTime == c->created && c->ci && setter.GetUser() && !setter.GetUser()->server->IsULined()) { @@ -470,7 +470,7 @@ public: if (cu && cm && !cu->status.HasMode(cm->mchar)) { /* Our -o and their mode change crossing, bounce their mode */ - c->RemoveMode(c->ci->WhoSends(), mode, param); + c->RemoveMode(c->ci->WhoSends(), mode, data.value); /* We don't set mlocks until after the join has finished processing, it will stack with this change, * so there isn't much for the user to remove except -nt etc which is likely locked anyway. */ diff --git a/modules/chanserv/cs_mode.cpp b/modules/chanserv/cs_mode.cpp index 26741654f..d6339311e 100644 --- a/modules/chanserv/cs_mode.cpp +++ b/modules/chanserv/cs_mode.cpp @@ -1008,7 +1008,7 @@ public: if (cm->type == MODE_REGULAR) { if (!c->HasMode(cm->name) && ml->set) - c->SetMode(NULL, cm, "", false); + c->SetMode(NULL, cm, {}, false); else if (c->HasMode(cm->name) && !ml->set) c->RemoveMode(NULL, cm, "", false); } diff --git a/modules/chanserv/cs_set.cpp b/modules/chanserv/cs_set.cpp index d3236ea77..8761a3c47 100644 --- a/modules/chanserv/cs_set.cpp +++ b/modules/chanserv/cs_set.cpp @@ -1121,13 +1121,19 @@ class CSSet final const ChannelInfo *ci = anope_dynamic_static_cast<const ChannelInfo *>(s); Anope::string modes; - for (const auto &[last_mode, last_value] : ci->last_modes) + for (const auto &[last_mode, last_data] : ci->last_modes) { if (!modes.empty()) modes += " "; + + modes += '+'; modes += last_mode; - if (!last_value.empty()) - modes += "," + last_value; + if (!last_data.value.empty()) + { + modes += "," + Anope::ToString(last_data.set_at); + modes += "," + last_data.set_by; + modes += "," + last_data.value; + } } data.Store("last_modes", modes); } @@ -1145,11 +1151,32 @@ class CSSet final ci->last_modes.clear(); for (spacesepstream sep(modes); sep.GetToken(modes);) { - size_t c = modes.find(','); - if (c == Anope::string::npos) - ci->last_modes.emplace(modes, ""); + if (modes[0] == '+') + { + commasepstream mode(modes, true); + mode.GetToken(modes); + modes.erase(0, 1); + + ModeData info; + Anope::string set_at; + mode.GetToken(set_at); + info.set_at = Anope::Convert(set_at, 0); + mode.GetToken(info.set_by); + info.value = mode.GetRemaining(); + + ci->last_modes.emplace(modes, info); + continue; + } else - ci->last_modes.emplace(modes.substr(0, c), modes.substr(c + 1)); + { + // Begin 2.0 compatibility + size_t c = modes.find(','); + if (c == Anope::string::npos) + ci->last_modes.emplace(modes, ModeData()); + else + ci->last_modes.emplace(modes.substr(0, c), ModeData(modes.substr(c + 1))); + // End 2.0 compatibility. + } } } } keep_modes; @@ -1207,8 +1234,8 @@ public: if (c->ci && keep_modes.HasExt(c->ci)) { Channel::ModeList ml = c->ci->last_modes; - for (const auto &[last_mode, last_value] : ml) - c->SetMode(c->ci->WhoSends(), last_mode, last_value); + for (const auto &[last_mode, last_data] : ml) + c->SetMode(c->ci->WhoSends(), last_mode, last_data); } } @@ -1230,7 +1257,7 @@ public: persist.Unset(ci); } - EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) override + EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override { if (c->ci) { diff --git a/modules/chanstats.cpp b/modules/chanstats.cpp index 97a03b013..2f48c8abf 100644 --- a/modules/chanstats.cpp +++ b/modules/chanstats.cpp @@ -540,7 +540,7 @@ public: this->RunQuery(query); } - EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) override + EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override { this->OnModeChange(c, setter.GetUser()); return EVENT_CONTINUE; diff --git a/modules/database/db_atheme.cpp b/modules/database/db_atheme.cpp index 950432d10..971a45068 100644 --- a/modules/database/db_atheme.cpp +++ b/modules/database/db_atheme.cpp @@ -84,14 +84,14 @@ public: } }; -struct ModeData final +struct ModeLockData final { char letter; Anope::string name; Anope::string value; bool set; - ModeData(const Anope::string &n, bool s, const Anope::string &v = "") + ModeLockData(const Anope::string &n, bool s, const Anope::string &v = "") : letter(0) , name(n) , value(v) @@ -99,7 +99,7 @@ struct ModeData final { } - ModeData(char l, const Anope::string &v = "") + ModeLockData(char l, const Anope::string &v = "") : letter(l) , value(v) , set(true) @@ -123,7 +123,7 @@ struct ChannelData final Anope::string info_adder; Anope::string info_message; time_t info_ts = 0; - std::vector<ModeData> mlocks; + std::vector<ModeLockData> mlocks; Anope::string suspend_by; Anope::string suspend_reason; time_t suspend_ts = 0; diff --git a/modules/helpchan.cpp b/modules/helpchan.cpp index 1854b78c7..80e4c1a30 100644 --- a/modules/helpchan.cpp +++ b/modules/helpchan.cpp @@ -16,11 +16,11 @@ public: { } - EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string ¶m) override + EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const ModeData &data) override { if (mode->name == "OP" && c && c->ci && c->name.equals_ci(Config->GetModule(this).Get<const Anope::string>("helpchannel"))) { - User *u = User::Find(param); + User *u = User::Find(data.value); if (u && c->ci->AccessFor(u).HasPriv("OPME")) u->SetMode(Config->GetClient("OperServ"), "HELPOP"); diff --git a/modules/irc2sql/irc2sql.cpp b/modules/irc2sql/irc2sql.cpp index fc402dc95..629a749d2 100644 --- a/modules/irc2sql/irc2sql.cpp +++ b/modules/irc2sql/irc2sql.cpp @@ -232,11 +232,11 @@ void IRC2SQL::OnJoinChannel(User *u, Channel *c) this->RunQuery(query); } -EventReturn IRC2SQL::OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) +EventReturn IRC2SQL::OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) { if (mode->type == MODE_STATUS) { - User *u = User::Find(param); + User *u = User::Find(data.value); if (u == NULL) return EVENT_CONTINUE; diff --git a/modules/irc2sql/irc2sql.h b/modules/irc2sql/irc2sql.h index 52a15e7f6..95d01cc4a 100644 --- a/modules/irc2sql/irc2sql.h +++ b/modules/irc2sql/irc2sql.h @@ -79,7 +79,7 @@ public: void OnChannelDelete(Channel *c) override; void OnLeaveChannel(User *u, Channel *c) override; void OnJoinChannel(User *u, Channel *c) override; - EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) override; + EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override; EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) override; void OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic) override; diff --git a/modules/nickserv/ns_set_keepmodes.cpp b/modules/nickserv/ns_set_keepmodes.cpp index faa44b9d3..8e5c902b2 100644 --- a/modules/nickserv/ns_set_keepmodes.cpp +++ b/modules/nickserv/ns_set_keepmodes.cpp @@ -128,13 +128,19 @@ private: const NickCore *nc = anope_dynamic_static_cast<const NickCore *>(s); Anope::string modes; - for (const auto &[last_mode, last_value] : nc->last_modes) + for (const auto &[last_mode, last_data] : nc->last_modes) { if (!modes.empty()) modes += " "; + + modes += '+'; modes += last_mode; - if (!last_value.empty()) - modes += "," + last_value; + if (!last_data.value.empty()) + { + modes += "," + Anope::ToString(last_data.set_at); + modes += "," + last_data.set_by; + modes += "," + last_data.value; + } } data.Store("last_modes", modes); } @@ -152,11 +158,32 @@ private: nc->last_modes.clear(); for (spacesepstream sep(modes); sep.GetToken(modes);) { - size_t c = modes.find(','); - if (c == Anope::string::npos) - nc->last_modes.emplace(modes, ""); + if (modes[0] == '+') + { + commasepstream mode(modes, true); + mode.GetToken(modes); + modes.erase(0, 1); + + ModeData info; + Anope::string set_at; + mode.GetToken(set_at); + info.set_at = Anope::Convert(set_at, 0); + mode.GetToken(info.set_by); + info.value = mode.GetRemaining(); + + nc->last_modes.emplace(modes, info); + continue; + } else - nc->last_modes.emplace(modes.substr(0, c), modes.substr(c + 1)); + { + // Begin 2.0 compatibility + size_t c = modes.find(','); + if (c == Anope::string::npos) + nc->last_modes.emplace(modes, ModeData()); + else + nc->last_modes.emplace(modes.substr(0, c), ModeData(modes.substr(c + 1))); + // End 2.0 compatibility. + } } } } keep_modes; @@ -197,11 +224,11 @@ public: { const auto norestore = Config->GetModule(this).Get<const Anope::string>("norestore"); User::ModeList modes = u->Account()->last_modes; - for (const auto &[last_mode, last_value] : modes) + for (const auto &[last_mode, last_data] : modes) { auto *um = ModeManager::FindUserModeByName(last_mode); if (um && um->CanSet(nullptr) && norestore.find(um->mchar) == Anope::string::npos) - u->SetMode(nullptr, last_mode, last_value); + u->SetMode(nullptr, last_mode, last_data); } } } diff --git a/modules/operserv/os_defcon.cpp b/modules/operserv/os_defcon.cpp index 9fd47c659..2d32e6a28 100644 --- a/modules/operserv/os_defcon.cpp +++ b/modules/operserv/os_defcon.cpp @@ -407,11 +407,11 @@ public: this->ParseModeString(); } - EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string ¶m) override + EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const ModeData &data) override { if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOff.count(mode->name) && source.GetUser() && !source.GetBot()) { - c->RemoveMode(Config->GetClient("OperServ"), mode, param); + c->RemoveMode(Config->GetClient("OperServ"), mode, data.value); return EVENT_STOP; } diff --git a/modules/operserv/os_mode.cpp b/modules/operserv/os_mode.cpp index 0ac9b48d4..d623d2e71 100644 --- a/modules/operserv/os_mode.cpp +++ b/modules/operserv/os_mode.cpp @@ -36,8 +36,8 @@ public: { bool all = params.size() > 2 && params[2].equals_ci("ALL"); - for (const auto &[mode, value] : c->GetModes()) - c->RemoveMode(c->WhoSends(), mode, value, false); + for (const auto &[mode, data] : c->GetModes()) + c->RemoveMode(c->WhoSends(), mode, data.value, false); if (!c) { diff --git a/modules/protocol/inspircd.cpp b/modules/protocol/inspircd.cpp index 6665a4581..684c32efe 100644 --- a/modules/protocol/inspircd.cpp +++ b/modules/protocol/inspircd.cpp @@ -434,6 +434,41 @@ public: Uplink::SendInternal({}, Me, "NUM", newparams); } + void SendMode(const MessageSource &source, Channel *chan, const ModeManager::Change &change) + { + std::map<char, std::vector<Anope::string>> listchanges; + ModeManager::Change otherchanges; + + for (const auto &[mode, info] : change) + { + if (spanningtree_proto_ver >= 1206 && mode->type == MODE_LIST && info.first) + { + // Adding to a list mode. + const auto &data = info.second; + + auto &listchange = listchanges[mode->mchar]; + listchange.push_back(data.value); + listchange.push_back(data.set_by); + listchange.push_back(Anope::ToString(data.set_at)); + } + else + { + // Regular mode change or mode removal. + otherchanges.emplace(mode, info); + } + } + + for (auto &[mode, params] : listchanges) + { + // :<sid> LMODE <chan> <chants> <modechr> [<mask> <setter> <setts>]+ + params.insert(params.begin(), { chan->name, Anope::ToString(chan->created), Anope::ToString(mode) }); + Uplink::SendInternal({}, source, "LMODE", params); + } + + if (!otherchanges.empty()) + IRCDProto::SendMode(source, chan, otherchanges); + } + void SendModeInternal(const MessageSource &source, Channel *chan, const Anope::string &modes, const std::vector<Anope::string> &values) override { auto params = values; @@ -2310,7 +2345,7 @@ struct IRCDMessageLMode final void Run(MessageSource &source, const std::vector<Anope::string> ¶ms, const Anope::map<Anope::string> &tags) override { - // :<sid> LMODE <chan> <chants> <modechr> [<mask> <setts> <setter>]+ + // :<sid> LMODE <chan> <chants> <modechr> [<mask> <setter> <setts>]+ auto *chan = Channel::Find(params[0]); if (!chan) return; // Channel doesn't exist. @@ -2327,10 +2362,14 @@ struct IRCDMessageLMode final if (params.size() % 3) return; // Invalid parameter count. - for (auto it = params.begin() + 3; it != params.end(); it += 3) + for (auto it = params.begin() + 3; it != params.end(); ) { - // TODO: Anope doesn't store set time and setter for list modes yet. - chan->SetModeInternal(source, cm, *it); + ModeData data; + data.value = *it++; + data.set_by = *it++; + data.set_at = Anope::Convert(*it++, 0); + + chan->SetModeInternal(source, cm, data, true); } } }; diff --git a/modules/rpc/rpc_data.cpp b/modules/rpc/rpc_data.cpp index 71c0fee71..13dec3cf2 100644 --- a/modules/rpc/rpc_data.cpp +++ b/modules/rpc/rpc_data.cpp @@ -220,15 +220,15 @@ public: } std::vector<Anope::string> modelist = { "+" }; - for (const auto &[mname, mvalue] : c->GetModes()) + for (const auto &[mname, mdata] : c->GetModes()) { auto *cm = ModeManager::FindChannelModeByName(mname); if (!cm || cm->type == MODE_LIST) continue; modelist.front().push_back(cm->mchar); - if (!mvalue.empty()) - modelist.push_back(mvalue); + if (!mdata.value.empty()) + modelist.push_back(mdata.value); } auto &modes = root.ReplyArray("modes"); for (const auto &modeparam : modelist) @@ -522,15 +522,15 @@ public: root.Reply("fingerprint", u->fingerprint); std::vector<Anope::string> modelist = { "+" }; - for (const auto &[mname, mvalue] : u->GetModeList()) + for (const auto &[mname, mdata] : u->GetModeList()) { auto *um = ModeManager::FindUserModeByName(mname); if (!um || um->type == MODE_LIST) continue; modelist.front().push_back(um->mchar); - if (!mvalue.empty()) - modelist.push_back(mvalue); + if (!mdata.value.empty()) + modelist.push_back(mdata.value); } auto &modes = root.ReplyArray("modes"); for (const auto &modeparam : modelist) diff --git a/src/channels.cpp b/src/channels.cpp index b8fa74443..25826ad1a 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -209,7 +209,7 @@ Anope::string Channel::GetModes(bool complete, bool plus) { Anope::string res, params; - for (const auto &[mode, value] : this->modes) + for (const auto &[mode, data] : this->modes) { ChannelMode *cm = ModeManager::FindChannelModeByName(mode); if (!cm || cm->type == MODE_LIST) @@ -217,14 +217,14 @@ Anope::string Channel::GetModes(bool complete, bool plus) res += cm->mchar; - if (complete && !value.empty()) + if (complete && !data.value.empty()) { ChannelModeParam *cmp = NULL; if (cm->type == MODE_PARAM) cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm); if (plus || !cmp || !cmp->minus_no_arg) - params += " " + value; + params += " " + data.value; } } @@ -236,46 +236,42 @@ const Channel::ModeList &Channel::GetModes() const return this->modes; } -template<typename F, typename S> -struct second final -{ - S operator()(const std::pair<F, S> &p) - { - return p.second; - } -}; - std::vector<Anope::string> Channel::GetModeList(const Anope::string &mname) { std::vector<Anope::string> r; - std::transform(modes.lower_bound(mname), modes.upper_bound(mname), std::back_inserter(r), second<Anope::string, Anope::string>()); + std::transform(modes.lower_bound(mname), modes.upper_bound(mname), std::back_inserter(r), [](const auto &mode) { + return mode.second.value; + }); return r; } -void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Anope::string &oparam, bool enforce_mlock) +void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const ModeData &data, bool enforce_mlock) { if (!ocm) return; - Anope::string param = oparam; - ChannelMode *cm = ocm->Unwrap(param); + // We build a mode data which has more than what the caller gives us. + ModeData mdata; + mdata.set_at = data.set_at ? data.set_at : Anope::CurTime; + mdata.set_by = data.set_by.empty() ? setter.GetName() : data.set_by; + mdata.value = data.value; + auto *cm = ocm->Unwrap(mdata.value); EventReturn MOD_RESULT; /* Setting v/h/o/a/q etc */ if (cm->type == MODE_STATUS) { - if (param.empty()) + if (mdata.value.empty()) { Log() << "Channel::SetModeInternal() mode " << cm->mchar << " with no parameter for channel " << this->name; return; } - User *u = User::Find(param); - + auto *u = User::Find(mdata.value); if (!u) { - Log(LOG_DEBUG) << "MODE " << this->name << " +" << cm->mchar << " for nonexistent user " << param; + Log(LOG_DEBUG) << "MODE " << this->name << " +" << cm->mchar << " for nonexistent user " << mdata.value; return; } @@ -286,7 +282,7 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano if (cc) cc->status.AddMode(cm->mchar); - FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param)); + FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, data)); /* Enforce secureops, etc */ if (enforce_mlock && MOD_RESULT != EVENT_STOP) @@ -296,12 +292,12 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano if (cm->type != MODE_LIST) this->modes.erase(cm->name); - else if (this->HasMode(cm->name, param)) + else if (this->HasMode(cm->name, mdata.value)) return; - this->modes.emplace(cm->name, param); + this->modes.emplace(cm->name, mdata); - if (param.empty() && cm->type != MODE_REGULAR) + if (mdata.value.empty() && cm->type != MODE_REGULAR) { Log() << "Channel::SetModeInternal() mode " << cm->mchar << " for " << this->name << " with no parameter, but is a param mode"; return; @@ -310,10 +306,10 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano if (cm->type == MODE_LIST) { ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm); - cml->OnAdd(this, param); + cml->OnAdd(this, mdata.value); } - FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param)); + FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, data)); /* Check if we should enforce mlock */ if (!enforce_mlock || MOD_RESULT == EVENT_STOP) @@ -368,7 +364,7 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const if (cm->type == MODE_LIST) { for (Channel::ModeList::iterator it = modes.lower_bound(cm->name), it_end = modes.upper_bound(cm->name); it != it_end; ++it) - if (param.equals_ci(it->second)) + if (param.equals_ci(it->second.value)) { this->modes.erase(it); break; @@ -401,27 +397,33 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const this->CheckModes(); } -void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, bool enforce_mlock) +void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const ModeData &data, bool enforce_mlock) { - Anope::string wparam = param; if (!cm) return; + + // We build a mode data which has more than what the caller gives us. + ModeData mdata; + mdata.set_at = data.set_at ? data.set_at : Anope::CurTime; + mdata.set_by = data.set_by.empty() && bi ? bi->nick : data.set_by; + mdata.value = data.value; + /* Don't set modes already set */ if (cm->type == MODE_REGULAR && HasMode(cm->name)) return; else if (cm->type == MODE_PARAM) { ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm); - if (!cmp->IsValid(wparam)) + if (!cmp->IsValid(mdata.value)) return; Anope::string cparam; - if (GetParam(cm->name, cparam) && cparam.equals_cs(wparam)) + if (GetParam(cm->name, cparam) && cparam.equals_cs(mdata.value)) return; } else if (cm->type == MODE_STATUS) { - User *u = User::Find(param); + User *u = User::Find(mdata.value); if (!u || HasUserStatus(u, anope_dynamic_static_cast<ChannelModeStatus *>(cm))) return; } @@ -429,10 +431,10 @@ void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, { ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm); - if (!cml->IsValid(wparam)) + if (!cml->IsValid(mdata.value)) return; - if (this->HasMode(cm->name, wparam)) + if (this->HasMode(cm->name, mdata.value)) return; } @@ -447,16 +449,16 @@ void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, this->chanserv_modecount++; } - ChannelMode *wcm = cm->Wrap(wparam); + ChannelMode *wcm = cm->Wrap(mdata.value); - ModeManager::StackerAdd(bi, this, wcm, true, wparam); + ModeManager::StackerAdd(bi, this, wcm, true, mdata); MessageSource ms(bi); - SetModeInternal(ms, wcm, wparam, enforce_mlock); + SetModeInternal(ms, wcm, mdata, enforce_mlock); } -void Channel::SetMode(BotInfo *bi, const Anope::string &mname, const Anope::string ¶m, bool enforce_mlock) +void Channel::SetMode(BotInfo *bi, const Anope::string &mname, const ModeData &data, bool enforce_mlock) { - SetMode(bi, ModeManager::FindChannelModeByName(mname), param, enforce_mlock); + SetMode(bi, ModeManager::FindChannelModeByName(mname), data, enforce_mlock); } void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string &wparam, bool enforce_mlock) @@ -520,13 +522,13 @@ void Channel::RemoveMode(BotInfo *bi, const Anope::string &mname, const Anope::s bool Channel::GetParam(const Anope::string &mname, Anope::string &target) const { - std::multimap<Anope::string, Anope::string>::const_iterator it = this->modes.find(mname); + const auto it = this->modes.find(mname); target.clear(); if (it != this->modes.end()) { - target = it->second; + target = it->second.value; return true; } @@ -586,7 +588,7 @@ void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const Anope::string &cmo this->SetMode(bi, cm, sbuf, enforce_mlock); } else - this->SetMode(bi, cm, "", enforce_mlock); + this->SetMode(bi, cm, {}, enforce_mlock); } else if (!add) { @@ -659,12 +661,16 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &modes modestring += cm->mchar; } + ModeData data; + data.set_by = source.GetName(); + data.set_at = ts ? ts : Anope::CurTime; + if (cm->type == MODE_REGULAR) { /* something changed if we are adding a mode we don't have, or removing one we have */ changed |= !!add != this->HasMode(cm->name); if (add) - this->SetModeInternal(source, cm, "", false); + this->SetModeInternal(source, cm, data, false); else this->RemoveModeInternal(source, cm, "", false); continue; @@ -691,7 +697,10 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &modes changed |= !!add != this->HasMode(cm->name, token); /* CheckModes below doesn't check secureops (+ the module event) */ if (add) - this->SetModeInternal(source, cm, token, enforce_mlock); + { + data.value = token; + this->SetModeInternal(source, cm, data, enforce_mlock); + } else this->RemoveModeInternal(source, cm, token, enforce_mlock); } diff --git a/src/modes.cpp b/src/modes.cpp index fdaae7716..c68389c2d 100644 --- a/src/modes.cpp +++ b/src/modes.cpp @@ -41,19 +41,20 @@ unsigned ModeManager::GenericChannelModes = 0, ModeManager::GenericUserModes = 0 struct StackerInfo final { + using ModeList = std::list<std::pair<Mode *, ModeData>>; /* Modes to be added */ - std::list<std::pair<Mode *, Anope::string> > AddModes; + ModeList AddModes; /* Modes to be deleted */ - std::list<std::pair<Mode *, Anope::string> > DelModes; + ModeList DelModes; /* Bot this is sent from */ BotInfo *bi = nullptr; /** Add a mode to this object * @param mode The mode * @param set true if setting, false if unsetting - * @param param The param for the mode + * @param data Data about the mode. */ - void AddMode(Mode *mode, bool set, const Anope::string ¶m); + void AddMode(Mode *mode, bool set, const ModeData &data); }; ChannelStatus::ChannelStatus(const Anope::string &m) : modes(m) @@ -246,11 +247,11 @@ bool ChannelModeNoone::CanSet(User *u) const return false; } -void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string ¶m) +void StackerInfo::AddMode(Mode *mode, bool set, const ModeData &data) { bool is_param = mode->type == MODE_PARAM; - std::list<std::pair<Mode *, Anope::string> > *list, *otherlist; + ModeList *list, *otherlist; if (set) { list = &AddModes; @@ -263,13 +264,13 @@ void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string ¶m) } /* Loop through the list and find if this mode is already on here */ - std::list<std::pair<Mode *, Anope::string > >::iterator it, it_end; + StackerInfo::ModeList::iterator it, it_end; for (it = list->begin(), it_end = list->end(); it != it_end; ++it) { /* The param must match too (can have multiple status or list modes), but * if it is a param mode it can match no matter what the param is */ - if (it->first == mode && (is_param || param.equals_cs(it->second))) + if (it->first == mode && (is_param || data.value.equals_cs(it->second.value))) { list->erase(it); /* It can only be on this list once */ @@ -282,7 +283,7 @@ void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string ¶m) /* The param must match too (can have multiple status or list modes), but * if it is a param mode it can match no matter what the param is */ - if (it->first == mode && (is_param || param.equals_cs(it->second))) + if (it->first == mode && (is_param || data.value.equals_cs(it->second.value))) { otherlist->erase(it); return; @@ -294,7 +295,7 @@ void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string ¶m) } /* Add this mode and its param to our list */ - list->emplace_back(mode, param); + list->emplace_back(mode, data); } static class ModePipe final @@ -323,72 +324,6 @@ static StackerInfo *GetInfo(List &l, Object *o) return s; } -/** Build a list of mode strings to send to the IRCd from the mode stacker - * @param info The stacker info for a channel or user - * @return a list of strings - */ -static auto BuildModeStrings(StackerInfo *info) -{ - std::list<std::pair<Anope::string, std::vector<Anope::string>>> ret; - std::list<std::pair<Mode *, Anope::string> >::iterator it, it_end; - Anope::string buf = "+"; - std::vector<Anope::string> parambuf; - unsigned NModes = 0; - size_t paramlen = 0; - - for (it = info->AddModes.begin(), it_end = info->AddModes.end(); it != it_end; ++it) - { - if ((IRCD->MaxModes && ++NModes > IRCD->MaxModes) || (IRCD->MaxLine && buf.length() + paramlen > IRCD->MaxLine - 100)) // Leave room for command, channel, etc - { - ret.push_back({buf, parambuf}); - buf = "+"; - parambuf.clear(); - paramlen = 0; - NModes = 1; - } - - buf += it->first->mchar; - - if (!it->second.empty()) - { - parambuf.push_back(it->second); - paramlen += it->second.length() + 1; - } - } - - if (buf[buf.length() - 1] == '+') - buf.erase(buf.length() - 1); - - buf += "-"; - for (it = info->DelModes.begin(), it_end = info->DelModes.end(); it != it_end; ++it) - { - if ((IRCD->MaxModes && ++NModes > IRCD->MaxModes) || (IRCD->MaxLine && buf.length() + paramlen > IRCD->MaxLine - 100)) // Leave room for command, channel, etc - { - ret.push_back({buf, parambuf}); - buf = "-"; - parambuf.clear(); - paramlen = 0; - NModes = 1; - } - - buf += it->first->mchar; - - if (!it->second.empty()) - { - parambuf.push_back(it->second); - paramlen += it->second.length() + 1; - } - } - - if (buf[buf.length() - 1] == '-') - buf.erase(buf.length() - 1); - - if (!buf.empty()) - ret.push_back({buf, parambuf}); - - return ret; -} - bool ModeManager::AddUserMode(UserMode *um) { if (ModeManager::FindUserModeByChar(um->mchar) != NULL) @@ -606,10 +541,10 @@ void ModeManager::RebuildStatusModes() std::sort(ChannelModesByStatus.begin(), ChannelModesByStatus.end(), statuscmp); } -void ModeManager::StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, const Anope::string &Param) +void ModeManager::StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, const ModeData &data) { StackerInfo *s = GetInfo(ChannelStackerObjects, c); - s->AddMode(cm, Set, Param); + s->AddMode(cm, Set, data); if (bi) s->bi = bi; else @@ -620,10 +555,10 @@ void ModeManager::StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, modePipe->Notify(); } -void ModeManager::StackerAdd(BotInfo *bi, User *u, UserMode *um, bool Set, const Anope::string &Param) +void ModeManager::StackerAdd(BotInfo *bi, User *u, UserMode *um, bool Set, const ModeData &data) { StackerInfo *s = GetInfo(UserStackerObjects, u); - s->AddMode(um, Set, Param); + s->AddMode(um, Set, data); if (bi) s->bi = bi; @@ -632,14 +567,24 @@ void ModeManager::StackerAdd(BotInfo *bi, User *u, UserMode *um, bool Set, const modePipe->Notify(); } +static auto BuildModeMap(StackerInfo *info) +{ + // TODO: make the stacker store this so we don't need to build it. + ModeManager::Change change; + for (const auto &[mode, data] : info->AddModes) + change.emplace(mode, std::make_pair(true, data)); + for (const auto &[mode, data] : info->DelModes) + change.emplace(mode, std::make_pair(false, data)); + return change; +} + void ModeManager::ProcessModes() { if (!UserStackerObjects.empty()) { for (const auto &[u, s] : UserStackerObjects) { - for (const auto &modestr : BuildModeStrings(s)) - IRCD->SendModeInternal(s->bi, u, modestr.first, modestr.second); + IRCD->SendMode(s->bi, u, BuildModeMap(s)); delete s; } UserStackerObjects.clear(); @@ -649,8 +594,7 @@ void ModeManager::ProcessModes() { for (const auto &[c, s] : ChannelStackerObjects) { - for (const auto &modestr : BuildModeStrings(s)) - IRCD->SendModeInternal(s->bi, c, modestr.first, modestr.second); + IRCD->SendMode(s->bi, c, BuildModeMap(s)); delete s; } ChannelStackerObjects.clear(); @@ -664,9 +608,7 @@ static void StackerDel(std::map<T *, StackerInfo *> &map, T *obj) if (it != map.end()) { StackerInfo *si = it->second; - for (const auto &modestr : BuildModeStrings(si)) - IRCD->SendModeInternal(si->bi, obj, modestr.first, modestr.second); - + IRCD->SendMode(si->bi, obj, BuildModeMap(si)); delete si; map.erase(it); } @@ -689,7 +631,7 @@ void ModeManager::StackerDel(Mode *m) StackerInfo *si = it->second; ++it; - for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;) + for (StackerInfo::ModeList::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;) { if (it2->first == m) it2 = si->AddModes.erase(it2); @@ -697,7 +639,7 @@ void ModeManager::StackerDel(Mode *m) ++it2; } - for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;) + for (StackerInfo::ModeList::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;) { if (it2->first == m) it2 = si->DelModes.erase(it2); @@ -711,7 +653,7 @@ void ModeManager::StackerDel(Mode *m) StackerInfo *si = it->second; ++it; - for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;) + for (StackerInfo::ModeList::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;) { if (it2->first == m) it2 = si->AddModes.erase(it2); @@ -719,7 +661,7 @@ void ModeManager::StackerDel(Mode *m) ++it2; } - for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;) + for (StackerInfo::ModeList::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;) { if (it2->first == m) it2 = si->DelModes.erase(it2); diff --git a/src/protocol.cpp b/src/protocol.cpp index 7a167582a..882ef6c5c 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -113,6 +113,61 @@ void IRCDProto::SendSVSKill(const MessageSource &source, User *user, const Anope Uplink::Send(source, "KILL", user->GetUID(), buf); } +static auto BuildModeChange(const ModeManager::Change &change) +{ + std::list<std::pair<Anope::string, std::vector<Anope::string>>> modes; + + Anope::string modebuf; + size_t modecount = 0; + std::vector<Anope::string> parambuf; + size_t paramlen; + + auto adding = true; + for (const auto &[mode, info] : change) + { + const auto reached_max_line = IRCD->MaxLine && modebuf.length() + paramlen > IRCD->MaxLine - 100; // Leave room for command, channel, etc + const auto reached_max_modes = IRCD->MaxModes && ++modecount > IRCD->MaxModes; + if (reached_max_modes || reached_max_line) + { + modes.push_back({modebuf, parambuf}); + + modebuf.clear(); + modecount = 0; + + parambuf.clear(); + paramlen = 0; + } + + // Push the mode. + const auto direction = info.first; + if (modebuf.empty() || adding != direction) + { + adding = direction; + modebuf += (adding ? '+' : '-'); + } + modebuf += mode->mchar; + + // If it has a value push that too. + const auto &data = info.second; + if (!data.value.empty()) + { + parambuf.push_back(data.value); + paramlen += data.value.length() + 1; + } + } + + if (!modebuf.empty()) + modes.push_back({modebuf, parambuf}); + + return modes; +} + +void IRCDProto::SendMode(const MessageSource &source, Channel *chan, const ModeManager::Change &change) +{ + for (const auto &[modes, params] : BuildModeChange(change)) + IRCD->SendModeInternal(source, chan, modes, params); +} + void IRCDProto::SendModeInternal(const MessageSource &source, Channel *chan, const Anope::string &modes, const std::vector<Anope::string> &values) { auto params = values; @@ -120,6 +175,12 @@ void IRCDProto::SendModeInternal(const MessageSource &source, Channel *chan, con Uplink::SendInternal({}, source, "MODE", params); } +void IRCDProto::SendMode(const MessageSource &source, User *dest, const ModeManager::Change &change) +{ + for (const auto &[modes, params] : BuildModeChange(change)) + IRCD->SendModeInternal(source, dest, modes, params); +} + void IRCDProto::SendModeInternal(const MessageSource &source, User *dest, const Anope::string &modes, const std::vector<Anope::string> &values) { auto params = values; diff --git a/src/servers.cpp b/src/servers.cpp index 9f98aeb07..a9962f9ab 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -117,12 +117,12 @@ Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Ano IRCD->SendJoin(uc->user, c, &uc->status); } - for (const auto &[mode, value] : c->GetModes()) + for (const auto &[mode, data] : c->GetModes()) { ChannelMode *cm = ModeManager::FindChannelModeByName(mode); if (!cm || cm->type != MODE_LIST) continue; - ModeManager::StackerAdd(c->WhoSends(), c, cm, true, value); + ModeManager::StackerAdd(c->WhoSends(), c, cm, true, data); } if (!c->topic.empty() && !c->topic_setter.empty()) diff --git a/src/users.cpp b/src/users.cpp index 3d6034691..63a524488 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -548,12 +548,12 @@ bool User::HasMode(const Anope::string &mname) const return this->modes.count(mname); } -void User::SetModeInternal(const MessageSource &source, UserMode *um, const Anope::string ¶m) +void User::SetModeInternal(const MessageSource &source, UserMode *um, const ModeData &data) { if (!um) return; - this->modes[um->name] = param; + this->modes[um->name] = data; if (um->name == "OPER") { @@ -609,18 +609,18 @@ void User::RemoveModeInternal(const MessageSource &source, UserMode *um) FOREACH_MOD(OnUserModeUnset, (source, this, um->name)); } -void User::SetMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) +void User::SetMode(BotInfo *bi, UserMode *um, const ModeData &data) { if (!um || HasMode(um->name)) return; - ModeManager::StackerAdd(bi, this, um, true, param); - SetModeInternal(bi, um, param); + ModeManager::StackerAdd(bi, this, um, true, data); + SetModeInternal(bi, um, data); } -void User::SetMode(BotInfo *bi, const Anope::string &uname, const Anope::string ¶m) +void User::SetMode(BotInfo *bi, const Anope::string &uname, const ModeData &data) { - SetMode(bi, ModeManager::FindUserModeByName(uname), param); + SetMode(bi, ModeManager::FindUserModeByName(uname), data); } void User::RemoveMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) @@ -730,7 +730,7 @@ Anope::string User::GetModes() const { Anope::string m, params; - for (const auto &[mode, value] : this->modes) + for (const auto &[mode, data] : this->modes) { UserMode *um = ModeManager::FindUserModeByName(mode); if (um == NULL) @@ -738,8 +738,8 @@ Anope::string User::GetModes() const m += um->mchar; - if (!value.empty()) - params += " " + value; + if (!data.value.empty()) + params += " " + data.value; } return m + params; |