summaryrefslogtreecommitdiff
path: root/modules/chanserv/main
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2015-12-14 16:52:24 -0500
committerAdam <Adam@anope.org>2015-12-14 16:52:24 -0500
commit6302f980fe6dad83aab7d2dc1046dadea5ffd939 (patch)
tree4c27d33f55fc32ce34827977932dac4b3e5ceedd /modules/chanserv/main
parent64dac60071fab652745a6e7a06cf6b7bdbbd3625 (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.txt1
-rw-r--r--modules/chanserv/main/chanaccess.cpp127
-rw-r--r--modules/chanserv/main/chanaccess.h30
-rw-r--r--modules/chanserv/main/chanaccesstype.h21
-rw-r--r--modules/chanserv/main/channel.cpp429
-rw-r--r--modules/chanserv/main/channel.h68
-rw-r--r--modules/chanserv/main/channeltype.cpp45
-rw-r--r--modules/chanserv/main/channeltype.h34
-rw-r--r--modules/chanserv/main/chanserv.cpp587
-rw-r--r--modules/chanserv/main/level.cpp33
-rw-r--r--modules/chanserv/main/level.h16
-rw-r--r--modules/chanserv/main/leveltype.h16
-rw-r--r--modules/chanserv/main/mode.cpp33
-rw-r--r--modules/chanserv/main/mode.h17
-rw-r--r--modules/chanserv/main/modetype.h15
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();