From 57608fe351cff19679b1d78fb5cbfb7cad89dfc1 Mon Sep 17 00:00:00 2001 From: brain Date: Wed, 2 Apr 2008 23:53:29 +0000 Subject: Fixes for bug #493, tidyups to clearing of channel modes on losing FJOIN. Module unloads may also be tidied at a future date but it means reordering some loops in mode.cpp. See around the comment added. git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@9283 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/mode.h | 4 ++-- include/modes/cmode_b.h | 4 ++-- include/modes/cmode_h.h | 4 ++-- include/modes/cmode_k.h | 4 ++-- include/modes/cmode_o.h | 4 ++-- include/modes/cmode_v.h | 4 ++-- include/u_listmode.h | 12 +++++++++--- src/mode.cpp | 29 +++++++++++++++++++++++------ src/modes/cmode_b.cpp | 17 ++++++++++++----- src/modes/cmode_h.cpp | 17 ++++++++++++----- src/modes/cmode_k.cpp | 13 +++++++++---- src/modes/cmode_o.cpp | 15 ++++++++++----- src/modes/cmode_v.cpp | 15 ++++++++++----- src/modules/m_chanprotect.cpp | 22 ++++++++++++++-------- src/modules/m_spanningtree/fjoin.cpp | 22 ++++++++++++++++++++-- 15 files changed, 131 insertions(+), 55 deletions(-) diff --git a/include/mode.h b/include/mode.h index ea52acf36..e15ddeeb0 100644 --- a/include/mode.h +++ b/include/mode.h @@ -276,7 +276,7 @@ class CoreExport ModeHandler : public Extensible * your mode properly from each user. * @param user The user which the server wants to remove your mode from */ - virtual void RemoveMode(User* user); + virtual void RemoveMode(User* user, irc::modestacker* stack = NULL); /** * When a MODETYPE_CHANNEL mode handler is being removed, the server will call this method for every channel on the server. @@ -286,7 +286,7 @@ class CoreExport ModeHandler : public Extensible * your mode properly from each channel. Note that in the case of listmodes, you should remove the entire list of items. * @param channel The channel which the server wants to remove your mode from */ - virtual void RemoveMode(Channel* channel); + virtual void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); char GetNeededPrefix(); diff --git a/include/modes/cmode_b.h b/include/modes/cmode_b.h index fc5eb0892..bbeef1c62 100644 --- a/include/modes/cmode_b.h +++ b/include/modes/cmode_b.h @@ -30,7 +30,7 @@ class ModeChannelBan : public ModeHandler void DisplayList(User* user, Channel* channel); void DisplayEmptyList(User* user, Channel* channel); ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string ¶meter); - void RemoveMode(User* user); - void RemoveMode(Channel* channel); + void RemoveMode(User* user, irc::modestacker* stack = NULL); + void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); }; diff --git a/include/modes/cmode_h.h b/include/modes/cmode_h.h index c8ea793c0..9c72a1431 100644 --- a/include/modes/cmode_h.h +++ b/include/modes/cmode_h.h @@ -28,7 +28,7 @@ class ModeChannelHalfOp : public ModeHandler std::string DelHalfOp(User *user,const char *dest,Channel *chan,int status); ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string ¶meter); unsigned int GetPrefixRank(); - void RemoveMode(Channel* channel); - void RemoveMode(User* user); + void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); + void RemoveMode(User* user, irc::modestacker* stack = NULL); }; diff --git a/include/modes/cmode_k.h b/include/modes/cmode_k.h index dce0550fe..c06c0c007 100644 --- a/include/modes/cmode_k.h +++ b/include/modes/cmode_k.h @@ -24,6 +24,6 @@ class ModeChannelKey : public ModeHandler ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode); ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string ¶meter); bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, Channel* channel); - void RemoveMode(Channel* channel); - void RemoveMode(User* user); + void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); + void RemoveMode(User* user, irc::modestacker* stack = NULL); }; diff --git a/include/modes/cmode_o.h b/include/modes/cmode_o.h index f78ac8eb0..0c48eff1e 100644 --- a/include/modes/cmode_o.h +++ b/include/modes/cmode_o.h @@ -28,7 +28,7 @@ class ModeChannelOp : public ModeHandler std::string DelOp(User *user,const char *dest,Channel *chan,int status); ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string ¶meter); unsigned int GetPrefixRank(); - void RemoveMode(Channel* channel); - void RemoveMode(User* user); + void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); + void RemoveMode(User* user, irc::modestacker* stack = NULL); }; diff --git a/include/modes/cmode_v.h b/include/modes/cmode_v.h index f66761809..4e699fe9d 100644 --- a/include/modes/cmode_v.h +++ b/include/modes/cmode_v.h @@ -28,7 +28,7 @@ class ModeChannelVoice : public ModeHandler std::string DelVoice(User *user,const char *dest,Channel *chan,int status); ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string ¶meter); unsigned int GetPrefixRank(); - void RemoveMode(User* user); - void RemoveMode(Channel* channel); + void RemoveMode(User* user, irc::modestacker* stack = NULL); + void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); }; diff --git a/include/u_listmode.h b/include/u_listmode.h index a388d7f18..6c6e2ca28 100644 --- a/include/u_listmode.h +++ b/include/u_listmode.h @@ -168,7 +168,7 @@ class ListModeBase : public ModeHandler * See mode.h * @param channel The channel to remove all instances of the mode from */ - virtual void RemoveMode(Channel* channel) + virtual void RemoveMode(Channel* channel, irc::modestacker* stack) { modelist* el; channel->GetExt(infokey, el); @@ -181,9 +181,15 @@ class ListModeBase : public ModeHandler for (modelist::iterator it = el->begin(); it != el->end(); it++) { - modestack.Push(this->GetModeChar(), assign(it->mask)); + if (stack) + stack->Push(this->GetModeChar(), assign(it->mask)); + else + modestack.Push(this->GetModeChar(), assign(it->mask)); } + if (stack) + return; + while (modestack.GetStackedLine(stackresult)) { for (size_t j = 0; j < stackresult.size(); j++) @@ -198,7 +204,7 @@ class ListModeBase : public ModeHandler /** See mode.h */ - virtual void RemoveMode(User*) + virtual void RemoveMode(User*, irc::modestacker* stack) { /* Listmodes dont get set on users */ } diff --git a/src/mode.cpp b/src/mode.cpp index 9b90599ce..83aff70cf 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -776,6 +776,9 @@ bool ModeParser::DelMode(ModeHandler* mh) if (!modehandlers[pos]) return false; + /* Note: We can't stack here, as we have modes potentially being removed across many different channels. + * To stack here we have to make the algorithm slower. Discuss. + */ switch (mh->GetModeType()) { case MODETYPE_USER: @@ -1048,30 +1051,44 @@ bool ModeParser::DelModeWatcher(ModeWatcher* mw) /** This default implementation can remove simple user modes */ -void ModeHandler::RemoveMode(User* user) +void ModeHandler::RemoveMode(User* user, irc::modestacker* stack) { char moderemove[MAXBUF]; const char* parameters[] = { user->nick, moderemove }; if (user->IsModeSet(this->GetModeChar())) { - sprintf(moderemove,"-%c",this->GetModeChar()); - ServerInstance->Parser->CallHandler("MODE", parameters, 2, user); + if (stack) + { + stack->Push(this->GetModeChar()); + } + else + { + sprintf(moderemove,"-%c",this->GetModeChar()); + ServerInstance->Parser->CallHandler("MODE", parameters, 2, user); + } } } /** This default implementation can remove simple channel modes * (no parameters) */ -void ModeHandler::RemoveMode(Channel* channel) +void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack) { char moderemove[MAXBUF]; const char* parameters[] = { channel->name, moderemove }; if (channel->IsModeSet(this->GetModeChar())) { - sprintf(moderemove,"-%c",this->GetModeChar()); - ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient); + if (stack) + { + stack->Push(this->GetModeChar()); + } + else + { + sprintf(moderemove,"-%c",this->GetModeChar()); + ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient); + } } } diff --git a/src/modes/cmode_b.cpp b/src/modes/cmode_b.cpp index 1efb5d399..4eea2e44d 100644 --- a/src/modes/cmode_b.cpp +++ b/src/modes/cmode_b.cpp @@ -49,7 +49,7 @@ ModeAction ModeChannelBan::OnModeChange(User* source, User*, Channel* channel, s return MODEACTION_ALLOW; } -void ModeChannelBan::RemoveMode(Channel* channel) +void ModeChannelBan::RemoveMode(Channel* channel, irc::modestacker* stack) { BanList copy; char moderemove[MAXBUF]; @@ -61,13 +61,20 @@ void ModeChannelBan::RemoveMode(Channel* channel) for (BanList::iterator i = copy.begin(); i != copy.end(); i++) { - sprintf(moderemove,"-%c",this->GetModeChar()); - const char* parameters[] = { channel->name, moderemove, i->data }; - ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + if (stack) + { + stack->Push(this->GetModeChar(), i->data); + } + else + { + sprintf(moderemove,"-%c",this->GetModeChar()); + const char* parameters[] = { channel->name, moderemove, i->data }; + ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + } } } -void ModeChannelBan::RemoveMode(User*) +void ModeChannelBan::RemoveMode(User*, irc::modestacker* stack) { } diff --git a/src/modes/cmode_h.cpp b/src/modes/cmode_h.cpp index 26ec55de3..8217ccc2d 100644 --- a/src/modes/cmode_h.cpp +++ b/src/modes/cmode_h.cpp @@ -45,7 +45,7 @@ ModePair ModeChannelHalfOp::ModeSet(User*, User*, Channel* channel, const std::s return std::make_pair(false, parameter); } -void ModeChannelHalfOp::RemoveMode(Channel* channel) +void ModeChannelHalfOp::RemoveMode(Channel* channel, irc::modestacker* stack) { CUList* clist = channel->GetHalfoppedUsers(); CUList copy; @@ -59,14 +59,21 @@ void ModeChannelHalfOp::RemoveMode(Channel* channel) for (CUList::iterator i = copy.begin(); i != copy.end(); i++) { - sprintf(moderemove,"-%c",this->GetModeChar()); - const char* parameters[] = { channel->name, moderemove, i->first->nick }; - ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + if (stack) + { + stack->Push(this->GetModeChar(), i->first->nick); + } + else + { + sprintf(moderemove,"-%c",this->GetModeChar()); + const char* parameters[] = { channel->name, moderemove, i->first->nick }; + ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + } } } -void ModeChannelHalfOp::RemoveMode(User*) +void ModeChannelHalfOp::RemoveMode(User*, irc::modestacker* stack) { } diff --git a/src/modes/cmode_k.cpp b/src/modes/cmode_k.cpp index 21b5d8464..194c0efcb 100644 --- a/src/modes/cmode_k.cpp +++ b/src/modes/cmode_k.cpp @@ -33,7 +33,7 @@ ModePair ModeChannelKey::ModeSet(User*, User*, Channel* channel, const std::stri } } -void ModeChannelKey::RemoveMode(Channel* channel) +void ModeChannelKey::RemoveMode(Channel* channel, irc::modestacker* stack) { /** +k needs a parameter when being removed, * so we have a special-case RemoveMode here for it @@ -43,12 +43,17 @@ void ModeChannelKey::RemoveMode(Channel* channel) if (channel->IsModeSet(this->GetModeChar())) { - sprintf(moderemove,"-%c",this->GetModeChar()); - ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + if (stack) + stack->Push(this->GetModeChar(), channel->key); + else + { + sprintf(moderemove,"-%c",this->GetModeChar()); + ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + } } } -void ModeChannelKey::RemoveMode(User*) +void ModeChannelKey::RemoveMode(User*, irc::modestacker* stack) { } diff --git a/src/modes/cmode_o.cpp b/src/modes/cmode_o.cpp index f62635658..c4e3c241e 100644 --- a/src/modes/cmode_o.cpp +++ b/src/modes/cmode_o.cpp @@ -46,7 +46,7 @@ ModePair ModeChannelOp::ModeSet(User*, User*, Channel* channel, const std::strin } -void ModeChannelOp::RemoveMode(Channel* channel) +void ModeChannelOp::RemoveMode(Channel* channel, irc::modestacker* stack) { CUList* clist = channel->GetOppedUsers(); CUList copy; @@ -60,13 +60,18 @@ void ModeChannelOp::RemoveMode(Channel* channel) for (CUList::iterator i = copy.begin(); i != copy.end(); i++) { - sprintf(moderemove,"-%c",this->GetModeChar()); - const char* parameters[] = { channel->name, moderemove, i->first->nick }; - ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + if (stack) + stack->Push(this->GetModeChar(), i->first->nick); + else + { + sprintf(moderemove,"-%c",this->GetModeChar()); + const char* parameters[] = { channel->name, moderemove, i->first->nick }; + ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + } } } -void ModeChannelOp::RemoveMode(User*) +void ModeChannelOp::RemoveMode(User*, irc::modestacker* stack) { } diff --git a/src/modes/cmode_v.cpp b/src/modes/cmode_v.cpp index 45a9e1879..15196d4a8 100644 --- a/src/modes/cmode_v.cpp +++ b/src/modes/cmode_v.cpp @@ -46,7 +46,7 @@ ModePair ModeChannelVoice::ModeSet(User*, User*, Channel* channel, const std::st return std::make_pair(false, parameter); } -void ModeChannelVoice::RemoveMode(Channel* channel) +void ModeChannelVoice::RemoveMode(Channel* channel, irc::modestacker* stack) { CUList* clist = channel->GetVoicedUsers(); CUList copy; @@ -60,13 +60,18 @@ void ModeChannelVoice::RemoveMode(Channel* channel) for (CUList::iterator i = copy.begin(); i != copy.end(); i++) { - sprintf(moderemove,"-%c",this->GetModeChar()); - const char* parameters[] = { channel->name, moderemove, i->first->nick }; - ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + if (stack) + stack->Push(this->GetModeChar(), i->first->nick); + else + { + sprintf(moderemove,"-%c",this->GetModeChar()); + const char* parameters[] = { channel->name, moderemove, i->first->nick }; + ServerInstance->SendMode(parameters, 3, ServerInstance->FakeClient); + } } } -void ModeChannelVoice::RemoveMode(User*) +void ModeChannelVoice::RemoveMode(User*, irc::modestacker* stack) { } diff --git a/src/modules/m_chanprotect.cpp b/src/modules/m_chanprotect.cpp index daa728e61..0cc4fe8d7 100644 --- a/src/modules/m_chanprotect.cpp +++ b/src/modules/m_chanprotect.cpp @@ -62,7 +62,7 @@ class FounderProtectBase return std::make_pair(false, parameter); } - void RemoveMode(Channel* channel, char mc) + void RemoveMode(Channel* channel, char mc, irc::modestacker* stack) { CUList* cl = channel->GetUsers(); std::string item = extend + std::string(channel->name); @@ -75,10 +75,16 @@ class FounderProtectBase { if (i->first->GetExt(item)) { - modestack.Push(mc, i->first->nick); + if (stack) + stack->Push(mc, i->first->nick); + else + modestack.Push(mc, i->first->nick); } } + if (stack) + return; + while (modestack.GetStackedLine(stackresult)) { for (size_t j = 0; j < stackresult.size(); j++) @@ -165,12 +171,12 @@ class ChanFounder : public ModeHandler, public FounderProtectBase return FounderProtectBase::ModeSet(source, dest, channel, parameter); } - void RemoveMode(Channel* channel) + void RemoveMode(Channel* channel, irc::modestacker* stack) { - FounderProtectBase::RemoveMode(channel, this->GetModeChar()); + FounderProtectBase::RemoveMode(channel, this->GetModeChar(), stack); } - void RemoveMode(User* user) + void RemoveMode(User* user, irc::modestacker* stack) { } @@ -231,12 +237,12 @@ class ChanProtect : public ModeHandler, public FounderProtectBase return FounderProtectBase::ModeSet(source, dest, channel, parameter); } - void RemoveMode(Channel* channel) + void RemoveMode(Channel* channel, irc::modestacker* stack) { - FounderProtectBase::RemoveMode(channel, this->GetModeChar()); + FounderProtectBase::RemoveMode(channel, this->GetModeChar(), stack); } - void RemoveMode(User* user) + void RemoveMode(User* user, irc::modestacker* stack) { } diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp index 0bddb4da7..3d119ee78 100644 --- a/src/modules/m_spanningtree/fjoin.cpp +++ b/src/modules/m_spanningtree/fjoin.cpp @@ -189,11 +189,29 @@ bool TreeSocket::RemoveStatus(const std::string &prefix, std::deque if (c) { - for (char modeletter = 'A'; modeletter <= 'z'; modeletter++) + irc::modestacker stack(false); + std::deque stackresult; + const char* mode_junk[MAXMODES+2]; + mode_junk[0] = c->name; + + for (char modeletter = 'A'; modeletter <= 'z'; ++modeletter) { ModeHandler* mh = Instance->Modes->FindMode(modeletter, MODETYPE_CHANNEL); + + /* Passing a pointer to a modestacker here causes the mode to be put onto the mode stack, + * rather than applied immediately. Module unloads require this to be done immediately, + * for this function we require tidyness instead. Fixes bug #493 + */ if (mh) - mh->RemoveMode(c); + mh->RemoveMode(c, &stack); + } + + while (stack.GetStackedLine(stackresult)) + { + for (size_t j = 0; j < stackresult.size(); j++) + mode_junk[j+1] = stackresult[j].c_str(); + + Instance->SendMode(mode_junk, stackresult.size() + 1, Instance->FakeClient); } } return true; -- cgit v1.2.3