if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
continue;
- }
+ } else if (MB_TYPE(mbuf, i) & MODE_FREE)
+ MyFree(MB_STRING(mbuf, i)); /* free string if needed */
MB_TYPE(mbuf, i) = 0;
MB_UINT(mbuf, i) = 0;
* MODE_ADD or MODE_DEL
*/
void
-modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string)
+modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
+ int free)
{
assert(0 != mbuf);
assert(0 != (mode & (MODE_ADD | MODE_DEL)));
- MB_TYPE(mbuf, mbuf->mb_count) = mode;
+ MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
MB_STRING(mbuf, mbuf->mb_count) = string;
/* when we've reached the maximal count, flush the buffer */
if (state->flags & MODE_PARSE_BOUNCE) {
if (*state->chptr->mode.key) /* reset old key */
modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
- state->chptr->mode.key);
+ state->chptr->mode.key, 0);
else /* remove new bogus key */
- modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str);
+ modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
} else /* send new key */
- modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str);
+ modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
if (state->flags & MODE_PARSE_SET) {
if (state->dir == MODE_ADD) /* set the new key */
return;
}
+ t_str = collapse(pretty_mask(t_str));
+
/* remember the ban for the moment... */
if (state->dir == MODE_ADD) {
newban = state->banlist + (state->numbans++);
newban->next = 0;
- newban->value.ban.banstr = t_str;
+ DupString(newban->value.ban.banstr, t_str);
newban->value.ban.who = state->sptr->name;
newban->value.ban.when = CurrentTime;
newban->flags |= CHFL_BAN_IPMASK;
}
+ if (!state->chptr->banlist) {
+ state->chptr->banlist = newban; /* add our ban with its flags */
+ state->done |= DONE_BANCLEAN;
+ return;
+ }
+
/* Go through all bans */
for (ban = state->chptr->banlist; ban; ban = ban->next) {
/* first, clean the ban flags up a bit */
if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
break;
- } else if (!mmatch(ban->value.ban.banstr, t_str))
- newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
- else if (!mmatch(t_str, ban->value.ban.banstr))
+ continue;
+ } else if (!mmatch(ban->value.ban.banstr, t_str)) {
+ if (!(ban->flags & MODE_DEL))
+ newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
+ } else if (!mmatch(t_str, ban->value.ban.banstr))
ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
- else if (!ban->next)
+
+ if (!ban->next) {
ban->next = newban; /* add our ban with its flags */
+ break; /* get out of loop */
+ }
}
}
state->done |= DONE_BANCLEAN;
mode_process_bans(struct ParseState *state)
{
struct SLink *ban, *newban, *prevban, *nextban;
+ int count = 0;
+ int len = 0;
+ int banlen;
int changed = 0;
for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
+ count++;
+ banlen = strlen(ban->value.ban.banstr);
+ len += banlen;
nextban = ban->next;
- if (ban->flags & MODE_DEL) { /* Deleted a ban? */
+ if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
+ if (prevban)
+ prevban->next = 0; /* Break the list; ban isn't a real ban */
+ else
+ state->chptr->banlist = 0;
+
+ count--;
+ len -= banlen;
+
+ MyFree(ban->value.ban.banstr);
+
+ continue;
+ } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
- ban->value.ban.banstr);
+ ban->value.ban.banstr,
+ state->flags & MODE_PARSE_SET);
if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
if (prevban) /* clip it out of the list... */
else
state->chptr->banlist = ban->next;
- MyFree(ban->value.ban.banstr); /* free it */
+ count--;
+ len -= banlen;
+
MyFree(ban->value.ban.who);
free_link(ban);
} else
ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
} else if (ban->flags & MODE_ADD) { /* adding a ban? */
- prevban->next = 0; /* Break the list; ban isn't a real ban */
+ if (prevban)
+ prevban->next = 0; /* Break the list; ban isn't a real ban */
+ else
+ state->chptr->banlist = 0;
/* If we're supposed to ignore it, do so. */
if (ban->flags & CHFL_BAN_OVERLAPPED &&
!(state->flags & MODE_PARSE_BOUNCE)) {
- prevban = ban;
- continue;
- }
+ count--;
+ len -= banlen;
- /* add the ban to the buffer */
- modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
- ban->value.ban.banstr);
-
- if (state->flags & MODE_PARSE_SET) { /* create a new ban */
- newban = make_link();
- DupString(newban->value.ban.banstr, ban->value.ban.banstr);
- DupString(newban->value.ban.who, ban->value.ban.who);
- newban->value.ban.when = ban->value.ban.when;
- newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
-
- newban->next = state->chptr->banlist; /* and link it in */
- state->chptr->banlist = newban;
-
- changed++;
+ MyFree(ban->value.ban.banstr);
+ } else {
+ if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
+ (len > MAXBANLENGTH || count >= MAXBANS)) {
+ send_error_to_client(state->sptr, ERR_BANLISTFULL,
+ state->chptr->chname, ban->value.ban.banstr);
+ count--;
+ len -= banlen;
+
+ MyFree(ban->value.ban.banstr);
+ } else {
+ /* add the ban to the buffer */
+ modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
+ ban->value.ban.banstr,
+ !(state->flags & MODE_PARSE_SET));
+
+ if (state->flags & MODE_PARSE_SET) { /* create a new ban */
+ newban = make_link();
+ newban->value.ban.banstr = ban->value.ban.banstr;
+ DupString(newban->value.ban.who, ban->value.ban.who);
+ newban->value.ban.when = ban->value.ban.when;
+ newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
+
+ newban->next = state->chptr->banlist; /* and link it in */
+ state->chptr->banlist = newban;
+
+ changed++;
+ }
+ }
}
}
- prevban = ban; /* keep track of where we've been */
+ prevban = ban;
} /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
if (changed) /* if we changed the ban list, we must invalidate the bans */
* the key until after modebuf_* are done with it
*/
if (del_mode & MODE_KEY && *chptr->mode.key)
- modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key);
+ modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
/* If we're removing the limit, note that and clear the limit */
if (del_mode & MODE_LIMIT && chptr->mode.limit) {
* Go through and mark the bans for deletion; note that we can't
* free them until after modebuf_* are done with them
*/
- if (del_mode & MODE_BAN)
- for (link = chptr->banlist; link; link = link->next)
- modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, link->value.ban.banstr);
+ if (del_mode & MODE_BAN) {
+ for (link = chptr->banlist; link; link = next) {
+ next = link->next;
+
+ modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, /* delete ban */
+ link->value.ban.banstr, 1);
+
+ MyFree(link->value.ban.who); /* free up who string */
+ free_link(link); /* and of course the link itself */
+ }
+
+ chptr->banlist = 0;
+ }
/* Deal with users on the channel */
if (del_mode & (MODE_BAN | MODE_CHANOP | MODE_VOICE))
if (del_mode & MODE_KEY)
chptr->mode.key[0] = '\0';
- /* and free the bans */
- if (del_mode & MODE_BAN) {
- for (link = chptr->banlist; link; link = next) {
- next = link->next;
-
- MyFree(link->value.ban.banstr);
- MyFree(link->value.ban.who);
- free_link(link);
- }
-
- chptr->banlist = 0;
- }
-
/* Don't propagate CLEARMODE if it's a local channel */
if (IsLocalChannel(chptr->chname))
return 0;