diff options
-rw-r--r-- | include/mode.h | 29 | ||||
-rw-r--r-- | src/mode.cpp | 76 | ||||
-rw-r--r-- | src/modules/m_operchans.cpp | 3 |
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 ¶meter); + + /** + * 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); } }; |