int opped_members_index = 0;
struct Membership** opped_members = NULL;
int last_oplevel = 0;
- int feat_oplevels = (chptr->mode.apass[0]) != '\0';
+ int send_oplevels = 0;
assert(0 != cptr);
assert(0 != chptr);
++number_of_ops;
else
opped_members[opped_members_index++] = member;
+ /* We also send oplevels if anyone is below the weakest level. */
+ if (OpLevel(member) < MAXOPLEVEL)
+ send_oplevels = 1;
}
/* Only handle the members with the flags that we are interested in. */
if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
{
/* append the absolute value of the oplevel */
- if (feat_oplevels)
+ if (send_oplevels)
loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
else
tbuf[loc++] = 'o';
msgq_append(&me, mb, tbuf);
new_mode = 0;
}
- else if (feat_oplevels && flag_cnt > 1 && last_oplevel != member->oplevel)
+ else if (send_oplevels && flag_cnt > 1 && last_oplevel != member->oplevel)
{
/*
* This can't be the first member of a (continued) BURST
}
/* if we're changing oplevels and we know the oplevel, pass it on */
- if (mbuf->mb_channel->mode.apass[0]
- && (MB_TYPE(mbuf, i) & MODE_CHANOP)
+ if ((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",
modebuf_flush_int(mbuf, 0);
}
+/** Check a channel for join-delayed members.
+ * @param[in] chan Channel to search.
+ * @return Non-zero if any members are join-delayed; false if none are.
+ */
+static int
+find_delayed_joins(const struct Channel *chan)
+{
+ const struct Membership *memb;
+ for (memb = chan->members; memb; memb = memb->next_member)
+ if (IsDelayedJoin(memb))
+ return 1;
+ return 0;
+}
+
/** The exported binding for modebuf_flush()
*
* @param mbuf The mode buffer to flush.
int
modebuf_flush(struct ModeBuf *mbuf)
{
- struct Membership *memb;
-
- /* Check if MODE_WASDELJOINS should be set */
- if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
- && (mbuf->mb_rem & MODE_DELJOINS)) {
- for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
- if (IsDelayedJoin(memb)) {
- mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
- mbuf->mb_add |= MODE_WASDELJOINS;
- mbuf->mb_rem &= ~MODE_WASDELJOINS;
- break;
- }
- }
+ /* Check if MODE_WASDELJOINS should be set: */
+ /* Must be set if going -D and some clients are hidden */
+ if ((mbuf->mb_rem & MODE_DELJOINS)
+ && !(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
+ && find_delayed_joins(mbuf->mb_channel)) {
+ mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
+ mbuf->mb_add |= MODE_WASDELJOINS;
+ mbuf->mb_rem &= ~MODE_WASDELJOINS;
+ }
+ /* Must be cleared if +D is set */
+ if ((mbuf->mb_add & MODE_DELJOINS)
+ && ((mbuf->mb_channel->mode.mode & (MODE_WASDELJOINS | MODE_WASDELJOINS))
+ == (MODE_WASDELJOINS | MODE_WASDELJOINS))) {
+ mbuf->mb_channel->mode.mode &= ~MODE_WASDELJOINS;
+ mbuf->mb_add &= ~MODE_WASDELJOINS;
+ mbuf->mb_rem |= MODE_WASDELJOINS;
}
return modebuf_flush_int(mbuf, 1);
if (state->flags & MODE_PARSE_SET) {
if (state->dir == MODE_DEL) /* remove the old key */
*state->chptr->mode.key = '\0';
- else if (!state->chptr->mode.key[0]
- || ircd_strcmp(t_str, state->chptr->mode.key) < 0)
+ else
ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
}
}
!ircd_strcmp(state->chptr->mode.upass, t_str))
return; /* no upass change */
+ /* Skip if this is a burst, we have a Upass already and the new Upass is
+ * after the old one alphabetically */
+ if ((state->flags & MODE_PARSE_BURST) &&
+ *(state->chptr->mode.upass) &&
+ ircd_strcmp(state->chptr->mode.upass, t_str) <= 0)
+ return;
+
if (state->flags & MODE_PARSE_BOUNCE) {
if (*state->chptr->mode.upass) /* reset old upass */
modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
if (state->flags & MODE_PARSE_SET) {
if (state->dir == MODE_DEL) /* remove the old upass */
*state->chptr->mode.upass = '\0';
- else if (state->chptr->mode.upass[0] == '\0'
- || ircd_strcmp(t_str, state->chptr->mode.upass) < 0)
+ else
ircd_strncpy(state->chptr->mode.upass, t_str, KEYLEN);
}
}
!ircd_strcmp(state->chptr->mode.apass, t_str))
return; /* no apass change */
+ /* Skip if this is a burst, we have an Apass already and the new Apass is
+ * after the old one alphabetically */
+ if ((state->flags & MODE_PARSE_BURST) &&
+ *(state->chptr->mode.apass) &&
+ ircd_strcmp(state->chptr->mode.apass, t_str) <= 0)
+ return;
+
if (state->flags & MODE_PARSE_BOUNCE) {
if (*state->chptr->mode.apass) /* reset old apass */
modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
if (state->flags & MODE_PARSE_SET) {
if (state->dir == MODE_ADD) { /* set the new apass */
- /* Only accept the new apass if there is no current apass
- * (e.g. when a user sets it) or the new one is "less" than the
- * old (for resolving conflicts during burst).
- */
- if (state->chptr->mode.apass[0] == '\0'
- || ircd_strcmp(t_str, state->chptr->mode.apass) < 0)
+ /* Only accept the new apass if there is no current apass or
+ * this is a BURST. */
+ if (state->chptr->mode.apass[0] == '\0' ||
+ (state->flags & MODE_PARSE_BURST))
ircd_strncpy(state->chptr->mode.apass, t_str, KEYLEN);
/* Make it VERY clear to the user that this is a one-time password */
if (MyUser(state->sptr)) {
old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
if (res)
return res;
- /* Compare the addresses. */
- return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
+ /* If the old ban's mask mismatches, cannot be a superset. */
+ if (!ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits))
+ return 1;
+ /* Otherwise it depends on whether the old ban's text is a superset
+ * of the new. */
+ return mmatch(old_ban->banstr, new_ban->banstr);
}
/** Add a ban from a ban list and mark bans that should be removed
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 if (OpLevel(state->member) >= MAXOPLEVEL)
+ SetOpLevel(member, OpLevel(state->member));
else
SetOpLevel(member, OpLevel(state->member) + 1);
}
state->add &= ~MODE_SECRET;
state->del |= MODE_SECRET;
}
- if (flag_p[0] & MODE_DELJOINS) {
- state->add &= ~MODE_WASDELJOINS;
- state->del |= MODE_WASDELJOINS;
- }
} else {
state->add &= ~flag_p[0];
state->del |= flag_p[0];
void CheckDelayedJoins(struct Channel *chan)
{
- struct Membership *memb2;
-
- if (chan->mode.mode & MODE_WASDELJOINS) {
- for (memb2=chan->members;memb2;memb2=memb2->next_member)
- if (IsDelayedJoin(memb2))
- break;
-
- if (!memb2) {
- /* clear +d */
- chan->mode.mode &= ~MODE_WASDELJOINS;
- sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan, NULL, 0,
- "%H -d", chan);
- }
+ if ((chan->mode.mode & MODE_WASDELJOINS) && !find_delayed_joins(chan)) {
+ chan->mode.mode &= ~MODE_WASDELJOINS;
+ sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan, NULL, 0,
+ "%H -d", chan);
}
}