diff --git a/extensions/extb_canjoin.cc b/extensions/extb_canjoin.cc index 6b5c51ace..3f4c23fdd 100644 --- a/extensions/extb_canjoin.cc +++ b/extensions/extb_canjoin.cc @@ -59,7 +59,7 @@ eb_canjoin(const char *data, struct Client *client_p, chan::chan *chptr, mode::t return INVALID; #endif recurse = 1; - ret = is_banned(chptr2, client_p, NULL, NULL, NULL, NULL) == mode::BAN ? MATCH : NOMATCH; + ret = check(*chptr2, mode::BAN, *client_p)? MATCH : NOMATCH; recurse = 0; return ret; } diff --git a/include/ircd/channel.h b/include/ircd/channel.h index b0cf27b00..da0fd1f6e 100644 --- a/include/ircd/channel.h +++ b/include/ircd/channel.h @@ -5,6 +5,8 @@ * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 2002-2004 ircd-ratbox development team + * Copyright (C) 2004-2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +31,10 @@ namespace ircd { namespace chan { +IRCD_EXCEPTION(ircd::error, error) +IRCD_EXCEPTION(error, not_found) +IRCD_EXCEPTION(error, invalid_list) + enum status { PEON = 0x0000, // normal member of channel @@ -60,11 +66,16 @@ struct ban std::string who; std::string forward; time_t when; - rb_dlink_node node = {0}; - ban(const std::string &banstr, const std::string &who, const std::string &forward); + ban(const std::string &banstr, + const std::string &who = {}, + const std::string &forward = {}, + const time_t &when = 0); }; +bool operator<(const ban &a, const ban &b); +using list = std::set>; + struct modes { static constexpr size_t KEYLEN = 24; // 23+1 for \0 @@ -123,12 +134,12 @@ struct chan rb_dlink_list members; rb_dlink_list locmembers; - rb_dlink_list invites; - rb_dlink_list banlist; - rb_dlink_list exceptlist; - rb_dlink_list invexlist; - rb_dlink_list quietlist; + + list bans; + list excepts; + list invexs; + list quiets; uint join_count; // joins within delta uint join_delta; // last ts of join @@ -139,9 +150,9 @@ struct chan time_t bants; time_t channelts; time_t last_checked_ts; - client *last_checked_client; - uint last_checked_type; - int last_checked_result; + const client *last_checked_client; + mode::type last_checked_type; + bool last_checked_result; rb_dlink_node node = {0}; @@ -167,16 +178,35 @@ enum : int CAN_SEND_OPV = 2, }; int can_send(chan *, client *, membership *); +int can_join(client *source, chan *, const char *key, const char **forward); + +bool cache_check(const chan &, const mode::type &, const client &, bool &result); +void cache_result(chan &, const mode::type &, const client &, const bool &result, membership *const &msptr = nullptr); +void cache_invalidate(chan &, const mode::type &, time_t time = 0); + +const list &get(const chan &, const mode::type &); +list &get(chan &, const mode::type &); +size_t size(const chan &, const mode::type &); +bool empty(const chan &, const mode::type &); +size_t lists_size(const chan &); + +struct check_data +{ + membership *msptr; + const char *host; + const char *iphost; + const char **forward; +}; +bool check(chan &, const mode::type &, const client &, check_data *const &data = nullptr); +const ban &get(const chan &, const mode::type &, const std::string &mask); +bool add(chan &, const mode::type &, const std::string &mask, client &source, const std::string &forward = {}); +bool del(chan &, const mode::type &, const std::string &mask); bool flood_attack_channel(int p_or_n, client *source, chan *); -int is_banned(chan *, client *who, membership *, const char *, const char *, const char **); -int is_quieted(chan *, client *who, membership *, const char *, const char *); -int can_join(client *source, chan *, const char *key, const char **forward); void add_user_to_channel(chan *, client *, int flags); void remove_user_from_channel(membership *); void remove_user_from_channels(client *); void invalidate_bancache_user(client *); -void free_channel_list(rb_dlink_list *); void channel_member_names(chan *, client *, int show_eon); void del_invite(chan *, client *who); const char *channel_modes(chan *, client *who); @@ -191,8 +221,6 @@ void send_cap_mode_changes(client *, client *source, chan *, mode::change foo[], void resv_chan_forcepart(const char *name, const char *reason, int temp_time); void set_channel_mode(client *, client *source, chan *, membership *, int parc, const char *parv[]); void set_channel_mlock(client *, client *source, chan *, const char *newmlock, bool propagate); -bool add_id(client *source, chan *, const char *banid, const char *forward, rb_dlink_list * list, long mode_type); -ban *del_id(chan *, const char *banid, rb_dlink_list * list, long mode_type); int match_extban(const char *banstr, client *, chan *, long mode_type); int valid_extban(const char *banstr, client *, chan *, long mode_type); const char * get_extban_string(void); @@ -358,6 +386,12 @@ operator|(const modes &modes, const mode::type &value) return modes.mode | value; } +inline bool +operator<(const ban &a, const ban &b) +{ + return irccmp(a.banstr, b.banstr); +} + inline bool operator!(const topic &topic) { diff --git a/include/ircd/chmode.h b/include/ircd/chmode.h index d83ec7e64..2cf5ee525 100644 --- a/include/ircd/chmode.h +++ b/include/ircd/chmode.h @@ -5,7 +5,8 @@ * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 2002-2004 ircd-ratbox development team - * Copyright (C) 2008 charybdis development team + * Copyright (C) 2008-2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/include/ircd/stdinc.h b/include/ircd/stdinc.h index b3b99136a..e8fdcb4de 100644 --- a/include/ircd/stdinc.h +++ b/include/ircd/stdinc.h @@ -42,6 +42,7 @@ namespace ircd #include "listener.h" #include "s_assert.h" +#include "match.h" #include "chmode.h" #include "channel.h" @@ -60,7 +61,6 @@ namespace ircd #include "ircd_linker.h" #include "ircd_signal.h" #include "logger.h" -#include "match.h" #include "messages.h" #include "info.h" #include "modules.h" diff --git a/ircd/channel.cc b/ircd/channel.cc index c6e02e8c8..097db4395 100644 --- a/ircd/channel.cc +++ b/ircd/channel.cc @@ -5,6 +5,8 @@ * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 2002-2005 ircd-ratbox development team + * Copyright (C) 2005-2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +32,7 @@ int h_get_channel_access; struct config_channel_entry ircd::ConfigChannel; + rb_dlink_list chan::global_channel_list; //std::map> chan::chans; @@ -49,10 +52,6 @@ chan::chan::chan(const std::string &name) ,members{0} ,locmembers{0} ,invites{0} -,banlist{0} -,exceptlist{0} -,invexlist{0} -,quietlist{0} ,join_count{0} ,join_delta{0} ,flood_noticed{0} @@ -63,7 +62,7 @@ chan::chan::chan(const std::string &name) ,channelts{0} ,last_checked_ts{0} ,last_checked_client{nullptr} -,last_checked_type{0} +,last_checked_type{mode::type(0)} ,last_checked_result{0} { } @@ -75,12 +74,6 @@ noexcept RB_DLINK_FOREACH_SAFE(ptr, next_ptr, invites.head) del_invite(this, reinterpret_cast(ptr->data)); - /* free all bans/exceptions/denies */ - free_channel_list(&banlist); - free_channel_list(&exceptlist); - free_channel_list(&invexlist); - free_channel_list(&quietlist); - rb_dlinkDelete(&node, &global_channel_list); del_from_channel_hash(name.c_str(), this); } @@ -113,11 +106,12 @@ chan::modes::modes() chan::ban::ban(const std::string &banstr, const std::string &who, - const std::string &forward) + const std::string &forward, + const time_t &when) :banstr{banstr} ,who{who} ,forward{forward} -,when{0} +,when{when} { } @@ -345,27 +339,6 @@ chan::invalidate_bancache_user(client *client_p) } } -/* free_channel_list() - * - * input - rb_dlink list to free - * output - - * side effects - list of b/e/I modes is cleared - */ -void -chan::free_channel_list(rb_dlink_list * list) -{ - rb_dlink_node *ptr; - rb_dlink_node *next_ptr; - RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head) - { - const auto actualBan(reinterpret_cast(ptr->data)); - delete actualBan; - } - - list->head = list->tail = NULL; - list->length = 0; -} - /* channel_pub_or_secret() * * input - channel @@ -480,186 +453,183 @@ chan::del_invite(chan *chptr, client *who) rb_dlinkFindDestroy(chptr, &who->user->invited); } -/* is_banned_list() - * - * input - channel to check bans for, ban list (banlist or quietlist), - * user to check bans against, optional prebuilt buffers, - * optional forward channel pointer - * output - 1 if banned, else 0 - * side effects - - */ -static int -is_banned_list(chan::chan *chptr, rb_dlink_list *list, - Client *who, chan::membership *msptr, - const char *s, const char *s2, const char **forward) +bool +chan::cache_check(const chan &chan, + const mode::type &type, + const client &who, + bool &result) { - using namespace chan; + using namespace mode; - char src_host[NICKLEN + USERLEN + HOSTLEN + 6]; - char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6]; - char src_althost[NICKLEN + USERLEN + HOSTLEN + 6]; - char src_ip4host[NICKLEN + USERLEN + HOSTLEN + 6]; - char *s3 = NULL; - char *s4 = NULL; - struct sockaddr_in ip4; - rb_dlink_node *ptr; - ban *actualBan = NULL; - ban *actualExcept = NULL; + if (chan.last_checked_client != &who) + return false; - if(!MyClient(who)) - return 0; + if (chan.last_checked_ts <= chan.bants) + return false; - /* if the buffers havent been built, do it here */ - if(s == NULL) + switch (type) { - sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host); - sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost); + case BAN: + case QUIET: + result = chan.last_checked_result; + return true; - s = src_host; - s2 = src_iphost; + default: + return false; } - if(who->localClient->mangledhost != NULL) - { - /* if host mangling mode enabled, also check their real host */ - if(!strcmp(who->host, who->localClient->mangledhost)) - { - sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost); - s3 = src_althost; - } - /* if host mangling mode not enabled and no other spoof, - * also check the mangled form of their host */ - else if (!IsDynSpoof(who)) - { - sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost); - s3 = src_althost; - } - } -#ifdef RB_IPV6 - if(GET_SS_FAMILY(&who->localClient->ip) == AF_INET6 && - rb_ipv4_from_ipv6((const struct sockaddr_in6 *)&who->localClient->ip, &ip4)) - { - sprintf(src_ip4host, "%s!%s@", who->name, who->username); - s4 = src_ip4host + strlen(src_ip4host); - rb_inet_ntop_sock((struct sockaddr *)&ip4, - s4, src_ip4host + sizeof src_ip4host - s4); - s4 = src_ip4host; - } -#endif +} - RB_DLINK_FOREACH(ptr, list->head) +void +chan::cache_result(chan &chan, + const mode::type &type, + const client &client, + const bool &result, + membership *const &membership) +{ + using namespace mode; + + switch (type) { - actualBan = (ban *)ptr->data; - if(match(actualBan->banstr.c_str(), s) || - match(actualBan->banstr.c_str(), s2) || - match_cidr(actualBan->banstr.c_str(), s2) || - match_extban(actualBan->banstr.c_str(), who, chptr, mode::BAN) || - (s3 != NULL && match(actualBan->banstr.c_str(), s3)) -#ifdef RB_IPV6 - || - (s4 != NULL && (match(actualBan->banstr.c_str(), s4) || match_cidr(actualBan->banstr.c_str(), s4))) -#endif - ) + case BAN: + case QUIET: break; - else - actualBan = NULL; + + default: + return; } - if((actualBan != NULL) && ircd::ConfigChannel.use_except) + chan.last_checked_client = &client; + chan.last_checked_type = type; + chan.last_checked_result = result; + chan.last_checked_ts = rb_current_time(); + + if (membership) { - RB_DLINK_FOREACH(ptr, chptr->exceptlist.head) - { - actualExcept = (ban *)ptr->data; + membership->bants = chan.bants; - /* theyre exempted.. */ - if(match(actualExcept->banstr.c_str(), s) || - match(actualExcept->banstr.c_str(), s2) || - match_cidr(actualExcept->banstr.c_str(), s2) || - match_extban(actualExcept->banstr.c_str(), who, chptr, mode::EXCEPTION) || - (s3 != NULL && match(actualExcept->banstr.c_str(), s3))) - { - /* cache the fact theyre not banned */ - if(msptr != NULL) - { - msptr->bants = chptr->bants; - msptr->flags &= ~BANNED; - } - - return mode::EXCEPTION; - } - } - } - - /* cache the banned/not banned status */ - if(msptr != NULL) - { - msptr->bants = chptr->bants; - - if(actualBan != NULL) - { - msptr->flags |= BANNED; - return mode::BAN; - } + if (result) + membership->flags |= BANNED; else - { - msptr->flags &= ~BANNED; - return 0; - } + membership->flags &= ~BANNED; } - - if (actualBan && !actualBan->forward.empty() && forward) - *forward = actualBan->forward.c_str(); //TODO: XXX: ??? - - return actualBan? mode::BAN : mode::type(0); } -/* is_banned() - * - * input - channel to check bans for, user to check bans against - * optional prebuilt buffers, optional forward channel pointer - * output - 1 if banned, else 0 - * side effects - - */ -int -chan::is_banned(chan *chptr, client *who, membership *msptr, - const char *s, const char *s2, const char **forward) +bool +chan::check(chan &chan, + const mode::type &type, + const client &client, + check_data *const &data) { - if (chptr->last_checked_client != NULL && - who == chptr->last_checked_client && - chptr->last_checked_type == mode::BAN && - chptr->last_checked_ts > chptr->bants) - return chptr->last_checked_result; + bool result; + if (cache_check(chan, type, client, result)) + return result; - chptr->last_checked_client = who; - chptr->last_checked_type = mode::BAN; - chptr->last_checked_result = is_banned_list(chptr, &chptr->banlist, who, msptr, s, s2, forward); - chptr->last_checked_ts = rb_current_time(); + if (!my(client)) + return false; - return chptr->last_checked_result; -} + enum srcs { HOST, IPHOST, ALTHOST, IP4HOST, _NUM_ }; + char src[num_of()][NICKLEN + USERLEN + HOSTLEN + 6]; + const char *s[num_of()] + { + data? data->host : nullptr, + data? data->iphost : nullptr + }; -/* is_quieted() - * - * input - channel to check bans for, user to check bans against - * optional prebuilt buffers - * output - 1 if banned, else 0 - * side effects - - */ -int -chan::is_quieted(chan *chptr, client *who, membership *msptr, - const char *s, const char *s2) -{ - if (chptr->last_checked_client != NULL && - who == chptr->last_checked_client && - chptr->last_checked_type == mode::QUIET && - chptr->last_checked_ts > chptr->bants) - return chptr->last_checked_result; + // if the buffers havent been built, do it here + if (!s[HOST]) + { + sprintf(src[HOST], "%s!%s@%s", client.name, client.username, client.host); + s[HOST] = src[HOST]; + } - chptr->last_checked_client = who; - chptr->last_checked_type = mode::QUIET; - chptr->last_checked_result = is_banned_list(chptr, &chptr->quietlist, who, msptr, s, s2, NULL); - chptr->last_checked_ts = rb_current_time(); + if (!s[IPHOST]) + { + sprintf(src[IPHOST], "%s!%s@%s", client.name, client.username, client.sockhost); + s[IPHOST] = src[IPHOST]; + } - return chptr->last_checked_result; + if (client.localClient->mangledhost) + { + // if host mangling mode enabled, also check their real host + if (strcmp(client.host, client.localClient->mangledhost) == 0) + { + sprintf(src[ALTHOST], "%s!%s@%s", client.name, client.username, client.orighost); + s[ALTHOST] = src[ALTHOST]; + } + // if host mangling mode not enabled and no other spoof, check the mangled form of their host + else if (!IsDynSpoof(&client)) + { + sprintf(src[ALTHOST], "%s!%s@%s", client.name, client.username, client.localClient->mangledhost); + s[ALTHOST] = src[ALTHOST]; + } + } + +#ifdef RB_IPV6 + struct sockaddr_in ip4; + if (GET_SS_FAMILY(&client.localClient->ip) == AF_INET6 && + rb_ipv4_from_ipv6((const struct sockaddr_in6 *)&client.localClient->ip, &ip4)) + { + sprintf(src[IP4HOST], "%s!%s@", client.name, client.username); + char *const pos(src[IP4HOST] + strlen(src[IP4HOST])); + rb_inet_ntop_sock((struct sockaddr *)&ip4, pos, src[IP4HOST] + sizeof(src[IP4HOST]) - pos); + s[IP4HOST] = src[IP4HOST]; + } +#endif + + const auto matched([&s, &chan, &client] + (const ban &ban) + { + const auto &mask(ban.banstr); + if (match(mask, s[HOST])) + return true; + + if (match(mask, s[IPHOST])) + return true; + + if (match_cidr(mask, s[IPHOST])) + return true; + + if (s[ALTHOST] && match(mask, s[ALTHOST])) + return true; + + if (match_extban(mask.c_str(), const_cast(&client), &chan, mode::BAN)) + return true; + + #ifdef RB_IPV6 + if (s[IP4HOST] && match(mask, s[IP4HOST])) + return true; + + if (s[IP4HOST] && match_cidr(mask, s[IP4HOST])) + return true; + #endif + + return false; + }); + + const auto &list(get(chan, type)); + const auto it(std::find_if(begin(list), end(list), matched)); + const auto msptr(data? data->msptr : nullptr); + result = it != end(list); + + if (result && ircd::ConfigChannel.use_except) + { + const auto &list(get(chan, mode::EXCEPTION)); + if (std::any_of(begin(list), end(list), matched)) + { + cache_result(chan, type, client, false, msptr); + return false; + } + } + + if (result && data && data->forward) + { + const auto &ban(*it); + if (!ban.forward.empty()) + *data->forward = ban.forward.c_str(); //TODO: XXX: ??? + } + + cache_result(chan, type, client, result, msptr); + return result; } /* can_join() @@ -707,44 +677,65 @@ chan::can_join(client *source_p, chan *chptr, const char *key, const char **forw } } - if((is_banned(chptr, source_p, NULL, src_host, src_iphost, forward)) == mode::BAN) + check_data data + { + nullptr, + src_host, + src_iphost, + forward + }; + + if (check(*chptr, mode::BAN, *source_p, &data)) { moduledata.approved = ERR_BANNEDFROMCHAN; goto finish_join_check; } - if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key))) + if (*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key))) { moduledata.approved = ERR_BADCHANNELKEY; goto finish_join_check; } /* All checks from this point on will forward... */ - if(forward) + if (forward) *forward = chptr->mode.forward; - if(chptr->mode.mode & mode::INVITEONLY) + if (chptr->mode.mode & mode::INVITEONLY) { RB_DLINK_FOREACH(invite, source_p->user->invited.head) - { - if(invite->data == chptr) + if (invite->data == chptr) break; - } - if(invite == NULL) + + if (!invite) { - if(!ConfigChannel.use_invex) + if (!ConfigChannel.use_invex) moduledata.approved = ERR_INVITEONLYCHAN; - RB_DLINK_FOREACH(ptr, chptr->invexlist.head) + + const auto &list(get(*chptr, mode::INVEX)); + const bool matched(std::any_of(begin(list), end(list), [&] + (const auto &ban) { - invex = (ban *)ptr->data; - if(match(invex->banstr.c_str(), src_host) - || match(invex->banstr.c_str(), src_iphost) - || match_cidr(invex->banstr.c_str(), src_iphost) - || match_extban(invex->banstr.c_str(), source_p, chptr, mode::INVEX) - || (use_althost && match(invex->banstr.c_str(), src_althost))) - break; - } - if(ptr == NULL) + const auto &mask(ban.banstr); + if (match(mask, src_host)) + return true; + + if (match(mask, src_iphost)) + return true; + + if (match_cidr(mask, src_iphost)) + return true; + + if (match_extban(mask.c_str(), source_p, chptr, mode::INVEX)) + return true; + + if (use_althost && match(mask, src_althost)) + return true; + + return false; + })); + + if (!matched) moduledata.approved = ERR_INVITEONLYCHAN; } } @@ -831,10 +822,18 @@ chan::can_send(chan *chptr, client *source_p, membership *msptr) { if(can_send_banned(msptr)) moduledata.approved = CAN_SEND_NO; + } else { + check_data data + { + msptr + }; + + if (check(*chptr, mode::BAN, *source_p, &data)) + moduledata.approved = CAN_SEND_NO; + + if (check(*chptr, mode::QUIET, *source_p, &data)) + moduledata.approved = CAN_SEND_NO; } - else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == mode::BAN - || is_quieted(chptr, source_p, msptr, NULL, NULL) == mode::BAN) - moduledata.approved = CAN_SEND_NO; } if(is_chanop_voiced(msptr)) @@ -937,11 +936,22 @@ chan::find_bannickchange_channel(client *client_p) { if (can_send_banned(msptr)) return chptr; + } else { + check_data data + { + msptr, + src_host, + src_iphost, + }; + + if (check(*chptr, mode::BAN, *client_p, &data)) + return chptr; + + if (check(*chptr, mode::QUIET, *client_p, &data)) + return chptr; } - else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == mode::BAN - || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == mode::BAN) - return chptr; } + return NULL; } @@ -1304,3 +1314,167 @@ chan::resv_chan_forcepart(const char *name, const char *reason, int temp_time) } } } + +bool +chan::add(chan &chan, + const mode::type &type, + const std::string &mask, + client &source, + const std::string &forward) + +{ + // dont let local clients overflow the banlist, or set redundant bans + if (my(source)) + { + const bool large(chan.mode & mode::EXLIMIT); + const size_t &max(large? ConfigChannel.max_bans_large : ConfigChannel.max_bans); + if (lists_size(chan) > max) + { + sendto_one(&source, form_str(ERR_BANLISTFULL), + me.name, + source.name, + chan.name.c_str(), + mask.c_str()); + + return false; + } + + const auto matches([&mask](const ban &ban) + { + return match_mask(ban.banstr, mask); + }); + + const auto &list(get(chan, type)); + if (std::any_of(begin(list), end(list), matches)) + return false; + } + + auto &list(get(chan, type)); + auto insertion(list.emplace(mask, std::string{}, forward, rb_current_time())); + if (!insertion.second) + return false; + + auto &ban(const_cast(*insertion.first)); + if (is_person(source)) + { + static char who[USERHOST_REPLYLEN]; + snprintf(who, sizeof(who), "%s!%s@%s", source.name, source.username, source.host); + ban.who = who; + } + else ban.who = source.name; + + cache_invalidate(chan, type, ban.when); + return true; +} + +bool +chan::del(chan &chan, + const mode::type &type, + const std::string &mask) + +{ + if (mask.empty()) + return false; + + auto &list(get(chan, type)); + if (!list.erase(mask)) + return false; + + cache_invalidate(chan, type); + return true; +} + +const chan::ban & +chan::get(const chan &chan, + const mode::type &type, + const std::string &mask) +{ + const auto &list(get(chan, type)); + const auto &it(list.find(mask)); + if (it == end(list)) + throw not_found(); + + return *it; +} + +void +chan::cache_invalidate(chan &chan, + const mode::type &type, + time_t time) +{ + using namespace mode; + + if (!time) + time = rb_current_time(); + + switch (type) + { + case BAN: + case QUIET: + case EXCEPTION: + chan.bants = time; + break; + + default: + break; + } +} + +size_t +chan::lists_size(const chan &chan) +{ + using namespace mode; + + return size(chan, BAN) + + size(chan, EXCEPTION) + + size(chan, INVEX) + + size(chan, QUIET); +} + +size_t +chan::size(const chan &chan, + const mode::type &type) +{ + return get(chan, type).size(); +} + +bool +chan::empty(const chan &chan, + const mode::type &type) +{ + return get(chan, type).empty(); +} + +chan::list & +chan::get(chan &chan, + const mode::type &type) +{ + using namespace mode; + + switch (type) + { + case BAN: return chan.bans; + case EXCEPTION: return chan.excepts; + case INVEX: return chan.invexs; + case QUIET: return chan.quiets; + default: + throw invalid_list(); + } +} + +const chan::list & +chan::get(const chan &chan, + const mode::type &type) +{ + using namespace mode; + + switch (type) + { + case BAN: return chan.bans; + case EXCEPTION: return chan.excepts; + case INVEX: return chan.invexs; + case QUIET: return chan.quiets; + default: + throw invalid_list(); + } +} diff --git a/ircd/chmode.cc b/ircd/chmode.cc index afcbce394..880873f37 100644 --- a/ircd/chmode.cc +++ b/ircd/chmode.cc @@ -252,102 +252,6 @@ allow_mode_change(struct Client *source_p, chan::chan *chptr, int alevel, return true; } -/* add_id() - * - * inputs - client, channel, id to add, type, forward - * outputs - false on failure, true on success - * side effects - given id is added to the appropriate list - */ -bool -chan::add_id(client *source_p, chan *chptr, const char *banid, const char *forward, - rb_dlink_list * list, long mode_type) -{ - ban *actualBan; - static char who[USERHOST_REPLYLEN]; - char *realban = LOCAL_COPY(banid); - rb_dlink_node *ptr; - - /* dont let local clients overflow the banlist, or set redundant - * bans - */ - 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)) - { - sendto_one(source_p, form_str(ERR_BANLISTFULL), - me.name, source_p->name, chptr->name.c_str(), realban); - return false; - } - - RB_DLINK_FOREACH(ptr, list->head) - { - actualBan = (ban *)ptr->data; - if(match_mask(actualBan->banstr.c_str(), realban)) - return false; - } - } - /* dont let remotes set duplicates */ - else - { - RB_DLINK_FOREACH(ptr, list->head) - { - actualBan = (ban *)ptr->data; - if(!irccmp(actualBan->banstr.c_str(), realban)) - return false; - } - } - - - if(IsPerson(source_p)) - sprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host); - else - rb_strlcpy(who, source_p->name, sizeof(who)); - - actualBan = new ban(realban, who, forward?: std::string{}); - actualBan->when = rb_current_time(); - - rb_dlinkAdd(actualBan, &actualBan->node, list); - - /* invalidate the can_send() cache */ - if(mode_type == mode::BAN || mode_type == mode::QUIET || mode_type == mode::EXCEPTION) - chptr->bants = rb_current_time(); - - return true; -} - -/* del_id() - * - * inputs - channel, id to remove, type - * outputs - pointer to ban that was removed, if any - * side effects - given id is removed from the appropriate list and returned - */ -chan::ban * -chan::del_id(chan *chptr, const char *banid, rb_dlink_list * list, long mode_type) -{ - rb_dlink_node *ptr; - - if(EmptyString(banid)) - return NULL; - - RB_DLINK_FOREACH(ptr, list->head) - { - auto *const banptr(reinterpret_cast(ptr->data)); - - if(irccmp(banid, banptr->banstr.c_str()) == 0) - { - rb_dlinkDelete(&banptr->node, list); - - /* invalidate the can_send() cache */ - if(mode_type == mode::BAN || mode_type == mode::QUIET || mode_type == mode::EXCEPTION) - chptr->bants = rb_current_time(); - - return banptr; - } - } - - return NULL; -} - /* check_string() * * input - string to check @@ -775,10 +679,11 @@ mode::functor::ban(client *source_p, chan *chptr, int alevel, int parc, int *parn, const char **parv, int *errors, int dir, char c, type mode_type) { + namespace chan = ircd::chan; + const char *mask, *raw_mask; char *forward; - rb_dlink_list *list; - rb_dlink_node *ptr; + chan::list *list; int errorval; const char *rpl_list_p; const char *rpl_endlist_p; @@ -787,7 +692,7 @@ mode::functor::ban(client *source_p, chan *chptr, switch (mode_type) { case BAN: - list = &chptr->banlist; + list = &get(*chptr, mode_type); errorval = SM_ERR_RPL_B; rpl_list_p = form_str(RPL_BANLIST); rpl_endlist_p = form_str(RPL_ENDOFBANLIST); @@ -800,7 +705,7 @@ mode::functor::ban(client *source_p, chan *chptr, ((dir == MODE_ADD) && (parc > *parn))) return; - list = &chptr->exceptlist; + list = &get(*chptr, mode_type); errorval = SM_ERR_RPL_E; rpl_list_p = form_str(RPL_EXCEPTLIST); rpl_endlist_p = form_str(RPL_ENDOFEXCEPTLIST); @@ -817,7 +722,7 @@ mode::functor::ban(client *source_p, chan *chptr, (dir == MODE_ADD) && (parc > *parn)) return; - list = &chptr->invexlist; + list = &get(*chptr, mode_type); errorval = SM_ERR_RPL_I; rpl_list_p = form_str(RPL_INVITELIST); rpl_endlist_p = form_str(RPL_ENDOFINVITELIST); @@ -829,7 +734,7 @@ mode::functor::ban(client *source_p, chan *chptr, break; case QUIET: - list = &chptr->quietlist; + list = &get(*chptr, mode_type); errorval = SM_ERR_RPL_Q; rpl_list_p = form_str(RPL_QUIETLIST); rpl_endlist_p = form_str(RPL_ENDOFQUIETLIST); @@ -859,19 +764,23 @@ mode::functor::ban(client *source_p, chan *chptr, return; } - RB_DLINK_FOREACH(ptr, list->head) + for (const auto &ban : *list) { char buf[ban::LEN]; - auto *const banptr(reinterpret_cast(ptr->data)); - if(!banptr->forward.empty()) - snprintf(buf, sizeof(buf), "%s$%s", banptr->banstr.c_str(), banptr->forward.c_str()); + if(!ban.forward.empty()) + snprintf(buf, sizeof(buf), "%s$%s", ban.banstr.c_str(), ban.forward.c_str()); else - rb_strlcpy(buf, banptr->banstr.c_str(), sizeof(buf)); + rb_strlcpy(buf, ban.banstr.c_str(), sizeof(buf)); sendto_one(source_p, rpl_list_p, - me.name, source_p->name, chptr->name.c_str(), - buf, banptr->who.c_str(), banptr->when); + me.name, + source_p->name, + chptr->name.c_str(), + buf, + ban.who.c_str(), + ban.when); } + sendto_one(source_p, rpl_endlist_p, me.name, source_p->name, chptr->name.c_str()); return; } @@ -969,7 +878,7 @@ mode::functor::ban(client *source_p, chan *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(*chptr, mode_type, mask, *source_p, forward?: std::string{})) return; if(forward) @@ -983,24 +892,28 @@ mode::functor::ban(client *source_p, chan *chptr, } else if(dir == MODE_DEL) { - struct ban *removed; + // When this whole function gets hosed all of this will be better + static char buf[ban::LEN * MAXPARAMS]; - int old_removed_mask_pos = removed_mask_pos; - if((removed = del_id(chptr, mask, list, mode_type)) == NULL) + const int old_removed_mask_pos(removed_mask_pos); + std::string _mask(mask); + + auto it(list->find(_mask)); + if (it == end(*list)) { - /* mask isn't a valid ban, check raw_mask */ - if((removed = del_id(chptr, raw_mask, list, mode_type)) != NULL) - mask = raw_mask; + _mask = raw_mask; + it = list->find(_mask); } - if(removed && !removed->forward.empty()) - removed_mask_pos += snprintf(buf + old_removed_mask_pos, sizeof(buf), "%s$%s", removed->banstr.c_str(), removed->forward.c_str()) + 1; - else - removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, mask, sizeof(buf)) + 1; - if(removed) + if (it != end(*list)) { - delete removed; - removed = NULL; + const auto &ban(*it); + if (!ban.forward.empty()) + removed_mask_pos += snprintf(buf + old_removed_mask_pos, sizeof(buf), "%s$%s", ban.banstr.c_str(), ban.forward.c_str()) + 1; + else + removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, mask, sizeof(buf)) + 1; + + del(*chptr, mode_type, _mask); } mode_changes[mode_count].letter = c; diff --git a/ircd/s_serv.cc b/ircd/s_serv.cc index 28dc7db6f..04ca3db93 100644 --- a/ircd/s_serv.cc +++ b/ircd/s_serv.cc @@ -504,29 +504,24 @@ burst_ban(struct Client *client_p) * side effects - client is sent a list of +b, +e, or +I modes */ static void -burst_modes_TS6(struct Client *client_p, chan::chan *chptr, - rb_dlink_list *list, char flag) +burst_modes_TS6(Client &client, + chan::chan &chan, + chan::list &list, + const char &flag) { - rb_dlink_node *ptr; - char *t; - int tlen; - int mlen; - int cur_len; - - cur_len = mlen = sprintf(buf, ":%s BMASK %ld %s %c :", - me.id, (long) chptr->channelts, chptr->name.c_str(), flag); - t = buf + mlen; - - RB_DLINK_FOREACH(ptr, list->head) + auto mlen(sprintf(buf, ":%s BMASK %ld %s %c :", me.id, long(chan.channelts), chan.name.c_str(), flag)); + auto cur_len(mlen); + auto t(buf + mlen); + for (const auto &ban : list) { - auto *const banptr(reinterpret_cast(ptr->data)); + const auto &mask(ban.banstr); + const auto &forward(ban.forward); + const auto tlen(mask.size() + 1 + (forward.empty()? 0 : forward.size() + 1)); - tlen = banptr->banstr.size() + (banptr->forward.size() ? strlen(banptr->forward.c_str()) + 1 : 0) + 1; - - /* uh oh */ - if(cur_len + tlen > BUFSIZE - 3) + // uh oh + if (cur_len + tlen > BUFSIZE - 3) { - /* the one we're trying to send doesnt fit at all! */ + // the one we're trying to send doesnt fit at all! if(cur_len == mlen) { s_assert(0); @@ -535,15 +530,16 @@ burst_modes_TS6(struct Client *client_p, chan::chan *chptr, /* chop off trailing space and send.. */ *(t-1) = '\0'; - sendto_one(client_p, "%s", buf); + sendto_one(&client, "%s", buf); cur_len = mlen; t = buf + mlen; } - if (banptr->forward.size()) - sprintf(t, "%s$%s ", banptr->banstr.c_str(), banptr->forward.c_str()); + if (forward.size()) + sprintf(t, "%s$%s ", mask.c_str(), forward.c_str()); else - sprintf(t, "%s ", banptr->banstr.c_str()); + sprintf(t, "%s ", mask.c_str()); + t += tlen; cur_len += tlen; } @@ -552,7 +548,7 @@ burst_modes_TS6(struct Client *client_p, chan::chan *chptr, * chop off trailing space and send. */ *(t-1) = '\0'; - sendto_one(client_p, "%s", buf); + sendto_one(&client, "%s", buf); } /* @@ -681,21 +677,21 @@ burst_TS6(struct Client *client_p) } sendto_one(client_p, "%s", buf); - if(rb_dlink_list_length(&chptr->banlist) > 0) - burst_modes_TS6(client_p, chptr, &chptr->banlist, 'b'); + namespace mode = chan::mode; - if(IsCapable(client_p, CAP_EX) && - rb_dlink_list_length(&chptr->exceptlist) > 0) - burst_modes_TS6(client_p, chptr, &chptr->exceptlist, 'e'); + if (!empty(*chptr, mode::BAN)) + burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::BAN), 'b'); - if(IsCapable(client_p, CAP_IE) && - rb_dlink_list_length(&chptr->invexlist) > 0) - burst_modes_TS6(client_p, chptr, &chptr->invexlist, 'I'); + if (IsCapable(client_p, CAP_EX) && !empty(*chptr, mode::EXCEPTION)) + burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::EXCEPTION), 'e'); - if(rb_dlink_list_length(&chptr->quietlist) > 0) - burst_modes_TS6(client_p, chptr, &chptr->quietlist, 'q'); + if (IsCapable(client_p, CAP_IE) && !empty(*chptr, mode::INVEX)) + burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::INVEX), 'I'); - if(IsCapable(client_p, CAP_TB) && chptr->topic) + if (!empty(*chptr, mode::QUIET)) + burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::QUIET), 'q'); + + if (IsCapable(client_p, CAP_TB) && chptr->topic) sendto_one(client_p, ":%s TB %s %ld %s%s:%s", me.id, chptr->name.c_str(), @@ -704,7 +700,7 @@ burst_TS6(struct Client *client_p) ConfigChannel.burst_topicwho? " " : "", chptr->topic.text.c_str()); - if(IsCapable(client_p, CAP_MLOCK)) + if (IsCapable(client_p, CAP_MLOCK)) sendto_one(client_p, ":%s MLOCK %ld %s :%s", me.id, (long) chptr->channelts, chptr->name.c_str(), chptr->mode_lock.c_str()); diff --git a/modules/core/m_join.cc b/modules/core/m_join.cc index 46b3b4caa..6087a65b9 100644 --- a/modules/core/m_join.cc +++ b/modules/core/m_join.cc @@ -59,7 +59,7 @@ static void send_join_error(struct Client *source_p, int numeric, const char *na static void set_final_mode(chan::modes *mode, chan::modes *oldmode); static void remove_our_modes(chan::chan *chptr, struct Client *source_p); -static void remove_ban_list(chan::chan *chptr, struct Client *source_p, rb_dlink_list * list, char c, int mems); +static void remove_ban_list(chan::chan &chan, Client &source, chan::list &list, const char &c, const int &mems); static char modebuf[chan::mode::BUFLEN]; static char parabuf[chan::mode::BUFLEN]; @@ -702,23 +702,25 @@ ms_sjoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source /* Lost the TS, other side wins, so remove modes on this side */ if(!keep_our_modes) { + namespace mode = chan::mode; + using chan::empty; + remove_our_modes(chptr, fakesource_p); RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head) - { del_invite(chptr, (Client *)ptr->data); - } - if(rb_dlink_list_length(&chptr->banlist) > 0) - remove_ban_list(chptr, fakesource_p, &chptr->banlist, 'b', chan::ALL_MEMBERS); - if(rb_dlink_list_length(&chptr->exceptlist) > 0) - remove_ban_list(chptr, fakesource_p, &chptr->exceptlist, - 'e', chan::ONLY_CHANOPS); - if(rb_dlink_list_length(&chptr->invexlist) > 0) - remove_ban_list(chptr, fakesource_p, &chptr->invexlist, - 'I', chan::ONLY_CHANOPS); - if(rb_dlink_list_length(&chptr->quietlist) > 0) - remove_ban_list(chptr, fakesource_p, &chptr->quietlist, - 'q', chan::ALL_MEMBERS); + if (!empty(*chptr, chan::mode::BAN)) + remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::BAN), 'b', chan::ALL_MEMBERS); + + if (!empty(*chptr, mode::EXCEPTION)) + remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::EXCEPTION), 'e', chan::ONLY_CHANOPS); + + if (!empty(*chptr, mode::INVEX)) + remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::INVEX), 'I', chan::ONLY_CHANOPS); + + if (!empty(*chptr, mode::QUIET)) + remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::QUIET), 'q', chan::ALL_MEMBERS); + chptr->bants++; sendto_channel_local(chan::ALL_MEMBERS, chptr, @@ -1257,36 +1259,35 @@ remove_our_modes(chan::chan *chptr, struct Client *source_p) * side effects - given list is removed, with modes issued to local clients */ static void -remove_ban_list(chan::chan *chptr, struct Client *source_p, - rb_dlink_list * list, char c, int mems) +remove_ban_list(chan::chan &chan, + Client &source, + chan::list &list, + const char &c, + const int &mems) { - static char lmodebuf[BUFSIZE]; - static char lparabuf[BUFSIZE]; - rb_dlink_node *ptr; - rb_dlink_node *next_ptr; - char *pbuf; - int count = 0; - int cur_len, mlen, plen; + static char lmodebuf[BUFSIZE], lparabuf[BUFSIZE]; - pbuf = lparabuf; + int count (0); + char *pbuf(lparabuf); - cur_len = mlen = sprintf(lmodebuf, ":%s MODE %s -", source_p->name, chptr->name.c_str()); - mbuf = lmodebuf + mlen; + int cur_len, mlen; + cur_len = mlen = sprintf(lmodebuf, ":%s MODE %s -", source.name, chan.name.c_str()); + char *mbuf(lmodebuf + mlen); - RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head) + for (const auto &ban : list) { - const auto banptr((chan::ban *)ptr->data); + const auto &mask(ban.banstr); + const auto &fwd(ban.forward); - /* trailing space, and the mode letter itself */ - plen = banptr->banstr.size() + (!banptr->forward.empty()? banptr->forward.size() + 1 : 0) + 2; - - if(count >= chan::mode::MAXPARAMS || (cur_len + plen) > BUFSIZE - 4) + //trailing space, and the mode letter itself + const auto plen(mask.size() + 2 + (!fwd.empty()? fwd.size() + 1 : 0)); + if (count >= chan::mode::MAXPARAMS || (cur_len + plen) > BUFSIZE - 4) { - /* remove trailing space */ + // remove trailing space *mbuf = '\0'; *(pbuf - 1) = '\0'; - sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf); + sendto_channel_local(mems, &chan, "%s %s", lmodebuf, lparabuf); cur_len = mlen; mbuf = lmodebuf + mlen; @@ -1296,19 +1297,18 @@ remove_ban_list(chan::chan *chptr, struct Client *source_p, *mbuf++ = c; cur_len += plen; - if (!banptr->forward.empty()) - pbuf += sprintf(pbuf, "%s$%s ", banptr->banstr.c_str(), banptr->forward.c_str()); - else - pbuf += sprintf(pbuf, "%s ", banptr->banstr.c_str()); - count++; - delete banptr; + if (!fwd.empty()) + pbuf += sprintf(pbuf, "%s$%s ", mask.c_str(), fwd.c_str()); + else + pbuf += sprintf(pbuf, "%s ", mask.c_str()); + + count++; } *mbuf = '\0'; *(pbuf - 1) = '\0'; - sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf); - list->head = list->tail = NULL; - list->length = 0; + sendto_channel_local(mems, &chan, "%s %s", lmodebuf, lparabuf); + list.clear(); } diff --git a/modules/core/m_mode.cc b/modules/core/m_mode.cc index 6c2e0d0d3..6d8bab1d2 100644 --- a/modules/core/m_mode.cc +++ b/modules/core/m_mode.cc @@ -219,34 +219,33 @@ ms_mlock(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source static void possibly_remove_lower_forward(struct Client *fakesource_p, - int mems, - chan::chan *chptr, - rb_dlink_list *banlist, - int mchar, + const int &mems, + chan::chan &chan, + chan::list &list, + const int &mchar, const char *mask, const char *forward) { - rb_dlink_node *ptr; - RB_DLINK_FOREACH(ptr, banlist->head) + for (auto it(begin(list)); it != end(list); ++it) { - const auto actualBan((chan::ban *)ptr->data); - if(!irccmp(actualBan->banstr.c_str(), mask) && - (actualBan->forward.empty() || - irccmp(actualBan->forward.c_str(), forward) < 0)) - { - sendto_channel_local(mems, chptr, - ":%s MODE %s -%c %s%s%s", - fakesource_p->name, - chptr->name.c_str(), - mchar, - actualBan->banstr.c_str(), - actualBan->forward.size()? "$" : "", - actualBan->forward.size()? actualBan->forward.c_str() : ""); + const auto &ban(*it); - rb_dlinkDelete(&actualBan->node, banlist); - delete actualBan; - return; - } + if (irccmp(ban.banstr, mask) != 0) + continue; + + if (ban.forward.size() && irccmp(ban.forward, forward) >= 0) + continue; + + sendto_channel_local(mems, &chan, + ":%s MODE %s -%c %s%s%s", + fakesource_p->name, + chan.name.c_str(), + mchar, + ban.banstr.c_str(), + ban.forward.size()? "$" : "", + ban.forward.size()? ban.forward.c_str() : ""); + list.erase(it); + break; } } @@ -256,12 +255,12 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source static char modebuf[BUFSIZE]; static char parabuf[BUFSIZE]; chan::chan *chptr; - rb_dlink_list *banlist; + chan::list *list; + chan::mode::type mode_type; char *s, *forward; char *t; char *mbuf; char *pbuf; - long mode_type; int mlen; int plen = 0; int tlen; @@ -284,27 +283,23 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source switch (parv[3][0]) { case 'b': - banlist = &chptr->banlist; mode_type = chan::mode::BAN; mems = chan::ALL_MEMBERS; break; case 'e': - banlist = &chptr->exceptlist; mode_type = chan::mode::EXCEPTION; needcap = CAP_EX; mems = chan::ONLY_CHANOPS; break; case 'I': - banlist = &chptr->invexlist; mode_type = chan::mode::INVEX; needcap = CAP_IE; mems = chan::ONLY_CHANOPS; break; case 'q': - banlist = &chptr->quietlist; mode_type = chan::mode::QUIET; mems = chan::ALL_MEMBERS; break; @@ -314,6 +309,8 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source return; } + list = &get(*chptr, mode_type); + parabuf[0] = '\0'; s = LOCAL_COPY(parv[4]); @@ -359,11 +356,11 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source tlen--, forward = NULL; else possibly_remove_lower_forward(fakesource_p, - mems, chptr, banlist, + mems, *chptr, *list, parv[3][0], s, forward); } - if(add_id(fakesource_p, chptr, s, forward, banlist, mode_type)) + if (add(*chptr, mode_type, s, *fakesource_p, forward)) { /* this new one wont fit.. */ if(mlen + chan::mode::MAXPARAMS + plen + tlen > BUFSIZE - 5 || diff --git a/modules/m_knock.cc b/modules/m_knock.cc index 1282a9d1d..12e837af9 100644 --- a/modules/m_knock.cc +++ b/modules/m_knock.cc @@ -116,12 +116,11 @@ m_knock(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_ if(MyClient(source_p)) { - /* don't allow a knock if the user is banned */ - if(is_banned(chptr, source_p, NULL, NULL, NULL, NULL) == chan::mode::BAN || - is_quieted(chptr, source_p, NULL, NULL, NULL) == chan::mode::BAN) + // don't allow a knock if the user is banned + if (check(*chptr, chan::mode::BAN, *source_p) || + check(*chptr, chan::mode::QUIET, *source_p)) { - sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, - form_str(ERR_CANNOTSENDTOCHAN), name); + sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name); return; } diff --git a/modules/m_stats.cc b/modules/m_stats.cc index 267d90c52..2d7081f3f 100644 --- a/modules/m_stats.cc +++ b/modules/m_stats.cc @@ -1355,33 +1355,17 @@ stats_memory (struct Client *source_p) channel_users += rb_dlink_list_length(&chptr->members); channel_invites += rb_dlink_list_length(&chptr->invites); - RB_DLINK_FOREACH(rb_dlink, chptr->banlist.head) - { - channel_bans++; + channel_bans += size(*chptr, chan::mode::BAN); + channel_ban_memory += size(*chptr, chan::mode::BAN) * sizeof(chan::ban); - channel_ban_memory += sizeof(rb_dlink_node) + sizeof(chan::ban); - } + channel_except += size(*chptr, chan::mode::EXCEPTION); + channel_except_memory += size(*chptr, chan::mode::EXCEPTION) * sizeof(chan::ban); - RB_DLINK_FOREACH(rb_dlink, chptr->exceptlist.head) - { - channel_except++; + channel_invex += size(*chptr, chan::mode::INVEX); + channel_invex_memory += size(*chptr, chan::mode::INVEX) * sizeof(chan::ban); - channel_except_memory += (sizeof(rb_dlink_node) + sizeof(chan::ban)); - } - - RB_DLINK_FOREACH(rb_dlink, chptr->invexlist.head) - { - channel_invex++; - - channel_invex_memory += (sizeof(rb_dlink_node) + sizeof(chan::ban)); - } - - RB_DLINK_FOREACH(rb_dlink, chptr->quietlist.head) - { - channel_quiets++; - - channel_quiet_memory += (sizeof(rb_dlink_node) + sizeof(chan::ban)); - } + channel_quiets += size(*chptr, chan::mode::QUIET); + channel_quiet_memory += size(*chptr, chan::mode::QUIET) * sizeof(chan::ban); } /* count up all classes */