aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Sadie Powell2022-11-04 12:24:12 +0000
committerGravatar Sadie Powell2023-03-01 19:23:52 +0000
commit26a1c1955f926b54acdafeaa7b8132e53e90bdeb (patch)
tree0dbbbfbcae06195a6c7bac7d4dbafc4ab8d21a7d
parentFix renicking duplicate users when the casemapping changes. (diff)
Fix destroying duplicate channels when the casemapping changes.
-rw-r--r--src/modules/m_codepage.cpp53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/modules/m_codepage.cpp b/src/modules/m_codepage.cpp
index 40d63de37..bcaa7e78c 100644
--- a/src/modules/m_codepage.cpp
+++ b/src/modules/m_codepage.cpp
@@ -79,12 +79,63 @@ class ModuleCodepage
hashmap.swap(newhash);
}
+ void DestroyChannel(Channel* chan)
+ {
+ // Remove all of the users from the channel. Using KICK here will mean
+ // the user's client will probably attempt to rejoin and will enter the
+ // succeeding channel. Unfortunately this is the best we can do for now.
+ while (!chan->userlist.empty())
+ chan->KickUser(ServerInstance->FakeClient, chan->userlist.begin(), "This channel does not exist anymore.");
+
+ // Remove all modes from the channel just in case one of them keeps the channel open.
+ Modes::ChangeList changelist;
+ const ModeParser::ModeHandlerMap& chanmodes = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL);
+ for (ModeParser::ModeHandlerMap::const_iterator i = chanmodes.begin(); i != chanmodes.end(); ++i)
+ i->second->RemoveMode(chan, changelist);
+ ServerInstance->Modes->Process(ServerInstance->FakeClient, chan, NULL, changelist, ModeParser::MODE_LOCALONLY);
+
+ // The channel will be destroyed automatically by CheckDestroy.
+ }
+
void ChangeNick(User* user, const std::string& message)
{
user->WriteNumeric(RPL_SAVENICK, user->uuid, message);
user->ChangeNick(user->uuid);
}
+ void CheckDuplicateChan()
+ {
+ chan_hash duplicates;
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator iter = chans.begin(); iter != chans.end(); ++iter)
+ {
+ Channel* chan = iter->second;
+ std::pair<chan_hash::iterator, bool> check = duplicates.insert(std::make_pair(chan->name, chan));
+ if (check.second)
+ continue; // No duplicate.
+
+ Channel* otherchan = check.first->second;
+ if (otherchan->age < chan->age)
+ {
+ // The other channel was created first.
+ DestroyChannel(chan);
+ }
+ else if (otherchan->age > chan->age)
+ {
+ // The other channel was created last.
+ DestroyChannel(otherchan);
+ check.first->second = chan;
+ }
+ else
+ {
+ // Both created at the same time.
+ DestroyChannel(chan);
+ DestroyChannel(otherchan);
+ duplicates.erase(check.first);
+ }
+ }
+ }
+
void CheckDuplicateNick()
{
user_hash duplicates;
@@ -157,6 +208,7 @@ class ModuleCodepage
ServerInstance->Config->CaseMapping = origcasemapname;
national_case_insensitive_map = origcasemap;
+ CheckDuplicateChan();
CheckDuplicateNick();
CheckRehash(casemap);
@@ -239,6 +291,7 @@ class ModuleCodepage
ServerInstance->Config->CaseMapping = name;
national_case_insensitive_map = casemap;
+ CheckDuplicateChan();
CheckDuplicateNick();
CheckRehash(newcasemap);