0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-30 04:38:52 +02: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; return INVALID;
#endif #endif
recurse = 1; 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; recurse = 0;
return ret; return ret;
} }

View file

@ -5,6 +5,8 @@
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox 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 * 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 * it under the terms of the GNU General Public License as published by
@ -29,6 +31,10 @@
namespace ircd { namespace ircd {
namespace chan { namespace chan {
IRCD_EXCEPTION(ircd::error, error)
IRCD_EXCEPTION(error, not_found)
IRCD_EXCEPTION(error, invalid_list)
enum status enum status
{ {
PEON = 0x0000, // normal member of channel PEON = 0x0000, // normal member of channel
@ -60,11 +66,16 @@ struct ban
std::string who; std::string who;
std::string forward; std::string forward;
time_t when; 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 struct modes
{ {
static constexpr size_t KEYLEN = 24; // 23+1 for \0 static constexpr size_t KEYLEN = 24; // 23+1 for \0
@ -123,12 +134,12 @@ struct chan
rb_dlink_list members; rb_dlink_list members;
rb_dlink_list locmembers; rb_dlink_list locmembers;
rb_dlink_list invites; rb_dlink_list invites;
rb_dlink_list banlist;
rb_dlink_list exceptlist; list bans;
rb_dlink_list invexlist; list excepts;
rb_dlink_list quietlist; list invexs;
list quiets;
uint join_count; // joins within delta uint join_count; // joins within delta
uint join_delta; // last ts of join uint join_delta; // last ts of join
@ -139,9 +150,9 @@ struct chan
time_t bants; time_t bants;
time_t channelts; time_t channelts;
time_t last_checked_ts; time_t last_checked_ts;
client *last_checked_client; const client *last_checked_client;
uint last_checked_type; mode::type last_checked_type;
int last_checked_result; bool last_checked_result;
rb_dlink_node node = {0}; rb_dlink_node node = {0};
@ -167,16 +178,35 @@ enum : int
CAN_SEND_OPV = 2, CAN_SEND_OPV = 2,
}; };
int can_send(chan *, client *, membership *); 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 *); 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 add_user_to_channel(chan *, client *, int flags);
void remove_user_from_channel(membership *); void remove_user_from_channel(membership *);
void remove_user_from_channels(client *); void remove_user_from_channels(client *);
void invalidate_bancache_user(client *); void invalidate_bancache_user(client *);
void free_channel_list(rb_dlink_list *);
void channel_member_names(chan *, client *, int show_eon); void channel_member_names(chan *, client *, int show_eon);
void del_invite(chan *, client *who); void del_invite(chan *, client *who);
const char *channel_modes(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 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_mode(client *, client *source, chan *, membership *, int parc, const char *parv[]);
void set_channel_mlock(client *, client *source, chan *, const char *newmlock, bool propagate); 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 match_extban(const char *banstr, client *, chan *, long mode_type);
int valid_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); const char * get_extban_string(void);
@ -358,6 +386,12 @@ operator|(const modes &modes, const mode::type &value)
return modes.mode | value; return modes.mode | value;
} }
inline bool
operator<(const ban &a, const ban &b)
{
return irccmp(a.banstr, b.banstr);
}
inline bool inline bool
operator!(const topic &topic) operator!(const topic &topic)
{ {

View file

@ -5,7 +5,8 @@
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox 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 * 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 * 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 "listener.h"
#include "s_assert.h" #include "s_assert.h"
#include "match.h"
#include "chmode.h" #include "chmode.h"
#include "channel.h" #include "channel.h"
@ -60,7 +61,6 @@ namespace ircd
#include "ircd_linker.h" #include "ircd_linker.h"
#include "ircd_signal.h" #include "ircd_signal.h"
#include "logger.h" #include "logger.h"
#include "match.h"
#include "messages.h" #include "messages.h"
#include "info.h" #include "info.h"
#include "modules.h" #include "modules.h"

View file

@ -5,6 +5,8 @@
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox 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 * 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 * 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; struct config_channel_entry ircd::ConfigChannel;
rb_dlink_list chan::global_channel_list; rb_dlink_list chan::global_channel_list;
//std::map<std::string, std::unique_ptr<chan::chan>> chan::chans; //std::map<std::string, std::unique_ptr<chan::chan>> chan::chans;
@ -49,10 +52,6 @@ chan::chan::chan(const std::string &name)
,members{0} ,members{0}
,locmembers{0} ,locmembers{0}
,invites{0} ,invites{0}
,banlist{0}
,exceptlist{0}
,invexlist{0}
,quietlist{0}
,join_count{0} ,join_count{0}
,join_delta{0} ,join_delta{0}
,flood_noticed{0} ,flood_noticed{0}
@ -63,7 +62,7 @@ chan::chan::chan(const std::string &name)
,channelts{0} ,channelts{0}
,last_checked_ts{0} ,last_checked_ts{0}
,last_checked_client{nullptr} ,last_checked_client{nullptr}
,last_checked_type{0} ,last_checked_type{mode::type(0)}
,last_checked_result{0} ,last_checked_result{0}
{ {
} }
@ -75,12 +74,6 @@ noexcept
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, invites.head) RB_DLINK_FOREACH_SAFE(ptr, next_ptr, invites.head)
del_invite(this, reinterpret_cast<client *>(ptr->data)); 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); rb_dlinkDelete(&node, &global_channel_list);
del_from_channel_hash(name.c_str(), this); del_from_channel_hash(name.c_str(), this);
} }
@ -113,11 +106,12 @@ chan::modes::modes()
chan::ban::ban(const std::string &banstr, chan::ban::ban(const std::string &banstr,
const std::string &who, const std::string &who,
const std::string &forward) const std::string &forward,
const time_t &when)
:banstr{banstr} :banstr{banstr}
,who{who} ,who{who}
,forward{forward} ,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() /* channel_pub_or_secret()
* *
* input - channel * input - channel
@ -480,186 +453,183 @@ chan::del_invite(chan *chptr, client *who)
rb_dlinkFindDestroy(chptr, &who->user->invited); rb_dlinkFindDestroy(chptr, &who->user->invited);
} }
/* is_banned_list() bool
* chan::cache_check(const chan &chan,
* input - channel to check bans for, ban list (banlist or quietlist), const mode::type &type,
* user to check bans against, optional prebuilt buffers, const client &who,
* optional forward channel pointer bool &result)
* 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)
{ {
using namespace chan; using namespace mode;
char src_host[NICKLEN + USERLEN + HOSTLEN + 6]; if (chan.last_checked_client != &who)
char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6]; return false;
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(!MyClient(who)) if (chan.last_checked_ts <= chan.bants)
return 0; return false;
/* if the buffers havent been built, do it here */ switch (type)
if(s == NULL)
{ {
sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host); case BAN:
sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost); case QUIET:
result = chan.last_checked_result;
return true;
s = src_host; default:
s2 = src_iphost; 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)
{ {
actualBan = (ban *)ptr->data; using namespace mode;
if(match(actualBan->banstr.c_str(), s) ||
match(actualBan->banstr.c_str(), s2) || switch (type)
match_cidr(actualBan->banstr.c_str(), s2) || {
match_extban(actualBan->banstr.c_str(), who, chptr, mode::BAN) || case BAN:
(s3 != NULL && match(actualBan->banstr.c_str(), s3)) case QUIET:
#ifdef RB_IPV6
||
(s4 != NULL && (match(actualBan->banstr.c_str(), s4) || match_cidr(actualBan->banstr.c_str(), s4)))
#endif
)
break; break;
default:
return;
}
chan.last_checked_client = &client;
chan.last_checked_type = type;
chan.last_checked_result = result;
chan.last_checked_ts = rb_current_time();
if (membership)
{
membership->bants = chan.bants;
if (result)
membership->flags |= BANNED;
else else
actualBan = NULL; membership->flags &= ~BANNED;
}
} }
if((actualBan != NULL) && ircd::ConfigChannel.use_except) bool
chan::check(chan &chan,
const mode::type &type,
const client &client,
check_data *const &data)
{ {
RB_DLINK_FOREACH(ptr, chptr->exceptlist.head) bool result;
if (cache_check(chan, type, client, result))
return result;
if (!my(client))
return false;
enum srcs { HOST, IPHOST, ALTHOST, IP4HOST, _NUM_ };
char src[num_of<srcs>()][NICKLEN + USERLEN + HOSTLEN + 6];
const char *s[num_of<srcs>()]
{ {
actualExcept = (ban *)ptr->data; data? data->host : nullptr,
data? data->iphost : nullptr
};
/* theyre exempted.. */ // if the buffers havent been built, do it here
if(match(actualExcept->banstr.c_str(), s) || if (!s[HOST])
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 */ sprintf(src[HOST], "%s!%s@%s", client.name, client.username, client.host);
if(msptr != NULL) s[HOST] = src[HOST];
}
if (!s[IPHOST])
{ {
msptr->bants = chptr->bants; sprintf(src[IPHOST], "%s!%s@%s", client.name, client.username, client.sockhost);
msptr->flags &= ~BANNED; s[IPHOST] = src[IPHOST];
} }
return mode::EXCEPTION; if (client.localClient->mangledhost)
}
}
}
/* cache the banned/not banned status */
if(msptr != NULL)
{ {
msptr->bants = chptr->bants; // if host mangling mode enabled, also check their real host
if (strcmp(client.host, client.localClient->mangledhost) == 0)
if(actualBan != NULL)
{ {
msptr->flags |= BANNED; sprintf(src[ALTHOST], "%s!%s@%s", client.name, client.username, client.orighost);
return mode::BAN; s[ALTHOST] = src[ALTHOST];
} }
else // if host mangling mode not enabled and no other spoof, check the mangled form of their host
else if (!IsDynSpoof(&client))
{ {
msptr->flags &= ~BANNED; sprintf(src[ALTHOST], "%s!%s@%s", client.name, client.username, client.localClient->mangledhost);
return 0; s[ALTHOST] = src[ALTHOST];
} }
} }
if (actualBan && !actualBan->forward.empty() && forward) #ifdef RB_IPV6
*forward = actualBan->forward.c_str(); //TODO: XXX: ??? struct sockaddr_in ip4;
if (GET_SS_FAMILY(&client.localClient->ip) == AF_INET6 &&
return actualBan? mode::BAN : mode::type(0); rb_ipv4_from_ipv6((const struct sockaddr_in6 *)&client.localClient->ip, &ip4))
}
/* 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)
{ {
if (chptr->last_checked_client != NULL && sprintf(src[IP4HOST], "%s!%s@", client.name, client.username);
who == chptr->last_checked_client && char *const pos(src[IP4HOST] + strlen(src[IP4HOST]));
chptr->last_checked_type == mode::BAN && rb_inet_ntop_sock((struct sockaddr *)&ip4, pos, src[IP4HOST] + sizeof(src[IP4HOST]) - pos);
chptr->last_checked_ts > chptr->bants) s[IP4HOST] = src[IP4HOST];
return chptr->last_checked_result; }
#endif
chptr->last_checked_client = who; const auto matched([&s, &chan, &client]
chptr->last_checked_type = mode::BAN; (const ban &ban)
chptr->last_checked_result = is_banned_list(chptr, &chptr->banlist, who, msptr, s, s2, forward); {
chptr->last_checked_ts = rb_current_time(); const auto &mask(ban.banstr);
if (match(mask, s[HOST]))
return true;
return chptr->last_checked_result; 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;
}
} }
/* is_quieted() if (result && data && data->forward)
*
* 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 && const auto &ban(*it);
who == chptr->last_checked_client && if (!ban.forward.empty())
chptr->last_checked_type == mode::QUIET && *data->forward = ban.forward.c_str(); //TODO: XXX: ???
chptr->last_checked_ts > chptr->bants) }
return chptr->last_checked_result;
chptr->last_checked_client = who; cache_result(chan, type, client, result, msptr);
chptr->last_checked_type = mode::QUIET; return result;
chptr->last_checked_result = is_banned_list(chptr, &chptr->quietlist, who, msptr, s, s2, NULL);
chptr->last_checked_ts = rb_current_time();
return chptr->last_checked_result;
} }
/* can_join() /* can_join()
@ -707,7 +677,15 @@ 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; moduledata.approved = ERR_BANNEDFROMCHAN;
goto finish_join_check; goto finish_join_check;
@ -726,25 +704,38 @@ chan::can_join(client *source_p, chan *chptr, const char *key, const char **forw
if (chptr->mode.mode & mode::INVITEONLY) if (chptr->mode.mode & mode::INVITEONLY)
{ {
RB_DLINK_FOREACH(invite, source_p->user->invited.head) RB_DLINK_FOREACH(invite, source_p->user->invited.head)
{
if (invite->data == chptr) if (invite->data == chptr)
break; break;
}
if(invite == NULL) if (!invite)
{ {
if (!ConfigChannel.use_invex) if (!ConfigChannel.use_invex)
moduledata.approved = ERR_INVITEONLYCHAN; 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; const auto &mask(ban.banstr);
if(match(invex->banstr.c_str(), src_host) if (match(mask, src_host))
|| match(invex->banstr.c_str(), src_iphost) return true;
|| match_cidr(invex->banstr.c_str(), src_iphost)
|| match_extban(invex->banstr.c_str(), source_p, chptr, mode::INVEX) if (match(mask, src_iphost))
|| (use_althost && match(invex->banstr.c_str(), src_althost))) return true;
break;
} if (match_cidr(mask, src_iphost))
if(ptr == NULL) 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; moduledata.approved = ERR_INVITEONLYCHAN;
} }
} }
@ -831,10 +822,18 @@ chan::can_send(chan *chptr, client *source_p, membership *msptr)
{ {
if(can_send_banned(msptr)) if(can_send_banned(msptr))
moduledata.approved = CAN_SEND_NO; moduledata.approved = CAN_SEND_NO;
} } else {
else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == mode::BAN check_data data
|| is_quieted(chptr, source_p, msptr, NULL, NULL) == mode::BAN) {
msptr
};
if (check(*chptr, mode::BAN, *source_p, &data))
moduledata.approved = CAN_SEND_NO; moduledata.approved = CAN_SEND_NO;
if (check(*chptr, mode::QUIET, *source_p, &data))
moduledata.approved = CAN_SEND_NO;
}
} }
if(is_chanop_voiced(msptr)) if(is_chanop_voiced(msptr))
@ -937,11 +936,22 @@ chan::find_bannickchange_channel(client *client_p)
{ {
if (can_send_banned(msptr)) if (can_send_banned(msptr))
return chptr; return chptr;
} } else {
else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == mode::BAN check_data data
|| is_quieted(chptr, client_p, msptr, src_host, src_iphost) == mode::BAN) {
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; return chptr;
} }
}
return NULL; 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; 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() /* check_string()
* *
* input - string to check * input - string to check
@ -775,10 +679,11 @@ mode::functor::ban(client *source_p, chan *chptr,
int alevel, int parc, int *parn, int alevel, int parc, int *parn,
const char **parv, int *errors, int dir, char c, type mode_type) const char **parv, int *errors, int dir, char c, type mode_type)
{ {
namespace chan = ircd::chan;
const char *mask, *raw_mask; const char *mask, *raw_mask;
char *forward; char *forward;
rb_dlink_list *list; chan::list *list;
rb_dlink_node *ptr;
int errorval; int errorval;
const char *rpl_list_p; const char *rpl_list_p;
const char *rpl_endlist_p; const char *rpl_endlist_p;
@ -787,7 +692,7 @@ mode::functor::ban(client *source_p, chan *chptr,
switch (mode_type) switch (mode_type)
{ {
case BAN: case BAN:
list = &chptr->banlist; list = &get(*chptr, mode_type);
errorval = SM_ERR_RPL_B; errorval = SM_ERR_RPL_B;
rpl_list_p = form_str(RPL_BANLIST); rpl_list_p = form_str(RPL_BANLIST);
rpl_endlist_p = form_str(RPL_ENDOFBANLIST); rpl_endlist_p = form_str(RPL_ENDOFBANLIST);
@ -800,7 +705,7 @@ mode::functor::ban(client *source_p, chan *chptr,
((dir == MODE_ADD) && (parc > *parn))) ((dir == MODE_ADD) && (parc > *parn)))
return; return;
list = &chptr->exceptlist; list = &get(*chptr, mode_type);
errorval = SM_ERR_RPL_E; errorval = SM_ERR_RPL_E;
rpl_list_p = form_str(RPL_EXCEPTLIST); rpl_list_p = form_str(RPL_EXCEPTLIST);
rpl_endlist_p = form_str(RPL_ENDOFEXCEPTLIST); rpl_endlist_p = form_str(RPL_ENDOFEXCEPTLIST);
@ -817,7 +722,7 @@ mode::functor::ban(client *source_p, chan *chptr,
(dir == MODE_ADD) && (parc > *parn)) (dir == MODE_ADD) && (parc > *parn))
return; return;
list = &chptr->invexlist; list = &get(*chptr, mode_type);
errorval = SM_ERR_RPL_I; errorval = SM_ERR_RPL_I;
rpl_list_p = form_str(RPL_INVITELIST); rpl_list_p = form_str(RPL_INVITELIST);
rpl_endlist_p = form_str(RPL_ENDOFINVITELIST); rpl_endlist_p = form_str(RPL_ENDOFINVITELIST);
@ -829,7 +734,7 @@ mode::functor::ban(client *source_p, chan *chptr,
break; break;
case QUIET: case QUIET:
list = &chptr->quietlist; list = &get(*chptr, mode_type);
errorval = SM_ERR_RPL_Q; errorval = SM_ERR_RPL_Q;
rpl_list_p = form_str(RPL_QUIETLIST); rpl_list_p = form_str(RPL_QUIETLIST);
rpl_endlist_p = form_str(RPL_ENDOFQUIETLIST); rpl_endlist_p = form_str(RPL_ENDOFQUIETLIST);
@ -859,19 +764,23 @@ mode::functor::ban(client *source_p, chan *chptr,
return; return;
} }
RB_DLINK_FOREACH(ptr, list->head) for (const auto &ban : *list)
{ {
char buf[ban::LEN]; char buf[ban::LEN];
auto *const banptr(reinterpret_cast<struct ban *>(ptr->data)); if(!ban.forward.empty())
if(!banptr->forward.empty()) snprintf(buf, sizeof(buf), "%s$%s", ban.banstr.c_str(), ban.forward.c_str());
snprintf(buf, sizeof(buf), "%s$%s", banptr->banstr.c_str(), banptr->forward.c_str());
else 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, sendto_one(source_p, rpl_list_p,
me.name, source_p->name, chptr->name.c_str(), me.name,
buf, banptr->who.c_str(), banptr->when); 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()); sendto_one(source_p, rpl_endlist_p, me.name, source_p->name, chptr->name.c_str());
return; return;
} }
@ -969,7 +878,7 @@ mode::functor::ban(client *source_p, chan *chptr,
/* dont allow local clients to overflow the banlist, dont /* dont allow local clients to overflow the banlist, dont
* let remote servers set duplicate bans * 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; return;
if(forward) if(forward)
@ -983,24 +892,28 @@ mode::functor::ban(client *source_p, chan *chptr,
} }
else if(dir == MODE_DEL) 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]; static char buf[ban::LEN * MAXPARAMS];
int old_removed_mask_pos = removed_mask_pos; const int old_removed_mask_pos(removed_mask_pos);
if((removed = del_id(chptr, mask, list, mode_type)) == NULL) std::string _mask(mask);
auto it(list->find(_mask));
if (it == end(*list))
{ {
/* mask isn't a valid ban, check raw_mask */ _mask = raw_mask;
if((removed = del_id(chptr, raw_mask, list, mode_type)) != NULL) it = list->find(_mask);
mask = raw_mask;
} }
if(removed && !removed->forward.empty()) if (it != end(*list))
removed_mask_pos += snprintf(buf + old_removed_mask_pos, sizeof(buf), "%s$%s", removed->banstr.c_str(), removed->forward.c_str()) + 1; {
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 else
removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, mask, sizeof(buf)) + 1; removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, mask, sizeof(buf)) + 1;
if(removed)
{ del(*chptr, mode_type, _mask);
delete removed;
removed = NULL;
} }
mode_changes[mode_count].letter = c; 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 * side effects - client is sent a list of +b, +e, or +I modes
*/ */
static void static void
burst_modes_TS6(struct Client *client_p, chan::chan *chptr, burst_modes_TS6(Client &client,
rb_dlink_list *list, char flag) chan::chan &chan,
chan::list &list,
const char &flag)
{ {
rb_dlink_node *ptr; auto mlen(sprintf(buf, ":%s BMASK %ld %s %c :", me.id, long(chan.channelts), chan.name.c_str(), flag));
char *t; auto cur_len(mlen);
int tlen; auto t(buf + mlen);
int mlen; for (const auto &ban : list)
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 *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
/* uh oh */
if (cur_len + tlen > BUFSIZE - 3) 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) if(cur_len == mlen)
{ {
s_assert(0); s_assert(0);
@ -535,15 +530,16 @@ burst_modes_TS6(struct Client *client_p, chan::chan *chptr,
/* chop off trailing space and send.. */ /* chop off trailing space and send.. */
*(t-1) = '\0'; *(t-1) = '\0';
sendto_one(client_p, "%s", buf); sendto_one(&client, "%s", buf);
cur_len = mlen; cur_len = mlen;
t = buf + mlen; t = buf + mlen;
} }
if (banptr->forward.size()) if (forward.size())
sprintf(t, "%s$%s ", banptr->banstr.c_str(), banptr->forward.c_str()); sprintf(t, "%s$%s ", mask.c_str(), forward.c_str());
else else
sprintf(t, "%s ", banptr->banstr.c_str()); sprintf(t, "%s ", mask.c_str());
t += tlen; t += tlen;
cur_len += tlen; cur_len += tlen;
} }
@ -552,7 +548,7 @@ burst_modes_TS6(struct Client *client_p, chan::chan *chptr,
* chop off trailing space and send. * chop off trailing space and send.
*/ */
*(t-1) = '\0'; *(t-1) = '\0';
sendto_one(client_p, "%s", buf); sendto_one(&client, "%s", buf);
} }
/* /*
@ -681,19 +677,19 @@ burst_TS6(struct Client *client_p)
} }
sendto_one(client_p, "%s", buf); sendto_one(client_p, "%s", buf);
if(rb_dlink_list_length(&chptr->banlist) > 0) namespace mode = chan::mode;
burst_modes_TS6(client_p, chptr, &chptr->banlist, 'b');
if(IsCapable(client_p, CAP_EX) && if (!empty(*chptr, mode::BAN))
rb_dlink_list_length(&chptr->exceptlist) > 0) burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::BAN), 'b');
burst_modes_TS6(client_p, chptr, &chptr->exceptlist, 'e');
if(IsCapable(client_p, CAP_IE) && if (IsCapable(client_p, CAP_EX) && !empty(*chptr, mode::EXCEPTION))
rb_dlink_list_length(&chptr->invexlist) > 0) burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::EXCEPTION), 'e');
burst_modes_TS6(client_p, chptr, &chptr->invexlist, 'I');
if(rb_dlink_list_length(&chptr->quietlist) > 0) if (IsCapable(client_p, CAP_IE) && !empty(*chptr, mode::INVEX))
burst_modes_TS6(client_p, chptr, &chptr->quietlist, 'q'); burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::INVEX), 'I');
if (!empty(*chptr, mode::QUIET))
burst_modes_TS6(*client_p, *chptr, get(*chptr, mode::QUIET), 'q');
if (IsCapable(client_p, CAP_TB) && chptr->topic) if (IsCapable(client_p, CAP_TB) && chptr->topic)
sendto_one(client_p, ":%s TB %s %ld %s%s:%s", sendto_one(client_p, ":%s TB %s %ld %s%s:%s",

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 set_final_mode(chan::modes *mode, chan::modes *oldmode);
static void remove_our_modes(chan::chan *chptr, struct Client *source_p); 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 modebuf[chan::mode::BUFLEN];
static char parabuf[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 */ /* Lost the TS, other side wins, so remove modes on this side */
if(!keep_our_modes) if(!keep_our_modes)
{ {
namespace mode = chan::mode;
using chan::empty;
remove_our_modes(chptr, fakesource_p); remove_our_modes(chptr, fakesource_p);
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head) RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
{
del_invite(chptr, (Client *)ptr->data); del_invite(chptr, (Client *)ptr->data);
}
if(rb_dlink_list_length(&chptr->banlist) > 0) if (!empty(*chptr, chan::mode::BAN))
remove_ban_list(chptr, fakesource_p, &chptr->banlist, 'b', chan::ALL_MEMBERS); remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::BAN), 'b', chan::ALL_MEMBERS);
if(rb_dlink_list_length(&chptr->exceptlist) > 0)
remove_ban_list(chptr, fakesource_p, &chptr->exceptlist, if (!empty(*chptr, mode::EXCEPTION))
'e', chan::ONLY_CHANOPS); remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::EXCEPTION), 'e', chan::ONLY_CHANOPS);
if(rb_dlink_list_length(&chptr->invexlist) > 0)
remove_ban_list(chptr, fakesource_p, &chptr->invexlist, if (!empty(*chptr, mode::INVEX))
'I', chan::ONLY_CHANOPS); remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::INVEX), 'I', chan::ONLY_CHANOPS);
if(rb_dlink_list_length(&chptr->quietlist) > 0)
remove_ban_list(chptr, fakesource_p, &chptr->quietlist, if (!empty(*chptr, mode::QUIET))
'q', chan::ALL_MEMBERS); remove_ban_list(*chptr, *fakesource_p, get(*chptr, mode::QUIET), 'q', chan::ALL_MEMBERS);
chptr->bants++; chptr->bants++;
sendto_channel_local(chan::ALL_MEMBERS, chptr, 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 * side effects - given list is removed, with modes issued to local clients
*/ */
static void static void
remove_ban_list(chan::chan *chptr, struct Client *source_p, remove_ban_list(chan::chan &chan,
rb_dlink_list * list, char c, int mems) Client &source,
chan::list &list,
const char &c,
const int &mems)
{ {
static char lmodebuf[BUFSIZE]; static char lmodebuf[BUFSIZE], lparabuf[BUFSIZE];
static char lparabuf[BUFSIZE];
rb_dlink_node *ptr;
rb_dlink_node *next_ptr;
char *pbuf;
int count = 0;
int cur_len, mlen, plen;
pbuf = lparabuf; int count (0);
char *pbuf(lparabuf);
cur_len = mlen = sprintf(lmodebuf, ":%s MODE %s -", source_p->name, chptr->name.c_str()); int cur_len, mlen;
mbuf = lmodebuf + 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;
//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) if (count >= chan::mode::MAXPARAMS || (cur_len + plen) > BUFSIZE - 4)
{ {
/* remove trailing space */ // remove trailing space
*mbuf = '\0'; *mbuf = '\0';
*(pbuf - 1) = '\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; cur_len = mlen;
mbuf = lmodebuf + mlen; mbuf = lmodebuf + mlen;
@ -1296,19 +1297,18 @@ remove_ban_list(chan::chan *chptr, struct Client *source_p,
*mbuf++ = c; *mbuf++ = c;
cur_len += plen; 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'; *mbuf = '\0';
*(pbuf - 1) = '\0'; *(pbuf - 1) = '\0';
sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
list->head = list->tail = NULL; sendto_channel_local(mems, &chan, "%s %s", lmodebuf, lparabuf);
list->length = 0; list.clear();
} }

View file

@ -219,34 +219,33 @@ ms_mlock(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
static void static void
possibly_remove_lower_forward(struct Client *fakesource_p, possibly_remove_lower_forward(struct Client *fakesource_p,
int mems, const int &mems,
chan::chan *chptr, chan::chan &chan,
rb_dlink_list *banlist, chan::list &list,
int mchar, const int &mchar,
const char *mask, const char *mask,
const char *forward) const char *forward)
{ {
rb_dlink_node *ptr; for (auto it(begin(list)); it != end(list); ++it)
RB_DLINK_FOREACH(ptr, banlist->head)
{ {
const auto actualBan((chan::ban *)ptr->data); const auto &ban(*it);
if(!irccmp(actualBan->banstr.c_str(), mask) &&
(actualBan->forward.empty() || if (irccmp(ban.banstr, mask) != 0)
irccmp(actualBan->forward.c_str(), forward) < 0)) continue;
{
sendto_channel_local(mems, chptr, if (ban.forward.size() && irccmp(ban.forward, forward) >= 0)
continue;
sendto_channel_local(mems, &chan,
":%s MODE %s -%c %s%s%s", ":%s MODE %s -%c %s%s%s",
fakesource_p->name, fakesource_p->name,
chptr->name.c_str(), chan.name.c_str(),
mchar, mchar,
actualBan->banstr.c_str(), ban.banstr.c_str(),
actualBan->forward.size()? "$" : "", ban.forward.size()? "$" : "",
actualBan->forward.size()? actualBan->forward.c_str() : ""); ban.forward.size()? ban.forward.c_str() : "");
list.erase(it);
rb_dlinkDelete(&actualBan->node, banlist); break;
delete actualBan;
return;
}
} }
} }
@ -256,12 +255,12 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
static char modebuf[BUFSIZE]; static char modebuf[BUFSIZE];
static char parabuf[BUFSIZE]; static char parabuf[BUFSIZE];
chan::chan *chptr; chan::chan *chptr;
rb_dlink_list *banlist; chan::list *list;
chan::mode::type mode_type;
char *s, *forward; char *s, *forward;
char *t; char *t;
char *mbuf; char *mbuf;
char *pbuf; char *pbuf;
long mode_type;
int mlen; int mlen;
int plen = 0; int plen = 0;
int tlen; int tlen;
@ -284,27 +283,23 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
switch (parv[3][0]) switch (parv[3][0])
{ {
case 'b': case 'b':
banlist = &chptr->banlist;
mode_type = chan::mode::BAN; mode_type = chan::mode::BAN;
mems = chan::ALL_MEMBERS; mems = chan::ALL_MEMBERS;
break; break;
case 'e': case 'e':
banlist = &chptr->exceptlist;
mode_type = chan::mode::EXCEPTION; mode_type = chan::mode::EXCEPTION;
needcap = CAP_EX; needcap = CAP_EX;
mems = chan::ONLY_CHANOPS; mems = chan::ONLY_CHANOPS;
break; break;
case 'I': case 'I':
banlist = &chptr->invexlist;
mode_type = chan::mode::INVEX; mode_type = chan::mode::INVEX;
needcap = CAP_IE; needcap = CAP_IE;
mems = chan::ONLY_CHANOPS; mems = chan::ONLY_CHANOPS;
break; break;
case 'q': case 'q':
banlist = &chptr->quietlist;
mode_type = chan::mode::QUIET; mode_type = chan::mode::QUIET;
mems = chan::ALL_MEMBERS; mems = chan::ALL_MEMBERS;
break; break;
@ -314,6 +309,8 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
return; return;
} }
list = &get(*chptr, mode_type);
parabuf[0] = '\0'; parabuf[0] = '\0';
s = LOCAL_COPY(parv[4]); 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; tlen--, forward = NULL;
else else
possibly_remove_lower_forward(fakesource_p, possibly_remove_lower_forward(fakesource_p,
mems, chptr, banlist, mems, *chptr, *list,
parv[3][0], s, forward); 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.. */ /* this new one wont fit.. */
if(mlen + chan::mode::MAXPARAMS + plen + tlen > BUFSIZE - 5 || 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)) if(MyClient(source_p))
{ {
/* don't allow a knock if the user is banned */ // don't allow a knock if the user is banned
if(is_banned(chptr, source_p, NULL, NULL, NULL, NULL) == chan::mode::BAN || if (check(*chptr, chan::mode::BAN, *source_p) ||
is_quieted(chptr, source_p, NULL, NULL, NULL) == chan::mode::BAN) check(*chptr, chan::mode::QUIET, *source_p))
{ {
sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name);
form_str(ERR_CANNOTSENDTOCHAN), name);
return; return;
} }

View file

@ -1355,33 +1355,17 @@ stats_memory (struct Client *source_p)
channel_users += rb_dlink_list_length(&chptr->members); channel_users += rb_dlink_list_length(&chptr->members);
channel_invites += rb_dlink_list_length(&chptr->invites); channel_invites += rb_dlink_list_length(&chptr->invites);
RB_DLINK_FOREACH(rb_dlink, chptr->banlist.head) channel_bans += size(*chptr, chan::mode::BAN);
{ channel_ban_memory += size(*chptr, chan::mode::BAN) * sizeof(chan::ban);
channel_bans++;
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_invex += size(*chptr, chan::mode::INVEX);
{ channel_invex_memory += size(*chptr, chan::mode::INVEX) * sizeof(chan::ban);
channel_except++;
channel_except_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);
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));
}
} }
/* count up all classes */ /* count up all classes */