]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/mode.cpp
Added support for 472 numeric (Unknown mode char) - typobox43
[user/henk/code/inspircd.git] / src / mode.cpp
index f23546d75ef9d2a1da081ba431905c3105bf09c8..604111e6f8c179ffeb8a7d9254383871f91ef88a 100644 (file)
@@ -1,3 +1,19 @@
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
+ *                       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.
+ *
+ * ---------------------------------------------------
+ */
+
 #include "inspircd.h"
 #include "inspircd_io.h"
 #include "inspircd_util.h"
@@ -40,6 +56,8 @@ using namespace std;
 extern int MODCOUNT;
 extern vector<Module*> modules;
 extern vector<ircd_module*> factory;
+extern std::vector<std::string> module_names;
+
 
 extern int LogLevel;
 extern char ServerName[MAXBUF];
@@ -56,7 +74,12 @@ extern char list[MAXBUF];
 extern char PrefixQuit[MAXBUF];
 extern char DieValue[MAXBUF];
 
-int give_ops(userrec *user,char *dest,chanrec *chan,int status)
+extern bool AllowHalfop;
+extern bool AllowProtect;
+extern bool AllowFounder;
+
+
+char* give_ops(userrec *user,char *dest,chanrec *chan,int status)
 {
        userrec *d;
        int i;
@@ -64,54 +87,63 @@ int give_ops(userrec *user,char *dest,chanrec *chan,int status)
        if ((!user) || (!dest) || (!chan))
        {
                log(DEFAULT,"*** BUG *** give_ops was given an invalid parameter");
-               return 0;
+               return NULL;
        }
-       if ((status < STATUS_OP) && (!is_uline(user->server)))
+
+       if (!isnick(dest))
        {
-               log(DEBUG,"%s cant give ops to %s because they nave status %d and needs %d",user->nick,dest,status,STATUS_OP);
-               WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
-               return 0;
+               log(DEFAULT,"the target nickname given to give_ops was invalid");
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
+       }
+       d = Find(dest);
+       if (!d)
+       {
+               log(DEFAULT,"the target nickname given to give_ops couldnt be found");
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
        }
        else
        {
-               if (!isnick(dest))
-               {
-                       log(DEFAULT,"the target nickname given to give_ops was invalid");
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
-               }
-               d = Find(dest);
-               if (!d)
+
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_OP));
+               
+               if (MOD_RESULT == ACR_DENY)
+                       return NULL;
+               if (MOD_RESULT == ACR_DEFAULT)
                {
-                       log(DEFAULT,"the target nickname given to give_ops couldnt be found");
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
+                       if ((status < STATUS_OP) && (!is_uline(user->server)))
+                       {
+                               log(DEBUG,"%s cant give ops to %s because they nave status %d and needs %d",user->nick,dest,status,STATUS_OP);
+                               WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+                               return NULL;
+                       }
                }
-               else
+
+
+               for (int i = 0; i != MAXCHANS; i++)
                {
-                       for (int i = 0; i != MAXCHANS; i++)
+                       if ((d->chans[i].channel != NULL) && (chan != NULL))
+                       if (!strcasecmp(d->chans[i].channel->name,chan->name))
                        {
-                               if ((d->chans[i].channel != NULL) && (chan != NULL))
-                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
+                       if (d->chans[i].uc_modes & UCMODE_OP)
                                {
-                                       if (d->chans[i].uc_modes & UCMODE_OP)
-                                       {
-                                               /* mode already set on user, dont allow multiple */
-                                               log(DEFAULT,"The target user given to give_ops was already opped on the channel");
-                                               return 0;
-                                       }
-                                       d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
-                                       log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
-                                       return 1;
+                                       /* mode already set on user, dont allow multiple */
+                                       log(DEFAULT,"The target user given to give_ops was already opped on the channel");
+                                       return NULL;
                                }
+                               d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
+                               log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
+                               return d->nick;
                        }
-                       log(DEFAULT,"The target channel given to give_ops was not in the users mode list");
                }
+               log(DEFAULT,"The target channel given to give_ops was not in the users mode list");
        }
-       return 1;
+       return NULL;
 }
 
-int give_hops(userrec *user,char *dest,chanrec *chan,int status)
+char* give_hops(userrec *user,char *dest,chanrec *chan,int status)
 {
        userrec *d;
        int i;
@@ -119,49 +151,56 @@ int give_hops(userrec *user,char *dest,chanrec *chan,int status)
        if ((!user) || (!dest) || (!chan))
        {
                log(DEFAULT,"*** BUG *** give_hops was given an invalid parameter");
-               return 0;
+               return NULL;
        }
-       if ((status < STATUS_OP) && (!is_uline(user->server)))
+
+       d = Find(dest);
+       if (!isnick(dest))
        {
-               WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
-               return 0;
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
+       }
+       if (!d)
+       {
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
        }
        else
        {
-               d = Find(dest);
-               if (!isnick(dest))
-               {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
-               }
-               if (!d)
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_HALFOP));
+               
+               if (MOD_RESULT == ACR_DENY)
+                       return NULL;
+               if (MOD_RESULT == ACR_DEFAULT)
                {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
+                       if ((status < STATUS_OP) && (!is_uline(user->server)))
+                       {
+                               WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+                               return NULL;
+                       }
                }
-               else
+
+               for (int i = 0; i != MAXCHANS; i++)
                {
-                       for (int i = 0; i != MAXCHANS; i++)
+                       if ((d->chans[i].channel != NULL) && (chan != NULL))
+                       if (!strcasecmp(d->chans[i].channel->name,chan->name))
                        {
-                               if ((d->chans[i].channel != NULL) && (chan != NULL))
-                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
+                               if (d->chans[i].uc_modes & UCMODE_HOP)
                                {
-                                       if (d->chans[i].uc_modes & UCMODE_HOP)
-                                       {
-                                               /* mode already set on user, dont allow multiple */
-                                               return 0;
-                                       }
-                                       d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
-                                       log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
-                                       return 1;
+                                       /* mode already set on user, dont allow multiple */
+                                       return NULL;
                                }
+                               d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
+                               log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
+                               return d->nick;
                        }
                }
        }
-       return 1;
+       return NULL;
 }
 
-int give_voice(userrec *user,char *dest,chanrec *chan,int status)
+char* give_voice(userrec *user,char *dest,chanrec *chan,int status)
 {
        userrec *d;
        int i;
@@ -169,49 +208,56 @@ int give_voice(userrec *user,char *dest,chanrec *chan,int status)
        if ((!user) || (!dest) || (!chan))
        {
                log(DEFAULT,"*** BUG *** give_voice was given an invalid parameter");
-               return 0;
+               return NULL;
        }
-       if ((status < STATUS_HOP) && (!is_uline(user->server)))
+
+       d = Find(dest);
+       if (!isnick(dest))
        {
-               WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
-               return 0;
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
+       }
+       if (!d)
+       {
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
        }
        else
        {
-               d = Find(dest);
-               if (!isnick(dest))
-               {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
-               }
-               if (!d)
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_VOICE));
+               
+               if (MOD_RESULT == ACR_DENY)
+                       return NULL;
+               if (MOD_RESULT == ACR_DEFAULT)
                {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
+                       if ((status < STATUS_HOP) && (!is_uline(user->server)))
+                       {
+                               WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
+                               return NULL;
+                       }
                }
-               else
+
+               for (int i = 0; i != MAXCHANS; i++)
                {
-                       for (int i = 0; i != MAXCHANS; i++)
+                       if ((d->chans[i].channel != NULL) && (chan != NULL))
+                       if (!strcasecmp(d->chans[i].channel->name,chan->name))
                        {
-                               if ((d->chans[i].channel != NULL) && (chan != NULL))
-                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
+                               if (d->chans[i].uc_modes & UCMODE_VOICE)
                                {
-                                       if (d->chans[i].uc_modes & UCMODE_VOICE)
-                                       {
-                                               /* mode already set on user, dont allow multiple */
-                                               return 0;
-                                       }
-                                       d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
-                                       log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
-                                       return 1;
+                                       /* mode already set on user, dont allow multiple */
+                                       return NULL;
                                }
+                               d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
+                               log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
+                               return d->nick;
                        }
                }
        }
-       return 1;
+       return NULL;
 }
 
-int take_ops(userrec *user,char *dest,chanrec *chan,int status)
+char* take_ops(userrec *user,char *dest,chanrec *chan,int status)
 {
        userrec *d;
        int i;
@@ -219,53 +265,59 @@ int take_ops(userrec *user,char *dest,chanrec *chan,int status)
        if ((!user) || (!dest) || (!chan))
        {
                log(DEFAULT,"*** BUG *** take_ops was given an invalid parameter");
-               return 0;
+               return NULL;
        }
-       if ((status < STATUS_OP) && (!is_uline(user->server)))
+
+       d = Find(dest);
+       if (!isnick(dest))
        {
-               log(DEBUG,"%s cant give ops to %s because they have status %d and needs %d",user->nick,dest,status,STATUS_OP);
-               WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
-               return 0;
+               log(DEBUG,"take_ops was given an invalid target nickname of %s",dest);
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
+       }
+       if (!d)
+       {
+               log(DEBUG,"take_ops couldnt resolve the target nickname: %s",dest);
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
        }
        else
        {
-               d = Find(dest);
-               if (!isnick(dest))
-               {
-                       log(DEBUG,"take_ops was given an invalid target nickname of %s",dest);
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
-               }
-               if (!d)
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEOP));
+               
+               if (MOD_RESULT == ACR_DENY)
+                       return NULL;
+               if (MOD_RESULT == ACR_DEFAULT)
                {
-                       log(DEBUG,"take_ops couldnt resolve the target nickname: %s",dest);
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
+                       if ((status < STATUS_OP) && (!is_uline(user->server)))
+                       {
+                               WriteServ(user->fd,"482 %s %s :You are not a channel operator",user->nick, chan->name);
+                               return NULL;
+                       }
                }
-               else
+
+               for (int i = 0; i != MAXCHANS; i++)
                {
-                       for (int i = 0; i != MAXCHANS; i++)
+                       if ((d->chans[i].channel != NULL) && (chan != NULL))
+                       if (!strcasecmp(d->chans[i].channel->name,chan->name))
                        {
-                               if ((d->chans[i].channel != NULL) && (chan != NULL))
-                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
+                               if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
                                {
-                                       if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
-                                       {
-                                               /* mode already set on user, dont allow multiple */
-                                               return 0;
-                                       }
-                                       d->chans[i].uc_modes ^= UCMODE_OP;
-                                       log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
-                                       return 1;
+                                       /* mode already set on user, dont allow multiple */
+                                       return NULL;
                                }
+                               d->chans[i].uc_modes ^= UCMODE_OP;
+                               log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
+                               return d->nick;
                        }
-                       log(DEBUG,"take_ops couldnt locate the target channel in the target users list");
                }
+               log(DEBUG,"take_ops couldnt locate the target channel in the target users list");
        }
-       return 1;
+       return NULL;
 }
 
-int take_hops(userrec *user,char *dest,chanrec *chan,int status)
+char* take_hops(userrec *user,char *dest,chanrec *chan,int status)
 {
        userrec *d;
        int i;
@@ -273,49 +325,56 @@ int take_hops(userrec *user,char *dest,chanrec *chan,int status)
        if ((!user) || (!dest) || (!chan))
        {
                log(DEFAULT,"*** BUG *** take_hops was given an invalid parameter");
-               return 0;
+               return NULL;
+       }
+
+       d = Find(dest);
+       if (!isnick(dest))
+       {
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
        }
-       if ((status < STATUS_OP) && (!is_uline(user->server)))
+       if (!d)
        {
-               WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
-               return 0;
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
        }
        else
        {
-               d = Find(dest);
-               if (!isnick(dest))
-               {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
-               }
-               if (!d)
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEHALFOP));
+               
+               if (MOD_RESULT == ACR_DENY)
+                       return NULL;
+               if (MOD_RESULT == ACR_DEFAULT)
                {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
+                       if ((status < STATUS_OP) && (!is_uline(user->server)))
+                       {
+                               WriteServ(user->fd,"482 %s %s :You are not a channel operator",user->nick, chan->name);
+                               return NULL;
+                       }
                }
-               else
+
+               for (int i = 0; i != MAXCHANS; i++)
                {
-                       for (int i = 0; i != MAXCHANS; i++)
+                       if ((d->chans[i].channel != NULL) && (chan != NULL))
+                       if (!strcasecmp(d->chans[i].channel->name,chan->name))
                        {
-                               if ((d->chans[i].channel != NULL) && (chan != NULL))
-                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
+                               if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
                                {
-                                       if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
-                                       {
-                                               /* mode already set on user, dont allow multiple */
-                                               return 0;
-                                       }
-                                       d->chans[i].uc_modes ^= UCMODE_HOP;
-                                       log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
-                                       return 1;
+                                       /* mode already set on user, dont allow multiple */
+                                       return NULL;
                                }
+                               d->chans[i].uc_modes ^= UCMODE_HOP;
+                               log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
+                               return d->nick;
                        }
                }
        }
-       return 1;
+       return NULL;
 }
 
-int take_voice(userrec *user,char *dest,chanrec *chan,int status)
+char* take_voice(userrec *user,char *dest,chanrec *chan,int status)
 {
        userrec *d;
        int i;
@@ -323,80 +382,87 @@ int take_voice(userrec *user,char *dest,chanrec *chan,int status)
        if ((!user) || (!dest) || (!chan))
        {
                log(DEFAULT,"*** BUG *** take_voice was given an invalid parameter");
-               return 0;
+               return NULL;
        }
-       if ((status < STATUS_HOP) && (!is_uline(user->server)))
+
+       d = Find(dest);
+       if (!isnick(dest))
        {
-               WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
-               return 0;
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
+       }
+       if (!d)
+       {
+               WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+               return NULL;
        }
        else
        {
-               d = Find(dest);
-               if (!isnick(dest))
-               {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
-               }
-               if (!d)
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEVOICE));
+               
+               if (MOD_RESULT == ACR_DENY)
+                       return NULL;
+               if (MOD_RESULT == ACR_DEFAULT)
                {
-                       WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
-                       return 0;
+                       if ((status < STATUS_HOP) && (!is_uline(user->server)))
+                       {
+                               WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
+                               return NULL;
+                       }
                }
-               else
+
+               for (int i = 0; i != MAXCHANS; i++)
                {
-                       for (int i = 0; i != MAXCHANS; i++)
+                       if ((d->chans[i].channel != NULL) && (chan != NULL))
+                       if (!strcasecmp(d->chans[i].channel->name,chan->name))
                        {
-                               if ((d->chans[i].channel != NULL) && (chan != NULL))
-                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
+                               if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
                                {
-                                       if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
-                                       {
-                                               /* mode already set on user, dont allow multiple */
-                                               return 0;
-                                       }
-                                       d->chans[i].uc_modes ^= UCMODE_VOICE;
-                                       log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
-                                       return 1;
+                                       /* mode already set on user, dont allow multiple */
+                                       return NULL;
                                }
+                               d->chans[i].uc_modes ^= UCMODE_VOICE;
+                               log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
+                               return d->nick;
                        }
                }
        }
-       return 1;
+       return NULL;
 }
 
-int add_ban(userrec *user,char *dest,chanrec *chan,int status)
+char* add_ban(userrec *user,char *dest,chanrec *chan,int status)
 {
        if ((!user) || (!dest) || (!chan)) {
                log(DEFAULT,"*** BUG *** add_ban was given an invalid parameter");
-               return 0;
+               return NULL;
        }
 
        BanItem b;
        if ((!user) || (!dest) || (!chan))
-               return 0;
+               return NULL;
        if (strchr(dest,'!')==0)
-               return 0;
+               return NULL;
        if (strchr(dest,'@')==0)
-               return 0;
+               return NULL;
        for (int i = 0; i < strlen(dest); i++)
                if (dest[i] < 32)
-                       return 0;
+                       return NULL;
        for (int i = 0; i < strlen(dest); i++)
                if (dest[i] > 126)
-                       return 0;
+                       return NULL;
        int c = 0;
        for (int i = 0; i < strlen(dest); i++)
                if (dest[i] == '!')
                        c++;
        if (c>1)
-               return 0;
+               return NULL;
        c = 0;
        for (int i = 0; i < strlen(dest); i++)
                if (dest[i] == '@')
                        c++;
        if (c>1)
-               return 0;
+               return NULL;
        log(DEBUG,"add_ban: %s %s",chan->name,user->nick);
 
        TidyBan(dest);
@@ -405,7 +471,7 @@ int add_ban(userrec *user,char *dest,chanrec *chan,int status)
                if (!strcasecmp(i->data,dest))
                {
                        // dont allow a user to set the same ban twice
-                       return 0;
+                       return NULL;
                }
        }
 
@@ -413,10 +479,10 @@ int add_ban(userrec *user,char *dest,chanrec *chan,int status)
        strncpy(b.data,dest,MAXBUF);
        strncpy(b.set_by,user->nick,NICKMAX);
        chan->bans.push_back(b);
-       return 1;
+       return dest;
 }
 
-int take_ban(userrec *user,char *dest,chanrec *chan,int status)
+char* take_ban(userrec *user,char *dest,chanrec *chan,int status)
 {
        if ((!user) || (!dest) || (!chan)) {
                log(DEFAULT,"*** BUG *** take_ban was given an invalid parameter");
@@ -429,10 +495,10 @@ int take_ban(userrec *user,char *dest,chanrec *chan,int status)
                if (!strcasecmp(i->data,dest))
                {
                        chan->bans.erase(i);
-                       return 1;
+                       return dest;
                }
        }
-       return 0;
+       return NULL;
 }
 
 void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt, bool servermode, bool silent, bool local)
@@ -450,7 +516,7 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
        int pc = 0;
        int ptr = 0;
        int mdir = 1;
-       int r = 0;
+       char* r = NULL;
        bool k_set = false, l_set = false;
 
        if (pcnt < 2)
@@ -458,6 +524,12 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                return;
        }
 
+       int MOD_RESULT = 0;
+       FOREACH_RESULT(OnAccessCheck(user,NULL,chan,AC_GENERAL_MODE));
+       
+       if (MOD_RESULT == ACR_DENY)
+               return;
+
        log(DEBUG,"process_modes: start: parameters=%d",pcnt);
 
        strcpy(modelist,parameters[1]); /* mode list, e.g. +oo-o */
@@ -470,7 +542,7 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
 
        for (ptr = 0; ptr < strlen(modelist); ptr++)
        {
-               r = 0;
+               r = NULL;
 
                {
                        log(DEBUG,"process_modes: modechar: %c",modelist[ptr]);
@@ -525,12 +597,12 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                        if (r)
                                        {
                                                strcat(outlist,"o");
-                                               strcpy(outpars[pc++],parameters[param-1]);
+                                               strcpy(outpars[pc++],r);
                                        }
                                break;
                        
                                case 'h':
-                                       if ((param >= pcnt)) break;
+                                       if (((param >= pcnt)) || (!AllowHalfop)) break;
                                        if (mdir == 1)
                                        {
                                                r = give_hops(user,parameters[param++],chan,status);
@@ -542,7 +614,7 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                        if (r)
                                        {
                                                strcat(outlist,"h");
-                                               strcpy(outpars[pc++],parameters[param-1]);
+                                               strcpy(outpars[pc++],r);
                                        }
                                break;
                        
@@ -560,7 +632,7 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                        if (r)
                                        {
                                                strcat(outlist,"v");
-                                               strcpy(outpars[pc++],parameters[param-1]);
+                                               strcpy(outpars[pc++],r);
                                        }
                                break;
                                
@@ -659,7 +731,7 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                                
                                                // reported by mech: large values cause underflow
                                                if (chan->limit < 0)
-                                                       chan->limit = MAXINT;
+                                                       chan->limit = 0x7FFFFF;
                                                        
                                                if (chan->limit)
                                                {
@@ -743,13 +815,16 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                break;
                                
                                default:
-                                       log(DEBUG,"Preprocessing custom mode %c",modechar);
+                                       log(DEBUG,"Preprocessing custom mode %c: modelist: %s",modechar,chan->custom_modes);
                                        string_list p;
                                        p.clear();
                                        if (((!strchr(chan->custom_modes,modechar)) && (!mdir)) || ((strchr(chan->custom_modes,modechar)) && (mdir)))
                                        {
-                                               log(DEBUG,"Mode %c isnt set on %s but trying to remove!",modechar,chan->name);
-                                               break;
+                                               if (!ModeIsListMode(modechar,MT_CHANNEL))
+                                               {
+                                                       log(DEBUG,"Mode %c isnt set on %s but trying to remove!",modechar,chan->name);
+                                                       break;
+                                               }
                                        }
                                        if (ModeDefined(modechar,MT_CHANNEL))
                                        {
@@ -768,10 +843,10 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                                bool handled = false;
                                                if (param>=pcnt)
                                                {
-                                                       log(DEBUG,"Not enough parameters for module-mode %c",modechar);
                                                        // we're supposed to have a parameter, but none was given... so dont handle the mode.
                                                        if (((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir)) || ((ModeDefinedOff(modechar,MT_CHANNEL)>0) && (!mdir))) 
                                                        {
+                                                               log(DEBUG,"Not enough parameters for module-mode %c",modechar);
                                                                handled = true;
                                                                param++;
                                                        }
@@ -780,27 +855,46 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                                {
                                                        if (!handled)
                                                        {
-                                                               if (modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p))
+                                                               int t = modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p);
+                                                               if (t != 0)
                                                                {
                                                                        log(DEBUG,"OnExtendedMode returned nonzero for a module");
                                                                        char app[] = {modechar, 0};
-                                                                       if (ptr>0)
+                                                                       if (ModeIsListMode(modechar,MT_CHANNEL))
                                                                        {
-                                                                               if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
+                                                                               if (t == -1)
                                                                                {
-                                                                                       strcat(outlist, app);
+                                                                                       pc++;
                                                                                }
-                                                                               else if (!strchr(outlist,modechar))
+                                                                               else
                                                                                {
-                                                                                       strcat(outlist, app);
+                                                                                       if (ptr>0)
+                                                                                       {
+                                                                                               strcat(outlist, app);
+                                                                                       }
+                                                                                       strcpy(outpars[pc++],parameters[param++]);
                                                                                }
                                                                        }
-                                                                       chan->SetCustomMode(modechar,mdir);
-                                                                       // include parameters in output if mode has them
-                                                                       if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
+                                                                       else
                                                                        {
-                                                                               chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
-                                                                               strcpy(outpars[pc++],parameters[param++]);
+                                                                               if (ptr>0)
+                                                                               {
+                                                                                       if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
+                                                                                       {
+                                                                                               strcat(outlist, app);
+                                                                                       }
+                                                                                       else if (!strchr(outlist,modechar))
+                                                                                       {
+                                                                                               strcat(outlist, app);
+                                                                                       }
+                                                                               }
+                                                                               chan->SetCustomMode(modechar,mdir);
+                                                                               // include parameters in output if mode has them
+                                                                               if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
+                                                                               {
+                                                                                       chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
+                                                                                       strcpy(outpars[pc++],parameters[param++]);
+                                                                               }
                                                                        }
                                                                        // break, because only one module can handle the mode.
                                                                        handled = true;
@@ -808,6 +902,10 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                                        }
                                                }
                                        }
+                                       else
+                                       {
+                                               WriteServ(user->fd,"472 %s %c :is unknown mode char to me",user->nick,modechar);
+                                       }
                                break;
                                
                        }
@@ -930,7 +1028,7 @@ bool process_module_umode(char umode, userrec* source, void* dest, bool adding)
                {
                        if (modules[i]->OnExtendedMode(source,(void*)dest,umode,MT_CLIENT,adding,p))
                        {
-                               log(DEBUG,"Module claims umode %c",umode);
+                               log(DEBUG,"Module %s claims umode %c",module_names[i].c_str(),umode);
                                return true;
                        }
                }
@@ -970,7 +1068,7 @@ void handle_mode(char **parameters, int pcnt, userrec *user)
 
        if ((dest) && (pcnt == 1))
        {
-               WriteServ(user->fd,"221 %s :+%s",user->nick,user->modes);
+               WriteServ(user->fd,"221 %s :+%s",dest->nick,dest->modes);
                return;
        }
 
@@ -1178,10 +1276,18 @@ void handle_mode(char **parameters, int pcnt, userrec *user)
                        }
                }
 
-               if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
-               {
-                       WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, Ptr->name);
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(OnAccessCheck(user,NULL,Ptr,AC_GENERAL_MODE));
+               
+               if (MOD_RESULT == ACR_DENY)
                        return;
+               if (MOD_RESULT == ACR_DEFAULT)
+               {
+                       if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
+                       {
+                               WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, Ptr->name);
+                               return;
+                       }
                }
 
                process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,false);