diff options
| author | Adam <Adam@anope.org> | 2014-05-28 12:07:29 -0400 |
|---|---|---|
| committer | Adam <Adam@anope.org> | 2014-05-28 12:07:54 -0400 |
| commit | f29e1cf383529a1a29f02b0669d973f5ee0b7a66 (patch) | |
| tree | 3c33db276dc9328235bbd572641521ed44458176 /modules/pseudoclients | |
| parent | 1253c70e0682fa1490c99c3d2869049a0e3fa2e0 (diff) | |
Move most of the core pseudoclient logic to modules
Diffstat (limited to 'modules/pseudoclients')
23 files changed, 1761 insertions, 103 deletions
diff --git a/modules/pseudoclients/botserv/CMakeLists.txt b/modules/pseudoclients/botserv/CMakeLists.txt new file mode 100644 index 000000000..781f0ef1f --- /dev/null +++ b/modules/pseudoclients/botserv/CMakeLists.txt @@ -0,0 +1 @@ +build_subdir(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/modules/pseudoclients/botserv.cpp b/modules/pseudoclients/botserv/botserv.cpp index 2f4511f32..cbb76599a 100644 --- a/modules/pseudoclients/botserv.cpp +++ b/modules/pseudoclients/botserv/botserv.cpp @@ -10,9 +10,10 @@ */ #include "module.h" +#include "modules/botserv.h" #include "modules/help.h" -class BotServCore : public Module +class BotServCore : public Module, public BotServ::BotServService , public EventHook<Event::SetCorrectModes> , public EventHook<Event::BotAssign> , public EventHook<Event::JoinChannel> @@ -28,6 +29,7 @@ class BotServCore : public Module public: BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR) + , BotServ::BotServService(this) , EventHook<Event::SetCorrectModes>("OnSetCorrectModes") , EventHook<Event::BotAssign>("OnBotAssign") , EventHook<Event::JoinChannel>("OnJoinChannel") @@ -48,7 +50,7 @@ class BotServCore : public Module BotServ = BotInfo::Find(bsnick, true); } - void OnSetCorrectModes(User *user, Channel *chan, AccessGroup &access, bool &give_modes, bool &take_modes) override + void OnSetCorrectModes(User *user, Channel *chan, ChanServ::AccessGroup &access, bool &give_modes, bool &take_modes) override { /* Do not allow removing bot modes on our service bots */ if (chan->ci && chan->ci->bi == user) @@ -59,7 +61,7 @@ class BotServCore : public Module } } - void OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi) override + void OnBotAssign(User *sender, ChanServ::Channel *ci, BotInfo *bi) override { if (ci->c && ci->c->users.size() >= Config->GetModule(this)->Get<unsigned>("minusers")) { @@ -128,7 +130,7 @@ class BotServCore : public Module /* Channel is persistent, it shouldn't be deleted and the service bot should stay */ if (c->ci && persist && persist->HasExt(c->ci)) return; - + /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediatly * We also don't part the bot here either, if necessary we will part it after the sync */ @@ -208,7 +210,7 @@ class BotServCore : public Module return EVENT_CONTINUE; } - void OnCreateChan(ChannelInfo *ci) override + void OnCreateChan(ChanServ::Channel *ci) override { /* Set default bot flags */ spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("defaults", "greet fantasy")); diff --git a/modules/pseudoclients/chanserv/CMakeLists.txt b/modules/pseudoclients/chanserv/CMakeLists.txt new file mode 100644 index 000000000..781f0ef1f --- /dev/null +++ b/modules/pseudoclients/chanserv/CMakeLists.txt @@ -0,0 +1 @@ +build_subdir(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/modules/pseudoclients/chanserv/channel.cpp b/modules/pseudoclients/chanserv/channel.cpp new file mode 100644 index 000000000..5364075ae --- /dev/null +++ b/modules/pseudoclients/chanserv/channel.cpp @@ -0,0 +1,605 @@ +/* Registered channel functions + * + * (C) 2003-2014 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + */ + +#include "module.h" +#include "channel.h" +#include "modules/cs_akick.h" + +ChannelImpl::ChannelImpl(const Anope::string &chname) +{ + if (chname.empty()) + throw CoreException("Empty channel passed to ChanServ::Channel constructor"); + + this->founder = NULL; + this->successor = NULL; + this->c = ::Channel::Find(chname); + if (this->c) + this->c->ci = this; + this->banexpire = 0; + this->bi = NULL; + this->last_topic_time = 0; + + this->name = chname; + + this->bantype = 2; + this->last_used = this->time_registered = Anope::CurTime; + + ChanServ::registered_channel_map& map = ChanServ::service->GetChannels(); + Channel* &ci = map[chname]; + if (ci) + Log(LOG_DEBUG) << "Duplicate channel " << this->name << " in registered channel table?"; + ci = this; + + Event::OnCreateChan(&Event::CreateChan::OnCreateChan, this); +} + +ChannelImpl::ChannelImpl(const ChanServ::Channel &ci) +{ + *this = ci; + + if (this->founder) + --this->founder->channelcount; + + this->access->clear(); + this->akick->clear(); + + for (unsigned i = 0; i < ci.GetAccessCount(); ++i) + { + const ChanServ::ChanAccess *taccess = ci.GetAccess(i); + ChanServ::AccessProvider *provider = taccess->provider; + + ChanServ::ChanAccess *newaccess = provider->Create(); + newaccess->ci = this; + newaccess->mask = taccess->mask; + newaccess->creator = taccess->creator; + newaccess->last_seen = taccess->last_seen; + newaccess->created = taccess->created; + newaccess->AccessUnserialize(taccess->AccessSerialize()); + + this->AddAccess(newaccess); + } + + for (unsigned i = 0; i < ci.GetAkickCount(); ++i) + { + const AutoKick *takick = ci.GetAkick(i); + if (takick->nc) + this->AddAkick(takick->creator, takick->nc, takick->reason, takick->addtime, takick->last_used); + else + this->AddAkick(takick->creator, takick->mask, takick->reason, takick->addtime, takick->last_used); + } + + Event::OnCreateChan(&Event::CreateChan::OnCreateChan, this); +} + +ChannelImpl::~ChannelImpl() +{ + Event::OnDelChan(&Event::DelChan::OnDelChan, this); + + Log(LOG_DEBUG) << "Deleting channel " << this->name; + + if (this->c) + { + if (this->bi && this->c->FindUser(this->bi)) + this->bi->Part(this->c); + + /* Parting the service bot can cause the channel to go away */ + + if (this->c) + { + if (this->c && this->c->CheckDelete()) + delete this->c; + + this->c = NULL; + } + } + + ChanServ::registered_channel_map& map = ChanServ::service->GetChannels(); + map.erase(this->name); + + this->SetFounder(NULL); + this->SetSuccessor(NULL); + + this->ClearAccess(); + this->ClearAkick(); + + if (this->memos) + { + for (unsigned i = 0, end = this->memos->memos->size(); i < end; ++i) + delete this->memos->GetMemo(i); + this->memos->memos->clear(); + delete memos; + } + + if (this->founder) + --this->founder->channelcount; +} + +void ChannelImpl::Serialize(Serialize::Data &data) const +{ + data["name"] << this->name; + if (this->founder) + data["founder"] << this->founder->display; + if (this->successor) + data["successor"] << this->successor->display; + data["description"] << this->desc; + data.SetType("time_registered", Serialize::Data::DT_INT); data["time_registered"] << this->time_registered; + data.SetType("last_used", Serialize::Data::DT_INT); data["last_used"] << this->last_used; + data["last_topic"] << this->last_topic; + data["last_topic_setter"] << this->last_topic_setter; + data.SetType("last_topic_time", Serialize::Data::DT_INT); data["last_topic_time"] << this->last_topic_time; + data.SetType("bantype", Serialize::Data::DT_INT); data["bantype"] << this->bantype; + { + Anope::string levels_buffer; + for (Anope::map<int16_t>::const_iterator it = this->levels.begin(), it_end = this->levels.end(); it != it_end; ++it) + levels_buffer += it->first + " " + stringify(it->second) + " "; + data["levels"] << levels_buffer; + } + if (this->bi) + data["bi"] << this->bi->nick; + data.SetType("banexpire", Serialize::Data::DT_INT); data["banexpire"] << this->banexpire; + if (memos) + { + data["memomax"] << this->memos->memomax; + for (unsigned i = 0; i < this->memos->ignores.size(); ++i) + data["memoignores"] << this->memos->ignores[i] << " "; + } + + Extensible::ExtensibleSerialize(this, this, data); +} + +Serializable* ChannelImpl::Unserialize(Serializable *obj, Serialize::Data &data) +{ + Anope::string sname, sfounder, ssuccessor, slevels, sbi; + + data["name"] >> sname; + data["founder"] >> sfounder; + data["successor"] >> ssuccessor; + data["levels"] >> slevels; + data["bi"] >> sbi; + + ChannelImpl *ci; + if (obj) + ci = anope_dynamic_static_cast<ChannelImpl *>(obj); + else + ci = new ChannelImpl(sname); + + ci->SetFounder(NickServ::FindAccount(sfounder)); + ci->SetSuccessor(NickServ::FindAccount(ssuccessor)); + + data["description"] >> ci->desc; + data["time_registered"] >> ci->time_registered; + data["last_used"] >> ci->last_used; + data["last_topic"] >> ci->last_topic; + data["last_topic_setter"] >> ci->last_topic_setter; + data["last_topic_time"] >> ci->last_topic_time; + data["bantype"] >> ci->bantype; + { + std::vector<Anope::string> v; + spacesepstream(slevels).GetTokens(v); + for (unsigned i = 0; i + 1 < v.size(); i += 2) + try + { + ci->levels[v[i]] = convertTo<int16_t>(v[i + 1]); + } + catch (const ConvertException &) { } + } + BotInfo *bi = BotInfo::Find(sbi); + if (*ci->bi != bi) + { + if (bi) + bi->Assign(NULL, ci); + else if (ci->bi) + ci->bi->UnAssign(NULL, ci); + } + data["banexpire"] >> ci->banexpire; + if (ci->memos) + { + data["memomax"] >> ci->memos->memomax; + { + Anope::string buf; + data["memoignores"] >> buf; + spacesepstream sep(buf); + ci->memos->ignores.clear(); + while (sep.GetToken(buf)) + ci->memos->ignores.push_back(buf); + } + } + + Extensible::ExtensibleUnserialize(ci, ci, data); + + /* compat */ + bool b; + b = false; + data["extensible:SECURE"] >> b; + if (b) + ci->Extend<bool>("CS_SECURE"); + b = false; + data["extensible:PRIVATE"] >> b; + if (b) + ci->Extend<bool>("CS_PRIVATE"); + b = false; + data["extensible:NO_EXPIRE"] >> b; + if (b) + ci->Extend<bool>("CS_NO_EXPIRE"); + b = false; + data["extensible:FANTASY"] >> b; + if (b) + ci->Extend<bool>("BS_FANTASY"); + b = false; + data["extensible:GREET"] >> b; + if (b) + ci->Extend<bool>("BS_GREET"); + b = false; + data["extensible:PEACE"] >> b; + if (b) + ci->Extend<bool>("PEACE"); + b = false; + data["extensible:SECUREFOUNDER"] >> b; + if (b) + ci->Extend<bool>("SECUREFOUNDER"); + b = false; + data["extensible:RESTRICTED"] >> b; + if (b) + ci->Extend<bool>("RESTRICTED"); + b = false; + data["extensible:KEEPTOPIC"] >> b; + if (b) + ci->Extend<bool>("KEEPTOPIC"); + b = false; + data["extensible:SIGNKICK"] >> b; + if (b) + ci->Extend<bool>("SIGNKICK"); + b = false; + data["extensible:SIGNKICK_LEVEL"] >> b; + if (b) + ci->Extend<bool>("SIGNKICK_LEVEL"); + /* end compat */ + + return ci; +} + + +void ChannelImpl::SetFounder(NickServ::Account *nc) +{ + if (this->founder) + { + --this->founder->channelcount; + this->founder->RemoveChannelReference(this); + } + + this->founder = nc; + + if (this->founder) + { + ++this->founder->channelcount; + this->founder->AddChannelReference(this); + } +} + +NickServ::Account *ChannelImpl::GetFounder() const +{ + return this->founder; +} + +void ChannelImpl::SetSuccessor(NickServ::Account *nc) +{ + if (this->successor) + this->successor->RemoveChannelReference(this); + this->successor = nc; + if (this->successor) + this->successor->AddChannelReference(this); +} + +NickServ::Account *ChannelImpl::GetSuccessor() const +{ + return this->successor; +} + +BotInfo *ChannelImpl::WhoSends() const +{ + if (this && this->bi) + return this->bi; + + BotInfo *ChanServ = Config->GetClient("ChanServ"); + if (ChanServ) + return ChanServ; + + if (!BotListByNick->empty()) + return BotListByNick->begin()->second; + + return NULL; +} + +void ChannelImpl::AddAccess(ChanServ::ChanAccess *taccess) +{ + this->access->push_back(taccess); + + const NickServ::Nick *na = NickServ::FindNick(taccess->mask); + if (na != NULL) + { + na->nc->AddChannelReference(this); + taccess->nc = na->nc; + } + else + { + ChanServ::Channel *ci = ChanServ::Find(taccess->mask); + if (ci != NULL) + ci->AddChannelReference(this->name); + } +} + +ChanServ::ChanAccess *ChannelImpl::GetAccess(unsigned index) const +{ + if (this->access->empty() || index >= this->access->size()) + return NULL; + + ChanServ::ChanAccess *acc = (*this->access)[index]; + acc->QueueUpdate(); + return acc; +} + +ChanServ::AccessGroup ChannelImpl::AccessFor(const User *u) +{ + ChanServ::AccessGroup group; + + if (u == NULL) + return group; + + const NickServ::Account *nc = u->Account(); + if (nc == NULL && !this->HasExt("NS_SECURE") && u->IsRecognized()) + { + const NickServ::Nick *na = NickServ::FindNick(u->nick); + if (na != NULL) + nc = na->nc; + } + + group.super_admin = u->super_admin; + group.founder = IsFounder(u); + group.ci = this; + group.nc = nc; + + for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i) + { + ChanServ::ChanAccess *a = this->GetAccess(i); + if (a->Matches(u, u->Account(), group.path)) + group.push_back(a); + } + + if (group.founder || !group.empty()) + { + this->last_used = Anope::CurTime; + + for (unsigned i = 0; i < group.size(); ++i) + group[i]->last_seen = Anope::CurTime; + } + + return group; +} + +ChanServ::AccessGroup ChannelImpl::AccessFor(const NickServ::Account *nc) +{ + ChanServ::AccessGroup group; + + group.founder = (this->founder && this->founder == nc); + group.ci = this; + group.nc = nc; + + for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i) + { + ChanServ::ChanAccess *a = this->GetAccess(i); + if (a->Matches(NULL, nc, group.path)) + group.push_back(a); + } + + if (group.founder || !group.empty()) + this->last_used = Anope::CurTime; + + /* don't update access last seen here, this isn't the user requesting access */ + + return group; +} + +unsigned ChannelImpl::GetAccessCount() const +{ + return this->access->size(); +} + +unsigned ChannelImpl::GetDeepAccessCount() const +{ + ChanServ::ChanAccess::Path path; + for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i) + { + ChanServ::ChanAccess *a = this->GetAccess(i); + a->Matches(NULL, NULL, path); + } + + unsigned count = this->GetAccessCount(); + std::set<const ChanServ::Channel *> channels; + channels.insert(this); + for (ChanServ::ChanAccess::Set::iterator it = path.first.begin(); it != path.first.end(); ++it) + { + const ChanServ::Channel *ci = it->first->ci; + if (!channels.count(ci)) + { + channels.count(ci); + count += ci->GetAccessCount(); + } + } + return count; +} + +ChanServ::ChanAccess *ChannelImpl::EraseAccess(unsigned index) +{ + if (this->access->empty() || index >= this->access->size()) + return NULL; + + ChanServ::ChanAccess *ca = this->access->at(index); + this->access->erase(this->access->begin() + index); + return ca; +} + +void ChannelImpl::ClearAccess() +{ + for (unsigned i = this->access->size(); i > 0; --i) + delete this->GetAccess(i - 1); +} + +AutoKick *ChannelImpl::AddAkick(const Anope::string &user, NickServ::Account *akicknc, const Anope::string &reason, time_t t, time_t lu) +{ + if (!::akick) + return nullptr; + + AutoKick *autokick = ::akick->Create(); + autokick->ci = this; + autokick->nc = akicknc; + autokick->reason = reason; + autokick->creator = user; + autokick->addtime = t; + autokick->last_used = lu; + + this->akick->push_back(autokick); + + akicknc->AddChannelReference(this); + + return autokick; +} + +AutoKick *ChannelImpl::AddAkick(const Anope::string &user, const Anope::string &mask, const Anope::string &reason, time_t t, time_t lu) +{ + if (!::akick) + return nullptr; + + AutoKick *autokick = ::akick->Create(); + autokick->ci = this; + autokick->mask = mask; + autokick->nc = NULL; + autokick->reason = reason; + autokick->creator = user; + autokick->addtime = t; + autokick->last_used = lu; + + this->akick->push_back(autokick); + + return autokick; +} + +AutoKick *ChannelImpl::GetAkick(unsigned index) const +{ + if (this->akick->empty() || index >= this->akick->size()) + return NULL; + + AutoKick *ak = (*this->akick)[index]; + ak->QueueUpdate(); + return ak; +} + +unsigned ChannelImpl::GetAkickCount() const +{ + return this->akick->size(); +} + +void ChannelImpl::EraseAkick(unsigned index) +{ + if (this->akick->empty() || index >= this->akick->size()) + return; + + delete this->GetAkick(index); +} + +void ChannelImpl::ClearAkick() +{ + while (!this->akick->empty()) + delete this->akick->back(); +} + +int16_t ChannelImpl::GetLevel(const Anope::string &priv) const +{ + if (!ChanServ::service || !ChanServ::service->FindPrivilege(priv)) + { + Log(LOG_DEBUG) << "Unknown privilege " + priv; + return ChanServ::ACCESS_INVALID; + } + + Anope::map<int16_t>::const_iterator it = this->levels.find(priv); + if (it == this->levels.end()) + return 0; + return it->second; +} + +void ChannelImpl::SetLevel(const Anope::string &priv, int16_t level) +{ + this->levels[priv] = level; +} + +void ChannelImpl::RemoveLevel(const Anope::string &priv) +{ + this->levels.erase(priv); +} + +void ChannelImpl::ClearLevels() +{ + this->levels.clear(); +} + +Anope::string ChannelImpl::GetIdealBan(User *u) const +{ + int bt = this ? this->bantype : -1; + switch (bt) + { + case 0: + return "*!" + u->GetVIdent() + "@" + u->GetDisplayedHost(); + case 1: + if (u->GetVIdent()[0] == '~') + return "*!*" + u->GetVIdent() + "@" + u->GetDisplayedHost(); + else + return "*!" + u->GetVIdent() + "@" + u->GetDisplayedHost(); + case 3: + return "*!" + u->Mask(); + case 2: + default: + return "*!*@" + u->GetDisplayedHost(); + } +} + +bool ChannelImpl::IsFounder(const User *user) +{ + if (!user) + return false; + + if (user->super_admin) + return true; + + if (user->Account() && user->Account() == this->GetFounder()) + return true; + + return false; +} + + +void ChannelImpl::AddChannelReference(const Anope::string &what) +{ + ++references[what]; +} + +void ChannelImpl::RemoveChannelReference(const Anope::string &what) +{ + int &i = references[what]; + if (--i <= 0) + references.erase(what); +} + +void ChannelImpl::GetChannelReferences(std::deque<Anope::string> &chans) +{ + chans.clear(); + for (Anope::map<int>::iterator it = references.begin(); it != references.end(); ++it) + chans.push_back(it->first); +} diff --git a/modules/pseudoclients/chanserv/channel.h b/modules/pseudoclients/chanserv/channel.h new file mode 100644 index 000000000..c9a85dba6 --- /dev/null +++ b/modules/pseudoclients/chanserv/channel.h @@ -0,0 +1,41 @@ + + +class ChannelImpl : public ChanServ::Channel +{ + public: + ChannelImpl(const Anope::string &chname); + ChannelImpl(const ChanServ::Channel &ci); + ~ChannelImpl(); + + void Serialize(Serialize::Data &data) const override; + static Serializable* Unserialize(Serializable *obj, Serialize::Data &); + + bool IsFounder(const User *user) override; + void SetFounder(NickServ::Account *nc) override; + NickServ::Account *GetFounder() const override; + void SetSuccessor(NickServ::Account *nc) override; + NickServ::Account *GetSuccessor() const override; + BotInfo *WhoSends() const override; + void AddAccess(ChanServ::ChanAccess *access) override; + ChanServ::ChanAccess *GetAccess(unsigned index) const override; + ChanServ::AccessGroup AccessFor(const User *u) override; + ChanServ::AccessGroup AccessFor(const NickServ::Account *nc) override; + unsigned GetAccessCount() const override; + unsigned GetDeepAccessCount() const override; + ChanServ::ChanAccess *EraseAccess(unsigned index) override; + void ClearAccess() override; + AutoKick* AddAkick(const Anope::string &user, NickServ::Account *akicknc, const Anope::string &reason, time_t t = Anope::CurTime, time_t lu = 0) override; + AutoKick* AddAkick(const Anope::string &user, const Anope::string &mask, const Anope::string &reason, time_t t = Anope::CurTime, time_t lu = 0) override; + AutoKick* GetAkick(unsigned index) const override; + unsigned GetAkickCount() const override; + void EraseAkick(unsigned index) override; + void ClearAkick() override; + int16_t GetLevel(const Anope::string &priv) const override; + void SetLevel(const Anope::string &priv, int16_t level) override; + void RemoveLevel(const Anope::string &priv) override; + void ClearLevels() override; + Anope::string GetIdealBan(User *u) const override; + void AddChannelReference(const Anope::string &what) override; + void RemoveChannelReference(const Anope::string &what) override; + void GetChannelReferences(std::deque<Anope::string> &chans) override; +}; diff --git a/modules/pseudoclients/chanserv.cpp b/modules/pseudoclients/chanserv/chanserv.cpp index 419f25fc3..d4f3aa1c7 100644 --- a/modules/pseudoclients/chanserv.cpp +++ b/modules/pseudoclients/chanserv/chanserv.cpp @@ -10,14 +10,17 @@ */ #include "module.h" +#include "channel.h" #include "modules/cs_mode.h" #include "modules/help.h" #include "modules/bs_bot.h" #include "modules/chanserv.h" #include "modules/cs_info.h" +#include "modules/cs_akick.h" class ChanServCore : public Module , public ChanServ::ChanServService + , public EventHook<Event::ChannelCreate> , public EventHook<Event::BotDelete> , public EventHook<Event::BotPrivmsg> , public EventHook<Event::DelCore> @@ -44,10 +47,15 @@ class ChanServCore : public Module bool always_lower; EventHandlers<ChanServ::Event::PreChanExpire> OnPreChanExpire; EventHandlers<ChanServ::Event::ChanExpire> OnChanExpire; + std::vector<ChanServ::Privilege> Privileges; + std::vector<ChanServ::AccessProvider *> Providers; + Serialize::Checker<ChanServ::registered_channel_map> registered_channels; + Serialize::Type channel_type, access_type; public: ChanServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR) , ChanServService(this) + , EventHook<Event::ChannelCreate>("OnChannelCreate") , EventHook<Event::BotDelete>("OnBotDelete") , EventHook<Event::BotPrivmsg>("OnBotPrivmsg") , EventHook<Event::DelCore>("OnDelCore") @@ -71,9 +79,33 @@ class ChanServCore : public Module , always_lower(false) , OnPreChanExpire(this, "OnPreChanExpire") , OnChanExpire(this, "OnChanExpire") + , registered_channels("ChannelInfo") + , channel_type("ChannelInfo", ChannelImpl::Unserialize) + , access_type("ChanAccess", Unserialize) { } + ChanServ::Channel *Create(const Anope::string &name) override + { + return new ChannelImpl(name); + } + + ChanServ::Channel *Create(const ChanServ::Channel &ci) override + { + return new ChannelImpl(ci); + } + + ChanServ::Channel *Find(const Anope::string &name) override + { + auto it = registered_channels->find(name); + return it != registered_channels->end() ? it->second : nullptr; + } + + ChanServ::registered_channel_map& GetChannels() override + { + return registered_channels; + } + void Hold(Channel *c) override { /** A timer used to keep the BotServ bot/ChanServ in the channel @@ -86,7 +118,7 @@ class ChanServCore : public Module Reference<Channel> c; public: - /** Constructor + /** Constructor * @param chan The channel */ ChanServTimer(Reference<BotInfo> &cs, ExtensibleItem<bool> &i, Module *m, Channel *chan) : Timer(m, Config->GetModule(m)->Get<time_t>("inhabit", "15s")), ChanServ(cs), inhabit(i), c(chan) @@ -137,6 +169,166 @@ class ChanServCore : public Module new ChanServTimer(ChanServ, inhabit, this->owner, c); } + void AddPrivilege(ChanServ::Privilege p) override + { + unsigned i; + for (i = 0; i < Privileges.size(); ++i) + { + ChanServ::Privilege &priv = Privileges[i]; + + if (priv.rank > p.rank) + break; + } + + Privileges.insert(Privileges.begin() + i, p); + } + + void RemovePrivilege(ChanServ::Privilege &p) override + { + std::vector<ChanServ::Privilege>::iterator it = std::find(Privileges.begin(), Privileges.end(), p); + if (it != Privileges.end()) + Privileges.erase(it); + + for (auto& cit : GetChannels()) + { + ChanServ::Channel *ci = cit.second; + ci->QueueUpdate(); + ci->RemoveLevel(p.name); + } + } + + ChanServ::Privilege *FindPrivilege(const Anope::string &name) override + { + for (unsigned i = Privileges.size(); i > 0; --i) + if (Privileges[i - 1].name.equals_ci(name)) + return &Privileges[i - 1]; + return NULL; + } + + std::vector<ChanServ::Privilege> &GetPrivileges() override + { + return Privileges; + } + + void ClearPrivileges() override + { + Privileges.clear(); + } + + std::vector<ChanServ::AccessProvider *>& GetProviders() override + { + return Providers; + } + + void Destruct(ChanServ::ChanAccess *access) override + { + if (access->ci) + { + std::vector<ChanServ::ChanAccess *>::iterator it = std::find(access->ci->access->begin(), access->ci->access->end(), access); + if (it != access->ci->access->end()) + access->ci->access->erase(it); + + const NickServ::Nick *na = NickServ::FindNick(access->mask); + if (na != NULL) + na->nc->RemoveChannelReference(access->ci); + else + { + ChanServ::Channel *c = this->Find(access->mask); + if (c) + c->RemoveChannelReference(access->ci->name); + } + } + } + + void Serialize(const ChanServ::ChanAccess *, Serialize::Data &data) override + { + } + + bool Matches(const ChanServ::ChanAccess *access, const User *u, const NickServ::Account *acc, ChanServ::ChanAccess::Path &p) override + { + if (access->nc) + return access->nc == acc; + + if (u) + { + bool is_mask = access->mask.find_first_of("!@?*") != Anope::string::npos; + if (is_mask && Anope::Match(u->nick, access->mask)) + return true; + else if (Anope::Match(u->GetDisplayedMask(), access->mask)) + return true; + } + + if (acc) + { + for (unsigned i = 0; i < acc->aliases->size(); ++i) + { + const NickServ::Nick *na = acc->aliases->at(i); + if (Anope::Match(na->nick, access->mask)) + return true; + } + } + + if (IRCD->IsChannelValid(access->mask)) + { + ChanServ::Channel *tci = Find(access->mask); + if (tci) + { + for (unsigned i = 0; i < tci->GetAccessCount(); ++i) + { + ChanServ::Cha |
