diff options
| author | Adam <Adam@anope.org> | 2015-12-14 16:52:24 -0500 |
|---|---|---|
| committer | Adam <Adam@anope.org> | 2015-12-14 16:52:24 -0500 |
| commit | 6302f980fe6dad83aab7d2dc1046dadea5ffd939 (patch) | |
| tree | 4c27d33f55fc32ce34827977932dac4b3e5ceedd /modules/chanserv/main | |
| parent | 64dac60071fab652745a6e7a06cf6b7bdbbd3625 (diff) | |
New source tree structure for modules. From commands/cs_access => chanserv/access etc.
Diffstat (limited to 'modules/chanserv/main')
| -rw-r--r-- | modules/chanserv/main/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | modules/chanserv/main/chanaccess.cpp | 127 | ||||
| -rw-r--r-- | modules/chanserv/main/chanaccess.h | 30 | ||||
| -rw-r--r-- | modules/chanserv/main/chanaccesstype.h | 21 | ||||
| -rw-r--r-- | modules/chanserv/main/channel.cpp | 429 | ||||
| -rw-r--r-- | modules/chanserv/main/channel.h | 68 | ||||
| -rw-r--r-- | modules/chanserv/main/channeltype.cpp | 45 | ||||
| -rw-r--r-- | modules/chanserv/main/channeltype.h | 34 | ||||
| -rw-r--r-- | modules/chanserv/main/chanserv.cpp | 587 | ||||
| -rw-r--r-- | modules/chanserv/main/level.cpp | 33 | ||||
| -rw-r--r-- | modules/chanserv/main/level.h | 16 | ||||
| -rw-r--r-- | modules/chanserv/main/leveltype.h | 16 | ||||
| -rw-r--r-- | modules/chanserv/main/mode.cpp | 33 | ||||
| -rw-r--r-- | modules/chanserv/main/mode.h | 17 | ||||
| -rw-r--r-- | modules/chanserv/main/modetype.h | 15 |
15 files changed, 1472 insertions, 0 deletions
diff --git a/modules/chanserv/main/CMakeLists.txt b/modules/chanserv/main/CMakeLists.txt new file mode 100644 index 000000000..781f0ef1f --- /dev/null +++ b/modules/chanserv/main/CMakeLists.txt @@ -0,0 +1 @@ +build_subdir(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/modules/chanserv/main/chanaccess.cpp b/modules/chanserv/main/chanaccess.cpp new file mode 100644 index 000000000..1601260c2 --- /dev/null +++ b/modules/chanserv/main/chanaccess.cpp @@ -0,0 +1,127 @@ +#include "module.h" +#include "chanaccess.h" +#include "chanaccesstype.h" + +ChanServ::Channel *ChanAccessImpl::GetChannel() +{ + return Get(&ChanAccessType::ci); +} + +void ChanAccessImpl::SetChannel(ChanServ::Channel *ci) +{ + Object::Set(&ChanAccessType::ci, ci); +} + +Anope::string ChanAccessImpl::GetCreator() +{ + return Get(&ChanAccessType::creator); +} + +void ChanAccessImpl::SetCreator(const Anope::string &c) +{ + Object::Set(&ChanAccessType::creator, c); +} + +time_t ChanAccessImpl::GetLastSeen() +{ + return Get(&ChanAccessType::last_seen); +} + +void ChanAccessImpl::SetLastSeen(const time_t &t) +{ + Object::Set(&ChanAccessType::last_seen, t); +} + +time_t ChanAccessImpl::GetCreated() +{ + return Get(&ChanAccessType::created); +} + +void ChanAccessImpl::SetCreated(const time_t &t) +{ + Object::Set(&ChanAccessType::created, t); +} + +Anope::string ChanAccessImpl::GetMask() +{ + return Get(&ChanAccessType::mask); +} + +void ChanAccessImpl::SetMask(const Anope::string &n) +{ + Object::Set(&ChanAccessType::mask, n); +} + +Serialize::Object *ChanAccessImpl::GetObj() +{ + return Get(&ChanAccessType::obj); +} + +void ChanAccessImpl::SetObj(Serialize::Object *o) +{ + Object::Set(&ChanAccessType::obj, o); +} + +Anope::string ChanAccessImpl::Mask() +{ + if (NickServ::Account *acc = GetAccount()) + return acc->GetDisplay(); + + return GetMask(); +} + +NickServ::Account *ChanAccessImpl::GetAccount() +{ + if (!GetObj() || GetObj()->GetSerializableType() != NickServ::account) + return nullptr; + + return anope_dynamic_static_cast<NickServ::Account *>(GetObj()); +} + +bool ChanAccessImpl::Matches(const User *u, NickServ::Account *acc, Path &p) +{ + if (this->GetAccount()) + return this->GetAccount() == 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 (NickServ::Nick *na : acc->GetRefs<NickServ::Nick *>(NickServ::nick)) + if (Anope::Match(na->GetNick(), this->Mask())) + return true; + + if (IRCD->IsChannelValid(this->Mask())) + { + ChanServ::Channel *tci = ChanServ::Find(this->Mask()); + if (tci) + { + for (unsigned i = 0; i < tci->GetAccessCount(); ++i) + { + ChanServ::ChanAccess *a = tci->GetAccess(i); + std::pair<ChanServ::ChanAccess *, ChanServ::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; +} diff --git a/modules/chanserv/main/chanaccess.h b/modules/chanserv/main/chanaccess.h new file mode 100644 index 000000000..bb65f79c5 --- /dev/null +++ b/modules/chanserv/main/chanaccess.h @@ -0,0 +1,30 @@ + +class ChanAccessImpl : public ChanServ::ChanAccess +{ + public: + ChanAccessImpl(Serialize::TypeBase *type) : ChanServ::ChanAccess(type) { } + ChanAccessImpl(Serialize::TypeBase *type, Serialize::ID id) : ChanServ::ChanAccess(type, id) { } + + ChanServ::Channel *GetChannel() override; + void SetChannel(ChanServ::Channel *ci) override; + + Anope::string GetCreator() override; + void SetCreator(const Anope::string &c) override; + + time_t GetLastSeen() override; + void SetLastSeen(const time_t &t) override; + + time_t GetCreated() override; + void SetCreated(const time_t &t) override; + + Anope::string GetMask() override; + void SetMask(const Anope::string &) override; + + Serialize::Object *GetObj() override; + void SetObj(Serialize::Object *) override; + + Anope::string Mask() override; + NickServ::Account *GetAccount() override; + + bool Matches(const User *u, NickServ::Account *acc, Path &p) override; +}; diff --git a/modules/chanserv/main/chanaccesstype.h b/modules/chanserv/main/chanaccesstype.h new file mode 100644 index 000000000..ca8dc1b79 --- /dev/null +++ b/modules/chanserv/main/chanaccesstype.h @@ -0,0 +1,21 @@ + +class ChanAccessType : public Serialize::AbstractType +{ + public: + Serialize::ObjectField<ChanServ::ChanAccess, ChanServ::Channel *> ci; + Serialize::Field<ChanServ::ChanAccess, Anope::string> mask; + Serialize::ObjectField<ChanServ::ChanAccess, Serialize::Object *> obj; + Serialize::Field<ChanServ::ChanAccess, Anope::string> creator; + Serialize::Field<ChanServ::ChanAccess, time_t> last_seen; + Serialize::Field<ChanServ::ChanAccess, time_t> created; + + ChanAccessType(Module *me, const Anope::string &name) : Serialize::AbstractType(me, name) + , ci(this, "ci", true) + , mask(this, "mask") + , obj(this, "obj", true) + , creator(this, "creator") + , last_seen(this, "last_seen") + , created(this, "created") + { + } +}; diff --git a/modules/chanserv/main/channel.cpp b/modules/chanserv/main/channel.cpp new file mode 100644 index 000000000..b24edcc0c --- /dev/null +++ b/modules/chanserv/main/channel.cpp @@ -0,0 +1,429 @@ +/* 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 "channeltype.h" +#include "modules/cs_akick.h" + +ChannelImpl::ChannelImpl(Serialize::TypeBase *type, const Anope::string &chname) : ChanServ::Channel(type) +{ + SetName(chname); + SetTimeRegistered(Anope::CurTime); + SetLastUsed(Anope::CurTime); +} + +ChannelImpl::~ChannelImpl() +{ + ChanServ::registered_channel_map& map = ChanServ::service->GetChannels(); + map.erase(this->GetName()); +} + +void ChannelImpl::Delete() +{ + Event::OnDelChan(&Event::DelChan::OnDelChan, this); + + Log(LOG_DEBUG) << "Deleting channel " << this->GetName(); + + if (this->c) + { + if (this->GetBot() && this->c->FindUser(this->GetBot())) + this->GetBot()->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; + } + } + + return Serialize::Object::Delete(); +} + +Anope::string ChannelImpl::GetName() +{ + return Get<Anope::string>(&ChannelType::name); +} + +void ChannelImpl::SetName(const Anope::string &name) +{ + Set(&ChannelType::name, name); +} + +Anope::string ChannelImpl::GetDesc() +{ + return Get(&ChannelType::desc); +} + +void ChannelImpl::SetDesc(const Anope::string &desc) +{ + Set(&ChannelType::desc, desc); +} + +time_t ChannelImpl::GetTimeRegistered() +{ + return Get(&ChannelType::time_registered); +} + +void ChannelImpl::SetTimeRegistered(const time_t &t) +{ + Set(&ChannelType::time_registered, t); +} + +time_t ChannelImpl::GetLastUsed() +{ + return Get(&ChannelType::last_used); +} + +void ChannelImpl::SetLastUsed(const time_t &t) +{ + Set(&ChannelType::last_used, t); +} + +Anope::string ChannelImpl::GetLastTopic() +{ + return Get(&ChannelType::last_topic); +} + +void ChannelImpl::SetLastTopic(const Anope::string &topic) +{ + Set(&ChannelType::last_topic, topic); +} + +Anope::string ChannelImpl::GetLastTopicSetter() +{ + return Get(&ChannelType::last_topic_setter); +} + +void ChannelImpl::SetLastTopicSetter(const Anope::string &setter) +{ + Set(&ChannelType::last_topic_setter, setter); +} + +time_t ChannelImpl::GetLastTopicTime() +{ + return Get(&ChannelType::last_topic_time); +} + +void ChannelImpl::SetLastTopicTime(const time_t &t) +{ + Set(&ChannelType::last_topic_time, t); +} + +int16_t ChannelImpl::GetBanType() +{ + return Get(&ChannelType::bantype); +} + +void ChannelImpl::SetBanType(const int16_t &i) +{ + Set(&ChannelType::bantype, i); +} + +time_t ChannelImpl::GetBanExpire() +{ + return Get(&ChannelType::banexpire); +} + +void ChannelImpl::SetBanExpire(const time_t &t) +{ + Set(&ChannelType::banexpire, t); +} + +BotInfo *ChannelImpl::GetBI() +{ + return Get(&ChannelType::bi); +} + +void ChannelImpl::SetBI(BotInfo *bi) +{ + Set(&ChannelType::bi, bi); +} + +ServiceBot *ChannelImpl::GetBot() +{ + BotInfo *bi = GetBI(); + return bi ? bi->bot : nullptr; +} + +void ChannelImpl::SetBot(ServiceBot *bi) +{ + SetBI(bi->bi); +} + +MemoServ::MemoInfo *ChannelImpl::GetMemos() +{ + return GetRef<MemoServ::MemoInfo *>(MemoServ::memoinfo); +} + +void ChannelImpl::SetFounder(NickServ::Account *nc) +{ + Set(&ChannelType::founder, nc); +} + +NickServ::Account *ChannelImpl::GetFounder() +{ + return Get(&ChannelType::founder); +} + +void ChannelImpl::SetSuccessor(NickServ::Account *nc) +{ + Set(&ChannelType::successor, nc); +} + +NickServ::Account *ChannelImpl::GetSuccessor() +{ + return Get(&ChannelType::successor); +} + +ChanServ::ChanAccess *ChannelImpl::GetAccess(unsigned index) +{ + std::vector<ChanServ::ChanAccess *> a = GetRefs<ChanServ::ChanAccess *>(ChanServ::chanaccess); + return a.size() > index ? a[index] : nullptr; +} + +ChanServ::AccessGroup ChannelImpl::AccessFor(const User *u, bool updateLastUsed) +{ + ChanServ::AccessGroup group; + + if (u == NULL) + return group; + + const NickServ::Account *nc = u->Account(); + if (nc == NULL && !this->HasFieldS("NS_SECURE") && u->IsRecognized()) + { + NickServ::Nick *na = NickServ::FindNick(u->nick); + if (na != NULL) + nc = na->GetAccount(); + } + + 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()) + { + if (updateLastUsed) + this->SetLastUsed(Anope::CurTime); + + for (unsigned i = 0; i < group.size(); ++i) + group[i]->SetLastSeen(Anope::CurTime); + } + + return group; +} + +ChanServ::AccessGroup ChannelImpl::AccessFor(NickServ::Account *nc, bool updateLastUsed) +{ + ChanServ::AccessGroup group; + + group.founder = GetFounder() && GetFounder() == 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()) + if (updateLastUsed) + this->SetLastUsed(Anope::CurTime); + + /* don't update access last seen here, this isn't the user requesting access */ + + return group; +} + +unsigned ChannelImpl::GetAccessCount() +{ + return GetRefs<ChanServ::ChanAccess *>(ChanServ::chanaccess).size(); +} + +unsigned ChannelImpl::GetDeepAccessCount() const +{ + return 0; +#if 0 + 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->GetChannel(); + if (!channels.count(ci)) + { + channels.count(ci); + count += ci->GetAccessCount(); + } + } + return count; +#endif +} + +void ChannelImpl::ClearAccess() +{ + for (ChanServ::ChanAccess *a : GetRefs<ChanServ::ChanAccess *>(ChanServ::chanaccess)) + a->Delete(); +} + +AutoKick *ChannelImpl::AddAkick(const Anope::string &user, NickServ::Account *akicknc, const Anope::string &reason, time_t t, time_t lu) +{ + AutoKick *ak = ::autokick.Create(); + ak->SetChannel(this); + ak->SetAccount(akicknc); + ak->SetReason(reason); + ak->SetCreator(user); + ak->SetAddTime(t); + ak->SetLastUsed(lu); + + return ak; +} + +AutoKick *ChannelImpl::AddAkick(const Anope::string &user, const Anope::string &mask, const Anope::string &reason, time_t t, time_t lu) +{ + AutoKick *ak = ::autokick.Create(); + ak->SetChannel(this); + ak->SetMask(mask); + ak->SetReason(reason); + ak->SetCreator(user); + ak->SetAddTime(t); + ak->SetLastUsed(lu); + + return ak; +} + +AutoKick *ChannelImpl::GetAkick(unsigned index) +{ + std::vector<AutoKick *> a = GetRefs<AutoKick *>(autokick); + return a.size() > index ? a[index] : nullptr; +} + +unsigned ChannelImpl::GetAkickCount() +{ + std::vector<AutoKick *> t = GetRefs<AutoKick *>(autokick); + return t.size(); +} + +void ChannelImpl::ClearAkick() +{ + for (AutoKick *ak : GetRefs<AutoKick *>(autokick)) + ak->Delete(); +} + +int16_t ChannelImpl::GetLevel(const Anope::string &priv) +{ + for (ChanServ::Level *l : this->GetRefs<ChanServ::Level *>(ChanServ::level)) + if (l->GetName() == priv) + return l->GetLevel(); + + ChanServ::Privilege *p = ChanServ::service ? ChanServ::service->FindPrivilege(priv) : nullptr; + if (!p) + { + Log(LOG_DEBUG) << "Unknown privilege " + priv; + return ChanServ::ACCESS_INVALID; + } + + return p->level; +} + +void ChannelImpl::SetLevel(const Anope::string &priv, int16_t level) +{ + for (ChanServ::Level *l : this->GetRefs<ChanServ::Level *>(ChanServ::level)) + if (l->GetName() == priv) + { + l->SetLevel(level); + return; + } + + ChanServ::Privilege *p = ChanServ::service ? ChanServ::service->FindPrivilege(priv) : nullptr; + if (!p) + { + Log(LOG_DEBUG) << "Unknown privilege " + priv; + return; + } + + ChanServ::Level *l = ChanServ::level.Create(); + l->SetChannel(this); + l->SetName(priv); + l->SetLevel(level); +} + +void ChannelImpl::RemoveLevel(const Anope::string &priv) +{ + for (ChanServ::Level *l : this->GetRefs<ChanServ::Level *>(ChanServ::level)) + if (l->GetName() == priv) + { + l->Delete(); + return; + } +} + +void ChannelImpl::ClearLevels() +{ + for (ChanServ::Level *l : this->GetRefs<ChanServ::Level *>(ChanServ::level)) + l->Delete(); +} + +Anope::string ChannelImpl::GetIdealBan(User *u) +{ + int bt = this->GetBanType(); + 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; +} + diff --git a/modules/chanserv/main/channel.h b/modules/chanserv/main/channel.h new file mode 100644 index 000000000..86e42a8f9 --- /dev/null +++ b/modules/chanserv/main/channel.h @@ -0,0 +1,68 @@ + + +class ChannelImpl : public ChanServ::Channel +{ + public: + ChannelImpl(Serialize::TypeBase *type) : ChanServ::Channel(type) { } + ChannelImpl(Serialize::TypeBase *type, Serialize::ID id) : ChanServ::Channel(type, id) { } + ChannelImpl(Serialize::TypeBase *type, const Anope::string &chname); + ~ChannelImpl(); + void Delete() override; + + Anope::string GetName() override; + void SetName(const Anope::string &) override; + + Anope::string GetDesc() override; + void SetDesc(const Anope::string &) override; + + time_t GetTimeRegistered() override; + void SetTimeRegistered(const time_t &) override; + + time_t GetLastUsed() override; + void SetLastUsed(const time_t &) override; + + Anope::string GetLastTopic() override; + void SetLastTopic(const Anope::string &) override; + + Anope::string GetLastTopicSetter() override; + void SetLastTopicSetter(const Anope::string &) override; + + time_t GetLastTopicTime() override; + void SetLastTopicTime(const time_t &) override; + + int16_t GetBanType() override; + void SetBanType(const int16_t &) override; + + time_t GetBanExpire() override; + void SetBanExpire(const time_t &) override; + + BotInfo *GetBI() override; + void SetBI(BotInfo *) override; + + ServiceBot *GetBot() override; + void SetBot(ServiceBot *) override; + + MemoServ::MemoInfo *GetMemos() override; + + bool IsFounder(const User *user) override; + void SetFounder(NickServ::Account *nc) override; + NickServ::Account *GetFounder() override; + void SetSuccessor(NickServ::Account *nc) override; + NickServ::Account *GetSuccessor() override; + ChanServ::ChanAccess *GetAccess(unsigned index) /*const*/ override; + ChanServ::AccessGroup AccessFor(const User *u, bool = true) override; + ChanServ::AccessGroup AccessFor(NickServ::Account *nc, bool = true) override; + unsigned GetAccessCount()/* const*/ override; + unsigned GetDeepAccessCount() const 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) override; + unsigned GetAkickCount() override; + void ClearAkick() override; + int16_t GetLevel(const Anope::string &priv) 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) override; +}; diff --git a/modules/chanserv/main/channeltype.cpp b/modules/chanserv/main/channeltype.cpp new file mode 100644 index 000000000..4143285a8 --- /dev/null +++ b/modules/chanserv/main/channeltype.cpp @@ -0,0 +1,45 @@ +#include "module.h" +#include "channeltype.h" + +ChannelType::ChannelType(Module *me) : Serialize::Type<ChannelImpl>(me, "ChannelInfo") + , name(this, "name") + , desc(this, "desc") + , time_registered(this, "time_registered") + , last_used(this, "last_used") + , last_topic(this, "last_topic") + , last_topic_setter(this, "last_topic_setter") + , last_topic_time(this, "last_topic_time") + , bantype(this, "bantype") + , banexpire(this, "banexpire") + , founder(this, "founder") + , successor(this, "successor") + , bi(this, "bi") +{ + +} + +void ChannelType::Name::SetField(ChanServ::Channel *c, const Anope::string &value) +{ + ChanServ::registered_channel_map& map = ChanServ::service->GetChannels(); + map.erase(GetField(c)); + + Serialize::Field<ChanServ::Channel, Anope::string>::SetField(c, value); + + map[value] = c; +} + +ChanServ::Channel *ChannelType::FindChannel(const Anope::string &chan) +{ + Serialize::ID id; + EventReturn result = Event::OnSerialize(&Event::SerializeEvents::OnSerializeFind, this, &this->name, chan, id); + if (result == EVENT_ALLOW) + return RequireID(id); + + // fall back + ChanServ::registered_channel_map& map = ChanServ::service->GetChannels(); + auto it = map.find(chan); + if (it != map.end()) + return it->second; + return nullptr; +} + diff --git a/modules/chanserv/main/channeltype.h b/modules/chanserv/main/channeltype.h new file mode 100644 index 000000000..7bc22a8f6 --- /dev/null +++ b/modules/chanserv/main/channeltype.h @@ -0,0 +1,34 @@ +#include "channel.h" + +class ChannelType : public Serialize::Type<ChannelImpl> +{ + public: + /* Channel name */ + struct Name : Serialize::Field<ChanServ::Channel, Anope::string> + { + using Serialize::Field<ChanServ::Channel, Anope::string>::Field; + + void SetField(ChanServ::Channel *c, const Anope::string &value) override; + } name; + Serialize::Field<ChanServ::Channel, Anope::string> desc; + Serialize::Field<ChanServ::Channel, time_t> time_registered; + Serialize::Field<ChanServ::Channel, time_t> last_used; + + Serialize::Field<ChanServ::Channel, Anope::string> last_topic; + Serialize::Field<ChanServ::Channel, Anope::string> last_topic_setter; + Serialize::Field<ChanServ::Channel, time_t> last_topic_time; + + Serialize::Field<ChanServ::Channel, int16_t> bantype; + Serialize::Field<ChanServ::Channel, time_t> banexpire; + + /* Channel founder */ + Serialize::ObjectField<ChanServ::Channel, NickServ::Account *> founder; + /* Who gets the channel if the founder nick is dropped or expires */ + Serialize::ObjectField<ChanServ::Channel, NickServ::Account *> successor; + + Serialize::ObjectField<ChanServ::Channel, BotInfo *> bi; + + ChannelType(Module *); + + ChanServ::Channel *FindChannel(const Anope::string &); +}; diff --git a/modules/chanserv/main/chanserv.cpp b/modules/chanserv/main/chanserv.cpp new file mode 100644 index 000000000..420051252 --- /dev/null +++ b/modules/chanserv/main/chanserv.cpp @@ -0,0 +1,587 @@ +/* ChanServ core 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 "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" +#include "channeltype.h" +#include "leveltype.h" +#include "modetype.h" +#include "chanaccesstype.h" +#include "chanaccess.h" + +class ChanServCore : public Module + , public ChanServ::ChanServService + , public EventHook<Event::ChannelCreate> + , public EventHook<Event::BotDelete> + , public EventHook<Event::BotPrivmsg> + , public EventHook<Event::DelCore> + , public EventHook<Event::DelChan> + , public EventHook<Event::Help> + , public EventHook<Event::CheckModes> + , public EventHook<Event::CreateChan> + , public EventHook<Event::CanSet> + , public EventHook<Event::ChannelSync> + , public EventHook<Event::Log> + , public EventHook<Event::ExpireTick> + , public EventHook<Event::CheckDelete> + , public EventHook<Event::PreUplinkSync> + , public EventHook<Event::ChanRegistered> + , public EventHook<Event::JoinChannel> + , public EventHook<Event::ChannelModeSet> + , public EventHook<Event::ChanInfo> + , public EventHook<Event::SetCorrectModes> +{ + Reference<ServiceBot> ChanServ; + std::vector<Anope::string> defaults; + ExtensibleItem<bool> inhabit; + ExtensibleRef<bool> persist;//XXX? + bool always_lower; + EventHandlers<ChanServ::Event::PreChanExpire> OnPreChanExpire; + EventHandlers<ChanServ::Event::ChanExpire> OnChanExpire; + std::vector<ChanServ::Privilege> Privileges; + ChanServ::registered_channel_map registered_channels; + ChannelType channel_type; + ChanAccessType chanaccess_type; + LevelType level_type; + CSModeType mode_type; + + public: + ChanServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR) + , ChanServService(this) + , inhabit(this, "inhabit") + , persist("PERSIST") + , always_lower(false) + , OnPreChanExpire(this) + , OnChanExpire(this) + , channel_type(this) + , chanaccess_type(this, "ChanAccess") + , level_type(this) + , mode_type(this) + { + } + + ChanServ::Channel *Find(const Anope::string &name) override + { + return channel_type.FindChannel(name); + } + + 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 + * after kicking the last user in a channel + */ + class ChanServTimer : public Timer + { + Reference<ServiceBot> &ChanServ; + ExtensibleItem<bool> &inhabit; + Reference<Channel> c; + + public: + /** Constructor + * @param chan The channel + */ + ChanServTimer(Reference<ServiceBot> &cs, ExtensibleItem<bool> &i, Module *m, Channel *chan) : Timer(m, Config->GetModule(m)->Get<time_t>("inhabit", "15s")), ChanServ(cs), inhabit(i), c(chan) + { + if (!ChanServ || !c) + return; + inhabit.Set(c, true); + if (!c->ci || !c->ci->GetBot()) + ChanServ->Join(c); + else if (!c->FindUser(c->ci->GetBot())) + c->ci->GetBot()->Join(c); + + /* Set +ntsi to prevent rejoin */ + c->SetMode(NULL, "NOEXTERNAL"); + c->SetMode(NULL, "TOPIC"); + c->SetMode(NULL, "SECRET"); + c->SetMode(NULL, "INVITE"); + } + + /** Called when the delay is up + * @param The current time + */ + void Tick(time_t) override + { + if (!c) + return; + + inhabit.Unset(c); + + /* In the event we don't part */ + c->RemoveMode(NULL, "SECRET"); + c->RemoveMode(NULL, "INVITE"); + + if (!c->ci || !c->ci->GetBot()) + { + if (ChanServ) + ChanServ->Part(c); + } + /* If someone has rejoined this channel in the meantime, don't part the bot */ + else if (c->users.size() <= 1) + c->ci->GetBot()->Part(c); + } + }; + + if (inhabit.HasExt(c)) + return; + + 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->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(); + } + + void OnReload(Configuration::Conf *conf) override + { + const Anope::string &channick = conf->GetModule(this)->Get<Anope::string>("client"); + + if (channick.empty()) + throw ConfigException(Module::name + ": <client> must be defined"); + + ServiceBot *bi = ServiceBot::Find(channick, true); + if (!bi) + throw ConfigException(Module::name + ": no bot named " + channick); + + ChanServ = bi; + + ClearPrivileges(); + for (int i = 0; i < conf->CountBlock("privilege"); ++i) + { + Configuration::Block *privilege = conf->GetBlock("privilege", i); + + const Anope::string &nname = privilege->Get<Anope::string>("name"), + &desc = privilege->Get<Anope::string>("desc"); + int rank = privilege->Get<int>("rank"); + Anope::string value = privilege->Get<Anope::string>("level"); + int level; + if (value.equals_ci("founder")) + level = ChanServ::ACCESS_FOUNDER; + else if (value.equals_ci("disabled")) + level = ChanServ::ACCESS_INVALID; + else + level = privilege->Get<int>("level"); + + AddPrivilege(ChanServ::Privilege(nname, desc, rank, level)); + } + + spacesepstream(conf->GetModule(this)->Get<Anope::string>("defaults", "greet fantasy")).GetTokens(defaults); + if (defaults.empty()) + { + defaults.push_back("KEEPTOPIC"); + defaults.push_back("CS_SECURE"); + defaults.push_back("SECUREFOUNDER"); + defaults.push_back("SIGNKICK"); + } + else if (defaults[0].equals_ci("none")) + defaults.clear(); |
