]> jfr.im git - irc/rqf/shadowircd.git/blobdiff - src/chmode.c
s/owner/admin/ throughout the source code and docs.
[irc/rqf/shadowircd.git] / src / chmode.c
index f6c393491045d0e30898918beda2d001d130bd35..a4b26bac1ffa4ff7e2e768b7028e5a8f6f68b060 100644 (file)
@@ -42,6 +42,7 @@
 #include "s_newconf.h"
 #include "logger.h"
 #include "chmode.h"
+#include "irc_dictionary.h"
 
 /* bitmasks for error returns, so we send once per call */
 #define SM_ERR_NOTS             0x00000001     /* No TS on channel */
@@ -90,7 +91,7 @@ construct_noparam_modes(void)
                        !(chmode_table[i].set_func == chm_throttle) &&
                         !(chmode_table[i].set_func == chm_key) &&
                         !(chmode_table[i].set_func == chm_limit) &&
-                       !(chmode_table[i].set_func == chm_owner) &&
+                       !(chmode_table[i].set_func == chm_admin) &&
                         !(chmode_table[i].set_func == chm_op) &&
                        !(chmode_table[i].set_func == chm_halfop) &&
                         !(chmode_table[i].set_func == chm_voice))
@@ -178,8 +179,8 @@ find_cflag_slot(void)
 static int
 get_channel_access(struct Client *source_p, struct membership *msptr)
 {
-       if(!MyClient(source_p) || is_owner(msptr))
-               return CHFL_OWNER;
+       if(!MyClient(source_p) || is_admin(msptr))
+               return CHFL_ADMIN;
        else if(is_chanop(msptr))
                return CHFL_CHANOP;
        else if(is_halfop(msptr))
@@ -501,8 +502,10 @@ chm_simple(struct Client *source_p, struct Channel *chptr,
 {
 
        int override = 0;
+       struct Metadata *md;
+       struct DictionaryIter iter;
        
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if (IsOverride(source_p))
                        override = 1;
@@ -540,6 +543,18 @@ chm_simple(struct Client *source_p, struct Channel *chptr,
        }
        else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
        {
+               /* cleanup metadata when the related mode is removed */
+               if(c == 'J')
+               {
+                       DICTIONARY_FOREACH(md, &iter, chptr->metadata)
+                       {
+                               if(!strcmp(md->value, "KICKNOREJOIN"))  
+                                       channel_metadata_delete(chptr, md->name, 0);
+                       }
+               }
+               if(c == 'K')
+                       channel_metadata_delete(chptr, "NOREPEAT", 0);
+
                chptr->mode.mode &= ~mode_type;
 
                mode_changes[mode_count].letter = c;
@@ -587,6 +602,59 @@ chm_orphaned(struct Client *source_p, struct Channel *chptr,
        }
 }
 
+void
+chm_hidden(struct Client *source_p, struct Channel *chptr,
+               int alevel, int parc, int *parn,
+               const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       if(!IsOper(source_p) && !IsServer(source_p))
+       {
+               if(!(*errors & SM_ERR_NOPRIVS))
+                       sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
+               *errors |= SM_ERR_NOPRIVS;
+               return;
+       }
+       if(MyClient(source_p) && !IsOperAdmin(source_p))
+       {
+               if(!(*errors & SM_ERR_NOPRIVS))
+                       sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
+                                       source_p->name, "cmodes");
+               *errors |= SM_ERR_NOPRIVS;
+               return;
+       }
+
+       if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
+               return;
+
+       /* setting + */
+       if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
+       {
+               chptr->mode.mode |= mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count].mems = ONLY_OPERS;
+               mode_changes[mode_count].override = 0;
+               mode_changes[mode_count++].arg = NULL;
+       }
+       else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
+       {
+               chptr->mode.mode &= ~mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ONLY_OPERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count].override = 0;
+               mode_changes[mode_count++].arg = NULL;
+       }
+}
+
 void
 chm_staff(struct Client *source_p, struct Channel *chptr,
          int alevel, int parc, int *parn,
@@ -726,11 +794,18 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
                *errors |= errorval;
 
                /* non-ops cant see +eI lists.. */
-               if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP && mode_type != CHFL_BAN &&
+               if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && mode_type != CHFL_BAN &&
                                mode_type != CHFL_QUIET)
                {
                        if(IsOverride(source_p))
-                               override = 1;
+                       {
+                               sendto_wallops_flags(UMODE_WALLOP, &me,
+                                               "%s is overriding modes on %s: (%s list)",
+                                               get_oper_name(source_p), chptr->chname, mode_type == CHFL_INVEX ? "invex" : "exempt");
+                               sendto_server(NULL, chptr, NOCAPS, NOCAPS,
+                                               ":%s WALLOPS :%s is overriding modes on %s: (%s list)",
+                                               use_id(source_p), get_oper_name(source_p), chptr->chname, mode_type == CHFL_INVEX ? "invex" : "exempt");
+                       }
                        else
                        {
 
@@ -756,7 +831,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
                return;
        }
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -844,16 +919,16 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
 }
 
 void
-chm_owner(struct Client *source_p, struct Channel *chptr,
+chm_admin(struct Client *source_p, struct Channel *chptr,
        int alevel, int parc, int *parn,
        const char **parv, int *errors, int dir, char c, long mode_type)
 {
        struct membership *mstptr;
-       const char *ownernick;
+       const char *adminnick;
        struct Client *targ_p;
        int override = 0;
 
-       if(!ConfigChannel.use_owner)
+       if(!ConfigChannel.use_admin)
        {
                if(*errors & SM_ERR_UNKNOWN)
                        return;
@@ -862,7 +937,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr,
                return;
        }
 
-       if(alevel != CHFL_OWNER)
+       if(alevel != CHFL_ADMIN)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -870,8 +945,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr,
                {
 
                        if(!(*errors & SM_ERR_NOOPS))
-                               sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
-                                               me.name, source_p->name, chptr->chname);
+                               sendto_one(source_p, ":%s 482 %s %s :You're not a channel administrator", me.name, source_p->name, chptr->chname);
                        *errors |= SM_ERR_NOOPS;
                        return;
                }
@@ -880,17 +954,17 @@ chm_owner(struct Client *source_p, struct Channel *chptr,
        if((dir == MODE_QUERY) || (parc <= *parn))
                return;
 
-       ownernick = parv[(*parn)];
+       adminnick = parv[(*parn)];
        (*parn)++;
 
        /* empty nick */
-       if(EmptyString(ownernick))
+       if(EmptyString(adminnick))
        {
                sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
                return;
        }
 
-       if((targ_p = find_chasing(source_p, ownernick, NULL)) == NULL)
+       if((targ_p = find_chasing(source_p, adminnick, NULL)) == NULL)
        {
                return;
        }
@@ -901,7 +975,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr,
        {
                if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
                        sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
-                                          form_str(ERR_USERNOTINCHANNEL), ownernick, chptr->chname);
+                                          form_str(ERR_USERNOTINCHANNEL), adminnick, chptr->chname);
                *errors |= SM_ERR_NOTONCHANNEL;
                return;
        }
@@ -914,8 +988,11 @@ chm_owner(struct Client *source_p, struct Channel *chptr,
                if(targ_p == source_p)
                {
                        no_override_deop = 1;
+                       /* Don't reject modes from remote. It desyncs, and this is perfectly
+                        * legitimate from a remote override oper.
                        if(!override)
                                return;
+                       */
                }
 
                mode_changes[mode_count].letter = c;
@@ -928,7 +1005,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr,
                mode_changes[mode_count].override = override;
                mode_changes[mode_count++].client = targ_p;
 
-               mstptr->flags |= CHFL_OWNER;
+               mstptr->flags |= CHFL_ADMIN;
        }
        else
        {
@@ -949,7 +1026,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr,
                mode_changes[mode_count].override = override;
                mode_changes[mode_count++].client = targ_p;
 
-               mstptr->flags &= ~CHFL_OWNER;
+               mstptr->flags &= ~CHFL_ADMIN;
        }
 }
 
@@ -963,7 +1040,7 @@ chm_op(struct Client *source_p, struct Channel *chptr,
        struct Client *targ_p;
        int override = 0;
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1015,8 +1092,11 @@ chm_op(struct Client *source_p, struct Channel *chptr,
                if(targ_p == source_p)
                {
                        no_override_deop = 1;
+                       /* Don't reject modes from remote. It desyncs, and this is perfectly
+                        * legitimate from a remote override oper.
                        if(!override)
                                return;
+                       */
                }
 
                mode_changes[mode_count].letter = c;
@@ -1073,7 +1153,7 @@ chm_halfop(struct Client *source_p, struct Channel *chptr,
                return;
        }
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1125,8 +1205,11 @@ chm_halfop(struct Client *source_p, struct Channel *chptr,
                if(targ_p == source_p)
                {
                        no_override_deop = 1;
+                       /* Don't reject modes from remote. It desyncs, and this is perfectly
+                        * legitimate from a remote override oper.
                        if(!override)
                                return;
+                       */
                }
 
                mode_changes[mode_count].letter = c;
@@ -1174,7 +1257,7 @@ chm_voice(struct Client *source_p, struct Channel *chptr,
        struct Client *targ_p;
        int override = 0;
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1261,7 +1344,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr,
        int limit;
        int override = 0;
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1328,7 +1411,7 @@ chm_throttle(struct Client *source_p, struct Channel *chptr,
        int joins = 0, timeslice = 0;
        int override = 0;
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1420,7 +1503,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr,
        }
 
 #ifndef FORWARD_OPERONLY
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1525,7 +1608,7 @@ chm_key(struct Client *source_p, struct Channel *chptr,
        char *key;
        int override = 0;
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1611,7 +1694,7 @@ chm_regonly(struct Client *source_p, struct Channel *chptr,
 {
        int override = 0;
 
-       if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
+       if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
        {
                if(IsOverride(source_p))
                        override = 1;
@@ -1731,7 +1814,7 @@ struct ChannelMode chmode_table[256] =
   {chm_simple, MODE_NOREJOIN },        /* J */
   {chm_simple, MODE_NOREPEAT },        /* K */
   {chm_staff,  MODE_EXLIMIT },         /* L */
-  {chm_nosuch, 0 },                    /* M */
+  {chm_hidden, MODE_NOOPERKICK },      /* M */
   {chm_simple, MODE_NONICK },          /* N */
   {chm_nosuch, 0 },                    /* O */
   {chm_staff,  MODE_PERMANENT },       /* P */
@@ -1751,7 +1834,7 @@ struct ChannelMode chmode_table[256] =
   {chm_nosuch, 0 },
   {chm_nosuch, 0 },
   {chm_nosuch, 0 },
-  {chm_owner,  0 },                    /* a */
+  {chm_admin,  0 },                    /* a */
   {chm_ban,    CHFL_BAN },             /* b */
   {chm_simple, MODE_NOCOLOR },         /* c */
   {chm_nosuch, 0 },                    /* d */
@@ -1949,6 +2032,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
        const char *ml = parv[0];
        char c;
        struct Client *fakesource_p;
+       int flags_list[3] = { ALL_MEMBERS, ONLY_CHANOPS, ONLY_OPERS };
 
        mask_pos = 0;
        mode_count = 0;
@@ -1998,7 +2082,9 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                                  source_p->name, source_p->username,
                                  source_p->host, chptr->chname);
 
-       for (override = 0; override < (IsOverride(source_p) ? 2 : 1); ++override)
+       mlen = 0;
+
+       for (override = 0; override < (IsOverride(source_p) && alevel != CHFL_CHANOP ? 2 : 1); ++override)
        {
                int was_on_chan = 0;
 
@@ -2013,7 +2099,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                                add_user_to_channel(chptr, source_p, CHFL_CHANOP);
                }
 
-               for(j = 0, flags = ALL_MEMBERS; j < 2; j++, flags = ONLY_CHANOPS)
+               for(j = 0, flags = flags_list[0]; j < 3; j++, flags = flags_list[j])
                {
                        cur_len = mlen;
                        mbuf = modebuf + mlen;
@@ -2025,6 +2111,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                        for(i = 0; i < mode_count; i++)
                        {
                                if(mode_changes[i].letter == 0 || mode_changes[i].mems != flags)
+                                       continue;
 
                                if(mode_changes[i].override != override)
                                        continue;
@@ -2043,20 +2130,24 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                                 * bufsize (4 == +/-,modechar,two spaces) send now.
                                 */
                                if(mode_changes[i].arg != NULL &&
-                                               ((paracount == MAXMODEPARAMSSERV) ||
-                                                ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3))))
+                                  ((paracount == MAXMODEPARAMSSERV) ||
+                                   ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3))))
                                {
                                        *mbuf = '\0';
 
                                        if(cur_len > mlen)
                                        {
                                                sendto_channel_local(flags, chptr, "%s%s %s",
-                                                               cmdbuf, modebuf, parabuf);
+                                                                    cmdbuf, modebuf, parabuf);
                                                if(override)
-                                                       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                               {
+                                                       sendto_wallops_flags(UMODE_WALLOP, &me,
                                                                        "%s is overriding modes on %s: %s %s",
-                                                                       get_oper_name(source_p), chptr->chname,
-                                                                       modebuf, parabuf);
+                                                                       get_oper_name(source_p), chptr->chname, modebuf, parabuf);
+                                                       sendto_server(NULL, chptr, NOCAPS, NOCAPS,
+                                                                       ":%s WALLOPS :%s is overriding modes on %s: %s %s",
+                                                                       use_id(source_p), get_oper_name(source_p), chptr->chname, modebuf, parabuf);
+                                               }
                                        }
                                        else
                                                continue;
@@ -2088,16 +2179,34 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                                }
                        }
 
-                       if(override)
+                       if(paralen && parabuf[paralen - 1] == ' ')
+                               parabuf[paralen - 1] = '\0';
+
+                       *mbuf = '\0';
+                       if(cur_len > mlen)
                        {
-                               if(!was_on_chan)
-                                       remove_user_from_channel(find_channel_membership(chptr, source_p));
-                               else if (!no_override_deop)
-                                       msptr->flags &= ~CHFL_CHANOP;
+                               sendto_channel_local(flags, chptr, "%s%s %s", cmdbuf, modebuf, parabuf);
+                               if(override)
+                               {
+                                       sendto_wallops_flags(UMODE_WALLOP, &me,
+                                                       "%s is overriding modes on %s: %s %s",
+                                                       get_oper_name(source_p), chptr->chname, modebuf, parabuf);
+                                       sendto_server(NULL, chptr, NOCAPS, NOCAPS,
+                                                       ":%s WALLOPS :%s is overriding modes on %s: %s %s",
+                                                       use_id(source_p), get_oper_name(source_p), chptr->chname, modebuf, parabuf);
+                               }
                        }
+               }
+               if(override)
+               {
+                       if(!was_on_chan)
+                               remove_user_from_channel(find_channel_membership(chptr, source_p));
+                       else if (!no_override_deop)
+                               msptr->flags &= ~CHFL_CHANOP;
+               }
        }
+
        /* only propagate modes originating locally, or if we're hubbing */
        if(MyClient(source_p) || rb_dlink_list_length(&serv_list) > 1)
                send_cap_mode_changes(client_p, source_p, chptr, mode_changes, mode_count);
-       }
 }