mirror of
https://github.com/anope/anope.git
synced 2026-06-29 18:16:38 +02:00
Allow channels on access lists
This commit is contained in:
@@ -153,6 +153,16 @@ module
|
||||
* and chanserv/ban.
|
||||
*/
|
||||
reasonmax = 200
|
||||
|
||||
/*
|
||||
* If set, prevents channel access entries from containing hostmasks.
|
||||
*/
|
||||
disallow_hostmask_access = false
|
||||
|
||||
/*
|
||||
* If set, prevents channels from being on access lists.
|
||||
*/
|
||||
disallow_channel_access = false
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+12
-2
@@ -75,6 +75,13 @@ class CoreExport AccessProvider : public Service
|
||||
class CoreExport ChanAccess : public Serializable
|
||||
{
|
||||
public:
|
||||
typedef std::multimap<const ChanAccess *, const ChanAccess *> Set;
|
||||
/* shows the 'path' taken to determine if an access entry matches a user
|
||||
* .first are access entries checked
|
||||
* .second are access entries which match
|
||||
*/
|
||||
typedef std::pair<Set, Set> Path;
|
||||
|
||||
/* The provider that created this access entry */
|
||||
AccessProvider *provider;
|
||||
/* Channel this access entry is on */
|
||||
@@ -95,8 +102,9 @@ class CoreExport ChanAccess : public Serializable
|
||||
/** Check if this access entry matches the given user or account
|
||||
* @param u The user
|
||||
* @param nc The account
|
||||
* @param p The path to the access object which matches will be put here
|
||||
*/
|
||||
virtual bool Matches(const User *u, const NickCore *nc) const;
|
||||
virtual bool Matches(const User *u, const NickCore *nc, Path &p) const;
|
||||
|
||||
/** Check if this access entry has the given privilege.
|
||||
* @param name The privilege name
|
||||
@@ -127,8 +135,10 @@ class CoreExport ChanAccess : public Serializable
|
||||
class CoreExport AccessGroup : public std::vector<ChanAccess *>
|
||||
{
|
||||
public:
|
||||
/* Channel these access entries are on */
|
||||
/* Channel these access entries are on */
|
||||
const ChannelInfo *ci;
|
||||
/* Path from these entries to other entries that they depend on */
|
||||
ChanAccess::Path path;
|
||||
/* Account these entries affect, if any */
|
||||
const NickCore *nc;
|
||||
/* super_admin always gets all privs. founder is a special case where ci->founder == nc */
|
||||
|
||||
+3
-3
@@ -597,10 +597,10 @@ class CoreExport Module : public Extensible
|
||||
*/
|
||||
virtual void OnBotDelete(BotInfo *bi) { throw NotImplementedException(); }
|
||||
|
||||
/** Called when access is deleted from a channel
|
||||
/** Called after an access entry is deleted from a channel
|
||||
* @param ci The channel
|
||||
* @param source The source of the command
|
||||
* @param access The access entry being removed
|
||||
* @param access The access entry that was removed
|
||||
*/
|
||||
virtual void OnAccessDel(ChannelInfo *ci, CommandSource &source, ChanAccess *access) { throw NotImplementedException(); }
|
||||
|
||||
@@ -704,7 +704,7 @@ class CoreExport Module : public Extensible
|
||||
* @param priv The privilege being checked for
|
||||
* @return EVENT_ALLOW for yes, EVENT_STOP to stop all processing
|
||||
*/
|
||||
virtual EventReturn OnCheckPriv(ChanAccess *access, const Anope::string &priv) { throw NotImplementedException(); }
|
||||
virtual EventReturn OnCheckPriv(const ChanAccess *access, const Anope::string &priv) { throw NotImplementedException(); }
|
||||
|
||||
/** Check whether an access group has a privilege
|
||||
* @param group The group
|
||||
|
||||
@@ -137,13 +137,18 @@ class CoreExport ChannelInfo : public Serializable, public Extensible
|
||||
*/
|
||||
unsigned GetAccessCount() const;
|
||||
|
||||
/** Get the number of access entries for this channel,
|
||||
* including those that are on other channels.
|
||||
*/
|
||||
unsigned GetDeepAccessCount() const;
|
||||
|
||||
/** Erase an entry from the channel access list
|
||||
*
|
||||
* @param index The index in the access list vector
|
||||
*
|
||||
* Clears the memory used by the given access entry and removes it from the vector.
|
||||
* @return The erased entry
|
||||
*/
|
||||
void EraseAccess(unsigned index);
|
||||
ChanAccess *EraseAccess(unsigned index);
|
||||
|
||||
/** Clear the entire channel access list
|
||||
*
|
||||
|
||||
@@ -128,16 +128,47 @@ class CommandCSAccess : public Command
|
||||
}
|
||||
}
|
||||
|
||||
if (mask.find_first_of("!*@") == Anope::string::npos && !NickAlias::Find(mask))
|
||||
if (IRCD->IsChannelValid(mask))
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
mask = "*!*@" + targ->GetDisplayedHost();
|
||||
else
|
||||
if (Config->GetModule("chanserv")->Get<bool>("disallow_channel_access"))
|
||||
{
|
||||
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
|
||||
source.Reply(_("Channels may not be on access lists."));
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelInfo *targ_ci = ChannelInfo::Find(mask);
|
||||
if (targ_ci == NULL)
|
||||
{
|
||||
source.Reply(CHAN_X_NOT_REGISTERED, mask.c_str());
|
||||
return;
|
||||
}
|
||||
else if (ci == targ_ci)
|
||||
{
|
||||
source.Reply(_("You can't add a channel to its own access list."));
|
||||
return;
|
||||
}
|
||||
|
||||
mask = targ_ci->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
const NickAlias *na = NickAlias::Find(mask);
|
||||
if (!na && Config->GetModule("chanserv")->Get<bool>("disallow_hostmask_access"))
|
||||
{
|
||||
source.Reply(_("Masks and unregistered users may not be on access lists."));
|
||||
return;
|
||||
}
|
||||
else if (mask.find_first_of("!*@") == Anope::string::npos && !na)
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
mask = "*!*@" + targ->GetDisplayedHost();
|
||||
else
|
||||
{
|
||||
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = ci->GetAccessCount(); i > 0; --i)
|
||||
@@ -151,15 +182,15 @@ class CommandCSAccess : public Command
|
||||
source.Reply(ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
ci->EraseAccess(i - 1);
|
||||
delete ci->EraseAccess(i - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024");
|
||||
if (access_max && ci->GetAccessCount() >= access_max)
|
||||
if (access_max && ci->GetDeepAccessCount() >= access_max)
|
||||
{
|
||||
source.Reply(_("Sorry, you can only have %d access entries on a channel."), access_max);
|
||||
source.Reply(_("Sorry, you can only have %d access entries on a channel, including access entries from other channels."), access_max);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,7 +218,7 @@ class CommandCSAccess : public Command
|
||||
{
|
||||
Anope::string mask = params[2];
|
||||
|
||||
if (!isdigit(mask[0]) && mask.find_first_of("!*@") == Anope::string::npos && !NickAlias::Find(mask))
|
||||
if (!isdigit(mask[0]) && mask.find_first_of("#!*@") == Anope::string::npos && !NickAlias::Find(mask))
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
@@ -258,9 +289,10 @@ class CommandCSAccess : public Command
|
||||
else
|
||||
Nicks = access->mask;
|
||||
|
||||
FOREACH_MOD(OnAccessDel, (ci, source, access));
|
||||
|
||||
ci->EraseAccess(Number - 1);
|
||||
|
||||
FOREACH_MOD(OnAccessDel, (ci, source, access));
|
||||
delete access;
|
||||
}
|
||||
}
|
||||
delcallback(source, ci, this, mask);
|
||||
@@ -284,6 +316,7 @@ class CommandCSAccess : public Command
|
||||
bool override = !u_access.founder && !u_access.HasPriv("ACCESS_CHANGE") && !access->mask.equals_ci(source.nc->display);
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to delete " << access->mask;
|
||||
|
||||
ci->EraseAccess(i - 1);
|
||||
FOREACH_MOD(OnAccessDel, (ci, source, access));
|
||||
delete access;
|
||||
}
|
||||
@@ -325,8 +358,11 @@ class CommandCSAccess : public Command
|
||||
Anope::string timebuf;
|
||||
if (ci->c)
|
||||
for (Channel::ChanUserList::const_iterator cit = ci->c->users.begin(), cit_end = ci->c->users.end(); cit != cit_end; ++cit)
|
||||
if (access->Matches(cit->second->user, cit->second->user->Account()))
|
||||
{
|
||||
ChanAccess::Path p;
|
||||
if (access->Matches(cit->second->user, cit->second->user->Account(), p))
|
||||
timebuf = "Now";
|
||||
}
|
||||
if (timebuf.empty())
|
||||
{
|
||||
if (access->last_seen == 0)
|
||||
@@ -359,8 +395,11 @@ class CommandCSAccess : public Command
|
||||
Anope::string timebuf;
|
||||
if (ci->c)
|
||||
for (Channel::ChanUserList::const_iterator cit = ci->c->users.begin(), cit_end = ci->c->users.end(); cit != cit_end; ++cit)
|
||||
if (access->Matches(cit->second->user, cit->second->user->Account()))
|
||||
{
|
||||
ChanAccess::Path p;
|
||||
if (access->Matches(cit->second->user, cit->second->user->Account(), p))
|
||||
timebuf = "Now";
|
||||
}
|
||||
if (timebuf.empty())
|
||||
{
|
||||
if (access->last_seen == 0)
|
||||
@@ -527,10 +566,13 @@ class CommandCSAccess : public Command
|
||||
"the level specified in the command. The \037level\037 specified\n"
|
||||
"must be less than that of the user giving the command, and\n"
|
||||
"if the \037mask\037 is already on the access list, the current\n"
|
||||
"access level of that nick must be less than the access level\n"
|
||||
"access level of that mask must be less than the access level\n"
|
||||
"of the user giving the command. When a user joins the channel\n"
|
||||
"the access they receive is from the highest level entry in the\n"
|
||||
"access list."));
|
||||
if (!Config->GetModule("chanserv")->Get<bool>("disallow_channel_access"))
|
||||
source.Reply(_("The given mask may also be a channel, which will use the\n"
|
||||
"access list from the other channel up to the given \037level\037"));
|
||||
source.Reply(" ");
|
||||
source.Reply(_("The \002ACCESS DEL\002 command removes the given nick from the\n"
|
||||
"access list. If a list of entry numbers is given, those\n"
|
||||
|
||||
@@ -84,23 +84,55 @@ class CommandCSFlags : public Command
|
||||
|
||||
AccessGroup u_access = source.AccessFor(ci);
|
||||
|
||||
if (mask.find_first_of("!*@") == Anope::string::npos && !NickAlias::Find(mask))
|
||||
if (IRCD->IsChannelValid(mask))
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
mask = "*!*@" + targ->GetDisplayedHost();
|
||||
else
|
||||
if (Config->GetModule("chanserv")->Get<bool>("disallow_channel_access"))
|
||||
{
|
||||
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
|
||||
source.Reply(_("Channels may not be on access lists."));
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelInfo *targ_ci = ChannelInfo::Find(mask);
|
||||
if (targ_ci == NULL)
|
||||
{
|
||||
source.Reply(CHAN_X_NOT_REGISTERED, mask.c_str());
|
||||
return;
|
||||
}
|
||||
else if (ci == targ_ci)
|
||||
{
|
||||
source.Reply(_("You can't add a channel to its own access list."));
|
||||
return;
|
||||
}
|
||||
|
||||
mask = targ_ci->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
const NickAlias *na = NickAlias::Find(mask);
|
||||
if (!na && Config->GetModule("chanserv")->Get<bool>("disallow_hostmask_access"))
|
||||
{
|
||||
source.Reply(_("Masks and unregistered users may not be on access lists."));
|
||||
return;
|
||||
}
|
||||
else if (mask.find_first_of("!*@") == Anope::string::npos && !na)
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
mask = "*!*@" + targ->GetDisplayedHost();
|
||||
else
|
||||
{
|
||||
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChanAccess *current = NULL;
|
||||
unsigned current_idx;
|
||||
std::set<char> current_flags;
|
||||
for (unsigned i = ci->GetAccessCount(); i > 0; --i)
|
||||
for (current_idx = ci->GetAccessCount(); current_idx > 0; --current_idx)
|
||||
{
|
||||
ChanAccess *access = ci->GetAccess(i - 1);
|
||||
ChanAccess *access = ci->GetAccess(current_idx - 1);
|
||||
if (mask.equals_ci(access->mask))
|
||||
{
|
||||
current = access;
|
||||
@@ -112,9 +144,9 @@ class CommandCSFlags : public Command
|
||||
}
|
||||
|
||||
unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024");
|
||||
if (access_max && ci->GetAccessCount() >= access_max)
|
||||
if (access_max && ci->GetDeepAccessCount() >= access_max)
|
||||
{
|
||||
source.Reply(_("Sorry, you can only have %d access entries on a channel."), access_max);
|
||||
source.Reply(_("Sorry, you can only have %d access entries on a channel, including access entries from other channels."), access_max);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -178,6 +210,7 @@ class CommandCSFlags : public Command
|
||||
{
|
||||
if (current != NULL)
|
||||
{
|
||||
ci->EraseAccess(current_idx - 1);
|
||||
FOREACH_MOD(OnAccessDel, (ci, source, current));
|
||||
delete current;
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to delete " << mask;
|
||||
|
||||
+45
-13
@@ -132,16 +132,47 @@ class CommandCSXOP : public Command
|
||||
}
|
||||
}
|
||||
|
||||
if (mask.find_first_of("!*@") == Anope::string::npos && !NickAlias::Find(mask))
|
||||
if (IRCD->IsChannelValid(mask))
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
mask = "*!*@" + targ->GetDisplayedHost();
|
||||
else
|
||||
if (Config->GetModule("chanserv")->Get<bool>("disallow_channel_access"))
|
||||
{
|
||||
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
|
||||
source.Reply(_("Channels may not be on access lists."));
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelInfo *targ_ci = ChannelInfo::Find(mask);
|
||||
if (targ_ci == NULL)
|
||||
{
|
||||
source.Reply(CHAN_X_NOT_REGISTERED, mask.c_str());
|
||||
return;
|
||||
}
|
||||
else if (ci == targ_ci)
|
||||
{
|
||||
source.Reply(_("You can't add a channel to its own access list."));
|
||||
return;
|
||||
}
|
||||
|
||||
mask = targ_ci->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
const NickAlias *na = NickAlias::Find(mask);
|
||||
if (!na && Config->GetModule("chanserv")->Get<bool>("disallow_hostmask_access"))
|
||||
{
|
||||
source.Reply(_("Masks and unregistered users may not be on access lists."));
|
||||
return;
|
||||
}
|
||||
else if (mask.find_first_of("!*@") == Anope::string::npos && !na)
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
mask = "*!*@" + targ->GetDisplayedHost();
|
||||
else
|
||||
{
|
||||
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
|
||||
@@ -156,15 +187,15 @@ class CommandCSXOP : public Command
|
||||
return;
|
||||
}
|
||||
|
||||
ci->EraseAccess(i);
|
||||
delete ci->EraseAccess(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024");
|
||||
if (access_max && ci->GetAccessCount() >= access_max)
|
||||
if (access_max && ci->GetDeepAccessCount() >= access_max)
|
||||
{
|
||||
source.Reply(_("Sorry, you can only have %d %s entries on a channel."), access_max, source.command.c_str());
|
||||
source.Reply(_("Sorry, you can only have %d access entries on a channel, including access entries from other channels."), access_max);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -217,7 +248,7 @@ class CommandCSXOP : public Command
|
||||
const ChanAccess *highest = access.Highest();
|
||||
bool override = false;
|
||||
|
||||
if (!isdigit(mask[0]) && mask.find_first_of("!*@") == Anope::string::npos && !NickAlias::Find(mask))
|
||||
if (!isdigit(mask[0]) && mask.find_first_of("#!*@") == Anope::string::npos && !NickAlias::Find(mask))
|
||||
{
|
||||
User *targ = User::Find(mask, true);
|
||||
if (targ != NULL)
|
||||
@@ -287,9 +318,9 @@ class CommandCSXOP : public Command
|
||||
else
|
||||
nicks = caccess->mask;
|
||||
|
||||
FOREACH_MOD(OnAccessDel, (ci, source, caccess));
|
||||
|
||||
ci->EraseAccess(number - 1);
|
||||
FOREACH_MOD(OnAccessDel, (ci, source, caccess));
|
||||
delete caccess;
|
||||
}
|
||||
}
|
||||
delcallback(source, ci, this, override, mask);
|
||||
@@ -307,6 +338,7 @@ class CommandCSXOP : public Command
|
||||
|
||||
source.Reply(_("\002%s\002 deleted from %s %s list."), a->mask.c_str(), ci->name.c_str(), source.command.c_str());
|
||||
|
||||
ci->EraseAccess(i);
|
||||
FOREACH_MOD(OnAccessDel, (ci, source, a));
|
||||
delete a;
|
||||
|
||||
@@ -428,7 +460,7 @@ class CommandCSXOP : public Command
|
||||
{
|
||||
const ChanAccess *access = ci->GetAccess(i - 1);
|
||||
if (XOPChanAccess::DetermineLevel(access) == source.command.upper())
|
||||
ci->EraseAccess(i - 1);
|
||||
delete ci->EraseAccess(i - 1);
|
||||
}
|
||||
|
||||
FOREACH_MOD(OnAccessClear, (ci, source));
|
||||
|
||||
@@ -22,12 +22,15 @@ class StatusUpdate : public Module
|
||||
{
|
||||
User *user = it->second->user;
|
||||
|
||||
if (user->server != Me && access->Matches(user, user->Account()))
|
||||
ChanAccess::Path p;
|
||||
if (user->server != Me && access->Matches(user, user->Account(), p))
|
||||
{
|
||||
AccessGroup ag = ci->AccessFor(user);
|
||||
|
||||
for (unsigned i = 0; i < ModeManager::GetStatusChannelModesByRank().size(); ++i)
|
||||
{
|
||||
ChannelModeStatus *cms = ModeManager::GetStatusChannelModesByRank()[i];
|
||||
if (!access->HasPriv("AUTO" + cms->name))
|
||||
if (!ag.HasPriv("AUTO" + cms->name))
|
||||
ci->c->RemoveMode(NULL, cms, user->GetUID());
|
||||
}
|
||||
ci->c->SetCorrectModes(user, true);
|
||||
@@ -42,13 +45,10 @@ class StatusUpdate : public Module
|
||||
{
|
||||
User *user = it->second->user;
|
||||
|
||||
if (user->server != Me && access->Matches(user, user->Account()))
|
||||
ChanAccess::Path p;
|
||||
if (user->server != Me && access->Matches(user, user->Account(), p))
|
||||
{
|
||||
/* Get user's current access and remove the entry about to be deleted */
|
||||
AccessGroup ag = ci->AccessFor(user);
|
||||
AccessGroup::iterator iter = std::find(ag.begin(), ag.end(), access);
|
||||
if (iter != ag.end())
|
||||
ag.erase(iter);
|
||||
|
||||
for (unsigned i = 0; i < ModeManager::GetStatusChannelModesByRank().size(); ++i)
|
||||
{
|
||||
|
||||
@@ -182,7 +182,7 @@ class ChanServCore : public Module, public ChanServService
|
||||
|
||||
if (anc && anc == nc)
|
||||
{
|
||||
ci->EraseAccess(j);
|
||||
delete ci->EraseAccess(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+76
-10
@@ -15,6 +15,7 @@
|
||||
#include "regchannel.h"
|
||||
#include "users.h"
|
||||
#include "account.h"
|
||||
#include "protocol.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
@@ -172,7 +173,7 @@ Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
Anope::string provider, chan;
|
||||
|
||||
data["provider"] >> provider;
|
||||
data["ci"] >>chan;
|
||||
data["ci"] >> chan;
|
||||
|
||||
ServiceReference<AccessProvider> aprovider("AccessProvider", provider);
|
||||
ChannelInfo *ci = ChannelInfo::Find(chan);
|
||||
@@ -199,20 +200,56 @@ Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
return access;
|
||||
}
|
||||
|
||||
bool ChanAccess::Matches(const User *u, const NickCore *acc) const
|
||||
bool ChanAccess::Matches(const User *u, const NickCore *acc, Path &p) const
|
||||
{
|
||||
bool is_mask = this->mask.find_first_of("!@?*") != Anope::string::npos;
|
||||
if (u && is_mask && Anope::Match(u->nick, this->mask))
|
||||
return true;
|
||||
else if (u && Anope::Match(u->GetDisplayedMask(), this->mask))
|
||||
return true;
|
||||
else if (acc)
|
||||
if (this->nc)
|
||||
return this->nc == acc;
|
||||
|
||||
if (u)
|
||||
{
|
||||
bool is_mask = this->mask.find_first_of("!@?*") != Anope::string::npos;
|
||||
if (is_mask && Anope::Match(u->nick, this->mask))
|
||||
return true;
|
||||
else if (Anope::Match(u->GetDisplayedMask(), this->mask))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (acc)
|
||||
{
|
||||
for (unsigned i = 0; i < acc->aliases->size(); ++i)
|
||||
{
|
||||
const NickAlias *na = acc->aliases->at(i);
|
||||
if (Anope::Match(na->nick, this->mask))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (IRCD->IsChannelValid(this->mask))
|
||||
{
|
||||
ChannelInfo *tci = ChannelInfo::Find(this->mask);
|
||||
if (tci)
|
||||
{
|
||||
for (unsigned i = 0; i < tci->GetAccessCount(); ++i)
|
||||
{
|
||||
ChanAccess *a = tci->GetAccess(i);
|
||||
std::pair<const ChanAccess *, const ChanAccess *> pair = std::make_pair(this, a);
|
||||
|
||||
std::pair<Set::iterator, Set::iterator> range = p.first.equal_range(this);
|
||||
for (; range.first != range.second; ++range.first)
|
||||
if (range.first->first == pair.first && range.first->second == pair.second)
|
||||
goto cont;
|
||||
|
||||
p.first.insert(pair);
|
||||
if (a->Matches(u, acc, p))
|
||||
p.second.insert(pair);
|
||||
|
||||
cont:;
|
||||
}
|
||||
|
||||
return p.second.count(this) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -299,6 +336,32 @@ AccessGroup::AccessGroup() : std::vector<ChanAccess *>()
|
||||
this->super_admin = this->founder = false;
|
||||
}
|
||||
|
||||
static bool HasPriv(const AccessGroup &ag, const ChanAccess *access, const Anope::string &name)
|
||||
{
|
||||
EventReturn MOD_RESULT;
|
||||
FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name));
|
||||
if (MOD_RESULT == EVENT_ALLOW || access->HasPriv(name))
|
||||
{
|
||||
typedef std::multimap<const ChanAccess *, const ChanAccess *> path;
|
||||
std::pair<path::const_iterator, path::const_iterator> it = ag.path.second.equal_range(access);
|
||||
if (it.first != it.second)
|
||||
/* check all of the paths for this entry */
|
||||
for (; it.first != it.second; ++it.first)
|
||||
{
|
||||
const ChanAccess *a = it.first->second;
|
||||
/* if only one path fully matches then we are ok */
|
||||
if (HasPriv(ag, a, name))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
/* entry is the end of a chain, all entries match, ok */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* entry does not match or none of the chains fully match */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AccessGroup::HasPriv(const Anope::string &name) const
|
||||
{
|
||||
if (this->super_admin)
|
||||
@@ -307,17 +370,20 @@ bool AccessGroup::HasPriv(const Anope::string &name) const
|
||||
return false;
|
||||
else if (this->founder)
|
||||
return true;
|
||||
|
||||
EventReturn MOD_RESULT;
|
||||
FOREACH_RESULT(OnGroupCheckPriv, MOD_RESULT, (this, name));
|
||||
if (MOD_RESULT != EVENT_CONTINUE)
|
||||
return MOD_RESULT == EVENT_ALLOW;
|
||||
|
||||
for (unsigned i = this->size(); i > 0; --i)
|
||||
{
|
||||
ChanAccess *access = this->at(i - 1);
|
||||
FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name));
|
||||
if (MOD_RESULT == EVENT_ALLOW || access->HasPriv(name))
|
||||
|
||||
if (::HasPriv(*this, access, name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+33
-23
@@ -400,16 +400,8 @@ AccessGroup ChannelInfo::AccessFor(const User *u)
|
||||
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i)
|
||||
{
|
||||
ChanAccess *a = this->GetAccess(i);
|
||||
|
||||
if (a->nc)
|
||||
{
|
||||
if (a->nc == nc)
|
||||
group.push_back(a);
|
||||
}
|
||||
else if (a->Matches(u, nc))
|
||||
{
|
||||
if (a->Matches(u, u->Account(), group.path))
|
||||
group.push_back(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (group.founder || !group.empty())
|
||||
@@ -434,18 +426,10 @@ AccessGroup ChannelInfo::AccessFor(const NickCore *nc)
|
||||
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i)
|
||||
{
|
||||
ChanAccess *a = this->GetAccess(i);
|
||||
|
||||
if (a->nc)
|
||||
{
|
||||
if (a->nc == nc)
|
||||
group.push_back(a);
|
||||
}
|
||||
else if (this->GetAccess(i)->Matches(NULL, nc))
|
||||
{
|
||||
group.push_back(this->GetAccess(i));
|
||||
}
|
||||
if (a->Matches(NULL, nc, group.path))
|
||||
group.push_back(a);
|
||||
}
|
||||
|
||||
|
||||
if (group.founder || !group.empty())
|
||||
{
|
||||
this->last_used = Anope::CurTime;
|
||||
@@ -462,12 +446,38 @@ unsigned ChannelInfo::GetAccessCount() const
|
||||
return this->access->size();
|
||||
}
|
||||
|
||||
void ChannelInfo::EraseAccess(unsigned index)
|
||||
unsigned ChannelInfo::GetDeepAccessCount() const
|
||||
{
|
||||
ChanAccess::Path path;
|
||||
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i)
|
||||
{
|
||||
ChanAccess *a = this->GetAccess(i);
|
||||
a->Matches(NULL, NULL, path);
|
||||
}
|
||||
|
||||
unsigned count = this->GetAccessCount();
|
||||
std::set<const ChannelInfo *> channels;
|
||||
channels.insert(this);
|
||||
for (ChanAccess::Set::iterator it = path.first.begin(); it != path.first.end(); ++it)
|
||||
{
|
||||
const ChannelInfo *ci = it->first->ci;
|
||||
if (!channels.count(ci))
|
||||
{
|
||||
channels.count(ci);
|
||||
count += ci->GetAccessCount();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
ChanAccess *ChannelInfo::EraseAccess(unsigned index)
|
||||
{
|
||||
if (this->access->empty() || index >= this->access->size())
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
delete this->access->at(index);
|
||||
ChanAccess *ca = this->access->at(index);
|
||||
this->access->erase(this->access->begin() + index);
|
||||
return ca;
|
||||
}
|
||||
|
||||
void ChannelInfo::ClearAccess()
|
||||
|
||||
Reference in New Issue
Block a user