Fix desync when an oplevel deop is bounced (#1298140).
authorMichael Poole <mdpoole@troilus.org>
Tue, 27 Sep 2005 02:41:57 +0000 (02:41 +0000)
committerMichael Poole <mdpoole@troilus.org>
Tue, 27 Sep 2005 02:41:57 +0000 (02:41 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1496 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
include/channel.h
ircd/channel.c
ircd/m_burst.c
ircd/m_clearmode.c
ircd/m_create.c
ircd/m_kick.c

index c7d9a84865adf038da219f82abb1dacd5b707f5c..208dff96ac1f106453058720d33611c9fa12dd53 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2005-09-26  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct ModeBuf): Add mbm_oplevel to args
+       array.
+       (MB_OPLEVEL): New corresponding macro.
+       (modebuf_mode_client): Add corresponding argument.
+
+       * ircd/channel.c (modebuf_flush_int): Adjust worst-case buffer
+       usage to include :999 suffix.  Change format for oplevel passing.
+       (modebuf_mode_client): Set oplevel field in mbuf args array.
+       (struct ParseState): Add oplevel field to cli_change array.
+       (mode_parse_client): Accept and record oplevel suffix from
+       servers; fix it up if we're bouncing a deop.
+       (mode_process_clients): If a valid oplevel was parsed, use it.
+
+       * ircd/m_burst.c (ms_burst): Pass oplevel to modebuf_mode_client().
+
+       * ircd/m_clearmode.c (do_clearmode): Likewise.
+
+       * ircd/m_create.c (ms_create): Likewise.
+
+       * ircd/m_kick.c (ms_kick): Likewise.
+
 2005-09-23  Michael Poole <mdpoole@troilus.org>
 
        * include/whocmds.h (WHOSELECT_DELAY): Define new constant.
index 6abc777ae37047ddd6867ca453e404927e05a9cc..f14bd784fbdceaa17996d6bbd7aab6b843c21e53 100644 (file)
@@ -317,6 +317,7 @@ struct ModeBuf {
       char            *mbma_string;    /**< A string */
       struct Client    *mbma_client;   /**< A client */
     }                  mbm_arg;        /**< The mode argument */
+    unsigned short      mbm_oplevel;    /**< Oplevel for a bounce */
   }                    mb_modeargs[MAXMODEPARAMS];
                                        /**< A mode w/args */
 };
@@ -339,6 +340,7 @@ struct ModeBuf {
 #define MB_UINT(mb, i)         ((mb)->mb_modeargs[(i)].mbm_arg.mbma_uint)
 #define MB_STRING(mb, i)       ((mb)->mb_modeargs[(i)].mbm_arg.mbma_string)
 #define MB_CLIENT(mb, i)       ((mb)->mb_modeargs[(i)].mbm_arg.mbma_client)
+#define MB_OPLEVEL(mb, i)       ((mb)->mb_modeargs[(i)].mbm_oplevel)
 
 /** A buffer represeting a list of joins to send */
 struct JoinBuf {
@@ -421,7 +423,7 @@ extern void modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode,
 extern void modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode,
                                char *string, int free);
 extern void modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
-                               struct Client *client);
+                               struct Client *client, int oplevel);
 extern int modebuf_flush(struct ModeBuf *mbuf);
 extern void modebuf_extract(struct ModeBuf *mbuf, char *buf);
 
index 01ec91a2c51d3e8e50c51f98e47601db4217e628..0b0fb0e857ef53c04121a0f61c9be6fd6598dd59 100644 (file)
@@ -1574,11 +1574,11 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
     if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
       tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
 
-      if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
+      if ((totalbuflen - IRCD_MAX(9, tmp)) <= 0) /* don't overflow buffer */
        MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
       else {
        bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
-       totalbuflen -= IRCD_MAX(5, tmp) + 1;
+       totalbuflen -= IRCD_MAX(9, tmp) + 1;
       }
     } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
       tmp = strlen(MB_STRING(mbuf, i));
@@ -1748,8 +1748,17 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
        strptr_i = &remstr_i;
       }
 
-      /* deal with modes that take clients */
-      if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
+      /* if we're changing oplevels we know the oplevel, pass it on */
+      if (mbuf->mb_channel->mode.apass[0]
+          && (MB_TYPE(mbuf, i) & MODE_CHANOP)
+          && MB_OPLEVEL(mbuf, i) < MAXOPLEVEL)
+          *strptr_i += ircd_snprintf(0, strptr + *strptr_i, BUFSIZE - *strptr_i,
+                                     " %s%s:%d",
+                                     NumNick(MB_CLIENT(mbuf, i)),
+                                     MB_OPLEVEL(mbuf, i));
+
+      /* deal with other modes that take clients */
+      else if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
        build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
 
       /* deal with modes that take strings */
@@ -1969,16 +1978,18 @@ modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
  * @param mbuf         The modebuf to append the mode to.
  * @param mode         The mode to append.
  * @param client       The client argument to append.
+ * @param oplevel       The oplevel the user had or will have
  */
 void
 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
-                   struct Client *client)
+                   struct Client *client, int oplevel)
 {
   assert(0 != mbuf);
   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
 
   MB_TYPE(mbuf, mbuf->mb_count) = mode;
   MB_CLIENT(mbuf, mbuf->mb_count) = client;
+  MB_OPLEVEL(mbuf, mbuf->mb_count) = oplevel;
 
   /* when we've reached the maximal count, flush the buffer */
   if (++mbuf->mb_count >=
@@ -2149,6 +2160,7 @@ struct ParseState {
   struct Ban banlist[MAXPARA];
   struct {
     unsigned int flag;
+    unsigned short oplevel;
     struct Client *client;
   } cli_change[MAXPARA];
 };
@@ -2829,6 +2841,8 @@ mode_parse_client(struct ParseState *state, int *flag_p)
 {
   char *t_str;
   struct Client *acptr;
+  struct Membership *member;
+  int oplevel = MAXOPLEVEL + 1;
   int i;
 
   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
@@ -2849,8 +2863,13 @@ mode_parse_client(struct ParseState *state, int *flag_p)
 
   if (MyUser(state->sptr)) /* find client we're manipulating */
     acptr = find_chasing(state->sptr, t_str, NULL);
-  else
+  else {
+    if (t_str[5] == ':') {
+      t_str[5] = '\0';
+      oplevel = atoi(t_str + 6);
+    }
     acptr = findNUser(t_str);
+  }
 
   if (!acptr)
     return; /* find_chasing() already reported an error to the user */
@@ -2860,8 +2879,16 @@ mode_parse_client(struct ParseState *state, int *flag_p)
                                       state->cli_change[i].flag & flag_p[0]))
       break; /* found a slot */
 
+  /* If we are going to bounce this deop, mark the correct oplevel. */
+  if (state->flags & MODE_PARSE_BOUNCE
+      && state->dir == MODE_DEL
+      && flag_p[0] == MODE_CHANOP
+      && (member = find_member_link(state->chptr, acptr)))
+      oplevel = OpLevel(member);
+
   /* Store what we're doing to them */
   state->cli_change[i].flag = state->dir | flag_p[0];
+  state->cli_change[i].oplevel = oplevel;
   state->cli_change[i].client = acptr;
 }
 
@@ -2939,20 +2966,22 @@ mode_process_clients(struct ParseState *state)
                       "deop", equal ? "the same" : "a higher");
          continue;
        }
-    }
+      }
     }
 
     /* set op-level of member being opped */
     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
        (MODE_ADD | MODE_CHANOP)) {
-      /* If being opped by an outsider, get oplevel 1 for an apass
-       *   channel, else MAXOPLEVEL.
+      /* If a valid oplevel was specified, use it.
+       * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
        * Otherwise, if not an apass channel, or state->member has
        *   MAXOPLEVEL, get oplevel MAXOPLEVEL.
        * Otherwise, get state->member's oplevel+1.
        */
-      if (!state->member)
-        SetOpLevel(member, state->chptr->mode.apass[0] ? 1 : MAXOPLEVEL);
+      if (state->cli_change[i].oplevel <= MAXOPLEVEL)
+        SetOpLevel(member, state->cli_change[i].oplevel);
+      else if (!state->member)
+        SetOpLevel(member, MAXOPLEVEL);
       else if (!state->chptr->mode.apass[0] || OpLevel(state->member) == MAXOPLEVEL)
         SetOpLevel(member, MAXOPLEVEL);
       else
@@ -2975,7 +3004,8 @@ mode_process_clients(struct ParseState *state)
 
     /* accumulate the change */
     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
-                       state->cli_change[i].client);
+                       state->cli_change[i].client,
+                        state->cli_change[i].oplevel);
   } /* for (i = 0; state->cli_change[i].flags; i++) */
 }
 
index 5914af44cbc63641c47ce31707fbbbb4ab8f29cc..1746fda68601edae3755f6ff43e5309c4eabc455 100644 (file)
@@ -523,14 +523,14 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     for (member = chptr->members; member; member = member->next_member) {
       if (member->status & CHFL_BURST_JOINED) { /* joined during burst */
        if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED))
-         modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user);
+         modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user, OpLevel(member));
        if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED))
-         modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user);
+         modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user, OpLevel(member));
       } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */
        if (member->status & CHFL_CHANOP)
-         modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user);
+         modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user, OpLevel(member));
        if (member->status & CHFL_VOICE)
-         modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user);
+         modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user, OpLevel(member));
        member->status = (member->status
                           & ~(CHFL_CHANNEL_MANAGER | CHFL_CHANOP | CHFL_VOICE))
                         | CHFL_DEOPPED;
index bd390f05bce3c73a84aaf971777ffe733401a550..81392da469942342c67b2c07f85302629874fd7f 100644 (file)
@@ -200,13 +200,13 @@ do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr,
 
       /* Drop channel operator status */
       if (IsChanOp(member) && del_mode & MODE_CHANOP) {
-       modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user);
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, MAXOPLEVEL + 1);
        member->status &= ~CHFL_CHANOP;
       }
 
       /* Drop voice */
       if (HasVoice(member) && del_mode & MODE_VOICE) {
-       modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user);
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1);
        member->status &= ~CHFL_VOICE;
       }
     }
index da94f5e51c3683dbeb67a0f8c418072cb02f34e7..8219f09e0c4a556826dbca7ee9594f89db3f8876 100644 (file)
@@ -174,7 +174,7 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                      MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
                      MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
 
-       modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr);
+       modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
 
        modebuf_flush(&mbuf);
 
index 076eafbc8b0183e248e2ac395e828dc541537ba0..b21f770c78cfa5fa6a2843a6604adc64a2819cb8 100644 (file)
@@ -234,9 +234,9 @@ int ms_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
                    MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */
 
       if (IsChanOp(member))
-       modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, who);
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, who, MAXOPLEVEL + 1);
       if (HasVoice(member))
-       modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, who);
+       modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, who, MAXOPLEVEL + 1);
 
       modebuf_flush(&mbuf);
     }