From: Michael Poole Date: Tue, 27 Sep 2005 02:41:57 +0000 (+0000) Subject: Fix desync when an oplevel deop is bounced (#1298140). X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=commitdiff_plain;h=5c1c1b577823ab730cc8232ef89b0c291dbccb83 Fix desync when an oplevel deop is bounced (#1298140). git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1496 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- diff --git a/ChangeLog b/ChangeLog index c7d9a84..208dff9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2005-09-26 Michael Poole + + * 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 * include/whocmds.h (WHOSELECT_DELAY): Define new constant. diff --git a/include/channel.h b/include/channel.h index 6abc777..f14bd78 100644 --- a/include/channel.h +++ b/include/channel.h @@ -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); diff --git a/ircd/channel.c b/ircd/channel.c index 01ec91a..0b0fb0e 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -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++) */ } diff --git a/ircd/m_burst.c b/ircd/m_burst.c index 5914af4..1746fda 100644 --- a/ircd/m_burst.c +++ b/ircd/m_burst.c @@ -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; diff --git a/ircd/m_clearmode.c b/ircd/m_clearmode.c index bd390f0..81392da 100644 --- a/ircd/m_clearmode.c +++ b/ircd/m_clearmode.c @@ -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; } } diff --git a/ircd/m_create.c b/ircd/m_create.c index da94f5e..8219f09 100644 --- a/ircd/m_create.c +++ b/ircd/m_create.c @@ -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); diff --git a/ircd/m_kick.c b/ircd/m_kick.c index 076eafb..b21f770 100644 --- a/ircd/m_kick.c +++ b/ircd/m_kick.c @@ -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); }