mirror of
https://github.com/matrix-construct/construct
synced 2024-12-26 15:33:54 +01:00
Upgrade bqeI channel lists.
This commit is contained in:
parent
c5224c8142
commit
a84fe8a09b
11 changed files with 594 additions and 496 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
604
ircd/channel.cc
604
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 <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();
|
||||
}
|
||||
}
|
||||
|
|
159
ircd/chmode.cc
159
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<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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue