0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-27 07:54:05 +01:00

Upgrade bqeI channel lists.

This commit is contained in:
Jason Volk 2016-08-18 22:58:17 -07:00
parent c5224c8142
commit a84fe8a09b
11 changed files with 594 additions and 496 deletions

View file

@ -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;
}

View file

@ -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 <jason@zemos.net>
*
* 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<ban, std::less<ban>>;
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)
{

View file

@ -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 <jason@zemos.net>
*
* 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

View file

@ -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"

View file

@ -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 <jason@zemos.net>
*
* 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<std::string, std::unique_ptr<chan::chan>> 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<client *>(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<ban *>(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<srcs>()][NICKLEN + USERLEN + HOSTLEN + 6];
const char *s[num_of<srcs>()]
{
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 *>(&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<struct ban &>(*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();
}
}

View file

@ -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<ban *>(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<struct ban *>(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;

View file

@ -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<chan::ban *>(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());

View file

@ -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();
}

View file

@ -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 ||

View file

@ -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;
}

View file

@ -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 */