assert(0 != chptr);
for (lp = chptr->banlist; lp; lp = lp->next)
- send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr, lp->who, lp->when);
+ if ((lp->flags & BAN_EXCEPTION) != BAN_EXCEPTION)
+ send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr, lp->who, lp->when);
send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
}
+/** send an exception list to a client for a channel
+ *
+ * @param cptr Client to send the banlist to.
+ * @param chptr Channel whose exception list to send.
+ */
+static void send_exception_list(struct Client* cptr, struct Channel* chptr)
+{
+ struct Ban* lp;
+
+ assert(0 != cptr);
+ assert(0 != chptr);
+
+ for (lp = chptr->banlist; lp; lp = lp->next)
+ if ((lp->flags & BAN_EXCEPTION) == BAN_EXCEPTION)
+ send_reply(cptr, RPL_EXCEPTLIST, chptr->chname, lp->banstr, lp->who, lp->when);
+
+ send_reply(cptr, RPL_ENDOFEXCEPTLIST, chptr->chname);
+}
+
/** Get a channel block, creating if necessary.
* Get Channel block for chname (and allocate a new channel
* block, if it didn't exists before).
MODE_QUARANTINE, 'Q',
MODE_AUDITORIUM, 'u',
MODE_SSLCHAN, 'S',
+/* MODE_BANEXCEPTION 'e', */
0x0, 0x0
};
static ulong64 local_flags[] = {
bufptr[(*bufptr_i)++] = 'v';
totalbuflen -= IRCD_MAX(9, tmp) + 1;
}
- } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD)) {
+ } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION)) {
tmp = strlen(MB_STRING(mbuf, i));
if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
else {
char mode_char;
- switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD))
+ switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION))
{
case MODE_APASS:
mode_char = 'A';
case MODE_NOFLOOD:
mode_char = 'f';
break;
+ case MODE_BAN:
+ mode_char = 'b';
+ break;
default:
- mode_char = 'b';
+ mode_char = 'e';
break;
}
bufptr[(*bufptr_i)++] = mode_char;
build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
/* deal with bans... */
- else if (MB_TYPE(mbuf, i) & (MODE_BAN))
+ else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_BANEXCEPTION))
build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
/* deal with keys... */
build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
/* deal with modes that take strings */
- else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD))
+ else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION))
build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
/*
MODE_AUDITORIUM, 'u',
MODE_SSLCHAN, 'S',
MODE_NOFLOOD, 'f',
+/* MODE_BANEXCEPTION, 'e', */
0x0, 0x0
};
ulong64 add;
#define DONE_ALTCHAN 0x800 /**< We've set the altchan */
#define DONE_ACCESS 0x1000 /**< We've set the access */
#define DONE_NOFLOOD 0x2000 /**< We've set the noflood options */
+#define DONE_EXCEPTLIST 0x4000 /**< We've sent the exception list */
struct ParseState {
struct ModeBuf *mbuf;
return;
}
+ if(feature_bool(FEAT_CHMODE_A_NOSET) && !(state->flags & MODE_PARSE_FORCE)) /* mode can'T be set. */
+ return;
+
if (!(state->flags & MODE_PARSE_WIPEOUT) &&
(!t_access || t_access == state->chptr->mode.access))
return;
struct Ban *ban, *newban;
if (state->parc <= 0) { /* Not enough args, send ban list */
- if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
- send_ban_list(state->sptr, state->chptr);
- state->done |= DONE_BANLIST;
+ if (MyUser(state->sptr)) {
+ if (*flag_p == MODE_BANEXCEPTION && !(state->done & DONE_EXCEPTLIST)) {
+ send_exception_list(state->sptr, state->chptr);
+ state->done |= DONE_EXCEPTLIST;
+ } else if (*flag_p == MODE_BAN && !(state->done & DONE_BANLIST)) {
+ send_ban_list(state->sptr, state->chptr);
+ state->done |= DONE_BANLIST;
+ }
}
return;
}
if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
if (prevban)
- prevban->next = 0; /* Break the list; ban isn't a real ban */
+ prevban->next = 0; /* Break the list; ban isn't a real ban */
else
- state->chptr->banlist = 0;
+ state->chptr->banlist = 0;
count--;
len -= banlen;
} else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
char *bandup;
DupString(bandup, ban->banstr);
- modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN, bandup, 1);
+ modebuf_mode_string(state->mbuf, MODE_DEL | ((ban->flags & BAN_EXCEPTION) ? MODE_BANEXCEPTION : MODE_BAN), bandup, 1);
if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
- if (prevban) /* clip it out of the list... */
- prevban->next = ban->next;
- else
- state->chptr->banlist = ban->next;
+ if (prevban) /* clip it out of the list... */
+ prevban->next = ban->next;
+ else
+ state->chptr->banlist = ban->next;
- count--;
- len -= banlen;
+ count--;
+ len -= banlen;
free_ban(ban);
- changed++;
- continue; /* next ban; keep prevban like it is */
+ changed++;
+ continue; /* next ban; keep prevban like it is */
} else
- ban->flags &= BAN_IPMASK; /* unset other flags */
+ ban->flags &= (BAN_IPMASK | BAN_EXCEPTION); /* unset other flags */
} else if (ban->flags & BAN_ADD) { /* adding a ban? */
if (prevban)
- prevban->next = 0; /* Break the list; ban isn't a real ban */
+ prevban->next = 0; /* Break the list; ban isn't a real ban */
else
- state->chptr->banlist = 0;
+ state->chptr->banlist = 0;
/* If we're supposed to ignore it, do so. */
- if (ban->flags & BAN_OVERLAPPED &&
- !(state->flags & MODE_PARSE_BOUNCE)) {
- count--;
- len -= banlen;
+ if (ban->flags & BAN_OVERLAPPED && !(state->flags & MODE_PARSE_BOUNCE)) {
+ count--;
+ len -= banlen;
} else {
- if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
- (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
- count > feature_int(FEAT_MAXBANS))) {
- send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
- ban->banstr);
- count--;
- len -= banlen;
- } else {
+ if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
+ (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
+ count > feature_int(FEAT_MAXBANS))) {
+ send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname, ban->banstr);
+ count--;
+ len -= banlen;
+ } else {
char *bandup;
- /* add the ban to the buffer */
+ /* add the ban to the buffer */
DupString(bandup, ban->banstr);
- modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN, bandup, 1);
+ modebuf_mode_string(state->mbuf, MODE_ADD | ((ban->flags & BAN_EXCEPTION) ? MODE_BANEXCEPTION : MODE_BAN), bandup, 1);
- if (state->flags & MODE_PARSE_SET) { /* create a new ban */
- newban = make_ban(ban->banstr);
+ if (state->flags & MODE_PARSE_SET) { /* create a new ban */
+ newban = make_ban(ban->banstr);
strcpy(newban->who, ban->who);
- newban->when = ban->when;
- newban->flags = ban->flags & BAN_IPMASK;
+ newban->when = ban->when;
+ newban->flags = ban->flags & (BAN_IPMASK | BAN_EXCEPTION);
- newban->next = state->chptr->banlist; /* and link it in */
- state->chptr->banlist = newban;
+ newban->next = state->chptr->banlist; /* and link it in */
+ state->chptr->banlist = newban;
- changed++;
- }
- }
+ changed++;
+ }
+ }
}
}
} else if (req_oplevel <= MAXOPLEVEL)
oplevel = req_oplevel;
}
- if(*flag_p == CHFL_CHANOP && state->member && !IsChanOp(state->member)) {
+ if(*flag_p == CHFL_CHANOP && state->member && !IsChanOp(state->member) && !(state->flags & MODE_PARSE_FORCE)) {
send_notoper(state);
return;
}
MODE_AUDITORIUM, 'u',
MODE_SSLCHAN, 'S',
MODE_NOFLOOD, 'f',
+ MODE_BANEXCEPTION, 'e',
MODE_ADD, '+',
MODE_DEL, '-',
0x0, 0x0
mode_parse_upass(&state, flag_p);
break;
case 'b': /* deal with bans */
+ case 'e': /* and exceptions */
mode_parse_ban(&state, flag_p);
break;