X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=ircd%2Fchannel.c;h=aae13e6e595cfd37babb8773212a6bd0f544393c;hp=355b99d958b3063e4fb37f553c61dc86021f6adc;hb=8fc59ec8ed68be82ca9314ac95a093a73623b882;hpb=b168d1cf9ec654e8a47b94c3c79c833ce650a721 diff --git a/ircd/channel.c b/ircd/channel.c index 355b99d..aae13e6 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -832,6 +832,8 @@ void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen, *mbuf++ = 'D'; else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS)) *mbuf++ = 'd'; + if (chptr->mode.mode & MODE_REGISTERED) + *mbuf++ = 'R'; if (chptr->mode.limit) { *mbuf++ = 'l'; ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit); @@ -1222,34 +1224,6 @@ static void send_ban_list(struct Client* cptr, struct Channel* chptr) send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname); } -/** Remove bells and commas from channel name - * - * @param cn Channel name to clean, modified in place. - */ -void clean_channelname(char *cn) -{ - int i; - - for (i = 0; cn[i]; i++) { - if (i >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN)) - || !IsChannelChar(cn[i])) { - cn[i] = '\0'; - return; - } - if (IsChannelLower(cn[i])) { - cn[i] = ToLower(cn[i]); -#ifndef FIXME - /* - * Remove for .08+ - * toupper(0xd0) - */ - if ((unsigned char)(cn[i]) == 0xd0) - cn[i] = (char) 0xf0; -#endif - } - } -} - /** Get a channel block, creating if necessary. * Get Channel block for chname (and allocate a new channel * block, if it didn't exists before). @@ -1540,6 +1514,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) MODE_NOPRIVMSGS, 'n', MODE_REGONLY, 'r', MODE_DELJOINS, 'D', + MODE_REGISTERED, 'R', /* MODE_KEY, 'k', */ /* MODE_BAN, 'b', */ MODE_LIMIT, 'l', @@ -1953,7 +1928,7 @@ modebuf_mode(struct ModeBuf *mbuf, unsigned int mode) mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED | MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY | - MODE_DELJOINS | MODE_WASDELJOINS); + MODE_DELJOINS | MODE_WASDELJOINS | MODE_REGISTERED); if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */ return; @@ -1983,7 +1958,7 @@ modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint) assert(0 != mbuf); assert(0 != (mode & (MODE_ADD | MODE_DEL))); - if (mode == (MODE_LIMIT | ((mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_ADD : MODE_DEL))) { + if (mode == (MODE_LIMIT | MODE_DEL)) { mbuf->mb_rem |= mode; return; } @@ -2113,6 +2088,7 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) MODE_KEY, 'k', MODE_APASS, 'A', MODE_UPASS, 'U', + MODE_REGISTERED, 'R', /* MODE_BAN, 'b', */ MODE_LIMIT, 'l', MODE_REGONLY, 'r', @@ -2172,9 +2148,10 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) return; } -/** Simple function to invalidate bans +/** Simple function to invalidate a channel's ban cache. * - * This function sets all bans as being valid. + * This function marks all members of the channel as being neither + * banned nor banned. * * @param chan The channel to operate on. */ @@ -2203,12 +2180,15 @@ mode_invite_clear(struct Channel *chan) /* What we've done for mode_parse so far... */ #define DONE_LIMIT 0x01 /**< We've set the limit */ -#define DONE_KEY 0x02 /**< We've set the key */ +#define DONE_KEY_ADD 0x02 /**< We've set the key */ #define DONE_BANLIST 0x04 /**< We've sent the ban list */ #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */ #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */ -#define DONE_UPASS 0x20 /**< We've set user pass */ -#define DONE_APASS 0x40 /**< We've set admin pass */ +#define DONE_UPASS_ADD 0x20 /**< We've set user pass */ +#define DONE_APASS_ADD 0x40 /**< We've set admin pass */ +#define DONE_KEY_DEL 0x80 /**< We've removed the key */ +#define DONE_UPASS_DEL 0x100 /**< We've removed the user pass */ +#define DONE_APASS_DEL 0x200 /**< We've removed the admin pass */ struct ParseState { struct ModeBuf *mbuf; @@ -2322,15 +2302,41 @@ mode_parse_limit(struct ParseState *state, int *flag_p) } } -/** Helper function to clean key-like parameters. */ -static void -clean_key(char *s) +/** Helper function to validate key-like parameters. + * + * @param[in] state Parse state for feedback to user. + * @param[in] s Key to validate. + * @param[in] command String to pass for need_more_params() command. + * @return Zero on an invalid key, non-zero if the key was okay. + */ +static int +is_clean_key(struct ParseState *state, char *s, char *command) { - int t_len = KEYLEN; + int ii; - while (*s > ' ' && *s != ':' && *s != ',' && t_len--) - s++; - *s = '\0'; + if (s[0] == '\0') { + if (MyUser(state->sptr)) + need_more_params(state->sptr, command); + return 0; + } + else if (s[0] == ':') { + if (MyUser(state->sptr)) + send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname); + return 0; + } + for (ii = 0; (ii <= KEYLEN) && (s[ii] != '\0'); ++ii) { + if ((unsigned char)s[ii] <= ' ' || s[ii] == ',') { + if (MyUser(state->sptr)) + send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname); + return 0; + } + } + if (ii > KEYLEN) { + if (MyUser(state->sptr)) + send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname); + return 0; + } + return 1; } /* @@ -2361,18 +2367,24 @@ mode_parse_key(struct ParseState *state, int *flag_p) return; } - if (state->done & DONE_KEY) /* allow key to be set only once */ - return; - state->done |= DONE_KEY; + /* allow removing and then adding key, but not adding and then removing */ + if (state->dir == MODE_ADD) + { + if (state->done & DONE_KEY_ADD) + return; + state->done |= DONE_KEY_ADD; + } + else + { + if (state->done & (DONE_KEY_ADD | DONE_KEY_DEL)) + return; + state->done |= DONE_KEY_DEL; + } - /* clean up the key string */ - clean_key(t_str); - if (!*t_str || *t_str == ':') { /* warn if empty */ - if (MyUser(state->sptr)) - need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" : - "MODE -k"); + /* If the key is invalid, tell the user and bail. */ + if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +k" : + "MODE -k")) return; - } if (!state->mbuf) return; @@ -2463,18 +2475,24 @@ mode_parse_upass(struct ParseState *state, int *flag_p) return; } - if (state->done & DONE_UPASS) /* allow upass to be set only once */ - return; - state->done |= DONE_UPASS; + /* allow removing and then adding upass, but not adding and then removing */ + if (state->dir == MODE_ADD) + { + if (state->done & DONE_UPASS_ADD) + return; + state->done |= DONE_UPASS_ADD; + } + else + { + if (state->done & (DONE_UPASS_ADD | DONE_UPASS_DEL)) + return; + state->done |= DONE_UPASS_DEL; + } - /* clean up the upass string */ - clean_key(t_str); - if (!*t_str || *t_str == ':') { /* warn if empty */ - if (MyUser(state->sptr)) - need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" : - "MODE -U"); + /* If the Upass is invalid, tell the user and bail. */ + if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +U" : + "MODE -U")) return; - } if (!state->mbuf) return; @@ -2600,18 +2618,24 @@ mode_parse_apass(struct ParseState *state, int *flag_p) } } - if (state->done & DONE_APASS) /* allow apass to be set only once */ - return; - state->done |= DONE_APASS; + /* allow removing and then adding apass, but not adding and then removing */ + if (state->dir == MODE_ADD) + { + if (state->done & DONE_APASS_ADD) + return; + state->done |= DONE_APASS_ADD; + } + else + { + if (state->done & (DONE_APASS_ADD | DONE_APASS_DEL)) + return; + state->done |= DONE_APASS_DEL; + } - /* clean up the apass string */ - clean_key(t_str); - if (!*t_str || *t_str == ':') { /* warn if empty */ - if (MyUser(state->sptr)) - need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" : - "MODE -A"); + /* If the Apass is invalid, tell the user and bail. */ + if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +A" : + "MODE -A")) return; - } if (!state->mbuf) return; @@ -2733,9 +2757,9 @@ int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free) assert(newban->flags & (BAN_ADD|BAN_DEL)); if (newban->flags & BAN_ADD) { size_t totlen = 0; - /* If a less specific entry is found, fail. */ + /* If a less specific *active* entry is found, fail. */ for (ban = *banlist; ban; ban = ban->next) { - if (!bmatch(ban, newban)) { + if (!bmatch(ban, newban) && !(ban->flags & BAN_DEL)) { if (do_free) free_ban(newban); return 1; @@ -2895,6 +2919,7 @@ mode_process_bans(struct ParseState *state) len -= banlen; } else { if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) && + !(state->mbuf->mb_dest & MODEBUF_DEST_OPMODE) && (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) || count > feature_int(FEAT_MAXBANS))) { send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname, @@ -2965,17 +2990,19 @@ mode_parse_client(struct ParseState *state, int *flag_p) if (colon != NULL) { *colon++ = '\0'; req_oplevel = atoi(colon); - if (!(state->flags & MODE_PARSE_FORCE) + if (*flag_p == CHFL_VOICE || state->dir == MODE_DEL) { + /* Ignore the colon and its argument. */ + } else if (!(state->flags & MODE_PARSE_FORCE) && state->member && (req_oplevel < OpLevel(state->member) || (req_oplevel == OpLevel(state->member) && OpLevel(state->member) < MAXOPLEVEL) - || req_oplevel > MAXOPLEVEL)) + || req_oplevel > MAXOPLEVEL)) { send_reply(state->sptr, ERR_NOTLOWEROPLEVEL, t_str, state->chptr->chname, OpLevel(state->member), req_oplevel, "op", OpLevel(state->member) == req_oplevel ? "the same" : "a higher"); - else if (req_oplevel <= MAXOPLEVEL) + } else if (req_oplevel <= MAXOPLEVEL) oplevel = req_oplevel; } /* find client we're manipulating */ @@ -3144,6 +3171,11 @@ mode_parse_mode(struct ParseState *state, int *flag_p) if (!state->mbuf) return; + /* Local users are not permitted to change registration status */ + if (flag_p[0] == MODE_REGISTERED && !(state->flags & MODE_PARSE_FORCE) && + MyUser(state->sptr)) + return; + if (state->dir == MODE_ADD) { state->add |= flag_p[0]; state->del &= ~flag_p[0]; @@ -3165,10 +3197,19 @@ mode_parse_mode(struct ParseState *state, int *flag_p) (state->add & (MODE_SECRET | MODE_PRIVATE))); } -/* +/** * This routine is intended to parse MODE or OPMODE commands and effect the - * changes (or just build the bounce buffer). We pass the starting offset - * as a + * changes (or just build the bounce buffer). + * + * \param[out] mbuf Receives parsed representation of mode change. + * \param[in] cptr Connection that sent the message to this server. + * \param[in] sptr Original source of the message. + * \param[in] chptr Channel whose modes are being changed. + * \param[in] parc Number of valid strings in \a parv. + * \param[in] parv Text arguments representing mode change, with the + * zero'th element containing a string like "+m" or "-o". + * \param[in] flags Set of bitwise MODE_PARSE_* flags. + * \param[in] member If non-null, the channel member attempting to change the modes. */ int mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, @@ -3187,6 +3228,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, MODE_KEY, 'k', MODE_APASS, 'A', MODE_UPASS, 'U', + MODE_REGISTERED, 'R', MODE_BAN, 'b', MODE_LIMIT, 'l', MODE_REGONLY, 'r', @@ -3327,7 +3369,9 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, } else { /* Server is desynced; bounce the mode and deop the source * to fix it. */ - state.mbuf->mb_dest &= ~MODEBUF_DEST_CHANNEL; + state.flags &= ~MODE_PARSE_SET; + state.flags |= MODE_PARSE_BOUNCE; + state.mbuf->mb_dest &= ~(MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK4); state.mbuf->mb_dest |= MODEBUF_DEST_BOUNCE | MODEBUF_DEST_HACK2; if (!IsServer(state.cptr)) state.mbuf->mb_dest |= MODEBUF_DEST_DEOP; @@ -3376,13 +3420,13 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, if (state.chptr->mode.limit && !(state.done & DONE_LIMIT)) modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT, state.chptr->mode.limit); - if (*state.chptr->mode.key && !(state.done & DONE_KEY)) + if (*state.chptr->mode.key && !(state.done & DONE_KEY_DEL)) modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY, state.chptr->mode.key, 0); - if (*state.chptr->mode.upass && !(state.done & DONE_UPASS)) + if (*state.chptr->mode.upass && !(state.done & DONE_UPASS_DEL)) modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS, state.chptr->mode.upass, 0); - if (*state.chptr->mode.apass && !(state.done & DONE_APASS)) + if (*state.chptr->mode.apass && !(state.done & DONE_APASS_DEL)) modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS, state.chptr->mode.apass, 0); } @@ -3595,3 +3639,12 @@ void CheckDelayedJoins(struct Channel *chan) "%H -d", chan); } } + +/** Send a join for the user if (s)he is a hidden member of the channel. + */ +void RevealDelayedJoinIfNeeded(struct Client *sptr, struct Channel *chptr) +{ + struct Membership *member = find_member_link(chptr, sptr); + if (member && IsDelayedJoin(member)) + RevealDelayedJoin(member); +}