]> jfr.im git - solanum.git/blobdiff - ircd/chmode.c
Support more human friendly k/d/x-line duration format
[solanum.git] / ircd / chmode.c
index 7b7dc5528d6fa4c6b35a641206d4680031830ae5..d6d9141a4de68314896ef30f20ae1153db298f41 100644 (file)
@@ -42,6 +42,7 @@
 #include "s_assert.h"
 #include "parse.h"
 #include "msgbuf.h"
+#include "packet.h"
 
 /* bitmasks for error returns, so we send once per call */
 #define SM_ERR_NOTS             0x00000001     /* No TS on channel */
@@ -62,8 +63,6 @@
 
 static struct ChModeChange mode_changes[BUFSIZE];
 static int mode_count;
-static int mode_limit;
-static int mode_limit_simple;
 static int mask_pos;
 static int removed_mask_pos;
 
@@ -118,7 +117,6 @@ construct_cflags_strings(void)
 
                /* Should we leave orphaned check here? -- dwr */
                if (chmode_table[i].set_func != NULL &&
-                               chmode_table[i].set_func != chm_nosuch &&
                                chmode_table[i].set_func != chm_orphaned)
                {
                    *ptr2++ = (char) i;
@@ -157,11 +155,10 @@ cflag_add(char c_, ChannelModeFunc function)
        int c = (unsigned char)c_;
 
        if (chmode_table[c].set_func != NULL &&
-                       chmode_table[c].set_func != chm_nosuch &&
                        chmode_table[c].set_func != chm_orphaned)
                return 0;
 
-       if (chmode_table[c].set_func == NULL || chmode_table[c].set_func == chm_nosuch)
+       if (chmode_table[c].set_func == NULL)
                chmode_table[c].mode_type = find_cflag_slot();
        if (chmode_table[c].mode_type == 0)
                return 0;
@@ -575,20 +572,6 @@ fix_key_remote(char *arg)
        return arg;
 }
 
-/* chm_*()
- *
- * The handlers for each specific mode.
- */
-void
-chm_nosuch(struct Client *source_p, struct Channel *chptr,
-          int alevel, const char *arg, int *errors, int dir, char c, long mode_type)
-{
-       if(*errors & SM_ERR_UNKNOWN)
-               return;
-       *errors |= SM_ERR_UNKNOWN;
-       sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
-}
-
 void
 chm_simple(struct Client *source_p, struct Channel *chptr,
           int alevel, const char *arg, int *errors, int dir, char c, long mode_type)
@@ -596,9 +579,6 @@ chm_simple(struct Client *source_p, struct Channel *chptr,
        if(!allow_mode_change(source_p, chptr, alevel, errors, c))
                return;
 
-       if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
-               return;
-
        /* setting + */
        if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
        {
@@ -676,9 +656,6 @@ chm_hidden(struct Client *source_p, struct Channel *chptr,
                return;
        }
 
-       if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
-               return;
-
        /* setting + */
        if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
        {
@@ -722,9 +699,6 @@ chm_staff(struct Client *source_p, struct Channel *chptr,
                return;
        }
 
-       if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
-               return;
-
        /* setting + */
        if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
        {
@@ -813,7 +787,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
                break;
 
        default:
-               sendto_realops_snomask(SNO_GENERAL, L_ALL, "chm_ban() called with unknown type!");
+               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "chm_ban() called with unknown type!");
                return;
        }
 
@@ -855,10 +829,6 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
        if (!allow_mode_change(source_p, chptr, alevel, errors, c))
                return;
 
-
-       if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
-               return;
-
        /* empty ban, or starts with ':' which messes up s2s, ignore it */
        if (EmptyString(arg) || *arg == ':')
                return;
@@ -1017,9 +987,6 @@ chm_op(struct Client *source_p, struct Channel *chptr,
                return;
        }
 
-       if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
-               return;
-
        if(dir == MODE_ADD)
        {
                if(targ_p == source_p && mstptr->flags & CHFL_CHANOP)
@@ -1085,9 +1052,6 @@ chm_voice(struct Client *source_p, struct Channel *chptr,
                return;
        }
 
-       if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
-               return;
-
        if(dir == MODE_ADD)
        {
                mode_changes[mode_count].letter = c;
@@ -1120,9 +1084,6 @@ chm_limit(struct Client *source_p, struct Channel *chptr,
        if (!allow_mode_change(source_p, chptr, alevel, errors, c))
                return;
 
-       if (MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
-               return;
-
        if (dir == MODE_ADD)
        {
                if (EmptyString(arg) || (limit = atoi(arg)) <= 0)
@@ -1162,9 +1123,6 @@ chm_throttle(struct Client *source_p, struct Channel *chptr,
        if (!allow_mode_change(source_p, chptr, alevel, errors, c))
                return;
 
-       if (MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
-               return;
-
        if (dir == MODE_ADD)
        {
                if (sscanf(arg, "%d:%d", &joins, &timeslice) < 2)
@@ -1234,9 +1192,6 @@ chm_forward(struct Client *source_p, struct Channel *chptr,
        }
 #endif
 
-       if (MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
-               return;
-
        if (dir == MODE_ADD)
        {
                if(EmptyString(arg))
@@ -1278,9 +1233,6 @@ chm_key(struct Client *source_p, struct Channel *chptr,
        if (!allow_mode_change(source_p, chptr, alevel, errors, c))
                return;
 
-       if (MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
-               return;
-
        if (dir == MODE_ADD)
        {
                key = LOCAL_COPY(arg);
@@ -1372,14 +1324,15 @@ void
 set_channel_mode(struct Client *client_p, struct Client *source_p,
                 struct Channel *chptr, struct membership *msptr, int parc, const char *parv[])
 {
-       static char modebuf[BUFSIZE];
+       static char modebuf[BUFSIZE * 2]; /* paranoid case: 2 canonical chars per input char */
        static char parabuf[BUFSIZE];
        char *mbuf;
        char *pbuf;
        int cur_len, mlen, paralen, paracount, arglen, len;
        int i, j, flags;
        int dir = MODE_ADD;
-       int access_dir = MODE_QUERY;
+       bool changes = false;
+       bool privileged_query = false;
        int parn = 1;
        int errors = 0;
        int alevel;
@@ -1387,12 +1340,12 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
        char c;
        struct Client *fakesource_p;
        int flags_list[3] = { ALL_MEMBERS, ONLY_CHANOPS, ONLY_OPERS };
+       int mode_limit = 0;
+       int mode_limit_simple = 0;
 
        mask_pos = 0;
        removed_mask_pos = 0;
        mode_count = 0;
-       mode_limit = 0;
-       mode_limit_simple = 0;
 
        /* Hide connecting server on netburst -- jilles */
        if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p))
@@ -1407,10 +1360,13 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                char mode;
        };
 
-       static struct modeset modesets[MAXPARA];
+       static struct modeset modesets[MAXMODEPARAMS + MAXMODES_SIMPLE];
        struct modeset *ms = modesets, *mend;
+       char canon_op = '\0';
+
+       mbuf = modebuf;
 
-       for (ml = parv[0]; *ml != 0; ml++)
+       for (ml = parv[0]; *ml != 0 && ms - modesets < ARRAY_SIZE(modesets); ml++)
        {
                c = *ml;
                switch (c)
@@ -1431,7 +1387,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                        bool use_arg = dir == MODE_ADD ? cm->flags & CHM_ARG_SET :
                                       dir == MODE_DEL ? cm->flags & CHM_ARG_DEL :
                                       false;
-                       if (cm->set_func == NULL || cm->set_func == chm_nosuch)
+                       if (cm->set_func == NULL)
                        {
                                sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
                                return;
@@ -1453,10 +1409,30 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                                 * does nothing for a query on a mode with no query. would it be
                                 * good to send an error here?
                                 */
+                               continue;
                        }
 
-                       if (effective_dir != MODE_QUERY && access_dir == MODE_QUERY)
-                               access_dir = effective_dir;
+                       if (MyClient(source_p))
+                       {
+                               if (use_arg && ++mode_limit > MAXMODEPARAMS)
+                                       continue;
+                               if (!use_arg && ++mode_limit_simple > MAXMODES_SIMPLE)
+                                       continue;
+                       }
+
+                       char op = effective_dir == MODE_ADD ? '+' :
+                                 effective_dir == MODE_DEL ? '-' :
+                                 '=';
+
+                       if (op != canon_op)
+                               *mbuf++ = canon_op = op;
+
+                       *mbuf++ = c;
+
+                       if (effective_dir != MODE_QUERY)
+                               changes = true;
+                       if (effective_dir == MODE_QUERY && cm->flags & CHM_OPS_QUERY)
+                               privileged_query = true;
 
                        ms->cm = cm;
                        ms->dir = effective_dir;
@@ -1470,28 +1446,51 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                }
        }
 
+       /* this will happen on something like MODE +-=++-.
+        * we'd have caught that with the if !mode_count
+        * later on, but this saves an override notice
+        */
+       if (ms == modesets)
+               return;
+
        if (parn < parc)
        {
                /* XXX we could reject excess params here */
        }
 
+       /* Finish the flood grace period if we were asked to do anything */
+       if (changes && MyClient(source_p) && !IsFloodDone(source_p))
+       {
+               flood_endgrace(source_p);
+       }
+
        mend = ms;
 
-       alevel = get_channel_access(source_p, chptr, msptr, access_dir, reconstruct_parv(parc, parv));
+       if (parn > 1)
+       {
+               strcpy(mbuf, " ");
+               rb_strlcat(modebuf, reconstruct_parv(parn - 1, parv + 1), sizeof modebuf);
+       }
+       else
+       {
+               *mbuf = '\0';
+       }
+       int access_dir = privileged_query ? MODE_OP_QUERY :
+                        changes ? MODE_ADD :
+                        MODE_QUERY;
+       alevel = get_channel_access(source_p, chptr, msptr, access_dir, modebuf);
 
        for (ms = modesets; ms < mend; ms++)
        {
-               ChannelModeFunc set_func = ms->cm->set_func;
-               if (set_func == NULL)
-                       set_func = chm_nosuch;
+               ChannelModeFunc *set_func = ms->cm->set_func;
                set_func(fakesource_p, chptr, alevel, ms->arg, &errors, ms->dir, ms->mode, ms->cm->mode_type);
        }
 
        /* bail out if we have nothing to do... */
-       if(!mode_count)
+       if (!mode_count)
                return;
 
-       if(IsServer(source_p))
+       if (IsServer(source_p))
                mlen = sprintf(modebuf, ":%s MODE %s ", fakesource_p->name, chptr->chname);
        else
                mlen = sprintf(modebuf, ":%s!%s@%s MODE %s ",