X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/73d759aeb4dc6b98b1e84195a308a2df23684b79..9dd98618d044c63ba4d30c79350f4b6a4a2c3453:/ircd/chmode.c diff --git a/ircd/chmode.c b/ircd/chmode.c index 9f2cc88b..41fe1c71 100644 --- a/ircd/chmode.c +++ b/ircd/chmode.c @@ -1,5 +1,5 @@ /* - * charybdis: A slightly useful ircd. + * Solanum: a slightly advanced ircd * chmode.c: channel mode management * * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center @@ -41,6 +41,8 @@ #include "chmode.h" #include "s_assert.h" #include "parse.h" +#include "msgbuf.h" +#include "packet.h" /* bitmasks for error returns, so we send once per call */ #define SM_ERR_NOTS 0x00000001 /* No TS on channel */ @@ -61,8 +63,6 @@ static struct ChModeChange mode_changes[BUFSIZE]; static int mode_count; -static int mode_limit; -static int mode_limit_simple; static int mask_pos; static int removed_mask_pos; @@ -86,13 +86,13 @@ construct_cflags_strings(void) for(i = 0; i < 256; i++) { - if( !(chmode_table[i].set_func == chm_ban) && - !(chmode_table[i].set_func == chm_forward) && - !(chmode_table[i].set_func == chm_throttle) && - !(chmode_table[i].set_func == chm_key) && - !(chmode_table[i].set_func == chm_limit) && - !(chmode_table[i].set_func == chm_op) && - !(chmode_table[i].set_func == chm_voice)) + if (chmode_table[i].set_func != chm_ban && + chmode_table[i].set_func != chm_forward && + chmode_table[i].set_func != chm_throttle && + chmode_table[i].set_func != chm_key && + chmode_table[i].set_func != chm_limit && + chmode_table[i].set_func != chm_op && + chmode_table[i].set_func != chm_voice) { chmode_flags[i] = chmode_table[i].mode_type; } @@ -116,7 +116,8 @@ construct_cflags_strings(void) } /* Should we leave orphaned check here? -- dwr */ - if(!(chmode_table[i].set_func == chm_nosuch) && !(chmode_table[i].set_func == chm_orphaned)) + if (chmode_table[i].set_func != NULL && + chmode_table[i].set_func != chm_orphaned) { *ptr2++ = (char) i; } @@ -153,11 +154,11 @@ cflag_add(char c_, ChannelModeFunc function) { int c = (unsigned char)c_; - if (chmode_table[c].set_func != chm_nosuch && + if (chmode_table[c].set_func != NULL && chmode_table[c].set_func != chm_orphaned) return 0; - if (chmode_table[c].set_func == chm_nosuch) + if (chmode_table[c].set_func == NULL) chmode_table[c].mode_type = find_cflag_slot(); if (chmode_table[c].mode_type == 0) return 0; @@ -248,37 +249,25 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const char *realban = LOCAL_COPY(banid); rb_dlink_node *ptr; - /* dont let local clients overflow the banlist, or set redundant - * bans - */ + /* dont let local clients overflow the banlist */ if(MyClient(source_p)) { - if((rb_dlink_list_length(&chptr->banlist) + rb_dlink_list_length(&chptr->exceptlist) + rb_dlink_list_length(&chptr->invexlist) + rb_dlink_list_length(&chptr->quietlist)) >= (unsigned long)(chptr->mode.mode & MODE_EXLIMIT ? ConfigChannel.max_bans_large : ConfigChannel.max_bans)) + if((rb_dlink_list_length(&chptr->banlist) + rb_dlink_list_length(&chptr->exceptlist) + rb_dlink_list_length(&chptr->invexlist) + rb_dlink_list_length(&chptr->quietlist)) >= (unsigned long)((chptr->mode.mode & MODE_EXLIMIT) ? ConfigChannel.max_bans_large : ConfigChannel.max_bans)) { sendto_one(source_p, form_str(ERR_BANLISTFULL), me.name, source_p->name, chptr->chname, realban); return false; } - - RB_DLINK_FOREACH(ptr, list->head) - { - actualBan = ptr->data; - if(mask_match(actualBan->banstr, realban)) - return false; - } } - /* dont let remotes set duplicates */ - else + + /* don't let anyone set duplicate bans */ + RB_DLINK_FOREACH(ptr, list->head) { - RB_DLINK_FOREACH(ptr, list->head) - { - actualBan = ptr->data; - if(!irccmp(actualBan->banstr, realban)) - return false; - } + actualBan = ptr->data; + if(!irccmp(actualBan->banstr, realban)) + return false; } - if(IsPerson(source_p)) sprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host); else @@ -571,32 +560,13 @@ fix_key_remote(char *arg) return arg; } -/* chm_*() - * - * The handlers for each specific mode. - */ -void -chm_nosuch(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) -{ - if(*errors & SM_ERR_UNKNOWN) - return; - *errors |= SM_ERR_UNKNOWN; - sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c); -} - void chm_simple(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { if(!allow_mode_change(source_p, chptr, alevel, errors, c)) return; - if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) - return; - /* setting + */ if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type)) { @@ -627,8 +597,7 @@ chm_simple(struct Client *source_p, struct Channel *chptr, void chm_orphaned(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { if(MyClient(source_p)) return; @@ -657,10 +626,9 @@ chm_orphaned(struct Client *source_p, struct Channel *chptr, void chm_hidden(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { - if(!IsOper(source_p) && !IsServer(source_p)) + if(MyClient(source_p) && !IsOperGeneral(source_p)) { if(!(*errors & SM_ERR_NOPRIVS)) sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); @@ -676,9 +644,6 @@ chm_hidden(struct Client *source_p, struct Channel *chptr, return; } - if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) - return; - /* setting + */ if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type)) { @@ -704,31 +669,24 @@ chm_hidden(struct Client *source_p, struct Channel *chptr, void chm_staff(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { - if(!IsOper(source_p) && !IsServer(source_p)) + if(MyClient(source_p) && !IsOper(source_p)) { if(!(*errors & SM_ERR_NOPRIVS)) sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); *errors |= SM_ERR_NOPRIVS; return; } - if(MyClient(source_p) && !IsOperResv(source_p)) + if(MyClient(source_p) && !HasPrivilege(source_p, "oper:cmodes")) { if(!(*errors & SM_ERR_NOPRIVS)) sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, - source_p->name, "resv"); + source_p->name, "cmodes"); *errors |= SM_ERR_NOPRIVS; return; } - if(!allow_mode_change(source_p, chptr, CHFL_CHANOP, errors, c)) - return; - - if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) - return; - /* setting + */ if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type)) { @@ -754,10 +712,9 @@ chm_staff(struct Client *source_p, struct Channel *chptr, void chm_ban(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { - const char *mask, *raw_mask; + const char *mask; char *forward; rb_dlink_list *list; rb_dlink_node *ptr; @@ -779,8 +736,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, case CHFL_EXCEPTION: /* if +e is disabled, allow all but +e locally */ - if(!ConfigChannel.use_except && MyClient(source_p) && - ((dir == MODE_ADD) && (parc > *parn))) + if (!ConfigChannel.use_except && MyClient(source_p) && dir == MODE_ADD) return; list = &chptr->exceptlist; @@ -796,8 +752,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, case CHFL_INVEX: /* if +I is disabled, allow all but +I locally */ - if(!ConfigChannel.use_invex && MyClient(source_p) && - (dir == MODE_ADD) && (parc > *parn)) + if (!ConfigChannel.use_invex && MyClient(source_p) && dir == MODE_ADD) return; list = &chptr->invexlist; @@ -820,12 +775,11 @@ chm_ban(struct Client *source_p, struct Channel *chptr, break; default: - sendto_realops_snomask(SNO_GENERAL, L_ALL, "chm_ban() called with unknown type!"); + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "chm_ban() called with unknown type!"); return; - break; } - if(dir == 0 || parc <= *parn) + if (dir == MODE_QUERY) { if((*errors & errorval) != 0) return; @@ -860,29 +814,22 @@ chm_ban(struct Client *source_p, struct Channel *chptr, return; } - if(!allow_mode_change(source_p, chptr, alevel, errors, c)) + if (!allow_mode_change(source_p, chptr, alevel, errors, c)) return; - - if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) - return; - - raw_mask = parv[(*parn)]; - (*parn)++; - /* empty ban, or starts with ':' which messes up s2s, ignore it */ - if(EmptyString(raw_mask) || *raw_mask == ':') + if (EmptyString(arg) || *arg == ':') return; - if(!MyClient(source_p)) + if (!MyClient(source_p)) { - if(strchr(raw_mask, ' ')) + if (strchr(arg, ' ')) return; - mask = raw_mask; + mask = arg; } else - mask = pretty_mask(raw_mask); + mask = pretty_mask(arg); /* we'd have problems parsing this, hyb6 does it too * also make sure it will always fit on a line with channel @@ -892,7 +839,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, { sendto_one_numeric(source_p, ERR_INVALIDBAN, form_str(ERR_INVALIDBAN), - chptr->chname, c, raw_mask); + chptr->chname, c, arg); return; } @@ -908,7 +855,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, } /* if we're adding a NEW id */ - if(dir == MODE_ADD) + if (dir == MODE_ADD) { if (*mask == '$' && MyClient(source_p)) { @@ -916,7 +863,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, { sendto_one_numeric(source_p, ERR_INVALIDBAN, form_str(ERR_INVALIDBAN), - chptr->chname, c, raw_mask); + chptr->chname, c, arg); return; } } @@ -924,28 +871,28 @@ chm_ban(struct Client *source_p, struct Channel *chptr, /* For compatibility, only check the forward channel from * local clients. Accept any forward channel from servers. */ - if(forward != NULL && MyClient(source_p)) + if (forward != NULL && MyClient(source_p)) { /* For simplicity and future flexibility, do not * allow '$' in forwarding targets. */ - if(!ConfigChannel.use_forward || + if (!ConfigChannel.use_forward || strchr(forward, '$') != NULL) { sendto_one_numeric(source_p, ERR_INVALIDBAN, form_str(ERR_INVALIDBAN), - chptr->chname, c, raw_mask); + chptr->chname, c, arg); return; } /* check_forward() sends its own error message */ - if(!check_forward(source_p, chptr, forward)) + if (!check_forward(source_p, chptr, forward)) return; /* Forwards only make sense for bans. */ - if(mode_type != CHFL_BAN) + if (mode_type != CHFL_BAN) { sendto_one_numeric(source_p, ERR_INVALIDBAN, form_str(ERR_INVALIDBAN), - chptr->chname, c, raw_mask); + chptr->chname, c, arg); return; } } @@ -953,10 +900,10 @@ chm_ban(struct Client *source_p, struct Channel *chptr, /* dont allow local clients to overflow the banlist, dont * let remote servers set duplicate bans */ - if(!add_id(source_p, chptr, mask, forward, list, mode_type)) + if (!add_id(source_p, chptr, mask, forward, list, mode_type)) return; - if(forward) + if (forward) forward[-1]= '$'; mode_changes[mode_count].letter = c; @@ -965,23 +912,23 @@ chm_ban(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].id = NULL; mode_changes[mode_count++].arg = mask; } - else if(dir == MODE_DEL) + else if (dir == MODE_DEL) { struct Ban *removed; static char buf[BANLEN * MAXMODEPARAMS]; int old_removed_mask_pos = removed_mask_pos; - if((removed = del_id(chptr, mask, list, mode_type)) == NULL) + if ((removed = del_id(chptr, mask, list, mode_type)) == NULL) { - /* mask isn't a valid ban, check raw_mask */ - if((removed = del_id(chptr, raw_mask, list, mode_type)) != NULL) - mask = raw_mask; + /* mask isn't a valid ban, check arg */ + if ((removed = del_id(chptr, arg, list, mode_type)) != NULL) + mask = arg; } - if(removed && removed->forward) + if (removed && removed->forward) removed_mask_pos += snprintf(buf + old_removed_mask_pos, sizeof(buf), "%s$%s", removed->banstr, removed->forward) + 1; else removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, mask, sizeof(buf)) + 1; - if(removed) + if (removed) { free_ban(removed); removed = NULL; @@ -997,30 +944,22 @@ chm_ban(struct Client *source_p, struct Channel *chptr, void chm_op(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { struct membership *mstptr; - const char *opnick; struct Client *targ_p; if(!allow_mode_change(source_p, chptr, alevel, errors, c)) return; - if((dir == MODE_QUERY) || (parc <= *parn)) - return; - - opnick = parv[(*parn)]; - (*parn)++; - /* empty nick */ - if(EmptyString(opnick)) + if(EmptyString(arg)) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*"); return; } - if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL) + if((targ_p = find_chasing(source_p, arg, NULL)) == NULL) { return; } @@ -1031,14 +970,11 @@ chm_op(struct Client *source_p, struct Channel *chptr, { if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p)) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, - form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname); + form_str(ERR_USERNOTINCHANNEL), arg, chptr->chname); *errors |= SM_ERR_NOTONCHANNEL; return; } - if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) - return; - if(dir == MODE_ADD) { if(targ_p == source_p && mstptr->flags & CHFL_CHANOP) @@ -1073,30 +1009,22 @@ chm_op(struct Client *source_p, struct Channel *chptr, void chm_voice(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { struct membership *mstptr; - const char *opnick; struct Client *targ_p; if(!allow_mode_change(source_p, chptr, alevel, errors, c)) return; - if((dir == MODE_QUERY) || parc <= *parn) - return; - - opnick = parv[(*parn)]; - (*parn)++; - /* empty nick */ - if(EmptyString(opnick)) + if(EmptyString(arg)) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*"); return; } - if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL) + if((targ_p = find_chasing(source_p, arg, NULL)) == NULL) { return; } @@ -1107,14 +1035,11 @@ chm_voice(struct Client *source_p, struct Channel *chptr, { if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p)) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, - form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname); + form_str(ERR_USERNOTINCHANNEL), arg, chptr->chname); *errors |= SM_ERR_NOTONCHANNEL; return; } - if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) - return; - if(dir == MODE_ADD) { mode_changes[mode_count].letter = c; @@ -1139,28 +1064,17 @@ chm_voice(struct Client *source_p, struct Channel *chptr, void chm_limit(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { - const char *lstr; static char limitstr[30]; int limit; - if(!allow_mode_change(source_p, chptr, alevel, errors, c)) - return; - - if(dir == MODE_QUERY) + if (!allow_mode_change(source_p, chptr, alevel, errors, c)) return; - if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) - return; - - if((dir == MODE_ADD) && parc > *parn) + if (dir == MODE_ADD) { - lstr = parv[(*parn)]; - (*parn)++; - - if(EmptyString(lstr) || (limit = atoi(lstr)) <= 0) + if (EmptyString(arg) || (limit = atoi(arg)) <= 0) return; sprintf(limitstr, "%d", limit); @@ -1173,7 +1087,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr, chptr->mode.limit = limit; } - else if(dir == MODE_DEL) + else if (dir == MODE_DEL) { if(!chptr->mode.limit) return; @@ -1190,23 +1104,16 @@ chm_limit(struct Client *source_p, struct Channel *chptr, void chm_throttle(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { int joins = 0, timeslice = 0; - if(!allow_mode_change(source_p, chptr, alevel, errors, c)) - return; - - if(dir == MODE_QUERY) + if (!allow_mode_change(source_p, chptr, alevel, errors, c)) return; - if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) - return; - - if((dir == MODE_ADD) && parc > *parn) + if (dir == MODE_ADD) { - if (sscanf(parv[(*parn)], "%d:%d", &joins, ×lice) < 2) + if (sscanf(arg, "%d:%d", &joins, ×lice) < 2) return; if(joins <= 0 || timeslice <= 0) @@ -1216,9 +1123,7 @@ chm_throttle(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].dir = MODE_ADD; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; - mode_changes[mode_count++].arg = parv[(*parn)]; - - (*parn)++; + mode_changes[mode_count++].arg = arg; chptr->mode.join_num = joins; chptr->mode.join_time = timeslice; @@ -1243,17 +1148,13 @@ chm_throttle(struct Client *source_p, struct Channel *chptr, void chm_forward(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { - const char *forward; - /* if +f is disabled, ignore local attempts to set it */ - if(!ConfigChannel.use_forward && MyClient(source_p) && - (dir == MODE_ADD) && (parc > *parn)) + if (!ConfigChannel.use_forward && MyClient(source_p) && dir == MODE_ADD) return; - if(dir == MODE_QUERY || (dir == MODE_ADD && parc <= *parn)) + if (dir == MODE_QUERY) { if (!(*errors & SM_ERR_RPL_F)) { @@ -1267,10 +1168,10 @@ chm_forward(struct Client *source_p, struct Channel *chptr, } #ifndef FORWARD_OPERONLY - if(!allow_mode_change(source_p, chptr, alevel, errors, c)) + if (!allow_mode_change(source_p, chptr, alevel, errors, c)) return; #else - if(!IsOper(source_p) && !IsServer(source_p)) + if (!IsOperGeneral(source_p) && !IsServer(source_p)) { if(!(*errors & SM_ERR_NOPRIVS)) sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); @@ -1279,28 +1180,22 @@ chm_forward(struct Client *source_p, struct Channel *chptr, } #endif - if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) - return; - - if(dir == MODE_ADD && parc > *parn) + if (dir == MODE_ADD) { - forward = parv[(*parn)]; - (*parn)++; - - if(EmptyString(forward)) + if(EmptyString(arg)) return; - if(!check_forward(source_p, chptr, forward)) + if(!check_forward(source_p, chptr, arg)) return; - rb_strlcpy(chptr->mode.forward, forward, sizeof(chptr->mode.forward)); + rb_strlcpy(chptr->mode.forward, arg, sizeof(chptr->mode.forward)); mode_changes[mode_count].letter = c; mode_changes[mode_count].dir = MODE_ADD; mode_changes[mode_count].mems = ConfigChannel.use_forward ? ALL_MEMBERS : ONLY_SERVERS; mode_changes[mode_count].id = NULL; - mode_changes[mode_count++].arg = forward; + mode_changes[mode_count++].arg = arg; } else if(dir == MODE_DEL) { @@ -1319,24 +1214,16 @@ chm_forward(struct Client *source_p, struct Channel *chptr, void chm_key(struct Client *source_p, struct Channel *chptr, - int alevel, int parc, int *parn, - const char **parv, int *errors, int dir, char c, long mode_type) + int alevel, const char *arg, int *errors, int dir, char c, long mode_type) { char *key; - if(!allow_mode_change(source_p, chptr, alevel, errors, c)) - return; - - if(dir == MODE_QUERY) - return; - - if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) + if (!allow_mode_change(source_p, chptr, alevel, errors, c)) return; - if((dir == MODE_ADD) && parc > *parn) + if (dir == MODE_ADD) { - key = LOCAL_COPY(parv[(*parn)]); - (*parn)++; + key = LOCAL_COPY(arg); if(MyClient(source_p)) fix_key(key); @@ -1360,9 +1247,6 @@ chm_key(struct Client *source_p, struct Channel *chptr, static char splat[] = "*"; int i; - if(parc > *parn) - (*parn)++; - if(!(*chptr->mode.key)) return; @@ -1389,272 +1273,29 @@ chm_key(struct Client *source_p, struct Channel *chptr, /* *INDENT-OFF* */ struct ChannelMode chmode_table[256] = { - {chm_nosuch, 0 }, /* 0x00 */ - {chm_nosuch, 0 }, /* 0x01 */ - {chm_nosuch, 0 }, /* 0x02 */ - {chm_nosuch, 0 }, /* 0x03 */ - {chm_nosuch, 0 }, /* 0x04 */ - {chm_nosuch, 0 }, /* 0x05 */ - {chm_nosuch, 0 }, /* 0x06 */ - {chm_nosuch, 0 }, /* 0x07 */ - {chm_nosuch, 0 }, /* 0x08 */ - {chm_nosuch, 0 }, /* 0x09 */ - {chm_nosuch, 0 }, /* 0x0a */ - {chm_nosuch, 0 }, /* 0x0b */ - {chm_nosuch, 0 }, /* 0x0c */ - {chm_nosuch, 0 }, /* 0x0d */ - {chm_nosuch, 0 }, /* 0x0e */ - {chm_nosuch, 0 }, /* 0x0f */ - {chm_nosuch, 0 }, /* 0x10 */ - {chm_nosuch, 0 }, /* 0x11 */ - {chm_nosuch, 0 }, /* 0x12 */ - {chm_nosuch, 0 }, /* 0x13 */ - {chm_nosuch, 0 }, /* 0x14 */ - {chm_nosuch, 0 }, /* 0x15 */ - {chm_nosuch, 0 }, /* 0x16 */ - {chm_nosuch, 0 }, /* 0x17 */ - {chm_nosuch, 0 }, /* 0x18 */ - {chm_nosuch, 0 }, /* 0x19 */ - {chm_nosuch, 0 }, /* 0x1a */ - {chm_nosuch, 0 }, /* 0x1b */ - {chm_nosuch, 0 }, /* 0x1c */ - {chm_nosuch, 0 }, /* 0x1d */ - {chm_nosuch, 0 }, /* 0x1e */ - {chm_nosuch, 0 }, /* 0x1f */ - {chm_nosuch, 0 }, /* 0x20 */ - {chm_nosuch, 0 }, /* 0x21 */ - {chm_nosuch, 0 }, /* 0x22 */ - {chm_nosuch, 0 }, /* 0x23 */ - {chm_nosuch, 0 }, /* 0x24 */ - {chm_nosuch, 0 }, /* 0x25 */ - {chm_nosuch, 0 }, /* 0x26 */ - {chm_nosuch, 0 }, /* 0x27 */ - {chm_nosuch, 0 }, /* 0x28 */ - {chm_nosuch, 0 }, /* 0x29 */ - {chm_nosuch, 0 }, /* 0x2a */ - {chm_nosuch, 0 }, /* 0x2b */ - {chm_nosuch, 0 }, /* 0x2c */ - {chm_nosuch, 0 }, /* 0x2d */ - {chm_nosuch, 0 }, /* 0x2e */ - {chm_nosuch, 0 }, /* 0x2f */ - {chm_nosuch, 0 }, /* 0x30 */ - {chm_nosuch, 0 }, /* 0x31 */ - {chm_nosuch, 0 }, /* 0x32 */ - {chm_nosuch, 0 }, /* 0x33 */ - {chm_nosuch, 0 }, /* 0x34 */ - {chm_nosuch, 0 }, /* 0x35 */ - {chm_nosuch, 0 }, /* 0x36 */ - {chm_nosuch, 0 }, /* 0x37 */ - {chm_nosuch, 0 }, /* 0x38 */ - {chm_nosuch, 0 }, /* 0x39 */ - {chm_nosuch, 0 }, /* 0x3a */ - {chm_nosuch, 0 }, /* 0x3b */ - {chm_nosuch, 0 }, /* 0x3c */ - {chm_nosuch, 0 }, /* 0x3d */ - {chm_nosuch, 0 }, /* 0x3e */ - {chm_nosuch, 0 }, /* 0x3f */ - - {chm_nosuch, 0 }, /* @ */ - {chm_nosuch, 0 }, /* A */ - {chm_nosuch, 0 }, /* B */ - {chm_nosuch, 0 }, /* C */ - {chm_nosuch, 0 }, /* D */ - {chm_nosuch, 0 }, /* E */ - {chm_simple, MODE_FREETARGET }, /* F */ - {chm_nosuch, 0 }, /* G */ - {chm_nosuch, 0 }, /* H */ - {chm_ban, CHFL_INVEX }, /* I */ - {chm_nosuch, 0 }, /* J */ - {chm_nosuch, 0 }, /* K */ - {chm_staff, MODE_EXLIMIT }, /* L */ - {chm_nosuch, 0 }, /* M */ - {chm_nosuch, 0 }, /* N */ - {chm_nosuch, 0 }, /* O */ - {chm_staff, MODE_PERMANENT }, /* P */ - {chm_simple, MODE_DISFORWARD }, /* Q */ - {chm_nosuch, 0 }, /* R */ - {chm_nosuch, 0 }, /* S */ - {chm_nosuch, 0 }, /* T */ - {chm_nosuch, 0 }, /* U */ - {chm_nosuch, 0 }, /* V */ - {chm_nosuch, 0 }, /* W */ - {chm_nosuch, 0 }, /* X */ - {chm_nosuch, 0 }, /* Y */ - {chm_nosuch, 0 }, /* Z */ - {chm_nosuch, 0 }, - {chm_nosuch, 0 }, - {chm_nosuch, 0 }, - {chm_nosuch, 0 }, - {chm_nosuch, 0 }, - {chm_nosuch, 0 }, - {chm_nosuch, 0 }, /* a */ - {chm_ban, CHFL_BAN }, /* b */ - {chm_nosuch, 0 }, /* c */ - {chm_nosuch, 0 }, /* d */ - {chm_ban, CHFL_EXCEPTION }, /* e */ - {chm_forward, 0 }, /* f */ - {chm_simple, MODE_FREEINVITE }, /* g */ - {chm_nosuch, 0 }, /* h */ - {chm_simple, MODE_INVITEONLY }, /* i */ - {chm_throttle, 0 }, /* j */ - {chm_key, 0 }, /* k */ - {chm_limit, 0 }, /* l */ - {chm_simple, MODE_MODERATED }, /* m */ - {chm_simple, MODE_NOPRIVMSGS }, /* n */ - {chm_op, 0 }, /* o */ - {chm_simple, MODE_PRIVATE }, /* p */ - {chm_ban, CHFL_QUIET }, /* q */ - {chm_simple, MODE_REGONLY }, /* r */ - {chm_simple, MODE_SECRET }, /* s */ - {chm_simple, MODE_TOPICLIMIT }, /* t */ - {chm_nosuch, 0 }, /* u */ - {chm_voice, 0 }, /* v */ - {chm_nosuch, 0 }, /* w */ - {chm_nosuch, 0 }, /* x */ - {chm_nosuch, 0 }, /* y */ - {chm_simple, MODE_OPMODERATE }, /* z */ - - {chm_nosuch, 0 }, /* 0x7b */ - {chm_nosuch, 0 }, /* 0x7c */ - {chm_nosuch, 0 }, /* 0x7d */ - {chm_nosuch, 0 }, /* 0x7e */ - {chm_nosuch, 0 }, /* 0x7f */ - - {chm_nosuch, 0 }, /* 0x80 */ - {chm_nosuch, 0 }, /* 0x81 */ - {chm_nosuch, 0 }, /* 0x82 */ - {chm_nosuch, 0 }, /* 0x83 */ - {chm_nosuch, 0 }, /* 0x84 */ - {chm_nosuch, 0 }, /* 0x85 */ - {chm_nosuch, 0 }, /* 0x86 */ - {chm_nosuch, 0 }, /* 0x87 */ - {chm_nosuch, 0 }, /* 0x88 */ - {chm_nosuch, 0 }, /* 0x89 */ - {chm_nosuch, 0 }, /* 0x8a */ - {chm_nosuch, 0 }, /* 0x8b */ - {chm_nosuch, 0 }, /* 0x8c */ - {chm_nosuch, 0 }, /* 0x8d */ - {chm_nosuch, 0 }, /* 0x8e */ - {chm_nosuch, 0 }, /* 0x8f */ - - {chm_nosuch, 0 }, /* 0x90 */ - {chm_nosuch, 0 }, /* 0x91 */ - {chm_nosuch, 0 }, /* 0x92 */ - {chm_nosuch, 0 }, /* 0x93 */ - {chm_nosuch, 0 }, /* 0x94 */ - {chm_nosuch, 0 }, /* 0x95 */ - {chm_nosuch, 0 }, /* 0x96 */ - {chm_nosuch, 0 }, /* 0x97 */ - {chm_nosuch, 0 }, /* 0x98 */ - {chm_nosuch, 0 }, /* 0x99 */ - {chm_nosuch, 0 }, /* 0x9a */ - {chm_nosuch, 0 }, /* 0x9b */ - {chm_nosuch, 0 }, /* 0x9c */ - {chm_nosuch, 0 }, /* 0x9d */ - {chm_nosuch, 0 }, /* 0x9e */ - {chm_nosuch, 0 }, /* 0x9f */ - - {chm_nosuch, 0 }, /* 0xa0 */ - {chm_nosuch, 0 }, /* 0xa1 */ - {chm_nosuch, 0 }, /* 0xa2 */ - {chm_nosuch, 0 }, /* 0xa3 */ - {chm_nosuch, 0 }, /* 0xa4 */ - {chm_nosuch, 0 }, /* 0xa5 */ - {chm_nosuch, 0 }, /* 0xa6 */ - {chm_nosuch, 0 }, /* 0xa7 */ - {chm_nosuch, 0 }, /* 0xa8 */ - {chm_nosuch, 0 }, /* 0xa9 */ - {chm_nosuch, 0 }, /* 0xaa */ - {chm_nosuch, 0 }, /* 0xab */ - {chm_nosuch, 0 }, /* 0xac */ - {chm_nosuch, 0 }, /* 0xad */ - {chm_nosuch, 0 }, /* 0xae */ - {chm_nosuch, 0 }, /* 0xaf */ - - {chm_nosuch, 0 }, /* 0xb0 */ - {chm_nosuch, 0 }, /* 0xb1 */ - {chm_nosuch, 0 }, /* 0xb2 */ - {chm_nosuch, 0 }, /* 0xb3 */ - {chm_nosuch, 0 }, /* 0xb4 */ - {chm_nosuch, 0 }, /* 0xb5 */ - {chm_nosuch, 0 }, /* 0xb6 */ - {chm_nosuch, 0 }, /* 0xb7 */ - {chm_nosuch, 0 }, /* 0xb8 */ - {chm_nosuch, 0 }, /* 0xb9 */ - {chm_nosuch, 0 }, /* 0xba */ - {chm_nosuch, 0 }, /* 0xbb */ - {chm_nosuch, 0 }, /* 0xbc */ - {chm_nosuch, 0 }, /* 0xbd */ - {chm_nosuch, 0 }, /* 0xbe */ - {chm_nosuch, 0 }, /* 0xbf */ - - {chm_nosuch, 0 }, /* 0xc0 */ - {chm_nosuch, 0 }, /* 0xc1 */ - {chm_nosuch, 0 }, /* 0xc2 */ - {chm_nosuch, 0 }, /* 0xc3 */ - {chm_nosuch, 0 }, /* 0xc4 */ - {chm_nosuch, 0 }, /* 0xc5 */ - {chm_nosuch, 0 }, /* 0xc6 */ - {chm_nosuch, 0 }, /* 0xc7 */ - {chm_nosuch, 0 }, /* 0xc8 */ - {chm_nosuch, 0 }, /* 0xc9 */ - {chm_nosuch, 0 }, /* 0xca */ - {chm_nosuch, 0 }, /* 0xcb */ - {chm_nosuch, 0 }, /* 0xcc */ - {chm_nosuch, 0 }, /* 0xcd */ - {chm_nosuch, 0 }, /* 0xce */ - {chm_nosuch, 0 }, /* 0xcf */ - - {chm_nosuch, 0 }, /* 0xd0 */ - {chm_nosuch, 0 }, /* 0xd1 */ - {chm_nosuch, 0 }, /* 0xd2 */ - {chm_nosuch, 0 }, /* 0xd3 */ - {chm_nosuch, 0 }, /* 0xd4 */ - {chm_nosuch, 0 }, /* 0xd5 */ - {chm_nosuch, 0 }, /* 0xd6 */ - {chm_nosuch, 0 }, /* 0xd7 */ - {chm_nosuch, 0 }, /* 0xd8 */ - {chm_nosuch, 0 }, /* 0xd9 */ - {chm_nosuch, 0 }, /* 0xda */ - {chm_nosuch, 0 }, /* 0xdb */ - {chm_nosuch, 0 }, /* 0xdc */ - {chm_nosuch, 0 }, /* 0xdd */ - {chm_nosuch, 0 }, /* 0xde */ - {chm_nosuch, 0 }, /* 0xdf */ - - {chm_nosuch, 0 }, /* 0xe0 */ - {chm_nosuch, 0 }, /* 0xe1 */ - {chm_nosuch, 0 }, /* 0xe2 */ - {chm_nosuch, 0 }, /* 0xe3 */ - {chm_nosuch, 0 }, /* 0xe4 */ - {chm_nosuch, 0 }, /* 0xe5 */ - {chm_nosuch, 0 }, /* 0xe6 */ - {chm_nosuch, 0 }, /* 0xe7 */ - {chm_nosuch, 0 }, /* 0xe8 */ - {chm_nosuch, 0 }, /* 0xe9 */ - {chm_nosuch, 0 }, /* 0xea */ - {chm_nosuch, 0 }, /* 0xeb */ - {chm_nosuch, 0 }, /* 0xec */ - {chm_nosuch, 0 }, /* 0xed */ - {chm_nosuch, 0 }, /* 0xee */ - {chm_nosuch, 0 }, /* 0xef */ - - {chm_nosuch, 0 }, /* 0xf0 */ - {chm_nosuch, 0 }, /* 0xf1 */ - {chm_nosuch, 0 }, /* 0xf2 */ - {chm_nosuch, 0 }, /* 0xf3 */ - {chm_nosuch, 0 }, /* 0xf4 */ - {chm_nosuch, 0 }, /* 0xf5 */ - {chm_nosuch, 0 }, /* 0xf6 */ - {chm_nosuch, 0 }, /* 0xf7 */ - {chm_nosuch, 0 }, /* 0xf8 */ - {chm_nosuch, 0 }, /* 0xf9 */ - {chm_nosuch, 0 }, /* 0xfa */ - {chm_nosuch, 0 }, /* 0xfb */ - {chm_nosuch, 0 }, /* 0xfc */ - {chm_nosuch, 0 }, /* 0xfd */ - {chm_nosuch, 0 }, /* 0xfe */ - {chm_nosuch, 0 }, /* 0xff */ + ['F'] = {chm_simple, MODE_FREETARGET, 0 }, + ['I'] = {chm_ban, CHFL_INVEX, CHM_QUERYABLE | CHM_OPS_QUERY }, + ['L'] = {chm_staff, MODE_EXLIMIT, 0 }, + ['P'] = {chm_staff, MODE_PERMANENT, 0 }, + ['Q'] = {chm_simple, MODE_DISFORWARD, 0 }, + ['b'] = {chm_ban, CHFL_BAN, CHM_QUERYABLE }, + ['e'] = {chm_ban, CHFL_EXCEPTION, CHM_QUERYABLE | CHM_OPS_QUERY }, + ['f'] = {chm_forward, 0, CHM_ARG_SET | CHM_CAN_QUERY }, /* weird because it's nonstandard and violates isupport */ + ['g'] = {chm_simple, MODE_FREEINVITE, 0 }, + ['i'] = {chm_simple, MODE_INVITEONLY, 0 }, + ['j'] = {chm_throttle, 0, CHM_ARG_SET }, + ['k'] = {chm_key, 0, CHM_QUERYABLE }, + ['l'] = {chm_limit, 0, CHM_ARG_SET }, + ['m'] = {chm_simple, MODE_MODERATED, 0 }, + ['n'] = {chm_simple, MODE_NOPRIVMSGS, 0 }, + ['o'] = {chm_op, 0, CHM_ARGS }, + ['p'] = {chm_simple, MODE_PRIVATE, 0 }, + ['q'] = {chm_ban, CHFL_QUIET, CHM_QUERYABLE }, + ['r'] = {chm_simple, MODE_REGONLY, 0 }, + ['s'] = {chm_simple, MODE_SECRET, 0 }, + ['t'] = {chm_simple, MODE_TOPICLIMIT, 0 }, + ['v'] = {chm_voice, 0, CHM_ARGS }, + ['z'] = {chm_simple, MODE_OPMODERATE, 0 }, }; /* *INDENT-ON* */ @@ -1671,27 +1312,28 @@ void set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr, struct membership *msptr, int parc, const char *parv[]) { - static char modebuf[BUFSIZE]; + static char modebuf[BUFSIZE * 2]; /* paranoid case: 2 canonical chars per input char */ static char parabuf[BUFSIZE]; char *mbuf; char *pbuf; int cur_len, mlen, paralen, paracount, arglen, len; int i, j, flags; - int dir = MODE_QUERY; + int dir = MODE_ADD; + bool changes = false; + bool privileged_query = false; int parn = 1; int errors = 0; int alevel; const char *ml = parv[0]; char c; struct Client *fakesource_p; - int reauthorized = 0; /* if we change from MODE_QUERY to MODE_ADD/MODE_DEL, then reauth once, ugly but it works */ int flags_list[3] = { ALL_MEMBERS, ONLY_CHANOPS, ONLY_OPERS }; + int mode_limit = 0; + int mode_limit_simple = 0; mask_pos = 0; removed_mask_pos = 0; mode_count = 0; - mode_limit = 0; - mode_limit_simple = 0; /* Hide connecting server on netburst -- jilles */ if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p)) @@ -1699,45 +1341,144 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, else fakesource_p = source_p; - alevel = get_channel_access(source_p, chptr, msptr, dir, reconstruct_parv(parc, parv)); + struct modeset { + const struct ChannelMode *cm; + const char *arg; + int dir; + char mode; + }; + + static struct modeset modesets[MAXMODEPARAMS + MAXMODES_SIMPLE]; + struct modeset *ms = modesets, *mend; + char canon_op = '\0'; + + mbuf = modebuf; - for(; (c = *ml) != 0; ml++) + for (ml = parv[0]; *ml != 0 && ms - modesets < ARRAY_SIZE(modesets); ml++) { + c = *ml; switch (c) { case '+': dir = MODE_ADD; - if (!reauthorized) - { - alevel = get_channel_access(source_p, chptr, msptr, dir, reconstruct_parv(parc, parv)); - reauthorized = 1; - } break; case '-': dir = MODE_DEL; - if (!reauthorized) - { - alevel = get_channel_access(source_p, chptr, msptr, dir, reconstruct_parv(parc, parv)); - reauthorized = 1; - } break; case '=': dir = MODE_QUERY; break; default: - chmode_table[(unsigned char) c].set_func(fakesource_p, chptr, alevel, - parc, &parn, parv, - &errors, dir, c, - chmode_table[(unsigned char) c].mode_type); - break; + { + int effective_dir = dir; + const struct ChannelMode *cm = &chmode_table[(unsigned char) c]; + bool use_arg = dir == MODE_ADD ? cm->flags & CHM_ARG_SET : + dir == MODE_DEL ? cm->flags & CHM_ARG_DEL : + false; + if (cm->set_func == NULL) + { + sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c); + return; + } + if (use_arg && parn >= parc) + { + if (!(cm->flags & CHM_CAN_QUERY)) + { + sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE"); + return; + } + effective_dir = MODE_QUERY; + use_arg = false; + } + + if (effective_dir == MODE_QUERY && !(cm->flags & CHM_CAN_QUERY)) + { + /* XXX this currently replicates traditional behaviour and just + * does nothing for a query on a mode with no query. would it be + * good to send an error here? + */ + continue; + } + + if (MyClient(source_p)) + { + if (use_arg && ++mode_limit > MAXMODEPARAMS) + continue; + if (!use_arg && ++mode_limit_simple > MAXMODES_SIMPLE) + continue; + } + + char op = effective_dir == MODE_ADD ? '+' : + effective_dir == MODE_DEL ? '-' : + '='; + + if (op != canon_op) + *mbuf++ = canon_op = op; + + *mbuf++ = c; + + if (effective_dir != MODE_QUERY) + changes = true; + if (effective_dir == MODE_QUERY && cm->flags & CHM_OPS_QUERY) + privileged_query = true; + + ms->cm = cm; + ms->dir = effective_dir; + if (use_arg) + ms->arg = parv[parn++]; + else + ms->arg = NULL; + ms->mode = c; + ms++; + } } } + /* this will happen on something like MODE +-=++-. + * we'd have caught that with the if !mode_count + * later on, but this saves an override notice + */ + if (ms == modesets) + return; + + if (parn < parc) + { + /* XXX we could reject excess params here */ + } + + /* Finish the flood grace period if we were asked to do anything */ + if (changes && MyClient(source_p) && !IsFloodDone(source_p)) + { + flood_endgrace(source_p); + } + + mend = ms; + + if (parn > 1) + { + strcpy(mbuf, " "); + rb_strlcat(modebuf, reconstruct_parv(parn - 1, parv + 1), sizeof modebuf); + } + else + { + *mbuf = '\0'; + } + int access_dir = privileged_query ? MODE_OP_QUERY : + changes ? MODE_ADD : + MODE_QUERY; + alevel = get_channel_access(source_p, chptr, msptr, access_dir, modebuf); + + for (ms = modesets; ms < mend; ms++) + { + ChannelModeFunc *set_func = ms->cm->set_func; + set_func(fakesource_p, chptr, alevel, ms->arg, &errors, ms->dir, ms->mode, ms->cm->mode_type); + } + /* bail out if we have nothing to do... */ - if(!mode_count) + if (!mode_count) return; - if(IsServer(source_p)) + if (IsServer(source_p)) mlen = sprintf(modebuf, ":%s MODE %s ", fakesource_p->name, chptr->chname); else mlen = sprintf(modebuf, ":%s!%s@%s MODE %s ", @@ -1746,7 +1487,13 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, for(j = 0; j < 3; j++) { - flags = flags_list[j]; + int send_flags = flags = flags_list[j]; + const char *priv = NULL; + if (flags == ONLY_OPERS) + { + send_flags = ALL_MEMBERS; + priv = "auspex:cmodes"; + } cur_len = mlen; mbuf = modebuf + mlen; pbuf = parabuf; @@ -1779,8 +1526,8 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, *mbuf = '\0'; if(cur_len > mlen) - sendto_channel_local(flags, chptr, "%s %s", modebuf, - parabuf); + sendto_channel_local_priv(IsServer(source_p) ? fakesource_p : source_p, + send_flags, priv, chptr, "%s %s", modebuf, parabuf); else continue; @@ -1816,7 +1563,8 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, *mbuf = '\0'; if(cur_len > mlen) - sendto_channel_local(flags, chptr, "%s %s", modebuf, parabuf); + sendto_channel_local_priv(IsServer(source_p) ? fakesource_p : source_p, + send_flags, priv, chptr, "%s %s", modebuf, parabuf); } /* only propagate modes originating locally, or if we're hubbing */