0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2025-01-14 00:34:18 +01:00

Upgrade channel membership lists.

This commit is contained in:
Jason Volk 2016-08-19 17:32:26 -07:00
parent 276cad4275
commit 5752be41b8
33 changed files with 447 additions and 394 deletions

View file

@ -52,7 +52,7 @@ m_findforwards(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *
/* Allow ircops to search for forwards to nonexistent channels */ /* Allow ircops to search for forwards to nonexistent channels */
if(!IsOper(source_p)) if(!IsOper(source_p))
{ {
if((chptr = find_channel(parv[1])) == NULL || (msptr = find_channel_membership(chptr, source_p)) == NULL) if((chptr = find_channel(parv[1])) == NULL || (msptr = get(chptr->members, *source_p, std::nothrow)) == NULL)
{ {
sendto_one_numeric(source_p, ERR_NOTONCHANNEL, sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
form_str(ERR_NOTONCHANNEL), parv[1]); form_str(ERR_NOTONCHANNEL), parv[1]);

View file

@ -84,7 +84,7 @@ mo_ojoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
if(*parv[1] == '@') if(*parv[1] == '@')
{ {
add_user_to_channel(chptr, source_p, chan::CHANOP); add(*chptr, *source_p, chan::CHANOP);
sendto_server(client_p, chptr, CAP_TS6, NOCAPS, sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
":%s SJOIN %ld %s + :@%s", ":%s SJOIN %ld %s + :@%s",
me.id, (long) chptr->channelts, chptr->name.c_str(), source_p->id); me.id, (long) chptr->channelts, chptr->name.c_str(), source_p->id);
@ -95,7 +95,7 @@ mo_ojoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
} }
else if(*parv[1] == '+') else if(*parv[1] == '+')
{ {
add_user_to_channel(chptr, source_p, chan::VOICE); add(*chptr, *source_p, chan::VOICE);
sendto_server(client_p, chptr, CAP_TS6, NOCAPS, sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
":%s SJOIN %ld %s + :+%s", ":%s SJOIN %ld %s + :+%s",
me.id, (long) chptr->channelts, chptr->name.c_str(), source_p->id); me.id, (long) chptr->channelts, chptr->name.c_str(), source_p->id);
@ -105,7 +105,7 @@ mo_ojoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
} }
else else
{ {
add_user_to_channel(chptr, source_p, chan::PEON); add(*chptr, *source_p, chan::PEON);
sendto_server(client_p, chptr, CAP_TS6, NOCAPS, sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
":%s JOIN %ld %s +", ":%s JOIN %ld %s +",
source_p->id, (long) chptr->channelts, chptr->name.c_str()); source_p->id, (long) chptr->channelts, chptr->name.c_str());

View file

@ -97,7 +97,7 @@ mo_okick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
return; return;
} }
if((msptr = find_channel_membership(chptr, target_p)) == NULL) if((msptr = get(chptr->members, *target_p, std::nothrow)) == NULL)
{ {
sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), parv[1], parv[2]); sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), parv[1], parv[2]);
return; return;
@ -120,5 +120,6 @@ mo_okick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
me.name, chptr->name.c_str(), who->name, comment); me.name, chptr->name.c_str(), who->name, comment);
sendto_server(&me, chptr, CAP_TS6, NOCAPS, sendto_server(&me, chptr, CAP_TS6, NOCAPS,
":%s KICK %s %s :%s", me.id, chptr->name.c_str(), who->id, comment); ":%s KICK %s %s :%s", me.id, chptr->name.c_str(), who->id, comment);
remove_user_from_channel(msptr);
del(*chptr, *target_p);
} }

View file

@ -76,7 +76,7 @@ mo_omode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
} }
/* Now know the channel exists */ /* Now know the channel exists */
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
wasonchannel = msptr != NULL; wasonchannel = msptr != NULL;
if (is_chanop(msptr)) if (is_chanop(msptr))
@ -133,8 +133,8 @@ mo_omode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
msptr->flags |= chan::CHANOP; msptr->flags |= chan::CHANOP;
else else
{ {
add_user_to_channel(chptr, source_p, chan::CHANOP); add(*chptr, *source_p, chan::CHANOP);
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
} }
set_channel_mode(client_p, source_p, chptr, msptr, set_channel_mode(client_p, source_p, chptr, msptr,
parc - 2, parv + 2); parc - 2, parv + 2);
@ -144,7 +144,7 @@ mo_omode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
if (wasonchannel) if (wasonchannel)
msptr->flags &= ~chan::CHANOP; msptr->flags &= ~chan::CHANOP;
else else
remove_user_from_channel(msptr); del(*chptr, get_client(*msptr));
} }
#endif #endif
} }

View file

@ -57,9 +57,9 @@ mo_opme(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
return; return;
} }
RB_DLINK_FOREACH(ptr, chptr->members.head) for(auto &pit : chptr->members.global)
{ {
msptr = (chan::membership *)ptr->data; msptr = &pit.second;
if(is_chanop(msptr)) if(is_chanop(msptr))
{ {
@ -68,7 +68,7 @@ mo_opme(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
} }
} }
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if(msptr == NULL) if(msptr == NULL)
return; return;

View file

@ -80,7 +80,7 @@ m_remove(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
if(!IsServer(source_p)) if(!IsServer(source_p))
{ {
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if((msptr == NULL) && MyConnect(source_p)) if((msptr == NULL) && MyConnect(source_p))
{ {
@ -139,7 +139,7 @@ m_remove(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
return; return;
} }
msptr = find_channel_membership(chptr, who); msptr = get(chptr->members, *who, std::nothrow);
if(msptr != NULL) if(msptr != NULL)
{ {
@ -190,7 +190,7 @@ m_remove(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
":%s KICK %s %s :%s", ":%s KICK %s %s :%s",
use_id(source_p), chptr->name.c_str(), use_id(who), comment); use_id(source_p), chptr->name.c_str(), use_id(who), comment);
remove_user_from_channel(msptr); del(*chptr, get_client(*msptr));
} }
else if (MyClient(source_p)) else if (MyClient(source_p))
sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,

View file

@ -140,7 +140,7 @@ m_displaymsg(struct MsgBuf *msgbuf_p, struct Client *source_p, const char *chann
return; return;
} }
if(!(msptr = find_channel_membership(chptr, source_p))) if(!(msptr = get(chptr->members, *source_p, std::nothrow)))
{ {
sendto_one_numeric(source_p, ERR_NOTONCHANNEL, sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
form_str(ERR_NOTONCHANNEL), chptr->name.c_str()); form_str(ERR_NOTONCHANNEL), chptr->name.c_str());

View file

@ -43,7 +43,7 @@ h_scc_channel_join(void *vdata)
struct Client *source_p = data->client; struct Client *source_p = data->client;
/* If they just joined a channel, and it only has one member, then they just created it. */ /* If they just joined a channel, and it only has one member, then they just created it. */
if(rb_dlink_list_length(&chptr->members) == 1 && is_chanop(find_channel_membership(chptr, source_p))) if(size(chptr->members) == 1 && is_chanop(get(chptr->members, *source_p, std::nothrow)))
{ {
sendto_realops_snomask(snomask_modes['l'], L_NETWIDE, "%s is creating new channel %s", sendto_realops_snomask(snomask_modes['l'], L_NETWIDE, "%s is creating new channel %s",
source_p->name, chptr->name.c_str()); source_p->name, chptr->name.c_str());

View file

@ -165,11 +165,10 @@ int chans_add(struct chan *const chan)
if(!rb_radixtree_add(chans, chan->name.c_str(), chan)) if(!rb_radixtree_add(chans, chan->name.c_str(), chan))
return 0; return 0;
rb_dlink_node *ptr; for(const auto &pit : chan->members.global)
RB_DLINK_FOREACH(ptr, chan->members.head)
{ {
const auto msptr(reinterpret_cast<membership *>(ptr->data)); const auto &client(pit.first);
bloom_add_str(msptr->client->name); bloom_add_str(client->name);
} }
return 1; return 1;

View file

@ -34,6 +34,7 @@ namespace chan {
IRCD_EXCEPTION(ircd::error, error) IRCD_EXCEPTION(ircd::error, error)
IRCD_EXCEPTION(error, not_found) IRCD_EXCEPTION(error, not_found)
IRCD_EXCEPTION(error, invalid_list) IRCD_EXCEPTION(error, invalid_list)
IRCD_EXCEPTION(error, invalid_argument)
enum status enum status
{ {
@ -96,17 +97,15 @@ uint operator~(const modes &);
struct membership struct membership
{ {
rb_dlink_node channode; using global = std::map<client *, membership>;
rb_dlink_node locchannode; using local = std::list<membership *>;
rb_dlink_node usernode;
struct chan *chan;
Client *client;
unsigned int flags;
uint flags;
time_t bants; time_t bants;
global::iterator git;
local::iterator lit;
membership(); membership(const uint &flags = 0);
~membership() noexcept; ~membership() noexcept;
}; };
@ -119,6 +118,27 @@ bool is_chanop_voiced(const membership *const &);
bool can_send_banned(const membership &); bool can_send_banned(const membership &);
bool can_send_banned(const membership *const &); bool can_send_banned(const membership *const &);
const char *find_status(const membership *const &msptr, const int &combine); const char *find_status(const membership *const &msptr, const int &combine);
const client &get_client(const membership &);
client &get_client(membership &);
struct members
{
membership::global global;
membership::local local;
members();
~members() noexcept;
};
bool empty(const members &);
size_t size(const members &);
bool local_empty(const members &);
size_t local_size(const members &);
bool exists(const members &, const client &);
const membership *get(const members &, const client &, std::nothrow_t);
const membership &get(const members &, const client &);
membership *get(members &, const client &, std::nothrow_t);
membership &get(members &, const client &);
bool has_prefix(const char *const &name); bool has_prefix(const char *const &name);
bool has_prefix(const std::string &name); bool has_prefix(const std::string &name);
@ -131,11 +151,8 @@ struct chan
struct modes mode; struct modes mode;
std::string mode_lock; std::string mode_lock;
struct topic topic; struct topic topic;
struct members members;
rb_dlink_list members;
rb_dlink_list locmembers;
std::set<client *> invites; std::set<client *> invites;
list bans; list bans;
list excepts; list excepts;
list invexs; list invexs;
@ -160,6 +177,7 @@ struct chan
~chan() noexcept; ~chan() noexcept;
}; };
const auto &name(const chan &);
bool is_secret(const chan &); bool is_secret(const chan &);
bool is_secret(const chan *const &); bool is_secret(const chan *const &);
bool is_hidden(const chan &); bool is_hidden(const chan &);
@ -206,9 +224,6 @@ void del_invite(chan &, client &);
void clear_invites(chan &); void clear_invites(chan &);
bool flood_attack_channel(int p_or_n, client *source, chan *); bool flood_attack_channel(int p_or_n, client *source, chan *);
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 invalidate_bancache_user(client *);
void channel_member_names(chan *, client *, int show_eon); void channel_member_names(chan *, client *, int show_eon);
const char *channel_modes(chan *, client *who); const char *channel_modes(chan *, client *who);
@ -227,13 +242,17 @@ 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);
int get_channel_access(client *source, chan *, membership *, int dir, const char *modestr); int get_channel_access(client *source, chan *, membership *, int dir, const char *modestr);
membership *find_channel_membership(chan *chptr, client *client_p);
void send_join(chan &, client &); void send_join(chan &, client &);
//extern std::map<std::string, std::unique_ptr<chan>> chans; //extern std::map<std::string, std::unique_ptr<chan>> chans;
extern rb_dlink_list global_channel_list; extern rb_dlink_list global_channel_list;
// Add and remove clients from channels
void add(chan &, client &, const int &flags = PEON);
void del(chan &, client &);
void del(client &); // remove from all channels
// Initialize subsystem
void init(); void init();
@ -276,8 +295,7 @@ is_public(const chan *const &c)
inline bool inline bool
is_member(const chan &c, const client &client) is_member(const chan &c, const client &client)
{ {
//return client.user && get(c, client, std::nothrow) != nullptr; return exists(c.members, client);
return find_channel_membership(const_cast<struct chan *>(&c), const_cast<Client *>(&client)) != nullptr;
} }
inline bool inline bool
@ -322,6 +340,42 @@ valid_name(const std::string &name)
return !name.empty() && std::all_of(begin(name), end(name), rfc1459::is_chan); return !name.empty() && std::all_of(begin(name), end(name), rfc1459::is_chan);
} }
inline const auto &
name(const chan &chan)
{
return chan.name;
}
inline size_t
local_size(const members &m)
{
return std::distance(begin(m.local), end(m.local));
}
inline bool
local_empty(const members &m)
{
return m.local.empty();
}
inline size_t
size(const members &m)
{
return m.global.size();
}
inline bool
empty(const members &m)
{
return m.global.empty();
}
inline bool
exists(const members &m, const client &c)
{
return m.global.count(const_cast<client *>(&c));
}
inline bool inline bool
is_chanop(const membership &m) is_chanop(const membership &m)
{ {
@ -358,6 +412,18 @@ is_chanop_voiced(const membership *const &m)
return m && is_chanop_voiced(*m); return m && is_chanop_voiced(*m);
} }
inline client &
get_client(membership &m)
{
return *m.git->first;
}
inline const client &
get_client(const membership &m)
{
return *m.git->first;
}
inline bool inline bool
can_send_banned(const membership &m) can_send_banned(const membership &m)
{ {

View file

@ -68,7 +68,7 @@ typedef int SSL_OPEN_CB(struct Client *, int status);
*/ */
struct User struct User
{ {
rb_dlink_list channel; /* chain of channel pointer blocks */ std::map<chan::chan *, chan::membership *> channel;
std::set<chan::chan *> invited; std::set<chan::chan *> invited;
char *away; /* pointer to away message */ char *away; /* pointer to away message */
int refcnt; /* Number of times this block is referenced */ int refcnt; /* Number of times this block is referenced */

View file

@ -49,8 +49,7 @@ chan::chan::chan(const std::string &name)
,mode{} ,mode{}
,mode_lock{} ,mode_lock{}
,topic{} ,topic{}
,members{0} ,members{}
,locmembers{0}
,join_count{0} ,join_count{0}
,join_delta{0} ,join_delta{0}
,flood_noticed{0} ,flood_noticed{0}
@ -74,13 +73,108 @@ noexcept
del_from_channel_hash(name.c_str(), this); del_from_channel_hash(name.c_str(), this);
} }
chan::membership::membership() /* remove_user_from_channels()
:channode{0} *
,locchannode{0} * input - user to remove from all channels
,usernode{0} * output -
,chan{nullptr} * side effects - user is removed from all channels
,client{nullptr} */
,flags{0} void
chan::del(client &client)
{
auto &client_chans(client.user->channel);
for(const auto &pit : client_chans)
{
auto &chan(*pit.first);
auto &member(*pit.second);
if (my(client))
chan.members.local.erase(member.lit);
chan.members.global.erase(member.git);
chan.invites.erase(&client);
if (empty(chan.members) && ~chan.mode & mode::PERMANENT)
delete &chan;
}
client_chans.clear();
client.user->invited.clear();
}
void
chan::del(chan &chan,
client &client)
{
// These are the relevant containers.
auto &global(chan.members.global);
auto &local(chan.members.local);
auto &client_chans(client.user->channel);
const auto it(client_chans.find(&chan));
if (it == end(client_chans))
return;
auto &member(*it->second);
if (my(client))
chan.members.local.erase(member.lit);
chan.members.global.erase(member.git); // The member is destroyed at this point.
client_chans.erase(it);
if (empty(chan.members) && ~chan.mode & mode::PERMANENT)
delete &chan;
}
void
chan::add(chan &chan,
client &client,
const int &flags)
{
if (!client.user)
{
s_assert(0);
return;
}
// These are the relevant containers.
auto &global(chan.members.global);
auto &local(chan.members.local);
auto &client_chans(client.user->channel);
// Add client to channel's global map
const auto iit(global.emplace(&client, flags));
if (!iit.second)
return;
// The global map hosts the membership structure.
auto &member(iit.first->second);
// Add iterator (pointer to the element) for constant time lookup/removal
member.git = iit.first;
// Add channel to client's channel map, pointing to the membership;
client_chans.emplace(&chan, &member);
// Add membership to a local list which can be iterated for local IO;
// iterator to this element is saved more crucially here to prevent linear removal
if (my(client))
member.lit = local.emplace(end(local), &member);
}
chan::members::members()
{
}
chan::members::~members()
noexcept
{
}
chan::membership::membership(const uint &flags)
:flags{flags}
,bants{0} ,bants{0}
{ {
} }
@ -144,46 +238,66 @@ chan::send_join(chan &chan,
client.user->away); client.user->away);
} }
/* find_channel_membership() chan::membership &
* chan::get(members &members,
* input - channel to find them in, client to find const client &client)
* output - membership of client in channel, else NULL
* side effects -
*/
chan::membership *
chan::find_channel_membership(chan *chptr, client *client_p)
{ {
struct membership *msptr; if (!is_client(client))
rb_dlink_node *ptr; throw invalid_argument();
if(!IsClient(client_p)) const auto key(const_cast<ircd::chan::client *>(&client)); //TODO: temp elaborated
return NULL; const auto it(members.global.find(key));
if (it == end(members.global))
throw not_found();
/* Pick the most efficient list to use to be nice to things like return it->second;
* CHANSERV which could be in a large number of channels }
*/
if(rb_dlink_list_length(&chptr->members) < rb_dlink_list_length(&client_p->user->channel))
{
RB_DLINK_FOREACH(ptr, chptr->members.head)
{
msptr = (membership *)ptr->data;
if(msptr->client == client_p) const chan::membership &
return msptr; chan::get(const members &members,
} const client &client)
} {
else if (!is_client(client))
{ throw invalid_argument();
RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
{
msptr = (membership *)ptr->data;
if(msptr->chan == chptr) const auto key(const_cast<ircd::chan::client *>(&client)); //TODO: temp elaborated
return msptr; const auto it(members.global.find(key));
} if (it == end(members.global))
} throw not_found();
return NULL; return it->second;
}
chan::membership *
chan::get(members &members,
const client &client,
std::nothrow_t)
{
if (!is_client(client))
return nullptr;
const auto key(const_cast<ircd::chan::client *>(&client)); //TODO: temp elaborated
const auto it(members.global.find(key));
if (it == end(members.global))
return nullptr;
return &it->second;
}
const chan::membership *
chan::get(const members &members,
const client &client,
std::nothrow_t)
{
if (!is_client(client))
return nullptr;
const auto key(const_cast<ircd::chan::client *>(&client)); //TODO: temp elaborated
const auto it(members.global.find(key));
if (it == end(members.global))
return nullptr;
return &it->second;
} }
/* find_channel_status() /* find_channel_status()
@ -215,102 +329,6 @@ chan::find_status(const membership *const &msptr,
return buffer; return buffer;
} }
/* add_user_to_channel()
*
* input - channel to add client to, client to add, channel flags
* output -
* side effects - user is added to channel
*/
void
chan::add_user_to_channel(chan *chptr, client *client_p, int flags)
{
membership *msptr;
s_assert(client_p->user != NULL);
if(client_p->user == NULL)
return;
msptr = new membership;
msptr->chan = chptr;
msptr->client = client_p;
msptr->flags = flags;
rb_dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
rb_dlinkAdd(msptr, &msptr->channode, &chptr->members);
if(MyClient(client_p))
rb_dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
}
/* remove_user_from_channel()
*
* input - membership pointer to remove from channel
* output -
* side effects - membership (thus user) is removed from channel
*/
void
chan::remove_user_from_channel(membership *msptr)
{
client *client_p;
chan *chptr;
s_assert(msptr != NULL);
if(msptr == NULL)
return;
client_p = msptr->client;
chptr = msptr->chan;
rb_dlinkDelete(&msptr->usernode, &client_p->user->channel);
rb_dlinkDelete(&msptr->channode, &chptr->members);
if(client_p->servptr == &me)
rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
if(!(chptr->mode.mode & mode::PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
delete chptr;
delete msptr;
return;
}
/* remove_user_from_channels()
*
* input - user to remove from all channels
* output -
* side effects - user is removed from all channels
*/
void
chan::remove_user_from_channels(client *client_p)
{
chan *chptr;
membership *msptr;
rb_dlink_node *ptr;
rb_dlink_node *next_ptr;
if(client_p == NULL)
return;
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
{
msptr = (membership *)ptr->data;
chptr = msptr->chan;
rb_dlinkDelete(&msptr->channode, &chptr->members);
if(client_p->servptr == &me)
rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
if(!(chptr->mode.mode & mode::PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
delete chptr;
delete msptr;
}
client_p->user->channel.head = client_p->user->channel.tail = NULL;
client_p->user->channel.length = 0;
}
/* invalidate_bancache_user() /* invalidate_bancache_user()
* *
* input - user to invalidate ban cache for * input - user to invalidate ban cache for
@ -319,19 +337,17 @@ chan::remove_user_from_channels(client *client_p)
* to be used after a nick change * to be used after a nick change
*/ */
void void
chan::invalidate_bancache_user(client *client_p) chan::invalidate_bancache_user(client *client)
{ {
membership *msptr; if(!client)
rb_dlink_node *ptr;
if(client_p == NULL)
return; return;
RB_DLINK_FOREACH(ptr, client_p->user->channel.head) for(const auto &pair : client->user->channel)
{ {
msptr = (membership *)ptr->data; auto &chan(*pair.first);
msptr->bants = 0; auto &member(*pair.second);
msptr->flags &= ~BANNED; member.bants = 0;
member.flags &= ~BANNED;
} }
} }
@ -358,7 +374,6 @@ channel_pub_or_secret(chan::chan *const &chptr)
void void
chan::channel_member_names(chan *chptr, client *client_p, int show_eon) chan::channel_member_names(chan *chptr, client *client_p, int show_eon)
{ {
membership *msptr;
client *target_p; client *target_p;
rb_dlink_node *ptr; rb_dlink_node *ptr;
char lbuf[BUFSIZE]; char lbuf[BUFSIZE];
@ -376,10 +391,10 @@ chan::channel_member_names(chan *chptr, client *client_p, int show_eon)
t = lbuf + cur_len; t = lbuf + cur_len;
RB_DLINK_FOREACH(ptr, chptr->members.head) for(const auto &pair : chptr->members.global)
{ {
msptr = (membership *)ptr->data; auto *const target_p(pair.first);
target_p = msptr->client; const auto &member(pair.second);
if(IsInvisible(target_p) && !is_member(chptr, client_p)) if(IsInvisible(target_p) && !is_member(chptr, client_p))
continue; continue;
@ -395,7 +410,7 @@ chan::channel_member_names(chan *chptr, client *client_p, int show_eon)
t = lbuf + mlen; t = lbuf + mlen;
} }
tlen = sprintf(t, "%s%s!%s@%s ", find_status(msptr, stack), tlen = sprintf(t, "%s%s!%s@%s ", find_status(&member, stack),
target_p->name, target_p->username, target_p->host); target_p->name, target_p->username, target_p->host);
} }
else else
@ -409,7 +424,7 @@ chan::channel_member_names(chan *chptr, client *client_p, int show_eon)
t = lbuf + mlen; t = lbuf + mlen;
} }
tlen = sprintf(t, "%s%s ", find_status(msptr, stack), tlen = sprintf(t, "%s%s ", find_status(&member, stack),
target_p->name); target_p->name);
} }
@ -733,8 +748,7 @@ chan::can_join(client *source_p, chan *chptr, const char *key, const char **forw
} }
} }
if(chptr->mode.limit && if(chptr->mode.limit && size(chptr->members) >= ulong(chptr->mode.limit))
rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
i = ERR_CHANNELISFULL; i = ERR_CHANNELISFULL;
if(chptr->mode.mode & mode::REGONLY && EmptyString(source_p->user->suser)) if(chptr->mode.mode & mode::REGONLY && EmptyString(source_p->user->suser))
i = ERR_NEEDREGGEDNICK; i = ERR_NEEDREGGEDNICK;
@ -783,7 +797,7 @@ chan::can_send(chan *chptr, client *source_p, membership *msptr)
if(msptr == NULL) if(msptr == NULL)
{ {
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if(msptr == NULL) if(msptr == NULL)
{ {
@ -828,7 +842,7 @@ chan::can_send(chan *chptr, client *source_p, membership *msptr)
moduledata.approved = CAN_SEND_OPV; moduledata.approved = CAN_SEND_OPV;
moduledata.client = source_p; moduledata.client = source_p;
moduledata.chptr = msptr->chan; moduledata.chptr = chptr;
moduledata.msptr = msptr; moduledata.msptr = msptr;
moduledata.target = NULL; moduledata.target = NULL;
moduledata.dir = moduledata.approved == CAN_SEND_NO? MODE_ADD : MODE_QUERY; moduledata.dir = moduledata.approved == CAN_SEND_NO? MODE_ADD : MODE_QUERY;
@ -913,10 +927,11 @@ chan::find_bannickchange_channel(client *client_p)
sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host); sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost); sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
RB_DLINK_FOREACH(ptr, client_p->user->channel.head) for(const auto &pit : client_p->user->channel)
{ {
msptr = (membership *)ptr->data; auto &chptr(pit.first);
chptr = msptr->chan; auto &msptr(pit.second);
if (is_chanop_voiced(msptr)) if (is_chanop_voiced(msptr))
continue; continue;
/* cached can_send */ /* cached can_send */
@ -1270,10 +1285,11 @@ chan::resv_chan_forcepart(const char *name, const char *reason, int temp_time)
chptr = find_channel(name); chptr = find_channel(name);
if(chptr != NULL) if(chptr != NULL)
{ {
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head) // Iterate a copy of the local list while all of this is going on
auto local(chptr->members.local);
for(auto &msptr : local)
{ {
msptr = (membership *)ptr->data; const auto target_p(msptr->git->first);
target_p = msptr->client;
if(IsExemptResv(target_p)) if(IsExemptResv(target_p))
continue; continue;
@ -1285,7 +1301,7 @@ chan::resv_chan_forcepart(const char *name, const char *reason, int temp_time)
target_p->name, target_p->username, target_p->name, target_p->username,
target_p->host, chptr->name.c_str(), target_p->name); target_p->host, chptr->name.c_str(), target_p->name);
remove_user_from_channel(msptr); del(*chptr, *target_p);
/* notify opers & user they were removed from the channel */ /* notify opers & user they were removed from the channel */
sendto_realops_snomask(SNO_GENERAL, L_ALL, sendto_realops_snomask(SNO_GENERAL, L_ALL,

View file

@ -409,8 +409,7 @@ pretty_mask(const char *idmask)
* side effects - numeric sent if not allowed * side effects - numeric sent if not allowed
*/ */
static bool static bool
check_forward(struct Client *source_p, chan::chan *chptr, check_forward(Client *source_p, chan::chan *chptr, const char *forward)
const char *forward)
{ {
chan::chan *targptr = NULL; chan::chan *targptr = NULL;
chan::membership *msptr; chan::membership *msptr;
@ -436,11 +435,13 @@ check_forward(struct Client *source_p, chan::chan *chptr,
} }
if(MyClient(source_p) && !(targptr->mode.mode & mode::FREETARGET)) if(MyClient(source_p) && !(targptr->mode.mode & mode::FREETARGET))
{ {
if((msptr = find_channel_membership(targptr, source_p)) == NULL || auto *const msptr(get(targptr->members, *source_p, std::nothrow));
chan::get_channel_access(source_p, targptr, msptr, MODE_QUERY, NULL) < chan::CHANOP) if(!msptr || get_channel_access(source_p, targptr, msptr, MODE_QUERY, NULL) < chan::CHANOP)
{ {
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
me.name, source_p->name, targptr->name.c_str()); me.name,
source_p->name,
targptr->name.c_str());
return false; return false;
} }
} }
@ -954,7 +955,7 @@ mode::functor::op(client *source_p, chan *chptr,
return; return;
} }
mstptr = find_channel_membership(chptr, targ_p); mstptr = get(chptr->members, *targ_p, std::nothrow);
if(mstptr == NULL) if(mstptr == NULL)
{ {
@ -1030,7 +1031,7 @@ mode::functor::voice(client *source_p, chan *chptr,
return; return;
} }
mstptr = find_channel_membership(chptr, targ_p); mstptr = get(chptr->members, *targ_p, std::nothrow);
if(mstptr == NULL) if(mstptr == NULL)
{ {

View file

@ -1265,10 +1265,10 @@ exit_generic_client(struct Client *client_p, struct Client *source_p, struct Cli
source_p->name, source_p->name,
source_p->username, source_p->host, comment); source_p->username, source_p->host, comment);
chan::remove_user_from_channels(source_p); chan::del(*source_p);
/* Should not be in any channels now */ /* Should not be in any channels now */
s_assert(source_p->user->channel.head == NULL); s_assert(source_p->user->channel.empty());
// Clean up invitefield // Clean up invitefield
for (auto &chan : source_p->user->invited) for (auto &chan : source_p->user->invited)
@ -1839,10 +1839,10 @@ free_user(struct User *user, struct Client *client_p)
/* /*
* sanity check * sanity check
*/ */
if(user->refcnt < 0 || !user->invited.empty() || user->channel.head) if(user->refcnt < 0 || !user->invited.empty() || !user->channel.empty())
{ {
sendto_realops_snomask(SNO_GENERAL, L_ALL, sendto_realops_snomask(SNO_GENERAL, L_ALL,
"* %p user (%s!%s@%s) %p %lu %p %lu %d *", "* %p user (%s!%s@%s) %p %lu %lu %d *",
client_p, client_p,
client_p ? client_p-> client_p ? client_p->
name : "<noname>", name : "<noname>",
@ -1850,12 +1850,11 @@ free_user(struct User *user, struct Client *client_p)
client_p->host, client_p->host,
user, user,
user->invited.size(), user->invited.size(),
user->channel.head, user->channel.size(),
rb_dlink_list_length(&user->channel),
user->refcnt); user->refcnt);
s_assert(!user->refcnt); s_assert(!user->refcnt);
s_assert(user->invited.empty()); s_assert(user->invited.empty());
s_assert(!user->channel.head); s_assert(user->channel.empty());
} }
rb_bh_free(user_heap, user); rb_bh_free(user_heap, user);

View file

@ -646,11 +646,12 @@ burst_TS6(struct Client *client_p)
t = buf + mlen; t = buf + mlen;
RB_DLINK_FOREACH(uptr, chptr->members.head) for (auto &pair : chptr->members.global)
{ {
msptr = (chan::membership *)uptr->data; msptr = &pair.second;
auto *const client(pair.first);
tlen = strlen(use_id(msptr->client)) + 1; tlen = strlen(use_id(client)) + 1;
if(is_chanop(msptr)) if(is_chanop(msptr))
tlen++; tlen++;
if(is_voiced(msptr)) if(is_voiced(msptr))
@ -664,13 +665,13 @@ burst_TS6(struct Client *client_p)
t = buf + mlen; t = buf + mlen;
} }
sprintf(t, "%s%s ", chan::find_status(msptr, 1), use_id(msptr->client)); sprintf(t, "%s%s ", chan::find_status(msptr, 1), use_id(client));
cur_len += tlen; cur_len += tlen;
t += tlen; t += tlen;
} }
if (rb_dlink_list_length(&chptr->members) > 0) if (!empty(chptr->members))
{ {
/* remove trailing space */ /* remove trailing space */
*(t-1) = '\0'; *(t-1) = '\0';

View file

@ -1473,11 +1473,10 @@ change_nick_user_host(struct Client *target_p, const char *nick, const char *use
{ {
rb_dlink_node *ptr; rb_dlink_node *ptr;
chan::chan *chptr; chan::chan *chptr;
chan::membership *mscptr;
int changed = irccmp(target_p->name, nick); int changed = irccmp(target_p->name, nick);
int changed_case = strcmp(target_p->name, nick); int changed_case = strcmp(target_p->name, nick);
int do_qjm = irccmp(target_p->username, user) || irccmp(target_p->host, host); int do_qjm = irccmp(target_p->username, user) || irccmp(target_p->host, host);
char mode[10], modeval[NICKLEN * 2 + 2], reason[256], *mptr; char mode[10], modeval[NICKLEN * 2 + 2], reason[256];
va_list ap; va_list ap;
modeval[0] = '\0'; modeval[0] = '\0';
@ -1499,20 +1498,20 @@ change_nick_user_host(struct Client *target_p, const char *nick, const char *use
target_p->name, target_p->username, target_p->host, target_p->name, target_p->username, target_p->host,
reason); reason);
RB_DLINK_FOREACH(ptr, target_p->user->channel.head) for(const auto &pit : target_p->user->channel)
{ {
mscptr = (chan::membership *)ptr->data; auto &chan(*pit.first);
chptr = mscptr->chan; auto &member(*pit.second);
mptr = mode; char *mptr(mode);
if(is_chanop(mscptr)) if(is_chanop(member))
{ {
*mptr++ = 'o'; *mptr++ = 'o';
strcat(modeval, nick); strcat(modeval, nick);
strcat(modeval, " "); strcat(modeval, " ");
} }
if(is_voiced(mscptr)) if(is_voiced(member))
{ {
*mptr++ = 'v'; *mptr++ = 'v';
strcat(modeval, nick); strcat(modeval, nick);
@ -1520,16 +1519,16 @@ change_nick_user_host(struct Client *target_p, const char *nick, const char *use
*mptr = '\0'; *mptr = '\0';
sendto_channel_local_with_capability_butone(target_p, chan::ALL_MEMBERS, NOCAPS, CLICAP_EXTENDED_JOIN | CLICAP_CHGHOST, chptr, sendto_channel_local_with_capability_butone(target_p, chan::ALL_MEMBERS, NOCAPS, CLICAP_EXTENDED_JOIN | CLICAP_CHGHOST, &chan,
":%s!%s@%s JOIN %s", nick, user, host, chptr->name.c_str()); ":%s!%s@%s JOIN %s", nick, user, host, chan.name.c_str());
sendto_channel_local_with_capability_butone(target_p, chan::ALL_MEMBERS, CLICAP_EXTENDED_JOIN, CLICAP_CHGHOST, chptr, sendto_channel_local_with_capability_butone(target_p, chan::ALL_MEMBERS, CLICAP_EXTENDED_JOIN, CLICAP_CHGHOST, &chan,
":%s!%s@%s JOIN %s %s :%s", nick, user, host, chptr->name.c_str(), ":%s!%s@%s JOIN %s %s :%s", nick, user, host, chan.name.c_str(),
EmptyString(target_p->user->suser) ? "*" : target_p->user->suser, EmptyString(target_p->user->suser) ? "*" : target_p->user->suser,
target_p->info); target_p->info);
if(*mode) if(*mode)
sendto_channel_local_with_capability_butone(target_p, chan::ALL_MEMBERS, NOCAPS, CLICAP_CHGHOST, chptr, sendto_channel_local_with_capability_butone(target_p, chan::ALL_MEMBERS, NOCAPS, CLICAP_CHGHOST, &chan,
":%s MODE %s +%s %s", target_p->servptr->name, chptr->name.c_str(), mode, modeval); ":%s MODE %s +%s %s", target_p->servptr->name, chan.name.c_str(), mode, modeval);
*modeval = '\0'; *modeval = '\0';
} }

View file

@ -485,8 +485,6 @@ sendto_channel_flags(struct Client *one, int type, struct Client *source_p,
va_list args; va_list args;
buf_head_t rb_linebuf_local; buf_head_t rb_linebuf_local;
buf_head_t rb_linebuf_id; buf_head_t rb_linebuf_id;
struct Client *target_p;
chan::membership *msptr;
rb_dlink_node *ptr; rb_dlink_node *ptr;
rb_dlink_node *next_ptr; rb_dlink_node *next_ptr;
int current_capmask = 0; int current_capmask = 0;
@ -506,10 +504,10 @@ sendto_channel_flags(struct Client *one, int type, struct Client *source_p,
linebuf_put_msgbuf(&msgbuf, &rb_linebuf_local, NOCAPS, "%s", buf); linebuf_put_msgbuf(&msgbuf, &rb_linebuf_local, NOCAPS, "%s", buf);
rb_linebuf_putmsg(&rb_linebuf_id, NULL, NULL, ":%s %s", use_id(source_p), buf); rb_linebuf_putmsg(&rb_linebuf_id, NULL, NULL, ":%s %s", use_id(source_p), buf);
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->members.head) for(const auto &pair : chptr->members.global)
{ {
msptr = (chan::membership *)ptr->data; auto *const target_p(pair.first);
target_p = msptr->client; const auto &member(pair.second);
if(!MyClient(source_p) && (IsIOError(target_p->from) || target_p->from == one)) if(!MyClient(source_p) && (IsIOError(target_p->from) || target_p->from == one))
continue; continue;
@ -517,7 +515,7 @@ sendto_channel_flags(struct Client *one, int type, struct Client *source_p,
if(MyClient(source_p) && !IsCapable(source_p, CLICAP_ECHO_MESSAGE) && target_p == one) if(MyClient(source_p) && !IsCapable(source_p, CLICAP_ECHO_MESSAGE) && target_p == one)
continue; continue;
if(type && ((msptr->flags & type) == 0)) if(type && ((member.flags & type) == 0))
continue; continue;
if(IsDeaf(target_p)) if(IsDeaf(target_p))
@ -572,8 +570,6 @@ sendto_channel_opmod(struct Client *one, struct Client *source_p,
buf_head_t rb_linebuf_local; buf_head_t rb_linebuf_local;
buf_head_t rb_linebuf_old; buf_head_t rb_linebuf_old;
buf_head_t rb_linebuf_new; buf_head_t rb_linebuf_new;
struct Client *target_p;
chan::membership *msptr;
rb_dlink_node *ptr; rb_dlink_node *ptr;
rb_dlink_node *next_ptr; rb_dlink_node *next_ptr;
@ -606,10 +602,10 @@ sendto_channel_opmod(struct Client *one, struct Client *source_p,
":%s %s =%s :%s", ":%s %s =%s :%s",
use_id(source_p), command, chptr->name.c_str(), text); use_id(source_p), command, chptr->name.c_str(), text);
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->members.head) for(const auto &pair : chptr->members.global)
{ {
msptr = (chan::membership *)ptr->data; auto *const target_p(pair.first);
target_p = msptr->client; const auto &member(pair.second);
if(!MyClient(source_p) && (IsIOError(target_p->from) || target_p->from == one)) if(!MyClient(source_p) && (IsIOError(target_p->from) || target_p->from == one))
continue; continue;
@ -617,7 +613,7 @@ sendto_channel_opmod(struct Client *one, struct Client *source_p,
if(MyClient(source_p) && !IsCapable(source_p, CLICAP_ECHO_MESSAGE) && target_p == one) if(MyClient(source_p) && !IsCapable(source_p, CLICAP_ECHO_MESSAGE) && target_p == one)
continue; continue;
if((msptr->flags & chan::CHANOP) == 0) if((member.flags & chan::CHANOP) == 0)
continue; continue;
if(IsDeaf(target_p)) if(IsDeaf(target_p))
@ -660,10 +656,6 @@ sendto_channel_local(int type, chan::chan *chptr, const char *pattern, ...)
{ {
va_list args; va_list args;
buf_head_t linebuf; buf_head_t linebuf;
chan::membership *msptr;
struct Client *target_p;
rb_dlink_node *ptr;
rb_dlink_node *next_ptr;
rb_linebuf_newbuf(&linebuf); rb_linebuf_newbuf(&linebuf);
@ -671,10 +663,10 @@ sendto_channel_local(int type, chan::chan *chptr, const char *pattern, ...)
rb_linebuf_putmsg(&linebuf, pattern, &args, NULL); rb_linebuf_putmsg(&linebuf, pattern, &args, NULL);
va_end(args); va_end(args);
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head) for (const auto &pair : chptr->members.global)
{ {
msptr = (chan::membership *)ptr->data; auto *const target_p(pair.first);
target_p = msptr->client; const auto &member(pair.second);
if(IsIOError(target_p)) if(IsIOError(target_p))
continue; continue;
@ -684,7 +676,7 @@ sendto_channel_local(int type, chan::chan *chptr, const char *pattern, ...)
if (!IsOper(target_p)) if (!IsOper(target_p))
continue; continue;
} }
else if(type && ((msptr->flags & type) == 0)) else if(type && ((member.flags & type) == 0))
continue; continue;
_send_linebuf(target_p, &linebuf); _send_linebuf(target_p, &linebuf);
@ -703,18 +695,13 @@ _sendto_channel_local_with_capability_butone(struct Client *one, int type, int c
const char *pattern, va_list * args) const char *pattern, va_list * args)
{ {
buf_head_t linebuf; buf_head_t linebuf;
chan::membership *msptr;
struct Client *target_p;
rb_dlink_node *ptr;
rb_dlink_node *next_ptr;
rb_linebuf_newbuf(&linebuf); rb_linebuf_newbuf(&linebuf);
rb_linebuf_putmsg(&linebuf, pattern, args, NULL); rb_linebuf_putmsg(&linebuf, pattern, args, NULL);
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head) for(const auto &member : chptr->members.local)
{ {
msptr = (chan::membership *)ptr->data; const auto target_p(member->git->first);
target_p = msptr->client;
if (target_p == one) if (target_p == one)
continue; continue;
@ -724,7 +711,7 @@ _sendto_channel_local_with_capability_butone(struct Client *one, int type, int c
!NotCapable(target_p, negcaps)) !NotCapable(target_p, negcaps))
continue; continue;
if(type && ((msptr->flags & type) == 0)) if(type && ((member->flags & type) == 0))
continue; continue;
_send_linebuf(target_p, &linebuf); _send_linebuf(target_p, &linebuf);
@ -780,8 +767,6 @@ sendto_channel_local_butone(struct Client *one, int type, chan::chan *chptr, con
{ {
va_list args; va_list args;
buf_head_t linebuf; buf_head_t linebuf;
chan::membership *msptr;
struct Client *target_p;
struct MsgBuf msgbuf; struct MsgBuf msgbuf;
rb_dlink_node *ptr; rb_dlink_node *ptr;
rb_dlink_node *next_ptr; rb_dlink_node *next_ptr;
@ -794,10 +779,9 @@ sendto_channel_local_butone(struct Client *one, int type, chan::chan *chptr, con
rb_linebuf_putmsg(&linebuf, pattern, &args, NULL); rb_linebuf_putmsg(&linebuf, pattern, &args, NULL);
va_end(args); va_end(args);
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head) for(const auto &member : chptr->members.local)
{ {
msptr = (chan::membership *)ptr->data; const auto target_p(member->git->first);
target_p = msptr->client;
if(target_p == one) if(target_p == one)
continue; continue;
@ -805,7 +789,7 @@ sendto_channel_local_butone(struct Client *one, int type, chan::chan *chptr, con
if(IsIOError(target_p)) if(IsIOError(target_p))
continue; continue;
if(type && ((msptr->flags & type) == 0)) if(type && ((member->flags & type) == 0))
continue; continue;
/* attach the present linebuf to the target */ /* attach the present linebuf to the target */
@ -848,15 +832,14 @@ sendto_common_channels_local(struct Client *user, int cap, int negcap, const cha
++current_serial; ++current_serial;
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, user->user->channel.head) for(const auto &pit : user->user->channel)
{ {
mscptr = (chan::membership *)ptr->data; auto &chptr(pit.first);
chptr = mscptr->chan; auto &mscptr(pit.second);
RB_DLINK_FOREACH_SAFE(uptr, next_uptr, chptr->locmembers.head) for(const auto &msptr : chptr->members.local)
{ {
msptr = (chan::membership *)uptr->data; const auto target_p(msptr->git->first);
target_p = msptr->client;
if(IsIOError(target_p) || if(IsIOError(target_p) ||
target_p->serial == current_serial || target_p->serial == current_serial ||
@ -915,15 +898,14 @@ sendto_common_channels_local_butone(struct Client *user, int cap, int negcap, co
/* Skip them -- jilles */ /* Skip them -- jilles */
user->serial = current_serial; user->serial = current_serial;
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, user->user->channel.head) for(const auto &pit : user->user->channel)
{ {
mscptr = (membership *)ptr->data; auto &chptr(pit.first);
chptr = mscptr->chan; auto &mscptr(pit.second);
RB_DLINK_FOREACH_SAFE(uptr, next_uptr, chptr->locmembers.head) for(const auto &msptr : chptr->members.local)
{ {
msptr = (membership *)uptr->data; const auto target_p(msptr->git->first);
target_p = msptr->client;
if(IsIOError(target_p) || if(IsIOError(target_p) ||
target_p->serial == current_serial || target_p->serial == current_serial ||

View file

@ -27,18 +27,18 @@ namespace ircd {
static int add_hashed_target(struct Client *source_p, uint32_t hashv); static int add_hashed_target(struct Client *source_p, uint32_t hashv);
chan::chan * chan::chan *
find_allowing_channel(struct Client *source_p, struct Client *target_p) find_allowing_channel(struct Client *source, struct Client *target)
{ {
rb_dlink_node *ptr; for(const auto &pit : source->user->channel)
chan::membership *msptr;
RB_DLINK_FOREACH(ptr, source_p->user->channel.head)
{ {
msptr = (chan::membership *)ptr->data; auto &chan(*pit.first);
if (is_chanop_voiced(msptr) && is_member(msptr->chan, target_p)) auto &member(*pit.second);
return msptr->chan;
if (is_chanop_voiced(member) && is_member(chan, *target))
return &chan;
} }
return NULL;
return nullptr;
} }
int int

View file

@ -48,7 +48,7 @@ chm_noctcp_process(hook_data_privmsg_channel *data)
data->approved = ERR_CANNOTSENDTOCHAN; data->approved = ERR_CANNOTSENDTOCHAN;
return; return;
} }
else if (rb_dlink_list_length(&data->chptr->locmembers) > (unsigned)(GlobalSetOptions.floodcount / 2)) else if (local_size(data->chptr->members) > (unsigned)(GlobalSetOptions.floodcount / 2))
data->source_p->large_ctcp_sent = rb_current_time(); data->source_p->large_ctcp_sent = rb_current_time();
} }

View file

@ -221,7 +221,7 @@ m_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
/* JOIN 0 simply parts all channels the user is in */ /* JOIN 0 simply parts all channels the user is in */
if(*name == '0' && !atoi(name)) if(*name == '0' && !atoi(name))
{ {
if(source_p->user->channel.head == NULL) if(source_p->user->channel.empty())
continue; continue;
do_join_0(&me, source_p); do_join_0(&me, source_p);
@ -265,10 +265,10 @@ m_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
flags = chan::CHANOP; flags = chan::CHANOP;
} }
if((rb_dlink_list_length(&source_p->user->channel) >= if(((source_p->user->channel.size()) >=
(unsigned long) ConfigChannel.max_chans_per_user) && (unsigned long) ConfigChannel.max_chans_per_user) &&
(!IsExtendChans(source_p) || (!IsExtendChans(source_p) ||
(rb_dlink_list_length(&source_p->user->channel) >= (source_p->user->channel.size() >=
(unsigned long) ConfigChannel.max_chans_per_user_large))) (unsigned long) ConfigChannel.max_chans_per_user_large)))
{ {
sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS), sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
@ -309,7 +309,7 @@ m_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
chan::check_spambot_warning(source_p, name); chan::check_spambot_warning(source_p, name);
/* add the user to the channel */ /* add the user to the channel */
add_user_to_channel(chptr, source_p, flags); add(*chptr, *source_p, flags);
if (chptr->mode.join_num && if (chptr->mode.join_num &&
rb_current_time() - chptr->join_delta >= chptr->mode.join_time) rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
{ {
@ -482,7 +482,7 @@ ms_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
if(!is_member(chptr, source_p)) if(!is_member(chptr, source_p))
{ {
add_user_to_channel(chptr, source_p, chan::PEON); add(*chptr, *source_p, chan::PEON);
if (chptr->mode.join_num && if (chptr->mode.join_num &&
rb_current_time() - chptr->join_delta >= chptr->mode.join_time) rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
{ {
@ -637,12 +637,11 @@ ms_sjoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
{ {
chan::membership *msptr; chan::membership *msptr;
struct Client *who; struct Client *who;
int l = rb_dlink_list_length(&chptr->members); int l = size(chptr->members);
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head) for(const auto &msptr : chptr->members.local)
{ {
msptr = (chan::membership *)ptr->data; who = &get_client(*msptr);
who = msptr->client;
sendto_one(who, ":%s KICK %s %s :Net Rider", sendto_one(who, ":%s KICK %s %s :Net Rider",
me.name, chptr->name.c_str(), who->name); me.name, chptr->name.c_str(), who->name);
@ -650,7 +649,7 @@ ms_sjoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
":%s KICK %s %s :Net Rider", ":%s KICK %s %s :Net Rider",
me.id, chptr->name.c_str(), me.id, chptr->name.c_str(),
who->id); who->id);
remove_user_from_channel(msptr); del(*chptr, *who);
if (--l == 0) if (--l == 0)
break; break;
} }
@ -822,7 +821,7 @@ ms_sjoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
if(!is_member(chptr, target_p)) if(!is_member(chptr, target_p))
{ {
add_user_to_channel(chptr, target_p, fl); add(*chptr, *target_p, fl);
send_join(*chptr, *target_p); send_join(*chptr, *target_p);
joins++; joins++;
} }
@ -953,18 +952,19 @@ do_join_0(struct Client *client_p, struct Client *source_p)
sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s JOIN 0", use_id(source_p)); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s JOIN 0", use_id(source_p));
while((ptr = source_p->user->channel.head)) for(const auto &pit : source_p->user->channel)
{ {
if(MyConnect(source_p) && if(MyConnect(source_p) &&
!IsOper(source_p) && !IsExemptSpambot(source_p)) !IsOper(source_p) && !IsExemptSpambot(source_p))
chan::check_spambot_warning(source_p, NULL); chan::check_spambot_warning(source_p, NULL);
msptr = (chan::membership *)ptr->data; auto &msptr(pit.second);
chptr = msptr->chan; auto &chptr(pit.first);
sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s!%s@%s PART %s", sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s!%s@%s PART %s",
source_p->name, source_p->name,
source_p->username, source_p->host, chptr->name.c_str()); source_p->username, source_p->host, chptr->name.c_str());
remove_user_from_channel(msptr);
del(*chptr, get_client(*msptr));
} }
} }
@ -1162,7 +1162,6 @@ set_final_mode(chan::modes *mode, chan::modes *oldmode)
static void static void
remove_our_modes(chan::chan *chptr, struct Client *source_p) remove_our_modes(chan::chan *chptr, struct Client *source_p)
{ {
chan::membership *msptr;
rb_dlink_node *ptr; rb_dlink_node *ptr;
char lmodebuf[chan::mode::BUFLEN]; char lmodebuf[chan::mode::BUFLEN];
char *lpara[chan::mode::MAXPARAMS]; char *lpara[chan::mode::MAXPARAMS];
@ -1175,14 +1174,15 @@ remove_our_modes(chan::chan *chptr, struct Client *source_p)
for(i = 0; i < chan::mode::MAXPARAMS; i++) for(i = 0; i < chan::mode::MAXPARAMS; i++)
lpara[i] = NULL; lpara[i] = NULL;
RB_DLINK_FOREACH(ptr, chptr->members.head) for(auto &pit : chptr->members.global)
{ {
msptr = (chan::membership *)ptr->data; auto &client(pit.first);
auto &msptr(pit.second);
if(is_chanop(msptr)) if(is_chanop(msptr))
{ {
msptr->flags &= ~chan::CHANOP; msptr.flags &= ~chan::CHANOP;
lpara[count++] = msptr->client->name; lpara[count++] = client->name;
*mbuf++ = 'o'; *mbuf++ = 'o';
/* +ov, might not fit so check. */ /* +ov, might not fit so check. */
@ -1206,15 +1206,15 @@ remove_our_modes(chan::chan *chptr, struct Client *source_p)
lpara[i] = NULL; lpara[i] = NULL;
} }
msptr->flags &= ~chan::VOICE; msptr.flags &= ~chan::VOICE;
lpara[count++] = msptr->client->name; lpara[count++] = client->name;
*mbuf++ = 'v'; *mbuf++ = 'v';
} }
} }
else if(is_voiced(msptr)) else if(is_voiced(msptr))
{ {
msptr->flags &= ~chan::VOICE; msptr.flags &= ~chan::VOICE;
lpara[count++] = msptr->client->name; lpara[count++] = client->name;
*mbuf++ = 'v'; *mbuf++ = 'v';
} }
else else

View file

@ -75,7 +75,7 @@ m_kick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
if(!IsServer(source_p)) if(!IsServer(source_p))
{ {
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if((msptr == NULL) && MyConnect(source_p)) if((msptr == NULL) && MyConnect(source_p))
{ {
@ -114,7 +114,7 @@ m_kick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
return; return;
} }
msptr = find_channel_membership(chptr, who); msptr = get(chptr->members, *who, std::nothrow);
if(msptr != NULL) if(msptr != NULL)
{ {
@ -168,7 +168,8 @@ m_kick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
sendto_server(client_p, chptr, CAP_TS6, NOCAPS, sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
":%s KICK %s %s :%s", ":%s KICK %s %s :%s",
use_id(source_p), chptr->name.c_str(), use_id(who), comment); use_id(source_p), chptr->name.c_str(), use_id(who), comment);
remove_user_from_channel(msptr);
del(*chptr, *who);
} }
else if (MyClient(source_p)) else if (MyClient(source_p))
sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,

View file

@ -336,7 +336,7 @@ build_target_list(enum message_type msgtype, struct Client *client_p,
{ {
chan::membership *msptr; chan::membership *msptr;
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if(!IsServer(source_p) && !IsService(source_p) && !is_chanop_voiced(msptr)) if(!IsServer(source_p) && !IsService(source_p) && !is_chanop_voiced(msptr))
{ {

View file

@ -120,7 +120,7 @@ m_mode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
} }
else else
{ {
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
/* Finish the flood grace period... */ /* Finish the flood grace period... */
if(MyClient(source_p) && !IsFloodDone(source_p)) if(MyClient(source_p) && !IsFloodDone(source_p))
@ -182,7 +182,7 @@ ms_tmode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
} }
else else
{ {
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
set_channel_mode(client_p, source_p, chptr, msptr, parc - 3, parv + 3); set_channel_mode(client_p, source_p, chptr, msptr, parc - 3, parv + 3);
} }

View file

@ -95,7 +95,7 @@ part_one_client(struct Client *client_p, struct Client *source_p, char *name, co
return; return;
} }
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if(msptr == NULL) if(msptr == NULL)
{ {
sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name);
@ -145,7 +145,7 @@ part_one_client(struct Client *client_p, struct Client *source_p, char *name, co
chptr->name.c_str()); chptr->name.c_str());
} }
remove_user_from_channel(msptr); del(*chptr, *source_p);
} }
/* /*

View file

@ -212,7 +212,6 @@ m_chantrace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
{ {
struct Client *target_p; struct Client *target_p;
chan::chan *chptr; chan::chan *chptr;
chan::membership *msptr;
const char *sockhost; const char *sockhost;
const char *name; const char *name;
rb_dlink_node *ptr; rb_dlink_node *ptr;
@ -251,10 +250,10 @@ m_chantrace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
return; return;
} }
RB_DLINK_FOREACH(ptr, chptr->members.head) for(const auto &pit : chptr->members.global)
{ {
msptr = (chan::membership *)ptr->data; auto &target_p(pit.first);
target_p = msptr->client; auto &member(pit.second);
if(EmptyString(target_p->sockhost)) if(EmptyString(target_p->sockhost))
sockhost = empty_sockhost; sockhost = empty_sockhost;

View file

@ -112,7 +112,7 @@ m_invite(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
return; return;
} }
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if(MyClient(source_p) && (msptr == NULL)) if(MyClient(source_p) && (msptr == NULL))
{ {
sendto_one_numeric(source_p, ERR_NOTONCHANNEL, sendto_one_numeric(source_p, ERR_NOTONCHANNEL,

View file

@ -98,7 +98,7 @@ m_knock(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
if(!((chptr->mode.mode & chan::mode::INVITEONLY) || (*chptr->mode.key) || if(!((chptr->mode.mode & chan::mode::INVITEONLY) || (*chptr->mode.key) ||
(chptr->mode.limit && (chptr->mode.limit &&
rb_dlink_list_length(&chptr->members) >= (unsigned long)chptr->mode.limit))) size(chptr->members) >= (unsigned long)chptr->mode.limit)))
{ {
sendto_one_numeric(source_p, ERR_CHANOPEN, sendto_one_numeric(source_p, ERR_CHANOPEN,
form_str(ERR_CHANOPEN), name); form_str(ERR_CHANOPEN), name);

View file

@ -291,7 +291,7 @@ static void list_one_channel(struct Client *source_p, chan::chan *chptr,
strip_colour(topic); strip_colour(topic);
sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name, sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name,
visible ? "" : "!", visible ? "" : "!",
chptr->name.c_str(), rb_dlink_list_length(&chptr->members), chptr->name.c_str(), size(chptr->members),
topic); topic);
} }
@ -422,8 +422,7 @@ static void safelist_one_channel(struct Client *source_p, chan::chan *chptr, str
if (!visible && !params->operspy) if (!visible && !params->operspy)
return; return;
if ((unsigned int)chptr->members.length < params->users_min if (size(chptr->members) < params->users_min || size(chptr->members) > params->users_max)
|| (unsigned int)chptr->members.length > params->users_max)
return; return;
if (params->topic_min && chptr->topic.time < params->topic_min) if (params->topic_min && chptr->topic.time < params->topic_min)

View file

@ -113,7 +113,6 @@ names_global(struct Client *source_p)
rb_dlink_node *lp, *ptr; rb_dlink_node *lp, *ptr;
struct Client *target_p; struct Client *target_p;
chan::chan *chptr = NULL; chan::chan *chptr = NULL;
chan::membership *msptr;
char buf[BUFSIZE]; char buf[BUFSIZE];
char *t; char *t;
@ -143,10 +142,9 @@ names_global(struct Client *source_p)
* both were missed out above. if the target is on a * both were missed out above. if the target is on a
* common channel with source, its already been shown. * common channel with source, its already been shown.
*/ */
RB_DLINK_FOREACH(lp, target_p->user->channel.head) for(const auto &pit : target_p->user->channel)
{ {
msptr = (chan::membership *)lp->data; auto &chptr(pit.first);
chptr = msptr->chan;
if(is_public(chptr) || is_member(chptr, source_p) || is_secret(chptr)) if(is_public(chptr) || is_member(chptr, source_p) || is_secret(chptr))
{ {

View file

@ -1336,7 +1336,7 @@ stats_memory (struct Client *source_p)
{ {
users_counted++; users_counted++;
users_invited_count += target_p->user->invited.size(); users_invited_count += target_p->user->invited.size();
user_channels += rb_dlink_list_length(&target_p->user->channel); user_channels += target_p->user->channel.size();
if(target_p->user->away) if(target_p->user->away)
{ {
aways_counted++; aways_counted++;
@ -1352,7 +1352,7 @@ stats_memory (struct Client *source_p)
channel_count++; channel_count++;
channel_memory += (strlen(chptr->name.c_str()) + sizeof(chan::chan)); channel_memory += (strlen(chptr->name.c_str()) + sizeof(chan::chan));
channel_users += rb_dlink_list_length(&chptr->members); channel_users += size(chptr->members);
channel_invites += chptr->invites.size(); channel_invites += chptr->invites.size();
channel_bans += size(*chptr, chan::mode::BAN); channel_bans += size(*chptr, chan::mode::BAN);

View file

@ -85,7 +85,7 @@ m_topic(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
/* setting topic */ /* setting topic */
if(parc > 2) if(parc > 2)
{ {
msptr = find_channel_membership(chptr, source_p); msptr = get(chptr->members, *source_p, std::nothrow);
if(msptr == NULL) if(msptr == NULL)
{ {

View file

@ -54,7 +54,7 @@ static void do_who_on_channel(struct Client *source_p, chan::chan *chptr,
struct who_format *fmt); struct who_format *fmt);
static void who_global(struct Client *source_p, const char *mask, int server_oper, int operspy, struct who_format *fmt); static void who_global(struct Client *source_p, const char *mask, int server_oper, int operspy, struct who_format *fmt);
static void do_who(struct Client *source_p, static void do_who(struct Client *source_p,
struct Client *target_p, chan::membership *msptr, struct Client *target_p, chan::chan *, chan::membership *msptr,
struct who_format *fmt); struct who_format *fmt);
struct Message who_msgtab = { struct Message who_msgtab = {
@ -144,10 +144,10 @@ m_who(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
if(source_p->user == NULL) if(source_p->user == NULL)
return; return;
if((lp = source_p->user->channel.head) != NULL) if (!source_p->user->channel.empty())
{ {
msptr = (chan::membership *)lp->data; auto *const chan(begin(source_p->user->channel)->first);
do_who_on_channel(source_p, msptr->chan, server_oper, true, &fmt); do_who_on_channel(source_p, chan, server_oper, true, &fmt);
} }
sendto_one(source_p, form_str(RPL_ENDOFWHO), sendto_one(source_p, form_str(RPL_ENDOFWHO),
@ -176,7 +176,7 @@ m_who(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
if(chptr != NULL) if(chptr != NULL)
{ {
if (!IsOper(source_p) && !ratelimit_client_who(source_p, rb_dlink_list_length(&chptr->members)/50)) if (!IsOper(source_p) && !ratelimit_client_who(source_p, size(chptr->members)/50))
{ {
sendto_one(source_p, form_str(RPL_LOAD2HI), sendto_one(source_p, form_str(RPL_LOAD2HI),
me.name, source_p->name, "WHO"); me.name, source_p->name, "WHO");
@ -207,27 +207,27 @@ m_who(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
int isinvis = 0; int isinvis = 0;
isinvis = IsInvisible(target_p); isinvis = IsInvisible(target_p);
RB_DLINK_FOREACH(lp, target_p->user->channel.head) for(const auto &pit : target_p->user->channel)
{ {
msptr = (chan::membership *)lp->data; chptr = pit.first;
chptr = msptr->chan; msptr = get(chptr->members, *source_p, std::nothrow);
member = is_member(chptr, source_p);
if(isinvis && !member) if(isinvis && !member)
{
msptr = nullptr;
continue; continue;
}
if(member || (!isinvis && is_public(chptr))) if(member || (!isinvis && is_public(chptr)))
break; break;
msptr = nullptr;
} }
/* if we stopped midlist, lp->data is the membership for /* if we stopped midlist, msptr is the membership for
* target_p of chptr * target_p of chptr
*/ */
if(lp != NULL) do_who(source_p, target_p, chptr, msptr, &fmt);
do_who(source_p, target_p, (chan::membership *)lp->data, &fmt);
else
do_who(source_p, target_p, NULL, &fmt);
sendto_one(source_p, form_str(RPL_ENDOFWHO), sendto_one(source_p, form_str(RPL_ENDOFWHO),
me.name, source_p->name, mask); me.name, source_p->name, mask);
@ -286,32 +286,28 @@ who_common_channel(struct Client *source_p, chan::chan *chptr,
const char *mask, int server_oper, int *maxmatches, const char *mask, int server_oper, int *maxmatches,
struct who_format *fmt) struct who_format *fmt)
{ {
chan::membership *msptr; for(const auto &pit : chptr->members.global)
struct Client *target_p;
rb_dlink_node *ptr;
RB_DLINK_FOREACH(ptr, chptr->members.head)
{ {
msptr = (chan::membership *)ptr->data; const auto &target(pit.first);
target_p = msptr->client; const auto &member(pit.second);
if(!IsInvisible(target_p) || IsMarked(target_p)) if(!IsInvisible(target) || IsMarked(target))
continue; continue;
if(server_oper && !IsOper(target_p)) if(server_oper && !IsOper(target))
continue; continue;
SetMark(target_p); SetMark(target);
if(*maxmatches > 0) if(*maxmatches > 0)
{ {
if((mask == NULL) || if((mask == NULL) ||
match(mask, target_p->name) || match(mask, target_p->username) || match(mask, target->name) || match(mask, target->username) ||
match(mask, target_p->host) || match(mask, target_p->servptr->name) || match(mask, target->host) || match(mask, target->servptr->name) ||
(IsOper(source_p) && match(mask, target_p->orighost)) || (IsOper(source_p) && match(mask, target->orighost)) ||
match(mask, target_p->info)) match(mask, target->info))
{ {
do_who(source_p, target_p, NULL, fmt); do_who(source_p, target, chptr, nullptr, fmt);
--(*maxmatches); --(*maxmatches);
} }
} }
@ -345,10 +341,10 @@ who_global(struct Client *source_p, const char *mask, int server_oper, int opers
*/ */
if(!operspy) if(!operspy)
{ {
RB_DLINK_FOREACH(lp, source_p->user->channel.head) for(const auto &pit : source_p->user->channel)
{ {
msptr = (chan::membership *)lp->data; auto &chan(pit.first);
who_common_channel(source_p, msptr->chan, mask, server_oper, &maxmatches, fmt); who_common_channel(source_p, chan, mask, server_oper, &maxmatches, fmt);
} }
} }
else if (!ConfigFileEntry.operspy_dont_care_user_info) else if (!ConfigFileEntry.operspy_dont_care_user_info)
@ -382,7 +378,7 @@ who_global(struct Client *source_p, const char *mask, int server_oper, int opers
(IsOper(source_p) && match(mask, target_p->orighost)) || (IsOper(source_p) && match(mask, target_p->orighost)) ||
match(mask, target_p->info)) match(mask, target_p->info))
{ {
do_who(source_p, target_p, NULL, fmt); do_who(source_p, target_p, nullptr, nullptr, fmt);
--maxmatches; --maxmatches;
} }
} }
@ -408,22 +404,18 @@ who_global(struct Client *source_p, const char *mask, int server_oper, int opers
*/ */
static void static void
do_who_on_channel(struct Client *source_p, chan::chan *chptr, do_who_on_channel(struct Client *source_p, chan::chan *chptr,
int server_oper, int member, struct who_format *fmt) int server_oper, int source_member, struct who_format *fmt)
{ {
struct Client *target_p; for(auto &pit : chptr->members.global)
chan::membership *msptr;
rb_dlink_node *ptr;
RB_DLINK_FOREACH(ptr, chptr->members.head)
{ {
msptr = (chan::membership *)ptr->data; const auto &target(pit.first);
target_p = msptr->client; auto &member(pit.second);
if(server_oper && !IsOper(target_p)) if(server_oper && !IsOper(target))
continue; continue;
if(member || !IsInvisible(target_p)) if(source_member || !IsInvisible(target))
do_who(source_p, target_p, msptr, fmt); do_who(source_p, target, chptr, &member, fmt);
} }
} }
@ -464,7 +456,7 @@ append_format(char *buf, size_t bufsize, size_t *pos, const char *fmt, ...)
*/ */
static void static void
do_who(struct Client *source_p, struct Client *target_p, chan::membership *msptr, struct who_format *fmt) do_who(struct Client *source_p, struct Client *target_p, chan::chan *chan, chan::membership *msptr, struct who_format *fmt)
{ {
char status[16]; char status[16];
char str[510 + 1]; /* linebuf.c will add \r\n */ char str[510 + 1]; /* linebuf.c will add \r\n */
@ -476,7 +468,7 @@ do_who(struct Client *source_p, struct Client *target_p, chan::membership *msptr
if (fmt->fields == 0) if (fmt->fields == 0)
sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, sendto_one(source_p, form_str(RPL_WHOREPLY), me.name,
source_p->name, msptr ? msptr->chan->name.c_str() : "*", source_p->name, msptr ? chan->name.c_str() : "*",
target_p->username, target_p->host, target_p->username, target_p->host,
target_p->servptr->name, target_p->name, status, target_p->servptr->name, target_p->name, status,
ConfigServerHide.flatten_links && !IsOper(source_p) && !IsExemptShide(source_p) ? 0 : target_p->hopcount, ConfigServerHide.flatten_links && !IsOper(source_p) && !IsExemptShide(source_p) ? 0 : target_p->hopcount,
@ -490,7 +482,7 @@ do_who(struct Client *source_p, struct Client *target_p, chan::membership *msptr
if (fmt->fields & FIELD_QUERYTYPE) if (fmt->fields & FIELD_QUERYTYPE)
append_format(str, sizeof str, &pos, " %s", fmt->querytype); append_format(str, sizeof str, &pos, " %s", fmt->querytype);
if (fmt->fields & FIELD_CHANNEL) if (fmt->fields & FIELD_CHANNEL)
append_format(str, sizeof str, &pos, " %s", msptr? msptr->chan->name.c_str() : "*"); append_format(str, sizeof str, &pos, " %s", msptr? name(*chan).c_str() : "*");
if (fmt->fields & FIELD_USER) if (fmt->fields & FIELD_USER)
append_format(str, sizeof str, &pos, " %s", target_p->username); append_format(str, sizeof str, &pos, " %s", target_p->username);
if (fmt->fields & FIELD_IP) if (fmt->fields & FIELD_IP)

View file

@ -252,10 +252,10 @@ single_whois(struct Client *source_p, struct Client *target_p, int operspy)
if (!IsService(target_p)) if (!IsService(target_p))
{ {
RB_DLINK_FOREACH(ptr, target_p->user->channel.head) for(const auto &pit : target_p->user->channel)
{ {
msptr = (chan::membership *)ptr->data; auto &chptr(pit.first);
chptr = msptr->chan; auto &msptr(pit.second);
hdata.chptr = chptr; hdata.chptr = chptr;