]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/mode.cpp
I'll give you ##TOAST, :p
[user/henk/code/inspircd.git] / src / mode.cpp
index 5d6be4e74a90cb3ff0ffec3c48f89368eb372dc1..bddd6cc3190f3d40dfb969f779a2baa194f78a93 100644 (file)
@@ -3,31 +3,23 @@
  *       +------------------------------------+
  *
  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
- *                      E-mail:
- *                <brain@chatspike.net>
- *               <Craig@chatspike.net>
+ *                      E-mail:
+ *             <brain@chatspike.net>
+ *               <Craig@chatspike.net>
  *     
  * Written by Craig Edwards, Craig McLure, and others.
  * This program is free but copyrighted software; see
- *            the file COPYING for details.
+ *         the file COPYING for details.
  *
  * ---------------------------------------------------
  */
 
 using namespace std;
 
-#include "inspircd_config.h"
 #include "inspircd.h"
-#include "configreader.h"
-#include <unistd.h>
-#include "hash_map.h"
-#include "connection.h"
 #include "users.h"
 #include "modules.h"
-#include "message.h"
 #include "inspstring.h"
-#include "helperfuncs.h"
-#include "commands.h"
 #include "mode.h"
 
 /* +s (secret) */
@@ -54,7 +46,6 @@ using namespace std;
 #include "modes/cmode_h.h"
 /* +v (channel voice) */
 #include "modes/cmode_v.h"
-
 /* +s (server notices) */
 #include "modes/umode_s.h"
 /* +w (see wallops) */
@@ -63,17 +54,11 @@ using namespace std;
 #include "modes/umode_i.h"
 /* +o (operator) */
 #include "modes/umode_o.h"
+/* +n (notice mask - our implementation of snomasks) */
+#include "modes/umode_n.h"
 
-extern int MODCOUNT;
-extern std::vector<Module*> modules;
-extern std::vector<ircd_module*> factory;
-extern InspIRCd* ServerInstance;
-extern ServerConfig* Config;
-
-extern time_t TIME;
-
-ModeHandler::ModeHandler(char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly)
-       : mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly)
+ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix)
+       : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix)
 {
 }
 
@@ -86,6 +71,11 @@ bool ModeHandler::IsListMode()
        return list;
 }
 
+unsigned int ModeHandler::GetPrefixRank()
+{
+       return 0;
+}
+
 ModeType ModeHandler::GetModeType()
 {
        return m_type;
@@ -96,6 +86,11 @@ bool ModeHandler::NeedsOper()
        return oper;
 }
 
+char ModeHandler::GetPrefix()
+{
+       return prefix;
+}
+
 int ModeHandler::GetNumParams(bool adding)
 {
        return adding ? n_params_on : n_params_off;
@@ -111,6 +106,18 @@ ModeAction ModeHandler::OnModeChange(userrec* source, userrec* dest, chanrec* ch
        return MODEACTION_DENY;
 }
 
+ModePair ModeHandler::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{
+       if (dest)
+       {
+               return std::make_pair(dest->IsModeSet(this->mode), "");
+       }
+       else
+       {
+               return std::make_pair(channel->IsModeSet(this->mode), "");
+       }
+}
+
 void ModeHandler::DisplayList(userrec* user, chanrec* channel)
 {
 }
@@ -120,7 +127,7 @@ bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string &
        return (ours < theirs);
 }
 
-ModeWatcher::ModeWatcher(char modeletter, ModeType type) : mode(modeletter), m_type(type)
+ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
 {
 }
 
@@ -154,10 +161,10 @@ userrec* ModeParser::SanityChecks(userrec *user,const char *dest,chanrec *chan,i
        {
                return NULL;
        }
-       d = Find(dest);
+       d = ServerInstance->FindNick(dest);
        if (!d)
        {
-               WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, dest);
+               user->WriteServ("401 %s %s :No such nick/channel",user->nick, dest);
                return NULL;
        }
        return d;
@@ -190,7 +197,7 @@ const char* ModeParser::Grant(userrec *d,chanrec *chan,int MASK)
                                        n->channel->AddVoicedUser(d);
                                break;
                        }
-                       log(DEBUG,"grant: %s %s",n->channel->name,d->nick);
+                       ServerInstance->Log(DEBUG,"grant: %s %s",n->channel->name,d->nick);
                        return d->nick;
                }
        }
@@ -224,7 +231,7 @@ const char* ModeParser::Revoke(userrec *d,chanrec *chan,int MASK)
                                        n->channel->DelVoicedUser(d);
                                break;
                        }
-                       log(DEBUG,"revoke: %s %s",n->channel->name,d->nick);
+                       ServerInstance->Log(DEBUG,"revoke: %s %s",n->channel->name,d->nick);
                        return d->nick;
                }
        }
@@ -236,37 +243,63 @@ void ModeParser::DisplayCurrentModes(userrec *user, userrec* targetuser, chanrec
        if (targetchannel)
        {
                /* Display channel's current mode string */
-               WriteServ(user->fd,"324 %s %s +%s",user->nick, targetchannel->name, chanmodes(targetchannel, targetchannel->HasUser(user)));
-               WriteServ(user->fd,"329 %s %s %d", user->nick, targetchannel->name, targetchannel->created);
+               user->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
+               user->WriteServ("329 %s %s %d", user->nick, targetchannel->name, targetchannel->created);
                return;
        }
        else if (targetuser)
        {
                /* Display user's current mode string */
-               WriteServ(user->fd,"221 %s :+%s",targetuser->nick,targetuser->FormatModes());
+               user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
+               if (*targetuser->oper)
+                       user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
                return;
        }
+
        /* No such nick/channel */
-       WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, text);
+       user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
        return;
 }
 
-void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool servermode)
+void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool servermode)
 {
        std::string target = parameters[0];
        ModeType type = MODETYPE_USER;
        unsigned char mask = 0;
-       chanrec* targetchannel = FindChan(parameters[0]);
-       userrec* targetuser  = Find(parameters[0]);
+       chanrec* targetchannel = ServerInstance->FindChan(parameters[0]);
+       userrec* targetuser  = ServerInstance->FindNick(parameters[0]);
+
+       ServerInstance->Log(DEBUG,"ModeParser::Process start");
+
+       LastParse = "";
 
-       log(DEBUG,"ModeParser::Process start");
+       /* Special case for displaying the list for listmodes,
+        * e.g. MODE #chan b, or MODE #chan +b without a parameter
+        */
+       if ((targetchannel) && (pcnt == 2))
+       {
+               ServerInstance->Log(DEBUG,"Spool list");
+               const char* mode = parameters[1];
+               if (*mode == '+')
+                       mode++;
+               unsigned char handler_id = ((*mode) - 65) | MASK_CHANNEL;
+               ModeHandler* mh = modehandlers[handler_id];
+               if ((mh) && (mh->IsListMode()))
+               {
+                       mh->DisplayList(user, targetchannel);
+                       return;
+               }
+       }
 
        if (pcnt == 1)
        {
+               ServerInstance->Log(DEBUG,"Mode list request");
                this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
        }
        else if (pcnt > 1)
        {
+               ServerInstance->Log(DEBUG,"More than one parameter");
+
                if (targetchannel)
                {
                        type = MODETYPE_CHANNEL;
@@ -276,20 +309,28 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
                         * (e.g. are they a (half)op?
                         */
 
-                       if (cstatus(user, targetchannel) < STATUS_HOP)
+                       if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP))
                        {
                                /* We don't have halfop */
-                               log(DEBUG,"The user is not a halfop or above, checking other reasons for being able to set the modes");
+                               ServerInstance->Log(DEBUG,"The user is not a halfop or above, checking other reasons for being able to set the modes");
 
-                               /* Are we a uline or is it a servermode? */
-                               if ((!is_uline(user->server)) && (!servermode))
-                               {
-                                       /* Not enough permission:
-                                        * NOT a uline and NOT a servermode,
-                                        * OR, NOT halfop or above.
-                                        */
-                                       WriteServ(user->fd,"482 %s %s :You're not a channel (half)operator",user->nick, targetchannel->name);
+                               int MOD_RESULT = 0;
+                               FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
+                               if (MOD_RESULT == ACR_DENY)
                                        return;
+
+                               if (MOD_RESULT == ACR_DEFAULT)
+                               {
+                                       /* Are we a uline or is it a servermode? */
+                                       if ((!ServerInstance->ULine(user->server)) && (!servermode))
+                                       {
+                                               /* Not enough permission:
+                                                * NOT a uline and NOT a servermode,
+                                                * OR, NOT halfop or above.
+                                                */
+                                               user->WriteServ("482 %s %s :You're not a channel (half)operator",user->nick, targetchannel->name);
+                                               return;
+                                       }
                                }
                        }
                }
@@ -301,28 +342,10 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
                else
                {
                        /* No such nick/channel */
-                       WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
                        return;
                }
 
-               /* Special case for displaying the list for listmodes,
-                * e.g. MODE #chan b, or MODE #chan +b without a parameter
-                */
-               if ((type== MODETYPE_CHANNEL) && (pcnt == 2))
-               {
-                       char* mode = parameters[1];
-                       if (*mode == '+')
-                               mode++;
-
-                       unsigned char handler_id = ((*mode) - 65) | mask;
-                       ModeHandler* mh = modehandlers[handler_id];
-
-                       if ((mh) && (mh->IsListMode()))
-                       {
-                               mh->DisplayList(user, targetchannel);
-                       }
-               }
-               
                std::string mode_sequence = parameters[1];
                std::string parameter = "";
                std::ostringstream parameter_list;
@@ -330,11 +353,18 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
                bool adding = true, state_change = false;
                unsigned char handler_id = 0;
                int parameter_counter = 2; /* Index of first parameter */
+               int parameter_count = 0;
+
+               /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
+               if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
+                       mode_sequence.insert(0, "+");
 
                for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
                {
                        unsigned char modechar = *letter;
 
+                       ServerInstance->Log(DEBUG,"Process letter %c", modechar);
+
                        switch (modechar)
                        {
                                /* NB:
@@ -389,6 +419,10 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
                                                                if (parameter_counter < pcnt)
                                                                {
                                                                        parameter = parameters[parameter_counter++];
+
+                                                                       /* Yerk, invalid! */
+                                                                       if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
+                                                                               parameter = "";
                                                                }
                                                                else
                                                                {
@@ -401,7 +435,12 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
                                                         * eat any parameter that  came with the mode, and continue to next
                                                         */
                                                        if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!*user->oper))
+                                                       {
+                                                               user->WriteServ("481 %s :Permission Denied- Only IRC operators may %sset %s mode %c", user->nick,
+                                                                               adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
+                                                                               modehandlers[handler_id]->GetModeChar());
                                                                continue;
+                                                       }
 
                                                        /* Call the handler for the mode */
                                                        ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
@@ -426,7 +465,18 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
 
                                                                /* Is there a valid parameter for this mode? If so add it to the parameter list */
                                                                if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter != ""))
+                                                               {
                                                                        parameter_list << " " << parameter;
+                                                                       parameter_count++;
+                                                                       /* Does this mode have a prefix? */
+                                                                       if (modehandlers[handler_id]->GetPrefix() && targetchannel)
+                                                                       {
+                                                                               userrec* user_to_prefix = ServerInstance->FindNick(parameter);
+                                                                               if (user_to_prefix)
+                                                                                       targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
+                                                                                                       modehandlers[handler_id]->GetPrefixRank(), adding);
+                                                                       }
+                                                               }
 
                                                                /* Call all the AfterMode events in the mode watchers for this mode */
                                                                for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
@@ -434,13 +484,21 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
 
                                                                /* Reset the state change flag */
                                                                state_change = false;
+
+                                                               if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
+                                                                               || (parameter_count > MAXMODES))
+                                                               {
+                                                                       /* We cant have a mode sequence this long */
+                                                                       letter = mode_sequence.end() - 1;
+                                                                       continue;
+                                                               }
                                                        }
                                                }
                                        }
                                        else
                                        {
                                                /* No mode handler? Unknown mode character then. */
-                                               WriteServ(user->fd,"472 %s %c :is unknown mode char to me",user->nick, modechar);
+                                               user->WriteServ("472 %s %c :is unknown mode char to me",user->nick, modechar);
                                        }
                                break;
                        }
@@ -452,40 +510,42 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool server
                        {
                                if (type == MODETYPE_CHANNEL)
                                {
-                                       WriteChannelWithServ(Config->ServerName,targetchannel,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
+                                       targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
+                                       this->LastParse = targetchannel->name;
                                }
                                else
                                {
-                                       WriteServ(targetuser->fd,"MODE %s %s",targetuser->nick,output_sequence.c_str());
+                                       targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
+                                       this->LastParse = targetuser->nick;
                                }
                        }
                        else
                        {
                                if (type == MODETYPE_CHANNEL)
                                {
-                                       log(DEBUG,"Write output sequence and parameters to channel: %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
-                                       WriteChannel(targetchannel,user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
+                                       ServerInstance->Log(DEBUG,"Write output sequence and parameters to channel: %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
+                                       targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
                                        FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
+                                       this->LastParse = targetchannel->name;
                                }
                                else
                                {
-                                       WriteTo(user,targetuser,"MODE %s %s",targetuser->nick,output_sequence.c_str());
+                                       user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
                                        FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence));
+                                       this->LastParse = targetuser->nick;
                                }
                        }
+
+                       LastParse.append(" ");
+                       LastParse.append(output_sequence);
+                       LastParse.append(parameter_list.str());
                }
        }
 }
 
-
-void cmd_mode::Handle (char **parameters, int pcnt, userrec *user)
+const std::string& ModeParser::GetLastParse()
 {
-       if (!user)
-               return;
-
-       ServerInstance->ModeGrok->Process(parameters, pcnt, user, false);
-
-       return;
+       return LastParse;
 }
 
 void ModeParser::CleanMask(std::string &mask)
@@ -521,10 +581,6 @@ void ModeParser::CleanMask(std::string &mask)
        }
 }
 
-void ModeParser::BuildModeString(userrec* user)
-{
-}
-
 bool ModeParser::AddMode(ModeHandler* mh, unsigned const char modeletter)
 {
        unsigned char mask = 0;
@@ -534,52 +590,364 @@ bool ModeParser::AddMode(ModeHandler* mh, unsigned const char modeletter)
         * If they do that, thats their problem, and if i ever EVER see an
         * official InspIRCd developer do that, i'll beat them with a paddle!
         */
-       if ((modeletter < 'A') || (modeletter > 'z'))
+       if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
+               return false;
+
+       /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
+        * A mode prefix of ':' will fuck up both server to server, and client to server.
+        */
+       if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':'))
                return false;
 
        mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
-       pos = (modeletter-65) | mask;
+       pos = (mh->GetModeChar()-65) | mask;
 
        if (modehandlers[pos])
                return false;
 
        modehandlers[pos] = mh;
-       log(DEBUG,"ModeParser::AddMode: added mode %c",modeletter);
+       ServerInstance->Log(DEBUG,"ModeParser::AddMode: added mode %c",mh->GetModeChar());
        return true;
 }
 
-ModeParser::ModeParser()
+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;
+       unsigned char pos = 0;
+
+       if ((modeletter < 'A') || (modeletter > 'z'))
+               return NULL;
+
+       mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (modeletter-65) | mask;
+
+       return modehandlers[pos];
+}
+
+std::string ModeParser::UserModeList()
+{
+       char modestr[256];
+       int pointer = 0;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_USER;
+
+               if (modehandlers[pos])
+                       modestr[pointer++] = mode;
+       }
+       modestr[pointer++] = 0;
+       return modestr;
+}
+
+std::string ModeParser::ChannelModeList()
+{
+       char modestr[256];
+       int pointer = 0;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if (modehandlers[pos])
+                       modestr[pointer++] = mode;
+       }
+       modestr[pointer++] = 0;
+       return modestr;
+}
+
+std::string ModeParser::ParaModeList()
+{
+       char modestr[256];
+       int pointer = 0;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
+                       modestr[pointer++] = mode;
+       }
+       modestr[pointer++] = 0;
+       return modestr;
+}
+
+ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
+{
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
+               {
+                       return modehandlers[pos];
+               }
+       }
+       return NULL;
+}
+
+std::string ModeParser::ModeString(userrec* user, chanrec* channel)
+{
+       std::string types;
+       std::string pars;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+               ModeHandler* mh = modehandlers[pos];
+               if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
+               {
+                       ModePair ret;
+                       ret = mh->ModeSet(NULL, user, channel, user->nick);
+                       if (ret.first)
+                       {
+                               pars.append(" ");
+                               pars.append(user->nick);
+                               types.push_back(mh->GetModeChar());
+                       }
+               }
+       }
+
+       return types+pars;
+}
+
+std::string ModeParser::ChanModes()
+{
+       std::string type1;      /* Listmodes EXCEPT those with a prefix */
+       std::string type2;      /* Modes that take a param when adding or removing */
+       std::string type3;      /* Modes that only take a param when adding */
+       std::string type4;      /* Modes that dont take a param */
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+                /* One parameter when adding */
+               if (modehandlers[pos])
+               {       
+                       if (modehandlers[pos]->GetNumParams(true))
+                       {
+                               if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
+                               {
+                                       type1 += modehandlers[pos]->GetModeChar();
+                               }
+                               else
+                               {
+                                       /* ... and one parameter when removing */
+                                       if (modehandlers[pos]->GetNumParams(false))
+                                       {
+                                               /* But not a list mode */
+                                               if (!modehandlers[pos]->GetPrefix())
+                                               {
+                                                       type2 += modehandlers[pos]->GetModeChar();
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* No parameters when removing */
+                                               type3 += modehandlers[pos]->GetModeChar();
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               type4 += modehandlers[pos]->GetModeChar();
+                       }
+               }
+                        
+       }
+
+       return type1 + "," + type2 + "," + type3 + "," + type4;
+}
+
+bool ModeParser::PrefixComparison(const prefixtype one, const prefixtype two)
+{       
+       return one.second > two.second;
+}
+
+std::string ModeParser::BuildPrefixes()
+{
+       std::string mletters = "";
+       std::string mprefixes = "";
+       pfxcontainer pfx;
+       std::map<char,char> prefix_to_mode;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
+               {
+                       pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
+                       prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
+               }
+       }
+
+       sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
+
+       for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
+       {
+               mletters = mletters + n->first;
+               mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
+       }
+
+       return "(" + mprefixes + ")" + mletters;
+}
+
+bool ModeParser::AddModeWatcher(ModeWatcher* mw)
+{
+       unsigned char mask = 0;
+       unsigned char pos = 0;
+
+       if (!mw)
+               return false;
+
+       if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
+               return false;
+
+       mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (mw->GetModeChar()-65) | mask;
+
+       modewatchers[pos].push_back(mw);
+       ServerInstance->Log(DEBUG,"ModeParser::AddModeWatcher: watching mode %c",mw->GetModeChar());
+
+       return true;
+}
+
+bool ModeParser::DelModeWatcher(ModeWatcher* mw)
+{
+       unsigned char mask = 0;
+       unsigned char pos = 0;
+
+       if (!mw)
+               return false;
+
+       if ((mw->GetModeType() < 'A') || (mw->GetModeType() > 'z'))
+               return false;
+
+       mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (mw->GetModeChar()-65) | mask;
+
+       ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
+
+       if (a == modewatchers[pos].end())
+               return false;
+
+       modewatchers[pos].erase(a);
+       ServerInstance->Log(DEBUG,"ModeParser::DelModeWatcher: stopped watching mode %c",mw->GetModeChar());
+
+       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 */
        memset(modehandlers, 0, sizeof(modehandlers));
        memset(modewatchers, 0, sizeof(modewatchers));
 
+       /* Last parse string */
+       LastParse = "";
+
        /* Initialise the RFC mode letters */
 
        /* Start with channel simple modes, no params */
-       this->AddMode(new ModeChannelSecret, 's');
-       this->AddMode(new ModeChannelPrivate, 'p');
-       this->AddMode(new ModeChannelModerated, 'm');
-       this->AddMode(new ModeChannelTopicOps, 't');
-       this->AddMode(new ModeChannelNoExternal, 'n');
-       this->AddMode(new ModeChannelInviteOnly, 'i');
+       this->AddMode(new ModeChannelSecret(Instance), 's');
+       this->AddMode(new ModeChannelPrivate(Instance), 'p');
+       this->AddMode(new ModeChannelModerated(Instance), 'm');
+       this->AddMode(new ModeChannelTopicOps(Instance), 't');
+       this->AddMode(new ModeChannelNoExternal(Instance), 'n');
+       this->AddMode(new ModeChannelInviteOnly(Instance), 'i');
 
        /* Cannel modes with params */
-       this->AddMode(new ModeChannelKey, 'k');
-       this->AddMode(new ModeChannelLimit, 'l');
+       this->AddMode(new ModeChannelKey(Instance), 'k');
+       this->AddMode(new ModeChannelLimit(Instance), 'l');
 
        /* Channel listmodes */
-       this->AddMode(new ModeChannelBan, 'b');
-       this->AddMode(new ModeChannelOp, 'o');
-       this->AddMode(new ModeChannelHalfOp, 'h');
-       this->AddMode(new ModeChannelVoice, 'v');
+       this->AddMode(new ModeChannelBan(Instance), 'b');
+       this->AddMode(new ModeChannelOp(Instance), 'o');
+       this->AddMode(new ModeChannelHalfOp(Instance), 'h');
+       this->AddMode(new ModeChannelVoice(Instance), 'v');
 
        /* Now for usermodes */
-       this->AddMode(new ModeUserServerNotice, 's');
-       this->AddMode(new ModeUserWallops, 'w');
-       this->AddMode(new ModeUserInvisible, 'i');
-       this->AddMode(new ModeUserOperator, 'o');
-
-       /* TODO: User modes +swio */
+       this->AddMode(new ModeUserServerNotice(Instance), 's');
+       this->AddMode(new ModeUserWallops(Instance), 'w');
+       this->AddMode(new ModeUserInvisible(Instance), 'i');
+       this->AddMode(new ModeUserOperator(Instance), 'o');
+       this->AddMode(new ModeUserServerNoticeMask(Instance), 'n');
 }