summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mode.h4
-rw-r--r--include/modes/cmode_b.h4
-rw-r--r--include/modes/cmode_h.h4
-rw-r--r--include/modes/cmode_k.h4
-rw-r--r--include/modes/cmode_o.h4
-rw-r--r--include/modes/cmode_v.h4
-rw-r--r--include/u_listmode.h12
-rw-r--r--src/mode.cpp29
-rw-r--r--src/modes/cmode_b.cpp17
-rw-r--r--src/modes/cmode_h.cpp17
-rw-r--r--src/modes/cmode_k.cpp13
-rw-r--r--src/modes/cmode_o.cpp15
-rw-r--r--src/modes/cmode_v.cpp15
-rw-r--r--src/modules/m_chanprotect.cpp22
-rw-r--r--src/modules/m_spanningtree/fjoin.cpp22
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 &parameter);
- 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 &parameter);
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 &parameter, bool adding, bool servermode);
ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter);
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 &parameter);
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 &parameter);
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<std::string>
if (c)
{
- for (char modeletter = 'A'; modeletter <= 'z'; modeletter++)
+ irc::modestacker stack(false);
+ std::deque<std::string> 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;