diff options
-rw-r--r-- | include/config.h | 8 | ||||
-rw-r--r-- | include/modules/sql.h | 4 | ||||
-rw-r--r-- | include/serialize.h | 76 | ||||
-rw-r--r-- | include/users.h | 1 | ||||
-rw-r--r-- | include/xline.h | 2 | ||||
-rw-r--r-- | modules/botserv/assign.cpp | 4 | ||||
-rw-r--r-- | modules/botserv/bot.cpp | 26 | ||||
-rw-r--r-- | modules/botserv/info.cpp | 7 | ||||
-rw-r--r-- | modules/botserv/set.cpp | 2 | ||||
-rw-r--r-- | modules/chanserv/main/channeltype.cpp | 8 | ||||
-rw-r--r-- | modules/chanserv/main/channeltype.h | 2 | ||||
-rw-r--r-- | modules/chanserv/main/chanserv.cpp | 16 | ||||
-rw-r--r-- | modules/database/old.cpp | 4 | ||||
-rw-r--r-- | modules/database/sql.cpp | 184 | ||||
-rw-r--r-- | modules/extra/mysql.cpp | 82 | ||||
-rw-r--r-- | modules/extra/sqlite.cpp | 124 | ||||
-rw-r--r-- | modules/nickserv/cert.cpp | 19 | ||||
-rw-r--r-- | modules/nickserv/main/accounttype.cpp | 13 | ||||
-rw-r--r-- | modules/nickserv/main/accounttype.h | 2 | ||||
-rw-r--r-- | modules/nickserv/main/nickserv.cpp | 9 | ||||
-rw-r--r-- | modules/nickserv/main/nicktype.cpp | 9 | ||||
-rw-r--r-- | modules/nickserv/main/nicktype.h | 2 | ||||
-rw-r--r-- | src/bots.cpp | 21 | ||||
-rw-r--r-- | src/config.cpp | 169 | ||||
-rw-r--r-- | src/init.cpp | 3 | ||||
-rw-r--r-- | src/service_manager.cpp | 8 | ||||
-rw-r--r-- | src/xline.cpp | 3 |
27 files changed, 426 insertions, 382 deletions
diff --git a/include/config.h b/include/config.h index dccadbe79..b6b36b726 100644 --- a/include/config.h +++ b/include/config.h @@ -102,8 +102,9 @@ namespace Configuration struct Usermode; struct Channelmode; - struct CoreExport Conf : Block + class CoreExport Conf : public Block { + public: /* options:readtimeout */ time_t ReadTimeout; /* options:useprivmsg */ @@ -162,6 +163,11 @@ namespace Configuration ServiceBot *GetClient(const Anope::string &name); Block *GetCommand(CommandSource &); + + void LoadBots(); + void ApplyBots(); + + void LoadOpers(); }; struct Uplink diff --git a/include/modules/sql.h b/include/modules/sql.h index 2e84db152..6770f407e 100644 --- a/include/modules/sql.h +++ b/include/modules/sql.h @@ -202,8 +202,8 @@ namespace SQL virtual std::vector<Query> InitSchema(const Anope::string &prefix) anope_abstract; virtual std::vector<Query> Replace(const Anope::string &table, const Query &, const std::set<Anope::string> &) anope_abstract; - virtual std::vector<Query> CreateTable(const Anope::string &prefix, const Anope::string &table) anope_abstract; - virtual std::vector<Query> AlterTable(const Anope::string &, const Anope::string &table, const Anope::string &field, bool object) anope_abstract; + virtual std::vector<Query> CreateTable(const Anope::string &prefix, Serialize::TypeBase *) anope_abstract; + virtual std::vector<Query> AlterTable(const Anope::string &, Serialize::TypeBase *, Serialize::FieldBase *) anope_abstract; virtual std::vector<Query> CreateIndex(const Anope::string &table, const Anope::string &field) anope_abstract; virtual Query BeginTransaction() anope_abstract; diff --git a/include/serialize.h b/include/serialize.h index 1d0fb9400..8f35e61c6 100644 --- a/include/serialize.h +++ b/include/serialize.h @@ -49,6 +49,9 @@ namespace Serialize inline T GetObject(); template<typename T> + inline std::vector<T> GetObjects_(TypeBase *); + + template<typename T> inline std::vector<T> GetObjects(const Anope::string &name); template<typename T> @@ -235,29 +238,6 @@ class CoreExport Serialize::TypeBase : public Service */ const Anope::string &GetName() { return this->name; } - /** - * Get all objects of the given type - */ - template<typename T> - std::vector<T> List() - { - std::vector<ID> ids; - EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializeList, this, ids); - if (result == EVENT_ALLOW) - { - std::vector<T> o; - for (ID id : ids) - { - Object *s = Require(id); - if (s) - o.push_back(anope_dynamic_static_cast<T>(s)); - } - return o; - } - - return GetObjects<T>(); - } - /** Create a new object of this type. */ virtual Object *Create() anope_abstract; @@ -306,7 +286,10 @@ class Serialize::Type : public Base return new T(this, id); if (s->GetSerializableType() != this) + { + Log(LOG_DEBUG) << "Mismatch for required id " << id << ", is of type " << s->GetSerializableType()->GetName() << " but wants " << this->GetName(); return nullptr; + } return static_cast<T *>(s); } @@ -387,6 +370,8 @@ class Serialize::FieldBase : public Service */ bool depends; + bool object = false; + FieldBase(Module *, const Anope::string &, const Anope::string &, bool); virtual ~FieldBase(); void Unregister(); @@ -592,7 +577,10 @@ class Serialize::Field : public CommonFieldBase<TypeImpl, T> // module returned us data, so we unserialize it T t2 = this->Unserialize(value); + // should cache the default value somehow, but can't differentiate not cached from cached and default + // Cache + OnSet(s, t2); this->Set_(s, t2); return t2; @@ -609,11 +597,18 @@ class Serialize::Field : public CommonFieldBase<TypeImpl, T> SetField(this->Upcast(s), value); } - virtual void SetField(TypeImpl *s, const T &value) + /** + * Override to hook to changes in the internally + * cached value + */ + virtual void OnSet(TypeImpl *s, const T &value) { } + + void SetField(TypeImpl *s, const T &value) { Anope::string strvalue = this->Serialize(value); EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializeSet, s, this, strvalue); + OnSet(s, value); this->Set_(s, value); } @@ -697,10 +692,12 @@ class Serialize::ObjectField : public CommonFieldBase<TypeImpl, T> public: ObjectField(TypeBase *t, const Anope::string &n, bool d = false) : CommonFieldBase<TypeImpl, T>(t, n, d) { + this->object = true; } ObjectField(TypeBase *t, const Anope::string &n, T TypeImpl::*field, bool d = false) : CommonFieldBase<TypeImpl, T>(t, n, field, d) { + this->object = true; } T GetField(TypeImpl *s) @@ -723,6 +720,7 @@ class Serialize::ObjectField : public CommonFieldBase<TypeImpl, T> T t2 = result == EVENT_ALLOW ? static_cast<T>(base->Require(sid)) : nullptr; + OnSet(s, t2); this->Set_(s, t2); return t2; @@ -739,7 +737,9 @@ class Serialize::ObjectField : public CommonFieldBase<TypeImpl, T> SetField(this->Upcast(s), value); } - virtual void SetField(TypeImpl *s, T value) + virtual void OnSet(TypeImpl *s, T value) { } + + void SetField(TypeImpl *s, T value) { EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializeSetSerializable, s, this, value); @@ -747,6 +747,7 @@ class Serialize::ObjectField : public CommonFieldBase<TypeImpl, T> if (old != nullptr && *old != nullptr) s->RemoveEdge(*old, this); + OnSet(s, value); this->Set_(s, value); if (value != nullptr) @@ -812,13 +813,34 @@ T Serialize::GetObject() } template<typename T> +std::vector<T> Serialize::GetObjects_(TypeBase *type) +{ + std::vector<T> o; + std::vector<ID> ids; + EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializeList, type, ids); + if (result == EVENT_ALLOW) + { + for (ID id : ids) + { + Object *s = type->Require(id); + if (s) + o.push_back(anope_dynamic_static_cast<T>(s)); + } + return o; + } + + std::transform(type->objects.begin(), type->objects.end(), std::back_inserter(o), [](Object *e) { return anope_dynamic_static_cast<T>(e); }); + return o; +} + +template<typename T> std::vector<T> Serialize::GetObjects(const Anope::string &name) { std::vector<T> objs; for (TypeBase *t : GetTypes(name)) - for (Object *s : t->objects) - objs.push_back(anope_dynamic_static_cast<T>(s)); + for (T obj : GetObjects_<T>(t)) + objs.push_back(obj); return objs; } diff --git a/include/users.h b/include/users.h index dacb7045e..be4ee2a39 100644 --- a/include/users.h +++ b/include/users.h @@ -38,7 +38,6 @@ extern CoreExport int OperCount; enum class UserType { USER, - //LOCAL_USER, BOT }; diff --git a/include/xline.h b/include/xline.h index 87b64d1da..05ddbe2d3 100644 --- a/include/xline.h +++ b/include/xline.h @@ -87,7 +87,7 @@ class XLineType : public Serialize::Type<XLine> { using Serialize::Field<XLine, Anope::string>::Field; - void SetField(XLine *s, const Anope::string &value) override; + void OnSet(XLine *s, const Anope::string &value) override; } mask; Serialize::Field<XLine, Anope::string> by, reason, id; Serialize::Field<XLine, time_t> created, expires; diff --git a/modules/botserv/assign.cpp b/modules/botserv/assign.cpp index eb6b8da10..a26b869fe 100644 --- a/modules/botserv/assign.cpp +++ b/modules/botserv/assign.cpp @@ -67,7 +67,7 @@ class CommandBSAssign : public Command return; } - if (bi->bi->GetOperOnly() && !source.HasPriv("botserv/administration")) + if (bi->bi && bi->bi->GetOperOnly() && !source.HasPriv("botserv/administration")) { source.Reply(_("Access denied. Bot \002{0}\002 is for operators only."), bi->nick); return; @@ -265,7 +265,7 @@ class BSAssign : public Module return; } - if (bi->bi->GetOperOnly() && !source->HasPriv("botserv/administration")) + if (bi->bi && bi->bi->GetOperOnly() && !source->HasPriv("botserv/administration")) { targ->SendMessage(bi, _("Access denied. Bot \002{0}\002 is for operators only."), bi->nick); return; diff --git a/modules/botserv/bot.cpp b/modules/botserv/bot.cpp index c93c4cf50..2e33b7ccb 100644 --- a/modules/botserv/bot.cpp +++ b/modules/botserv/bot.cpp @@ -93,6 +93,16 @@ class CommandBSBot : public Command ServiceBot *bi = new ServiceBot(nick, user, host, real); + BotInfo *botinfo = Serialize::New<BotInfo *>(); + botinfo->SetNick(nick); + botinfo->SetUser(user); + botinfo->SetHost(host); + botinfo->SetRealName(real); + botinfo->SetCreated(Anope::CurTime); + + bi->bi = botinfo; + botinfo->bot = bi; + Log(LOG_ADMIN, source, this) << "ADD " << bi->GetMask() << " " << bi->realname; source.Reply(_("\002{0}!{1}@{2}\002 (\002{3}\002) added to the bot list."), bi->nick, bi->GetIdent(), bi->host, bi->realname); @@ -121,7 +131,7 @@ class CommandBSBot : public Command return; } - if (bi->bi->conf) + if (bi->bi && bi->bi->conf) { source.Reply(_("Bot \002{0}\002 is not changeable because it is configured in services configuration."), bi->nick.c_str()); return; @@ -226,23 +236,27 @@ class CommandBSBot : public Command if (!nick.equals_cs(bi->nick)) { bi->SetNewNick(nick); - bi->bi->SetNick(nick); + if (bi->bi != nullptr) + bi->bi->SetNick(nick); } if (!user.equals_cs(bi->GetIdent())) { bi->SetIdent(user); - bi->bi->SetUser(user); + if (bi->bi != nullptr) + bi->bi->SetUser(user); } if (!host.equals_cs(bi->host)) { bi->host = host; - bi->bi->SetHost(host); + if (bi->bi != nullptr) + bi->bi->SetHost(host); } if (real.equals_cs(bi->realname)) { bi->realname = real; - bi->bi->SetRealName(real); + if (bi->bi != nullptr) + bi->bi->SetRealName(real); } if (!user.empty()) @@ -271,7 +285,7 @@ class CommandBSBot : public Command return; } - if (bi->bi->conf) + if (bi->bi && bi->bi->conf) { source.Reply(_("Bot \002{0}\002 is can not be deleted because it is configured in services configuration."), bi->nick); return; diff --git a/modules/botserv/info.cpp b/modules/botserv/info.cpp index 94b1bbbd7..4de86643f 100644 --- a/modules/botserv/info.cpp +++ b/modules/botserv/info.cpp @@ -41,8 +41,11 @@ class CommandBSInfo : public Command source.Reply(_("Information for bot \002%s\002:"), bi->nick.c_str()); info[_("Mask")] = bi->GetIdent() + "@" + bi->host; info[_("Real name")] = bi->realname; - info[_("Created")] = Anope::strftime(bi->bi->GetCreated(), source.GetAccount()); - info[_("Options")] = bi->bi->GetOperOnly() ? _("Private") : _("None"); + if (bi->bi) + { + info[_("Created")] = Anope::strftime(bi->bi->GetCreated(), source.GetAccount()); + info[_("Options")] = bi->bi->GetOperOnly() ? _("Private") : _("None"); + } info[_("Used on")] = stringify(bi->GetChannelCount()) + " channel(s)"; EventManager::Get()->Dispatch(&Event::ServiceBotEvent::OnServiceBot, source, bi, ci, info); diff --git a/modules/botserv/set.cpp b/modules/botserv/set.cpp index 47c5337d2..bb432e3f0 100644 --- a/modules/botserv/set.cpp +++ b/modules/botserv/set.cpp @@ -174,7 +174,7 @@ class CommandBSSetPrivate : public Command source.Reply(_("Services are in read-only mode. Any changes made may not persist.")); ServiceBot *bi = ServiceBot::Find(nick, true); - if (bi == NULL) + if (bi == NULL || !bi->bi) { source.Reply(_("Bot \002{0}\002 does not exist."), nick); return; diff --git a/modules/chanserv/main/channeltype.cpp b/modules/chanserv/main/channeltype.cpp index fa5e03e4c..37c290ef1 100644 --- a/modules/chanserv/main/channeltype.cpp +++ b/modules/chanserv/main/channeltype.cpp @@ -37,12 +37,12 @@ ChannelType::ChannelType(Module *me) : Serialize::Type<ChannelImpl>(me) } -void ChannelType::Name::SetField(ChannelImpl *c, const Anope::string &value) +void ChannelType::Name::OnSet(ChannelImpl *c, const Anope::string &value) { ChanServ::registered_channel_map& map = ChanServ::service->GetChannels(); - map.erase(GetField(c)); - - Serialize::Field<ChannelImpl, Anope::string>::SetField(c, value); + Anope::string *old = this->Get_(c); + if (old != nullptr) + map.erase(*old); map[value] = c; } diff --git a/modules/chanserv/main/channeltype.h b/modules/chanserv/main/channeltype.h index 95158427a..1f1c92201 100644 --- a/modules/chanserv/main/channeltype.h +++ b/modules/chanserv/main/channeltype.h @@ -27,7 +27,7 @@ class ChannelType : public Serialize::Type<ChannelImpl> { using Serialize::Field<ChannelImpl, Anope::string>::Field; - void SetField(ChannelImpl *c, const Anope::string &value) override; + void OnSet(ChannelImpl *c, const Anope::string &value) override; } name; Serialize::Field<ChannelImpl, Anope::string> desc; Serialize::Field<ChannelImpl, time_t> time_registered; diff --git a/modules/chanserv/main/chanserv.cpp b/modules/chanserv/main/chanserv.cpp index ec2e8a623..dc44173a0 100644 --- a/modules/chanserv/main/chanserv.cpp +++ b/modules/chanserv/main/chanserv.cpp @@ -322,7 +322,7 @@ class ChanServCore : public Module { ::Log(LOG_NORMAL, "chanserv/drop", ChanServ) << "Deleting channel " << ci->GetName() << " owned by deleted nick " << nc->GetDisplay(); - delete ci; + ci->Delete(); continue; } } @@ -330,6 +330,7 @@ class ChanServCore : public Module if (ci->GetSuccessor() == nc) ci->SetSuccessor(NULL); +#warning "these arent necessary?" /* are these necessary? */ for (unsigned j = 0; j < ci->GetAccessCount(); ++j) { @@ -338,7 +339,7 @@ class ChanServCore : public Module if (anc && anc == nc) { - delete ca; + ca->Delete(); break; } } @@ -348,7 +349,7 @@ class ChanServCore : public Module AutoKick *ak = ci->GetAkick(j); if (ak->GetAccount() == nc) { - delete ak; + ak->Delete(); break; } } @@ -359,6 +360,7 @@ class ChanServCore : public Module { /* remove access entries that are this channel */ +#warning "also not necessary?" for (ChanServ::Channel *c : ci->GetRefs<ChanServ::Channel *>()) { for (unsigned j = 0; j < c->GetAccessCount(); ++j) @@ -367,7 +369,7 @@ class ChanServCore : public Module if (a->Mask().equals_ci(ci->GetName())) { - delete a; + a->Delete(); break; } } @@ -465,7 +467,7 @@ class ChanServCore : public Module if (!chanserv_expire || Anope::NoExpire || Anope::ReadOnly) return; - for (ChanServ::Channel *ci : channel_type.List<ChanServ::Channel *>()) + for (ChanServ::Channel *ci : Serialize::GetObjects<ChanServ::Channel *>()) { bool expire = false; @@ -488,7 +490,7 @@ class ChanServCore : public Module { ::Log(LOG_NORMAL, "chanserv/expire", ChanServ) << "Expiring channel " << ci->GetName() << " (founder: " << (ci->GetFounder() ? ci->GetFounder()->GetDisplay() : "(none)") << ")"; EventManager::Get()->Dispatch(&ChanServ::Event::ChanExpire::OnChanExpire, ci); - delete ci; + ci->Delete(); } } } @@ -505,7 +507,7 @@ class ChanServCore : public Module void OnPreUplinkSync(Server *serv) override { /* Find all persistent channels and create them, as we are about to finish burst to our uplink */ - for (ChanServ::Channel *ci : channel_type.List<ChanServ::Channel *>()) + for (ChanServ::Channel *ci : Serialize::GetObjects<ChanServ::Channel *>()) { if (ci->HasFieldS("PERSIST")) { diff --git a/modules/database/old.cpp b/modules/database/old.cpp index d63b2c4d8..61be22e9d 100644 --- a/modules/database/old.cpp +++ b/modules/database/old.cpp @@ -777,6 +777,10 @@ static void LoadBots() ServiceBot *bi = ServiceBot::Find(nick, true); if (!bi) bi = new ServiceBot(nick, user, host, real); + + if (bi->bi == nullptr) + bi->bi = Serialize::New<BotInfo *>(); + bi->bi->SetCreated(created); if (flags & OLD_BI_PRIVATE) diff --git a/modules/database/sql.cpp b/modules/database/sql.cpp index d7ed1963a..aa1c94bc0 100644 --- a/modules/database/sql.cpp +++ b/modules/database/sql.cpp @@ -22,7 +22,7 @@ using namespace SQL; -class DBMySQL : public Module, public Pipe +class DBSQL : public Module, public Pipe , public EventHook<Event::SerializeEvents> { private: @@ -58,8 +58,6 @@ class DBMySQL : public Module, public Pipe SQL->RunQuery(q); } - Log(LOG_DEBUG_2) << query.Unsafe(); - return SQL->RunQuery(query); } @@ -85,7 +83,7 @@ class DBMySQL : public Module, public Pipe } public: - DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) + DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) , EventHook<Event::SerializeEvents>(this) { } @@ -129,10 +127,10 @@ class DBMySQL : public Module, public Pipe StartTransaction(); - for (Query &q : SQL->CreateTable(prefix, type->GetName())) + for (Query &q : SQL->CreateTable(prefix, type)) Run(q); - for (Query &q : SQL->AlterTable(prefix, type->GetName(), field->serialize_name, false)) + for (Query &q : SQL->AlterTable(prefix, type, field)) Run(q); for (const Query &q : SQL->CreateIndex(prefix + type->GetName(), field->serialize_name)) @@ -150,6 +148,7 @@ class DBMySQL : public Module, public Pipe catch (const ConvertException &) { } + return EVENT_CONTINUE; } @@ -159,7 +158,7 @@ class DBMySQL : public Module, public Pipe StartTransaction(); Query query = "SELECT `" + field->serialize_name + "` FROM `" + prefix + object->GetSerializableType()->GetName() + "` WHERE `id` = @id@"; - query.SetValue("id", object->id); + query.SetValue("id", object->id, false); Result res = Run(query); if (res.Rows() == 0) @@ -169,6 +168,40 @@ class DBMySQL : public Module, public Pipe return true; } + void GetRefs(Serialize::Object *object, Serialize::TypeBase *type, std::vector<Serialize::Edge> &edges) + { + for (Serialize::FieldBase *field : type->GetFields()) + { + if (field->object) + { + Anope::string table = prefix + type->GetName(); + + Query query = "SELECT " + table + ".id FROM " + table + + " INNER JOIN " + prefix + "objects AS o ON " + + table + "." + field->serialize_name + " = o.id " + "WHERE o.id = @id@"; + + query.SetValue("id", object->id, false); + + Result res = Run(query); + for (int i = 0; i < res.Rows(); ++i) + { + Serialize::ID id = convertTo<Serialize::ID>(res.Get(i, "id")); + + Serialize::Object *other = type->Require(id); + if (other == nullptr) + { + Log(LOG_DEBUG) << "Unable to require id " << id << " type " << type->GetName(); + continue; + } + + // other type, other field, direction + edges.emplace_back(other, field, false); + } + } + } + } + public: EventReturn OnSerializeGet(Serialize::Object *object, Serialize::FieldBase *field, Anope::string &value) override { @@ -193,93 +226,16 @@ class DBMySQL : public Module, public Pipe edges.clear(); - Query query; - if (type) - query = "SELECT field," + prefix + "edges.id,other_id,j1.type,j2.type AS other_type FROM `" + prefix + "edges` " - "JOIN `" + prefix + "objects` AS j1 ON " + prefix + "edges.id = j1.id " - "JOIN `" + prefix + "objects` AS j2 ON " + prefix + "edges.other_id = j2.id " - "WHERE " - " (" + prefix + "edges.id = @id@ AND j2.type = @other_type@) " - "OR" - " (other_id = @id@ AND j1.type = @other_type@)"; + if (type == nullptr) + { + for (Serialize::TypeBase *type : Serialize::TypeBase::GetTypes()) + GetRefs(object, type, edges); + } else - query = "SELECT field," + prefix + "edges.id,other_id,j1.type,j2.type AS other_type FROM `" + prefix + "edges` " - "JOIN `" + prefix + "objects` AS j1 ON " + prefix + "edges.id = j1.id " - "JOIN `" + prefix + "objects` AS j2 ON " + prefix + "edges.other_id = j2.id " - "WHERE " + prefix + "edges.id = @id@ OR other_id = @id@"; - - query.SetValue("type", object->GetSerializableType()->GetName()); - query.SetValue("id", object->id); - if (type) - query.SetValue("other_type", type->GetName()); - - Result res = Run(query); - for (int i = 0; i < res.Rows(); ++i) { - Serialize::ID id = convertTo<Serialize::ID>(res.Get(i, "id")); // object edge is on - - if (id == object->id) - { - // we want other type, this is my edge - Anope::string t = res.Get(i, "other_type"); - Anope::string f = res.Get(i, "field"); - id = convertTo<Serialize::ID>(res.Get(i, "other_id")); - - Serialize::FieldBase *obj_field = object->GetSerializableType()->GetField(f); - if (obj_field == nullptr) - { - Log(LOG_DEBUG) << "Unable to find field " << f << " on " << object->GetSerializableType()->GetName(); - continue; - } - - Serialize::TypeBase *obj_type = Serialize::TypeBase::Find(t); - if (obj_type == nullptr) - { - Log(LOG_DEBUG) << "Unable to find type " << t; - continue; - } - - Serialize::Object *other = obj_type->Require(id); - if (other == nullptr) - { - Log(LOG_DEBUG) << "Unable to require id " << id << " type " << obj_type->GetName(); - continue; - } - - edges.emplace_back(other, obj_field, true); - } - else - { - // edge to me - Anope::string t = res.Get(i, "type"); - Anope::string f = res.Get(i, "field"); - - Serialize::TypeBase *obj_type = Serialize::TypeBase::Find(t); - if (obj_type == nullptr) - { - Log(LOG_DEBUG) << "Unable to find type " << t; - continue; - } - - Serialize::FieldBase *obj_field = obj_type->GetField(f); - if (obj_field == nullptr) - { - Log(LOG_DEBUG) << "Unable to find field " << f << " on " << obj_type->GetName(); - continue; - } - - Serialize::Object *other = obj_type->Require(id); - if (other == nullptr) - { - Log(LOG_DEBUG) << "Unable to require id " << id << " type " << obj_type->GetName(); - continue; - } - - // other type, other field, - edges.emplace_back(other, obj_field, false); - } + GetRefs(object, type, edges); } - + return EVENT_ALLOW; } @@ -288,7 +244,7 @@ class DBMySQL : public Module, public Pipe StartTransaction(); Query query = "SELECT `id` FROM `" + prefix + type->GetName() + "` WHERE `id` = @id@"; - query.SetValue("id", id); + query.SetValue("id", id, false); Result res = Run(query); if (res.Rows() == 0) return EVENT_CONTINUE; @@ -302,7 +258,7 @@ class DBMySQL : public Module, public Pipe Query query = "SELECT `" + field->serialize_name + "`,j1.type AS " + field->serialize_name + "_type FROM `" + prefix + object->GetSerializableType()->GetName() + "` " "JOIN `" + prefix + "objects` AS j1 ON " + prefix + object->GetSerializableType()->GetName() + "." + field->serialize_name + " = j1.id " "WHERE " + prefix + object->GetSerializableType()->GetName() + ".id = @id@"; - query.SetValue("id", object->id); + query.SetValue("id", object->id, false); Result res = Run(query); if (res.Rows() == 0) @@ -329,16 +285,16 @@ class DBMySQL : public Module, public Pipe StartTransaction(); - for (Query &q : SQL->CreateTable(prefix, object->GetSerializableType()->GetName())) + for (Query &q : SQL->CreateTable(prefix, object->GetSerializableType())) Run(q); - for (Query &q : SQL->AlterTable(prefix, object->GetSerializableType()->GetName(), field->serialize_name, is_object)) + for (Query &q : SQL->AlterTable(prefix, object->GetSerializableType(), field)) Run(q); Query q; - q.SetValue("id", object->id); + q.SetValue("id", object->id, false); if (value) - q.SetValue(field->serialize_name, *value); + q.SetValue(field->serialize_name, *value, !is_object); else q.SetNull(field->serialize_name); @@ -364,23 +320,10 @@ class DBMySQL : public Module, public Pipe { Anope::string v = stringify(value->id); DoSet(object, field, true, &v); - - Query query; - query.SetValue("field", field->serialize_name); - query.SetValue("id", object->id); - query.SetValue("other_id", value->id); - - for (Query &q : SQL->Replace(prefix + "edges", query, { "id", "field" })) - Run(q); } else { DoSet(object, field, true, nullptr); - - Query query("DELETE FROM `" + prefix + "edges` WHERE `id` = @id@ AND `field` = @field@"); - query.SetValue("id", object->id); - query.SetValue("field", field->serialize_name); - Run(query); } return EVENT_STOP; @@ -395,12 +338,6 @@ class DBMySQL : public Module, public Pipe EventReturn OnSerializeUnsetSerializable(Serialize::Object *object, Serialize::FieldBase *field) override { DoSet(object, field, true, nullptr); - - Query query("DELETE FROM `" + prefix + "edges` WHERE `id` = @id@ AND `field` = @field@"); - query.SetValue("id", object->id); - query.SetValue("field", field->serialize_name); - Run(query); - return EVENT_STOP; } @@ -408,7 +345,14 @@ class DBMySQL : public Module, public Pipe { SQL::Result::Value v; - return GetValue(object, field, v) && !v.null ? EVENT_STOP : EVENT_CONTINUE; + if (!GetValue(object, field, v)) + return EVENT_CONTINUE; + + if (v.null) + return EVENT_CONTINUE; + + field->UnserializeFromString(object, v.value); + return EVENT_STOP; } EventReturn OnSerializableGetId(Serialize::ID &id) override @@ -427,7 +371,7 @@ class DBMySQL : public Module, public Pipe StartTransaction(); Query q = Query("INSERT INTO `" + prefix + "objects` (`id`,`type`) VALUES (@id@, @type@)"); - q.SetValue("id", object->id); + q.SetValue("id", object->id, false); q.SetValue("type", object->GetSerializableType()->GetName()); Run(q); } @@ -436,10 +380,10 @@ class DBMySQL : public Module, public Pipe { StartTransaction(); - Query query("DELETE FROM `" + prefix + object->GetSerializableType()->GetName() + "` WHERE `id` = " + stringify(object->id)); + Query query("DELETE FROM `" + prefix + "objects` WHERE `id` = " + stringify(object->id)); Run(query); } }; -MODULE_INIT(DBMySQL) +MODULE_INIT(DBSQL) diff --git a/modules/extra/mysql.cpp b/modules/extra/mysql.cpp index b0aec1f6d..b5ff0c3d9 100644 --- a/modules/extra/mysql.cpp +++ b/modules/extra/mysql.cpp @@ -156,8 +156,8 @@ class MySQLService : public Provider std::vector<Query> InitSchema(const Anope::string &prefix) override; std::vector<Query> Replace(const Anope::string &table, const Query &, const std::set<Anope::string> &) override; - std::vector<Query> CreateTable(const Anope::string &prefix, const Anope::string &table) override; - std::vector<Query> AlterTable(const Anope::string &, const Anope::string &table, const Anope::string &field, bool) override; + std::vector<Query> CreateTable(const Anope::string &prefix, Serialize::TypeBase *) override; + std::vector<Query> AlterTable(const Anope::string &, Serialize::TypeBase *, Serialize::FieldBase *) override; std::vector<Query> CreateIndex(const Anope::string &table, const Anope::string &field) override; Query BeginTransaction() override; @@ -393,24 +393,7 @@ std::vector<Query> MySQLService::InitSchema(const Anope::string &prefix) { std::vector<Query> queries; - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + "id` (" - "`id` bigint(20) NOT NULL" - ") ENGINE=InnoDB"; - queries.push_back(t); - - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` bigint(20) NOT NULL PRIMARY KEY, `type` varchar(256)) ENGINE=InnoDB"; - queries.push_back(t); - - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "edges` (" - "`id` bigint(20) NOT NULL," - "`field` varchar(64) NOT NULL," - "`other_id` bigint(20) NOT NULL," - "PRIMARY KEY (`id`, `field`)," - "KEY `other` (`other_id`)," - "CONSTRAINT `edges_id_fk` FOREIGN KEY (`id`) REFERENCES `" + prefix + "objects` (`id`)," - "CONSTRAINT `edges_other_id_fk` FOREIGN KEY (`other_id`) REFERENCES `" + prefix + "objects` (`id`)" - ") ENGINE=InnoDB"; - queries.push_back(t); + queries.push_back(Query("CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` bigint(20) NOT NULL PRIMARY KEY, `type` TINYTEXT) ENGINE=InnoDB")); return queries; } @@ -441,41 +424,52 @@ std::vector<Query> MySQLService::Replace(const Anope::string &table, const Query return queries; } -std::vector<Query> MySQLService::CreateTable(const Anope::string &prefix, const Anope::string &table) +std::vector<Query> MySQLService::CreateTable(const Anope::string &prefix, Serialize::TypeBase *base) { std::vector<Query> queries; - if (active_schema.find(prefix + table) == active_schema.end()) + if (active_schema.find(prefix + base->GetName()) == active_schema.end()) { - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + table + "` (`id` bigint(20) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"; + Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + base->GetName() + "` (`id` bigint(20) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"; queries.push_back(t); - t = "ALTER TABLE `" + prefix + table + "` " - "ADD CONSTRAINT `" + table + "_id_fk` FOREIGN KEY (`id`) REFERENCES `" + prefix + "objects` (`id`)"; + t = "ALTER TABLE `" + prefix + base->GetName() + "` " + "ADD CONSTRAINT `" + base->GetName() + "_id_fk` FOREIGN KEY (`id`) REFERENCES `" + prefix + "objects` (`id`) ON DELETE CASCADE"; queries.push_back(t); - active_schema[prefix + table]; + active_schema[prefix + base->GetName()]; } return queries; } -std::vector<Query> MySQLService::AlterTable(const Anope::string &prefix, const Anope::string &table, const Anope::string &field, bool object) +std::vector<Query> MySQLService::AlterTable(const Anope::string &prefix, Serialize::TypeBase *type, Serialize::FieldBase *field) { + const Anope::string &table = type->GetName(); + std::vector<Query> queries; std::set<Anope::string> &s = active_schema[prefix + table]; - if (!s.count(field)) + if (!s.count(field->serialize_name)) { - Query column; - if (!object) - column = "ALTER TABLE `" + prefix + table + "` ADD COLUMN `" + field + "` TINYTEXT"; + Anope::string buf = "ALTER TABLE `" + prefix + table + "` ADD COLUMN `" + field->serialize_name + "` "; + + if (!field->object) + { + buf += "TINYTEXT"; + } else - column = "ALTER TABLE `" + prefix + table + "` " - "ADD COLUMN `" + field + "` bigint(20), " - "ADD CONSTRAINT `" + table + "_" + field + "_fk` FOREIGN KEY (`" + field + "`) REFERENCES `" + prefix + "objects` (`id`)"; - queries.push_back(column); - s.insert(field); + { + buf += "bigint(20), ADD CONSTRAINT `" + table + "_" + field->serialize_name + "_fk` FOREIGN KEY (`" + field->serialize_name + "`) REFERENCES `" + prefix + "objects` (`id`) ON DELETE "; + + if (field->depends) + buf += "CASCADE"; + else + buf += "SET NULL"; + } + + queries.push_back(Query(buf)); + s.insert(field->serialize_name); } return queries; @@ -508,25 +502,19 @@ Query MySQLService::Commit() Serialize::ID MySQLService::GetID(const Anope::string &prefix) { - Query query("SELECT `id` FROM `" + prefix + "id` FOR UPDATE"); - Serialize::ID id; + Query query = "SELECT `id` FROM `" + prefix + "objects` ORDER BY `id` DESC LIMIT 1"; + Serialize::ID id = 0; Result res = RunQuery(query); if (res.Rows()) { id = convertTo<Serialize::ID>(res.Get(0, "id")); - Query update_query("UPDATE `" + prefix + "id` SET `id` = `id` + 1"); - RunQuery(update_query); + /* next id */ + ++id; } - else - { - id = 0; - Query insert_query("INSERT INTO `" + prefix + "id` (id) VALUES(@id@)"); - insert_query.SetValue("id", 1); - RunQuery(insert_query); - } + /* OnSerializableCreate is called immediately after this which does the insert */ return id; } diff --git a/modules/extra/sqlite.cpp b/modules/extra/sqlite.cpp index 2cd93923b..b9966af5f 100644 --- a/modules/extra/sqlite.cpp +++ b/modules/extra/sqlite.cpp @@ -91,8 +91,8 @@ class SQLiteService : public Provider std::vector<Query> InitSchema(const Anope::string &prefix) override; std::vector<Query> Replace(const Anope::string &table, const Query &, const std::set<Anope::string> &) override; - std::vector<Query> CreateTable(const Anope::string &, const Anope::string &table) override; - std::vector<Query> AlterTable(const Anope::string &, const Anope::string &table, const Anope::string &field, bool) override; + std::vector<Query> CreateTable(const Anope::string &, Serialize::TypeBase *) override; + std::vector<Query> AlterTable(const Anope::string &, Serialize::TypeBase *, Serialize::FieldBase *) override; std::vector<Query> CreateIndex(const Anope::string &table, const Anope::string &field) override; Query BeginTransaction() override; @@ -210,7 +210,11 @@ Result SQLiteService::RunQuery(const Query &query) int err = sqlite3_prepare_v2(this->sql, real_query.c_str(), real_query.length(), &stmt, NULL); if (err != SQLITE_OK) { - return SQLiteResult(query, real_query, sqlite3_errmsg(this->sql)); + const char *msg = sqlite3_errmsg(this->sql); + + Log(LOG_DEBUG) << "sqlite: error in query " << real_query << ": " << msg; + + return SQLiteResult(query, real_query, msg); } int id = sqlite3_last_insert_rowid(this->sql); @@ -218,6 +222,11 @@ Result SQLiteService::RunQuery(const Query &query) sqlite3_finalize(stmt); + if (!result.GetError().empty()) + Log(LOG_DEBUG) << "sqlite: error executing query " << real_query << ": " << result.GetError(); + else + Log(LOG_DEBUG) << "sqlite: executed: " << real_query; + return result; } @@ -225,23 +234,9 @@ std::vector<Query> SQLiteService::InitSchema(const Anope::string &prefix) { std::vector<Query> queries; - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + "id` (" - "`id`" - ")"; - queries.push_back(t); - - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` PRIMARY KEY, `type`)"; - queries.push_back(t); + queries.push_back(Query("PRAGMA foreign_keys = ON")); - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "edges` (" - "`id`," - "`field`," - "`other_id`," - "PRIMARY KEY (`id`, `field`)" - ")"; - queries.push_back(t); - - t = "CREATE INDEX IF NOT EXISTS idx_edge ON `" + prefix + "edges` (other_id)"; + Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` PRIMARY KEY, `type`)"; queries.push_back(t); return queries; @@ -287,31 +282,77 @@ std::vector<Query> SQLiteService::Replace(const Anope::string &table, const Quer return queries; } -std::vector<Query> SQLiteService::CreateTable(const Anope::string &prefix, const Anope::string &table) +std::vector<Query> SQLiteService::CreateTable(const Anope::string &prefix, Serialize::TypeBase *base) { std::vector<Query> queries; - if (active_schema.find(prefix + table) == active_schema.end()) + if (active_schema.find(prefix + base->GetName()) == active_schema.end()) { - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + table + "` (`id` bigint(20) NOT NULL, PRIMARY KEY (`id`))"; - queries.push_back(t); + Anope::string query = "CREATE TABLE IF NOT EXISTS `" + prefix + base->GetName() + "` ("; + std::set<Anope::string> fields; + + for (Serialize::FieldBase *field : base->GetFields()) + { + query += "`" + field->serialize_name + "` COLLATE NOCASE"; + fields.insert(field->serialize_name); + + if (field->object) + { + query += " REFERENCES " + prefix + "objects(id) ON DELETE "; + + if (field->depends) + { + query += "CASCADE"; + } + else + { + query += "SET NULL"; + } + + query += " DEFERRABLE INITIALLY DEFERRED"; + } + + query += ","; + } - active_schema[prefix + table]; + query += " `id` NOT NULL PRIMARY KEY, FOREIGN KEY (id) REFERENCES " + prefix + "objects(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"; + queries.push_back(query); + + active_schema[prefix + base->GetName()] = fields; } return queries; } -std::vector<Query> SQLiteService::AlterTable(const Anope::string &prefix, const Anope::string &table, const Anope::string &field, bool) +std::vector<Query> SQLiteService::AlterTable(const Anope::string &prefix, Serialize::TypeBase *type, Serialize::FieldBase *field) { + const Anope::string &table = type->GetName(); + std::vector<Query> queries; std::set<Anope::string> &s = active_schema[prefix + table]; - if (!s.count(field)) + if (!s.count(field->serialize_name)) { - Query t = "ALTER TABLE `" + prefix + table + "` ADD `" + field + "` COLLATE NOCASE"; - queries.push_back(t); - s.insert(field); + Anope::string buf = "ALTER TABLE `" + prefix + table + "` ADD `" + field->serialize_name + "` COLLATE NOCASE"; + + if (field->object) + { + buf += " REFERENCES " + prefix + "objects(id) ON DELETE "; + + if (field->depends) + { + buf += "CASCADE"; + } + else + { + buf += "SET NULL"; + } + + buf += " DEFERRABLE INITIALLY DEFERRED"; + } + + queries.push_back(Query(buf)); + s.insert(field->serialize_name); } return queries; @@ -344,27 +385,19 @@ Query SQLiteService::Commit() Serialize::ID SQLiteService::GetID(const Anope::string &prefix) { - /* must be in a deferred or reserved transaction here for atomic row update */ - - Query query("SELECT `id` FROM `" + prefix + "id`"); - Serialize::ID id; + Query query = "SELECT `id` FROM `" + prefix + "objects` ORDER BY `id` DESC LIMIT 1"; + Serialize::ID id = 0; Result res = RunQuery(query); if (res.Rows()) { id = convertTo<Serialize::ID>(res.Get(0, "id")); - Query update_query("UPDATE `" + prefix + "id` SET `id` = `id` + 1"); - RunQuery(update_query); + /* next id */ + ++id; } - else - { - id = 0; - Query insert_query("INSERT INTO `" + prefix + "id` (id) VALUES(@id@)"); - insert_query.SetValue("id", 1); - RunQuery(insert_query); - } + /* OnSerializableCreate is called immediately after this which does the insert */ return id; } @@ -376,10 +409,9 @@ Query SQLiteService::GetTables(const Anope::string &prefix) Anope::string SQLiteService::Escape(const Anope::string &query) { - char *e = sqlite3_mprintf("%q", query.c_str()); - Anope::string buffer = e; - sqlite3_free(e); - return buffer; + std::vector<char> buffer(query.length() * 2 + 1); + sqlite3_snprintf(buffer.size(), &buffer[0], "%q", query.c_str()); + return &buffer[0]; } Anope::string SQLiteService::BuildQuery(const Query &q) diff --git a/modules/nickserv/cert.cpp b/modules/nickserv/cert.cpp index ea0c41f51..94978fd88 100644 --- a/modules/nickserv/cert.cpp +++ b/modules/nickserv/cert.cpp @@ -31,6 +31,7 @@ class CertServiceImpl : public CertService NickServ::Account* FindAccountFromCert(const Anope::string &cert) override { +#warning "use serialize find" Anope::hash_map<NickServ::Account *>::iterator it = certmap.find(cert); if (it != certmap.end()) return it->second; @@ -78,15 +79,11 @@ class NSCertEntryType : public Serialize::Type<NSCertEntryImpl> { using Serialize::ObjectField<NSCertEntryImpl, NickServ::Account *>::ObjectField; - void SetField(NSCertEntryImpl *s, NickServ::Account *acc) override + void OnSet(NSCertEntryImpl *s, NickServ::Account *acc) override { const Anope::string &cert = s->GetCert(); - if (!cert.empty()) - certmap.erase(cert); - - Serialize::ObjectField<NSCertEntryImpl, NickServ::Account *>::SetField(s, acc); - if (!cert.empty() && s->GetAccount()) + if (!cert.empty()) certmap[cert] = acc; } } nc; @@ -95,13 +92,11 @@ class NSCertEntryType : public Serialize::Type<NSCertEntryImpl> { using Serialize::Field<NSCertEntryImpl, Anope::string>::Field; - void SetField(NSCertEntryImpl *s, const Anope::string &m) override + void OnSet(NSCertEntryImpl *s, const Anope::string &m) override { - const Anope::string &old = GetField(s); - if (!old.empty()) - certmap.erase(old); - - Serialize::Field<NSCertEntryImpl, Anope::string>::SetField(s, m); + Anope::string *old = this->Get_(s); + if (old != nullptr) + certmap.erase(*old); if (!m.empty() && s->GetAccount()) certmap[m] = s->GetAccount(); diff --git a/modules/nickserv/main/accounttype.cpp b/modules/nickserv/main/accounttype.cpp index 16abea415..6ea32cd83 100644 --- a/modules/nickserv/main/accounttype.cpp +++ b/modules/nickserv/main/accounttype.cpp @@ -29,18 +29,17 @@ AccountType::AccountType(Module *me) : Serialize::Type<AccountImpl>(me) } -void AccountType::Display::SetField(AccountImpl *acc, const Anope::string &disp) +void AccountType::Display::OnSet(AccountImpl *acc, const Anope::string &disp) { NickServ::nickcore_map& map = NickServ::service->GetAccountMap(); - if (!acc->GetDisplay().empty()) - map.erase(acc->GetDisplay()); + Anope::string *old = this->Get_(acc); + if (old != nullptr) + map.erase(*old); - Serialize::Field<AccountImpl, Anope::string>::SetField(acc, disp); - - if (!disp.empty()) - map[disp] = acc; + map[disp] = acc; +#warning "this is all wrong" acc->o = Oper::Find(disp); } diff --git a/modules/nickserv/main/accounttype.h b/modules/nickserv/main/accounttype.h index 4cdba74b0..27efd90dd 100644 --- a/modules/nickserv/main/accounttype.h +++ b/modules/nickserv/main/accounttype.h @@ -27,7 +27,7 @@ class AccountType : public Serialize::Type<AccountImpl> { using Serialize::Field<AccountImpl, Anope::string>::Field; - void SetField(AccountImpl *s, const Anope::string &) override; + void OnSet(AccountImpl *s, const Anope::string &) override; } display; /* User password in form of hashm:data */ Serialize::Field<AccountImpl, Anope::string> pass; diff --git a/modules/nickserv/main/nickserv.cpp b/modules/nickserv/main/nickserv.cpp index 2e766a9e2..461925927 100644 --- a/modules/nickserv/main/nickserv.cpp +++ b/modules/nickserv/main/nickserv.cpp @@ -219,7 +219,7 @@ class NickServCore : public Module, public NickServ::NickServService /* On shutdown, restart, or mod unload, remove all of our holds for nicks (svshold or qlines) * because some IRCds do not allow us to have these automatically expire */ - for (NickServ::Nick *na : nick_type.List<NickServ::Nick *>()) + for (NickServ::Nick *na : Serialize::GetObjects<NickServ::Nick *>()) this->Release(na); } @@ -362,7 +362,7 @@ class NickServCore : public Module, public NickServ::NickServService std::vector<NickServ::Nick *> GetNickList() override { - return nick_type.List<NickServ::Nick *>(); + return Serialize::GetObjects<NickServ::Nick *>(); } NickServ::nickalias_map& GetNickMap() override @@ -372,7 +372,7 @@ class NickServCore : public Module, public NickServ::NickServService std::vector<NickServ::Account *> GetAccountList() override { - return account_type.List<NickServ::Account *>(); + return Serialize::GetObjects<NickServ::Account *>(); } NickServ::nickcore_map& GetAccountMap() override @@ -532,6 +532,7 @@ class NickServCore : public Module, public NickServ::NickServService { if (u->HasMode("REGISTERED") && !u->IsIdentified(true)) u->RemoveMode(NickServ, "REGISTERED"); + if (!u->IsIdentified()) this->Validate(u); } @@ -640,7 +641,7 @@ class NickServCore : public Module, public NickServ::NickServService time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "21d"); - for (NickServ::Nick *na : nick_type.List<NickServ::Nick *>()) + for (NickServ::Nick *na : Serialize::GetObjects<NickServ::Nick *>()) { User *u = User::Find(na->GetNick(), true); if (u && (u->IsIdentified(true) || u->IsRecognized())) diff --git a/modules/nickserv/main/nicktype.cpp b/modules/nickserv/main/nicktype.cpp index 7b72f3e42..2cf1b2027 100644 --- a/modules/nickserv/main/nicktype.cpp +++ b/modules/nickserv/main/nicktype.cpp @@ -28,18 +28,19 @@ NickType::NickType(Module *me) : Serialize::Type<NickImpl>(me) , last_realhost(this, "last_realhost", &NickImpl::last_realhost) , time_registered(this, "time_registered", &NickImpl::time_registered) , last_seen(this, "last_seen", &NickImpl::last_seen) +#warning "this should depend?" , nc(this, "nc", &NickImpl::account) { } -void NickType::Nick::SetField(NickImpl *na, const Anope::string &value) +void NickType::Nick::OnSet(NickImpl *na, const Anope::string &value) { /* Remove us from the aliases list */ NickServ::nickalias_map &map = NickServ::service->GetNickMap(); - map.erase(GetField(na)); - - Serialize::Field<NickImpl, Anope::string>::SetField(na, value); + Anope::string *old = this->Get_(na); + if (old != nullptr) + map.erase(*old); map[value] = na; } diff --git a/modules/nickserv/main/nicktype.h b/modules/nickserv/main/nicktype.h index d94265132..0779b08da 100644 --- a/modules/nickserv/main/nicktype.h +++ b/modules/nickserv/main/nicktype.h @@ -26,7 +26,7 @@ class NickType : public Serialize::Type<NickImpl> { using Serialize::Field<NickImpl, Anope::string>::Field; - void SetField(NickImpl *s, const Anope::string &value) override; + void OnSet(NickImpl *s, const Anope::string &value) override; } nick; Serialize::Field<NickImpl, Anope::string> last_quit; Serialize::Field<NickImpl, Anope::string> last_realname; diff --git a/src/bots.cpp b/src/bots.cpp index 07d6ec858..2ba7bda67 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -37,15 +37,6 @@ ServiceBot::ServiceBot(const Anope::string &nnick, const Anope::string &nuser, c this->lastmsg = Anope::CurTime; this->introduced = false; - bi = Serialize::New<BotInfo *>(); - bi->bot = this; - - bi->SetNick(nnick); - bi->SetUser(nuser); - bi->SetHost(nhost); - bi->SetRealName(nreal); - bi->SetCreated(Anope::CurTime); - EventManager::Get()->Dispatch(&Event::CreateBot::OnCreateBot, this); // If we're synchronised with the uplink already, send the bot. @@ -65,8 +56,11 @@ ServiceBot::ServiceBot(const Anope::string &nnick, const Anope::string &nuser, c ServiceBot::~ServiceBot() { - bi->bot = nullptr; - bi->Delete(); + if (bi != nullptr) + { + bi->bot = nullptr; + bi->Delete(); + } EventManager::Get()->Dispatch(&Event::DelBot::OnDelBot, this); @@ -109,7 +103,8 @@ void ServiceBot::SetNewNick(const Anope::string &newnick) { UserListByNick.erase(this->nick); - bi->SetNick(newnick); + if (bi != nullptr) + bi->SetNick(newnick); this->nick = newnick; UserListByNick[this->nick] = this; @@ -117,7 +112,7 @@ void ServiceBot::SetNewNick(const Anope::string &newnick) std::vector<ChanServ::Channel *> ServiceBot::GetChannels() const { - return bi->GetRefs<ChanServ::Channel *>(); + return bi != nullptr ? bi->GetRefs<ChanServ::Channel *>() : std::vector<ChanServ::Channel *>(); } void ServiceBot::Assign(User *u, ChanServ::Channel *ci) diff --git a/src/config.cpp b/src/config.cpp index 0f083e3f8..6d671401e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -317,72 +317,7 @@ Conf::Conf() : Block("") this->MyOperTypes.push_back(ot); } - for (int i = 0; i < this->CountBlock("oper"); ++i) - { - Block *oper = this->GetBlock("oper", i); - - const Anope::string &nname = oper->Get<Anope::string>("name"), - &type = oper->Get<Anope::string>("type"), - &password = oper->Get<Anope::string>("password"), - &certfp = oper->Get<Anope::string>("certfp"), - &host = oper->Get<Anope::string>("host"), - &vhost = oper->Get<Anope::string>("vhost"); - bool require_oper = oper->Get<bool>("require_oper"); - - ValidateNotEmpty("oper", "name", nname); - ValidateNotEmpty("oper", "type", type); - - OperType *ot = NULL; - for (unsigned j = 0; j < this->MyOperTypes.size(); ++j) - if (this->MyOperTypes[j]->GetName() == type) - ot = this->MyOperTypes[j]; - if (ot == NULL) - throw ConfigException("Oper block for " + nname + " has invalid oper type " + type); - - Oper *o = Serialize::New<Oper *>(); - o->conf = this; - o->SetName(nname); - o->SetType(ot); - o->SetRequireOper(require_oper); - o->SetPassword(password); - o->SetCertFP(certfp); - o->SetHost(host); - o->SetVhost(vhost); - } - - for (BotInfo *bi : Serialize::GetObjects<BotInfo *>()) - bi->conf = nullptr; - for (int i = 0; i < this->CountBlock("service"); ++i) - { - Block *service = this->GetBlock("service", i); - - const Anope::string &nick = service->Get<Anope::string>("nick"), - &user = service->Get<Anope::string>("user"), - &host = service->Get<Anope::string>("host"), - &gecos = service->Get<Anope::string>("gecos"), - &modes = service->Get<Anope::string>("modes"), - &channels = service->Get<Anope::string>("channels"); - - ValidateNotEmpty("service", "nick", nick); - ValidateNotEmpty("service", "user", user); - ValidateNotEmpty("service", "host", host); - ValidateNotEmpty("service", "gecos", gecos); - ValidateNoSpaces("service", "channels", channels); - - if (User *u = User::Find(nick, true)) - { - if (u->type != UserType::BOT) - { - u->Kill(Me, "Nickname required by services"); - } - } - - ServiceBot *sb = ServiceBot::Find(nick, true); - if (!sb) - sb = new ServiceBot(nick, user, host, gecos, modes); - - sb->bi->conf = service; - } + this->LoadBots(); for (int i = 0; i < this->CountBlock("log"); ++i) { @@ -635,6 +570,9 @@ void Conf::Post(Conf *old) if (std::find(old->ModulesAutoLoad.begin(), old->ModulesAutoLoad.end(), this->ModulesAutoLoad[i]) == old->ModulesAutoLoad.end()) ModuleManager::LoadModule(this->ModulesAutoLoad[i], NULL); + LoadOpers(); + ApplyBots(); + ModeManager::Apply(old); /* Apply opertype changes, as non-conf opers still point to the old oper types */ @@ -699,6 +637,105 @@ void Conf::Post(Conf *old) } } +void Conf::LoadBots() +{ + for (BotInfo *bi : Serialize::GetObjects<BotInfo *>()) + bi->conf = nullptr; + for (int i = 0; i < this->CountBlock("service"); ++i) + { + Block *service = this->GetBlock("service", i); + + const Anope::string &nick = service->Get<Anope::string>("nick"), + &user = service->Get<Anope::string>("user"), + &host = service->Get<Anope::string>("host"), + &gecos = service->Get<Anope::string>("gecos"), + &modes = service->Get<Anope::string>("modes"), + &channels = service->Get<Anope::string>("channels"); + + ValidateNotEmpty("service", "nick", nick); + ValidateNotEmpty("service", "user", user); + ValidateNotEmpty("service", "host", host); + ValidateNotEmpty("service", "gecos", gecos); + ValidateNoSpaces("service", "channels", channels); + + if (User *u = User::Find(nick, true)) + { + if (u->type != UserType::BOT) + { + u->Kill(Me, "Nickname required by services"); + } + } + + ServiceBot *sb = ServiceBot::Find(nick, true); + if (!sb) + sb = new ServiceBot(nick, user, host, gecos, modes); + } +} + +void Conf::ApplyBots() +{ + for (std::pair<Anope::string, User *> p : UserListByNick) + { + User *u = p.second; + if (u->type != UserType::BOT) + continue; + + ServiceBot *sb = anope_dynamic_static_cast<ServiceBot *>(u); + if (sb->bi != nullptr) + continue; + + sb->bi = Serialize::New<BotInfo *>(); + sb->bi->bot = sb; + + sb->bi->SetNick(sb->nick); + sb->bi->SetUser(sb->GetIdent()); + sb->bi->SetHost(sb->host); + sb->bi->SetRealName(sb->realname); + sb->bi->SetCreated(Anope::CurTime); + } +} + +void Conf::LoadOpers() +{ + for (int i = 0; i < this->CountBlock("oper"); ++i) + { + Block *oper = this->GetBlock("oper", i); + + const Anope::string &nname = oper->Get<Anope::string>("name"), + &type = oper->Get<Anope::string>("type"), + &password = oper->Get<Anope::string>("password"), + &certfp = oper->Get<Anope::string>("certfp"), + &host = oper->Get<Anope::string>("host"), + &vhost = oper->Get<Anope::string>("vhost"); + bool require_oper = oper->Get<bool>("require_oper"); + + ValidateNotEmpty("oper", "name", nname); + ValidateNotEmpty("oper", "type", type); + + OperType *ot = NULL; + for (unsigned j = 0; j < this->MyOperTypes.size(); ++j) + if (this->MyOperTypes[j]->GetName() == type) + ot = this->MyOperTypes[j]; + if (ot == NULL) + { + Log() << "Oper block for " << nname << " has invalid oper type " << type; + continue; + } + + Oper *o = Serialize::New<Oper *>(); + o->conf = this; + o->SetName(nname); + o->SetType(ot); + o->SetRequireOper(require_oper); + o->SetPassword(password); + o->SetCertFP(certfp); + o->SetHost(host); + o->SetVhost(vhost); + + Log(LOG_DEBUG) << "Creating oper " << nname << " of type " << ot->GetName(); + } +} + Block *Conf::GetModule(Module *m) { if (!m) diff --git a/src/init.cpp b/src/init.cpp index ec23a7b4b..9ee720ebd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -543,6 +543,9 @@ void Anope::Init(int ac, char **av) for (int i = 0; i < Config->CountBlock("module"); ++i) ModuleManager::LoadModule(Config->GetBlock("module", i)->Get<Anope::string>("name"), NULL); + Config->LoadOpers(); + Config->ApplyBots(); + #ifndef _WIN32 /* We won't background later, so we should setuid now */ if (Anope::NoFork) diff --git a/src/service_manager.cpp b/src/service_manager.cpp index ef26fb13b..abebd1c3d 100644 --- a/src/service_manager.cpp +++ b/src/service_manager.cpp @@ -82,7 +82,7 @@ void ServiceManager::Register(Service *service) throw ModuleException("Service of type " + service->GetType() + " with name " + service->GetName() + " already exists"); } - Log(LOG_DEBUG_2) << "Service registered: " << service->GetType() << " " << service->GetName() << " address " << static_cast<void *>(this) << " by " << service->GetOwner(); + Log(LOG_DEBUG_3) << "Service registered: " << service->GetType() << " " << service->GetName() << " address " << static_cast<void *>(this) << " by " << service->GetOwner(); services.push_back(service); @@ -91,7 +91,7 @@ void ServiceManager::Register(Service *service) void ServiceManager::Unregister(Service *service) { - Log(LOG_DEBUG_2) << "Service unregistered: " << service->GetType() << " " << service->GetName() << " address " << static_cast<void *>(service) << " by " << service->GetOwner(); + Log(LOG_DEBUG_3) << "Service unregistered: " << service->GetType() << " " << service->GetName() << " address " << static_cast<void *>(service) << " by " << service->GetOwner(); auto it = std::find(services.begin(), services.end(), service); if (it != services.end()) @@ -107,13 +107,13 @@ void ServiceManager::Lookup(ServiceReferenceBase *reference) if (reference->GetName().empty()) { std::vector<Service *> services = this->FindServices(reference->GetType()); - Log(LOG_DEBUG_2) << "Service lookup " << static_cast<void *>(reference) << " type " << reference->GetType() << " name " << reference->GetName() << ": " << services.size() << " services"; + Log(LOG_DEBUG_3) << "Service lookup " << static_cast<void *>(reference) << " type " << reference->GetType() << " name " << reference->GetName() << ": " << services.size() << " services"; reference->SetServices(services); } else { Service *service = this->FindService(reference->GetType(), reference->GetName()); - Log(LOG_DEBUG_2) << "Service lookup " << static_cast<void *>(reference) << " type " << reference->GetType() << " name " << reference->GetName() << ": " << service; + Log(LOG_DEBUG_3) << "Service lookup " << static_cast<void *>(reference) << " type " << reference->GetType() << " name " << reference->GetName() << ": " << service; reference->SetService(service); } } diff --git a/src/xline.cpp b/src/xline.cpp index df65ae7dd..7d26461b4 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -215,9 +215,8 @@ XLineManager *XLine::GetManager() return ServiceManager::Get()->FindService<XLineManager *>(GetType()); } -void XLineType::Mask::SetField(XLine *s, const Anope::string &value) +void XLineType::Mask::OnSet(XLine *s, const Anope::string &value) { - Serialize::Field<XLine, Anope::string>::SetField(s, value); s->Recache(); } |