summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mode.h29
-rw-r--r--src/mode.cpp76
-rw-r--r--src/modules/m_operchans.cpp3
3 files changed, 107 insertions, 1 deletions
diff --git a/include/mode.h b/include/mode.h
index e0043fd10..27cdd890f 100644
--- a/include/mode.h
+++ b/include/mode.h
@@ -244,6 +244,26 @@ class ModeHandler : public Extensible
* This allows the local server to enforce our locally set parameters back to a remote server.
*/
virtual ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+
+ /**
+ * When a MODETYPE_USER mode handler is being removed, the server will call this method for every user on the server.
+ * Your mode handler should remove its user mode from the user by sending the appropriate server modes using
+ * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters,
+ * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove
+ * your mode properly from each user.
+ * @param user The user which the server wants to remove your mode from
+ */
+ virtual void RemoveMode(userrec* user);
+
+ /**
+ * When a MODETYPE_CHANNEL mode handler is being removed, the server will call this method for every channel on the server.
+ * Your mode handler should remove its user mode from the channel by sending the appropriate server modes using
+ * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters,
+ * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove
+ * 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(chanrec* channel);
};
/**
@@ -376,6 +396,15 @@ class ModeParser : public classbase
* @return True if the mode was successfully added.
*/
bool AddMode(ModeHandler* mh, unsigned const char modeletter);
+ /** Delete a mode from the mode parser.
+ * When a mode is deleted, the mode handler will be called
+ * for every user (if it is a user mode) or for every channel
+ * (if it is a channel mode) to unset the mode on all objects.
+ * This prevents modes staying in the system which no longer exist.
+ * @param mh The mode handler to remove
+ * @return True if the mode was successfully removed.
+ */
+ bool DelMode(ModeHandler* mh);
/** Add a mode watcher.
* A mode watcher is triggered before and after a mode handler is
* triggered. See the documentation of class ModeWatcher for more
diff --git a/src/mode.cpp b/src/mode.cpp
index c1a39d625..5da96249f 100644
--- a/src/mode.cpp
+++ b/src/mode.cpp
@@ -588,6 +588,41 @@ bool ModeParser::AddMode(ModeHandler* mh, unsigned const char modeletter)
return true;
}
+bool ModeParser::DelMode(ModeHandler* mh)
+{
+ unsigned char mask = 0;
+ unsigned char pos = 0;
+
+ if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
+ return false;
+
+ mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+ pos = (mh->GetModeChar()-65) | mask;
+
+ if (!modehandlers[pos])
+ return false;
+
+ switch (mh->GetModeType())
+ {
+ case MODETYPE_USER:
+ for (user_hash::iterator i = ServerInstance->clientlist.begin(); i != ServerInstance->clientlist.end(); i++)
+ {
+ mh->RemoveMode(i->second);
+ }
+ break;
+ case MODETYPE_CHANNEL:
+ for (chan_hash::iterator i = ServerInstance->chanlist.begin(); i != ServerInstance->chanlist.end(); i++)
+ {
+ mh->RemoveMode(i->second);
+ }
+ break;
+ }
+
+ modehandlers[pos] = NULL;
+
+ return true;
+}
+
ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
{
unsigned char mask = 0;
@@ -816,6 +851,47 @@ bool ModeParser::DelModeWatcher(ModeWatcher* mw)
return true;
}
+/** This default implementation can remove simple user modes
+ */
+void ModeHandler::RemoveMode(userrec* user)
+{
+ char moderemove[MAXBUF];
+ const char* parameters[] = { user->nick, moderemove };
+
+ if (user->IsModeSet(this->GetModeChar()))
+ {
+ userrec* n = new userrec(ServerInstance);
+
+ sprintf(moderemove,"-%c",this->GetModeChar());
+ n->SetFd(FD_MAGIC_NUMBER);
+
+ ServerInstance->SendMode(parameters, 2, n);
+
+ delete n;
+ }
+}
+
+/** This default implementation can remove simple channel modes
+ * (no parameters)
+ */
+void ModeHandler::RemoveMode(chanrec* channel)
+{
+ char moderemove[MAXBUF];
+ const char* parameters[] = { channel->name, moderemove };
+
+ if (channel->IsModeSet(this->GetModeChar()))
+ {
+ userrec* n = new userrec(ServerInstance);
+
+ sprintf(moderemove,"-%c",this->GetModeChar());
+ n->SetFd(FD_MAGIC_NUMBER);
+
+ ServerInstance->SendMode(parameters, 2, n);
+
+ delete n;
+ }
+}
+
ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
{
/* Clear mode list */
diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp
index 7f3b989aa..03444ea1a 100644
--- a/src/modules/m_operchans.cpp
+++ b/src/modules/m_operchans.cpp
@@ -88,12 +88,13 @@ class ModuleOperChans : public Module
virtual ~ModuleOperChans()
{
+ ServerInstance->Modes->DelMode(oc);
DELETE(oc);
}
virtual Version GetVersion()
{
- return Version(1,0,0,0,VF_STATIC|VF_VENDOR);
+ return Version(1,0,0,0,VF_VENDOR);
}
};