diff options
Diffstat (limited to 'modules/database')
-rw-r--r-- | modules/database/CMakeLists.txt | 2 | ||||
-rw-r--r-- | modules/database/db_flatfile.cpp | 415 | ||||
-rw-r--r-- | modules/database/db_redis.cpp | 644 | ||||
-rw-r--r-- | modules/database/db_sql.cpp | 261 | ||||
-rw-r--r-- | modules/database/db_sql_live.cpp | 265 | ||||
-rw-r--r-- | modules/database/flatfile.cpp | 807 | ||||
-rw-r--r-- | modules/database/old.cpp (renamed from modules/database/db_old.cpp) | 652 | ||||
-rw-r--r-- | modules/database/sql.cpp | 380 |
8 files changed, 1574 insertions, 1852 deletions
diff --git a/modules/database/CMakeLists.txt b/modules/database/CMakeLists.txt new file mode 100644 index 000000000..9a236d6d0 --- /dev/null +++ b/modules/database/CMakeLists.txt @@ -0,0 +1,2 @@ +build_modules(${CMAKE_CURRENT_SOURCE_DIR}) +build_modules_dependencies(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp deleted file mode 100644 index 171573d1c..000000000 --- a/modules/database/db_flatfile.cpp +++ /dev/null @@ -1,415 +0,0 @@ -/* - * - * (C) 2003-2016 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" - -#ifndef _WIN32 -#include <sys/wait.h> -#endif - -class SaveData : public Serialize::Data -{ - public: - Anope::string last; - std::fstream *fs; - - SaveData() : fs(NULL) { } - - std::iostream& operator[](const Anope::string &key) anope_override - { - if (key != last) - { - *fs << "\nDATA " << key << " "; - last = key; - } - - return *fs; - } -}; - -class LoadData : public Serialize::Data -{ - public: - std::fstream *fs; - unsigned int id; - std::map<Anope::string, Anope::string> data; - std::stringstream ss; - bool read; - - LoadData() : fs(NULL), id(0), read(false) { } - - std::iostream& operator[](const Anope::string &key) anope_override - { - if (!read) - { - for (Anope::string token; std::getline(*this->fs, token.str());) - { - if (token.find("ID ") == 0) - { - try - { - this->id = convertTo<unsigned int>(token.substr(3)); - } - catch (const ConvertException &) { } - - continue; - } - else if (token.find("DATA ") != 0) - break; - - size_t sp = token.find(' ', 5); // Skip DATA - if (sp != Anope::string::npos) - data[token.substr(5, sp - 5)] = token.substr(sp + 1); - } - - read = true; - } - - ss.clear(); - this->ss << this->data[key]; - return this->ss; - } - - std::set<Anope::string> KeySet() const anope_override - { - std::set<Anope::string> keys; - for (std::map<Anope::string, Anope::string>::const_iterator it = this->data.begin(), it_end = this->data.end(); it != it_end; ++it) - keys.insert(it->first); - return keys; - } - - size_t Hash() const anope_override - { - size_t hash = 0; - for (std::map<Anope::string, Anope::string>::const_iterator it = this->data.begin(), it_end = this->data.end(); it != it_end; ++it) - if (!it->second.empty()) - hash ^= Anope::hash_cs()(it->second); - return hash; - } - - void Reset() - { - id = 0; - read = false; - data.clear(); - } -}; - -class DBFlatFile : public Module, public Pipe -{ - /* Day the last backup was on */ - int last_day; - /* Backup file names */ - std::map<Anope::string, std::list<Anope::string> > backups; - bool loaded; - - int child_pid; - - void BackupDatabase() - { - tm *tm = localtime(&Anope::CurTime); - - if (tm->tm_mday != last_day) - { - last_day = tm->tm_mday; - - const std::vector<Anope::string> &type_order = Serialize::Type::GetTypeOrder(); - - std::set<Anope::string> dbs; - dbs.insert(Config->GetModule(this)->Get<const Anope::string>("database", "anope.db")); - - for (unsigned i = 0; i < type_order.size(); ++i) - { - Serialize::Type *stype = Serialize::Type::Find(type_order[i]); - - if (stype && stype->GetOwner()) - dbs.insert("module_" + stype->GetOwner()->name + ".db"); - } - - - for (std::set<Anope::string>::const_iterator it = dbs.begin(), it_end = dbs.end(); it != it_end; ++it) - { - const Anope::string &oldname = Anope::DataDir + "/" + *it; - Anope::string newname = Anope::DataDir + "/backups/" + *it + "-" + stringify(tm->tm_year + 1900) + Anope::printf("-%02i-", tm->tm_mon + 1) + Anope::printf("%02i", tm->tm_mday); - - /* Backup already exists or no database to backup */ - if (Anope::IsFile(newname) || !Anope::IsFile(oldname)) - continue; - - Log(LOG_DEBUG) << "db_flatfile: Attempting to rename " << *it << " to " << newname; - if (rename(oldname.c_str(), newname.c_str())) - { - Anope::string err = Anope::LastError(); - Log(this) << "Unable to back up database " << *it << " (" << err << ")!"; - - if (!Config->GetModule(this)->Get<bool>("nobackupokay")) - { - Anope::Quitting = true; - Anope::QuitReason = "Unable to back up database " + *it + " (" + err + ")"; - } - - continue; - } - - backups[*it].push_back(newname); - - unsigned keepbackups = Config->GetModule(this)->Get<unsigned>("keepbackups"); - if (keepbackups > 0 && backups[*it].size() > keepbackups) - { - unlink(backups[*it].front().c_str()); - backups[*it].pop_front(); - } - } - } - } - - public: - DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), last_day(0), loaded(false), child_pid(-1) - { - - } - -#ifndef _WIN32 - void OnRestart() anope_override - { - OnShutdown(); - } - - void OnShutdown() anope_override - { - if (child_pid > -1) - { - Log(this) << "Waiting for child to exit..."; - - int status; - waitpid(child_pid, &status, 0); - - Log(this) << "Done"; - } - } -#endif - - void OnNotify() anope_override - { - char buf[512]; - int i = this->Read(buf, sizeof(buf) - 1); - if (i <= 0) - return; - buf[i] = 0; - - child_pid = -1; - - if (!*buf) - { - Log(this) << "Finished saving databases"; - return; - } - - Log(this) << "Error saving databases: " << buf; - - if (!Config->GetModule(this)->Get<bool>("nobackupokay")) - Anope::Quitting = true; - } - - EventReturn OnLoadDatabase() anope_override - { - const std::vector<Anope::string> &type_order = Serialize::Type::GetTypeOrder(); - std::set<Anope::string> tried_dbs; - - const Anope::string &db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<const Anope::string>("database", "anope.db"); - - std::fstream fd(db_name.c_str(), std::ios_base::in | std::ios_base::binary); - if (!fd.is_open()) - { - Log(this) << "Unable to open " << db_name << " for reading!"; - return EVENT_STOP; - } - - std::map<Anope::string, std::vector<std::streampos> > positions; - - for (Anope::string buf; std::getline(fd, buf.str());) - if (buf.find("OBJECT ") == 0) - positions[buf.substr(7)].push_back(fd.tellg()); - - LoadData ld; - ld.fs = &fd; - - for (unsigned i = 0; i < type_order.size(); ++i) - { - Serialize::Type *stype = Serialize::Type::Find(type_order[i]); - if (!stype || stype->GetOwner()) - continue; - - std::vector<std::streampos> &pos = positions[stype->GetName()]; - - for (unsigned j = 0; j < pos.size(); ++j) - { - fd.clear(); - fd.seekg(pos[j]); - - Serializable *obj = stype->Unserialize(NULL, ld); - if (obj != NULL) - obj->id = ld.id; - ld.Reset(); - } - } - - fd.close(); - - loaded = true; - return EVENT_STOP; - } - - - void OnSaveDatabase() anope_override - { - if (child_pid > -1) - { - Log(this) << "Database save is already in progress!"; - return; - } - - BackupDatabase(); - - int i = -1; -#ifndef _WIN32 - if (!Anope::Quitting && Config->GetModule(this)->Get<bool>("fork")) - { - i = fork(); - if (i > 0) - { - child_pid = i; - return; - } - else if (i < 0) - Log(this) << "Unable to fork for database save"; - } -#endif - - try - { - std::map<Module *, std::fstream *> databases; - - /* First open the databases of all of the registered types. This way, if we have a type with 0 objects, that database will be properly cleared */ - for (std::map<Anope::string, Serialize::Type *>::const_iterator it = Serialize::Type::GetTypes().begin(), it_end = Serialize::Type::GetTypes().end(); it != it_end; ++it) - { - Serialize::Type *s_type = it->second; - - if (databases[s_type->GetOwner()]) - continue; - - Anope::string db_name; - if (s_type->GetOwner()) - db_name = Anope::DataDir + "/module_" + s_type->GetOwner()->name + ".db"; - else - db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<const Anope::string>("database", "anope.db"); - - if (Anope::IsFile(db_name)) - rename(db_name.c_str(), (db_name + ".tmp").c_str()); - - std::fstream *fs = databases[s_type->GetOwner()] = new std::fstream(db_name.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); - - if (!fs->is_open()) - Log(this) << "Unable to open " << db_name << " for writing"; - } - - SaveData data; - const std::list<Serializable *> &items = Serializable::GetItems(); - for (std::list<Serializable *>::const_iterator it = items.begin(), it_end = items.end(); it != it_end; ++it) - { - Serializable *base = *it; - Serialize::Type *s_type = base->GetSerializableType(); - - data.fs = databases[s_type->GetOwner()]; - if (!data.fs || !data.fs->is_open()) - continue; - - *data.fs << "OBJECT " << s_type->GetName(); - if (base->id) - *data.fs << "\nID " << base->id; - base->Serialize(data); - *data.fs << "\nEND\n"; - } - - for (std::map<Module *, std::fstream *>::iterator it = databases.begin(), it_end = databases.end(); it != it_end; ++it) - { - std::fstream *f = it->second; - const Anope::string &db_name = Anope::DataDir + "/" + (it->first ? (it->first->name + ".db") : Config->GetModule(this)->Get<const Anope::string>("database", "anope.db")); - - if (!f->is_open() || !f->good()) - { - this->Write("Unable to write database " + db_name); - - f->close(); - - if (Anope::IsFile((db_name + ".tmp").c_str())) - rename((db_name + ".tmp").c_str(), db_name.c_str()); - } - else - { - f->close(); - unlink((db_name + ".tmp").c_str()); - } - - delete f; - } - } - catch (...) - { - if (i) - throw; - } - - if (!i) - { - this->Notify(); - exit(0); - } - } - - /* Load just one type. Done if a module is reloaded during runtime */ - void OnSerializeTypeCreate(Serialize::Type *stype) anope_override - { - if (!loaded) - return; - - Anope::string db_name; - if (stype->GetOwner()) - db_name = Anope::DataDir + "/module_" + stype->GetOwner()->name + ".db"; - else - db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<const Anope::string>("database", "anope.db"); - - std::fstream fd(db_name.c_str(), std::ios_base::in | std::ios_base::binary); - if (!fd.is_open()) - { - Log(this) << "Unable to open " << db_name << " for reading!"; - return; - } - - LoadData ld; - ld.fs = &fd; - - for (Anope::string buf; std::getline(fd, buf.str());) - { - if (buf == "OBJECT " + stype->GetName()) - { - stype->Unserialize(NULL, ld); - ld.Reset(); - } - } - - fd.close(); - } -}; - -MODULE_INIT(DBFlatFile) - - diff --git a/modules/database/db_redis.cpp b/modules/database/db_redis.cpp deleted file mode 100644 index db12a2c5f..000000000 --- a/modules/database/db_redis.cpp +++ /dev/null @@ -1,644 +0,0 @@ -/* - * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - */ - -#include "module.h" -#include "modules/redis.h" - -using namespace Redis; - -class DatabaseRedis; -static DatabaseRedis *me; - -class Data : public Serialize::Data -{ - public: - std::map<Anope::string, std::stringstream *> data; - - ~Data() - { - for (std::map<Anope::string, std::stringstream *>::iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) - delete it->second; - } - - std::iostream& operator[](const Anope::string &key) anope_override - { - std::stringstream* &stream = data[key]; - if (!stream) - stream = new std::stringstream(); - return *stream; - } - - std::set<Anope::string> KeySet() const anope_override - { - std::set<Anope::string> keys; - for (std::map<Anope::string, std::stringstream *>::const_iterator it = this->data.begin(), it_end = this->data.end(); it != it_end; ++it) - keys.insert(it->first); - return keys; - } - - size_t Hash() const anope_override - { - size_t hash = 0; - for (std::map<Anope::string, std::stringstream *>::const_iterator it = this->data.begin(), it_end = this->data.end(); it != it_end; ++it) - if (!it->second->str().empty()) - hash ^= Anope::hash_cs()(it->second->str()); - return hash; - } -}; - -class TypeLoader : public Interface -{ - Anope::string type; - public: - TypeLoader(Module *creator, const Anope::string &t) : Interface(creator), type(t) { } - - void OnResult(const Reply &r) anope_override; -}; - -class ObjectLoader : public Interface -{ - Anope::string type; - int64_t id; - - public: - ObjectLoader(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { } - - void OnResult(const Reply &r) anope_override; -}; - -class IDInterface : public Interface -{ - Reference<Serializable> o; - public: - IDInterface(Module *creator, Serializable *obj) : Interface(creator), o(obj) { } - - void OnResult(const Reply &r) anope_override; -}; - -class Deleter : public Interface -{ - Anope::string type; - int64_t id; - public: - Deleter(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { } - - void OnResult(const Reply &r) anope_override; -}; - -class Updater : public Interface -{ - Anope::string type; - int64_t id; - public: - Updater(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { } - - void OnResult(const Reply &r) anope_override; -}; - -class ModifiedObject : public Interface -{ - Anope::string type; - int64_t id; - public: - ModifiedObject(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { } - - void OnResult(const Reply &r) anope_override; -}; - -class SubscriptionListener : public Interface -{ - public: - SubscriptionListener(Module *creator) : Interface(creator) { } - - void OnResult(const Reply &r) anope_override; -}; - -class DatabaseRedis : public Module, public Pipe -{ - SubscriptionListener sl; - std::set<Serializable *> updated_items; - - public: - ServiceReference<Provider> redis; - - DatabaseRedis(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), sl(this) - { - me = this; - - } - - /* Insert or update an object */ - void InsertObject(Serializable *obj) - { - Serialize::Type *t = obj->GetSerializableType(); - - /* If there is no id yet for this object, get one */ - if (!obj->id) - redis->SendCommand(new IDInterface(this, obj), "INCR id:" + t->GetName()); - else - { - Data data; - obj->Serialize(data); - - if (obj->IsCached(data)) - return; - - obj->UpdateCache(data); - - std::vector<Anope::string> args; - args.push_back("HGETALL"); - args.push_back("hash:" + t->GetName() + ":" + stringify(obj->id)); - - /* Get object attrs to clear before updating */ - redis->SendCommand(new Updater(this, t->GetName(), obj->id), args); - } - } - - void OnNotify() anope_override - { - for (std::set<Serializable *>::iterator it = this->updated_items.begin(), it_end = this->updated_items.end(); it != it_end; ++it) - { - Serializable *s = *it; - - this->InsertObject(s); - } - - this->updated_items.clear(); - } - - void OnReload(Configuration::Conf *conf) anope_override - { - Configuration::Block *block = conf->GetModule(this); - this->redis = ServiceReference<Provider>("Redis::Provider", block->Get<const Anope::string>("engine", "redis/main")); - } - - EventReturn OnLoadDatabase() anope_override - { - const std::vector<Anope::string> type_order = Serialize::Type::GetTypeOrder(); - for (unsigned i = 0; i < type_order.size(); ++i) - { - Serialize::Type *sb = Serialize::Type::Find(type_order[i]); - this->OnSerializeTypeCreate(sb); - } - - while (redis->BlockAndProcess()); - - redis->Subscribe(&this->sl, "__keyspace@*__:hash:*"); - - return EVENT_STOP; - } - - void OnSerializeTypeCreate(Serialize::Type *sb) anope_override - { - if (!redis) - return; - - std::vector<Anope::string> args; - args.push_back("SMEMBERS"); - args.push_back("ids:" + sb->GetName()); - - redis->SendCommand(new TypeLoader(this, sb->GetName()), args); - } - - void OnSerializableConstruct(Serializable *obj) anope_override - { - this->updated_items.insert(obj); - this->Notify(); - } - - void OnSerializableDestruct(Serializable *obj) anope_override - { - Serialize::Type *t = obj->GetSerializableType(); - - std::vector<Anope::string> args; - args.push_back("HGETALL"); - args.push_back("hash:" + t->GetName() + ":" + stringify(obj->id)); - - /* Get all of the attributes for this object */ - redis->SendCommand(new Deleter(this, t->GetName(), obj->id), args); - - this->updated_items.erase(obj); - t->objects.erase(obj->id); - this->Notify(); - } - - void OnSerializableUpdate(Serializable *obj) anope_override - { - this->updated_items.insert(obj); - this->Notify(); - } -}; - -void TypeLoader::OnResult(const Reply &r) -{ - if (r.type != Reply::MULTI_BULK || !me->redis) - { - delete this; - return; - } - - for (unsigned i = 0; i < r.multi_bulk.size(); ++i) - { - const Reply *reply = r.multi_bulk[i]; - - if (reply->type != Reply::BULK) - continue; - - int64_t id; - try - { - id = convertTo<int64_t>(reply->bulk); - } - catch (const ConvertException &) - { - continue; - } - - std::vector<Anope::string> args; - args.push_back("HGETALL"); - args.push_back("hash:" + this->type + ":" + stringify(id)); - - me->redis->SendCommand(new ObjectLoader(me, this->type, id), args); - } - - delete this; -} - -void ObjectLoader::OnResult(const Reply &r) -{ - Serialize::Type *st = Serialize::Type::Find(this->type); - - if (r.type != Reply::MULTI_BULK || r.multi_bulk.empty() || !me->redis || !st) - { - delete this; - return; - } - - Data data; - - for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2) - { - const Reply *key = r.multi_bulk[i], - *value = r.multi_bulk[i + 1]; - - data[key->bulk] << value->bulk; - } - - Serializable* &obj = st->objects[this->id]; - obj = st->Unserialize(obj, data); - if (obj) - { - obj->id = this->id; - obj->UpdateCache(data); - } - - delete this; -} - -void IDInterface::OnResult(const Reply &r) -{ - if (!o || r.type != Reply::INT || !r.i) - { - delete this; - return; - } - - Serializable* &obj = o->GetSerializableType()->objects[r.i]; - if (obj) - /* This shouldn't be possible */ - obj->id = 0; - - o->id = r.i; - obj = o; - - /* Now that we have the id, insert this object for real */ - anope_dynamic_static_cast<DatabaseRedis *>(this->owner)->InsertObject(o); - - delete this; -} - -void Deleter::OnResult(const Reply &r) -{ - if (r.type != Reply::MULTI_BULK || !me->redis || r.multi_bulk.empty()) - { - delete this; - return; - } - - /* Transaction start */ - me->redis->StartTransaction(); - - std::vector<Anope::string> args; - args.push_back("DEL"); - args.push_back("hash:" + this->type + ":" + stringify(this->id)); - - /* Delete hash object */ - me->redis->SendCommand(NULL, args); - - args.clear(); - args.push_back("SREM"); - args.push_back("ids:" + this->type); - args.push_back(stringify(this->id)); - - /* Delete id from ids set */ - me->redis->SendCommand(NULL, args); - - for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2) - { - const Reply *key = r.multi_bulk[i], - *value = r.multi_bulk[i + 1]; - - args.clear(); - args.push_back("SREM"); - args.push_back("value:" + this->type + ":" + key->bulk + ":" + value->bulk); - args.push_back(stringify(this->id)); - - /* Delete value -> object id */ - me->redis->SendCommand(NULL, args); - } - - /* Transaction end */ - me->redis->CommitTransaction(); - - delete this; -} - -void Updater::OnResult(const Reply &r) -{ - Serialize::Type *st = Serialize::Type::Find(this->type); - - if (!st) - { - delete this; - return; - } - - Serializable *obj = st->objects[this->id]; - if (!obj) - { - delete this; - return; - } - - Data data; - obj->Serialize(data); - - /* Transaction start */ - me->redis->StartTransaction(); - - for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2) - { - const Reply *key = r.multi_bulk[i], - *value = r.multi_bulk[i + 1]; - - std::vector<Anope::string> args; - args.push_back("SREM"); - args.push_back("value:" + this->type + ":" + key->bulk + ":" + value->bulk); - args.push_back(stringify(this->id)); - - /* Delete value -> object id */ - me->redis->SendCommand(NULL, args); - } - - /* Add object id to id set for this type */ - std::vector<Anope::string> args; - args.push_back("SADD"); - args.push_back("ids:" + this->type); - args.push_back(stringify(obj->id)); - me->redis->SendCommand(NULL, args); - - args.clear(); - args.push_back("HMSET"); - args.push_back("hash:" + this->type + ":" + stringify(obj->id)); - - typedef std::map<Anope::string, std::stringstream *> items; - for (items::iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) - { - const Anope::string &key = it->first; - std::stringstream *value = it->second; - - args.push_back(key); - args.push_back(value->str()); - - std::vector<Anope::string> args2; - - args2.push_back("SADD"); - args2.push_back("value:" + this->type + ":" + key + ":" + value->str()); - args2.push_back(stringify(obj->id)); - - /* Add to value -> object id set */ - me->redis->SendCommand(NULL, args2); - } - - ++obj->redis_ignore; - - /* Add object */ - me->redis->SendCommand(NULL, args); - - /* Transaction end */ - me->redis->CommitTransaction(); - - delete this; -} - -void SubscriptionListener::OnResult(const Reply &r) -{ - /* - * [May 15 13:59:35.645839 2013] Debug: pmessage - * [May 15 13:59:35.645866 2013] Debug: __keyspace@*__:anope:hash:* - * [May 15 13:59:35.645880 2013] Debug: __keyspace@0__:anope:hash:type:id - * [May 15 13:59:35.645893 2013] Debug: hset - */ - if (r.multi_bulk.size() != 4) - return; - - size_t sz = r.multi_bulk[2]->bulk.find(':'); - if (sz == Anope::string::npos) - return; - - const Anope::string &key = r.multi_bulk[2]->bulk.substr(sz + 1), - &op = r.multi_bulk[3]->bulk; - - sz = key.rfind(':'); - if (sz == Anope::string::npos) - return; - - const Anope::string &id = key.substr(sz + 1); - - size_t sz2 = key.rfind(':', sz - 1); - if (sz2 == Anope::string::npos) - return; - const Anope::string &type = key.substr(sz2 + 1, sz - sz2 - 1); - - Serialize::Type *s_type = Serialize::Type::Find(type); - - if (s_type == NULL) - return; - - uint64_t obj_id; - try - { - obj_id = convertTo<uint64_t>(id); - } - catch (const ConvertException &) - { - return; - } - - if (op == "hset" || op == "hdel") - { - Serializable *s = s_type->objects[obj_id]; - - if (s && s->redis_ignore) - { - --s->redis_ignore; - Log(LOG_DEBUG) << "redis: notify: got modify for object id " << obj_id << " of type " << type << ", but I am ignoring it"; - } - else - { - Log(LOG_DEBUG) << "redis: notify: got modify for object id " << obj_id << " of type " << type; - - std::vector<Anope::string> args; - args.push_back("HGETALL"); - args.push_back("hash:" + type + ":" + id); - - me->redis->SendCommand(new ModifiedObject(me, type, obj_id), args); - } - } - else if (op == "del") - { - Serializable* &s = s_type->objects[obj_id]; - if (s == NULL) - return; - - Log(LOG_DEBUG) << "redis: notify: deleting object id " << obj_id << " of type " << type; - - Data data; - - s->Serialize(data); - - /* Transaction start */ - me->redis->StartTransaction(); - - typedef std::map<Anope::string, std::stringstream *> items; - for (items::iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) - { - const Anope::string &k = it->first; - std::stringstream *value = it->second; - - std::vector<Anope::string> args; - args.push_back("SREM"); - args.push_back("value:" + type + ":" + k + ":" + value->str()); - args.push_back(id); - - /* Delete value -> object id */ - me->redis->SendCommand(NULL, args); - } - - std::vector<Anope::string> args; - args.push_back("SREM"); - args.push_back("ids:" + type); - args.push_back(stringify(s->id)); - - /* Delete object from id set */ - me->redis->SendCommand(NULL, args); - - /* Transaction end */ - me->redis->CommitTransaction(); - - delete s; - s = NULL; - } -} - -void ModifiedObject::OnResult(const Reply &r) -{ - Serialize::Type *st = Serialize::Type::Find(this->type); - - if (!st) - { - delete this; - return; - } - - Serializable* &obj = st->objects[this->id]; - - /* Transaction start */ - me->redis->StartTransaction(); - - /* Erase old object values */ - if (obj) - { - Data data; - - obj->Serialize(data); - - typedef std::map<Anope::string, std::stringstream *> items; - for (items::iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) - { - const Anope::string &key = it->first; - std::stringstream *value = it->second; - - std::vector<Anope::string> args; - args.push_back("SREM"); - args.push_back("value:" + st->GetName() + ":" + key + ":" + value->str()); - args.push_back(stringify(this->id)); - - /* Delete value -> object id */ - me->redis->SendCommand(NULL, args); - } - } - - Data data; - - for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2) - { - const Reply *key = r.multi_bulk[i], - *value = r.multi_bulk[i + 1]; - - data[key->bulk] << value->bulk; - } - - obj = st->Unserialize(obj, data); - if (obj) - { - obj->id = this->id; - obj->UpdateCache(data); - - /* Insert new object values */ - typedef std::map<Anope::string, std::stringstream *> items; - for (items::iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) - { - const Anope::string &key = it->first; - std::stringstream *value = it->second; - - std::vector<Anope::string> args; - args.push_back("SADD"); - args.push_back("value:" + st->GetName() + ":" + key + ":" + value->str()); - args.push_back(stringify(obj->id)); - - /* Add to value -> object id set */ - me->redis->SendCommand(NULL, args); - } - - std::vector<Anope::string> args; - args.push_back("SADD"); - args.push_back("ids:" + st->GetName()); - args.push_back(stringify(obj->id)); - - /* Add to type -> id set */ - me->redis->SendCommand(NULL, args); - } - - /* Transaction end */ - me->redis->CommitTransaction(); - - delete this; -} - -MODULE_INIT(DatabaseRedis) diff --git a/modules/database/db_sql.cpp b/modules/database/db_sql.cpp deleted file mode 100644 index 15501bc5f..000000000 --- a/modules/database/db_sql.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * - * (C) 2003-2016 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/sql.h" - -using namespace SQL; - -class SQLSQLInterface : public Interface -{ - public: - SQLSQLInterface(Module *o) : Interface(o) { } - - void OnResult(const Result &r) anope_override - { - Log(LOG_DEBUG) << "SQL successfully executed query: " << r.finished_query; - } - - void OnError(const Result &r) anope_override - { - if (!r.GetQuery().query.empty()) - Log(LOG_DEBUG) << "Error executing query " << r.finished_query << ": " << r.GetError(); - else - Log(LOG_DEBUG) << "Error executing query: " << r.GetError(); - } -}; - -class ResultSQLSQLInterface : public SQLSQLInterface -{ - Reference<Serializable> obj; - -public: - ResultSQLSQLInterface(Module *o, Serializable *ob) : SQLSQLInterface(o), obj(ob) { } - - void OnResult(const Result &r) anope_override - { - SQLSQLInterface::OnResult(r); - if (r.GetID() > 0 && this->obj) - this->obj->id = r.GetID(); - delete this; - } - - void OnError(const Result &r) anope_override - { - SQLSQLInterface::OnError(r); - delete this; - } -}; - -class DBSQL : public Module, public Pipe -{ - ServiceReference<Provider> sql; - SQLSQLInterface sqlinterface; - Anope::string prefix; - bool import; - - std::set<Serializable *> updated_items; - bool shutting_down; - bool loading_databases; - bool loaded; - bool imported; - - void RunBackground(const Query &q, Interface *iface = NULL) - { - if (!this->sql) - { - static time_t last_warn = 0; - if (last_warn + 300 < Anope::CurTime) - { - last_warn = Anope::CurTime; - Log(this) << "db_sql: Unable to execute query, is SQL configured correctly?"; - } - } - else if (!Anope::Quitting) - { - if (iface == NULL) - iface = &this->sqlinterface; - this->sql->Run(iface, q); - } - else - this->sql->RunQuery(q); - } - - public: - DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), sql("", ""), sqlinterface(this), shutting_down(false), loading_databases(false), loaded(false), imported(false) - { - - - if (ModuleManager::FindModule("db_sql_live") != NULL) - throw ModuleException("db_sql can not be loaded after db_sql_live"); - } - - void OnNotify() anope_override - { - for (std::set<Serializable *>::iterator it = this->updated_items.begin(), it_end = this->updated_items.end(); it != it_end; ++it) - { - Serializable *obj = *it; - - if (this->sql) - { - Data data; - obj->Serialize(data); - - if (obj->IsCached(data)) - continue; - - obj->UpdateCache(data); - - /* If we didn't load these objects and we don't want to import just update the cache and continue */ - if (!this->loaded && !this->imported && !this->import) - continue; - - Serialize::Type *s_type = obj->GetSerializableType(); - if (!s_type) - continue; - - std::vector<Query> create = this->sql->CreateTable(this->prefix + s_type->GetName(), data); - for (unsigned i = 0; i < create.size(); ++i) - this->RunBackground(create[i]); - - Query insert = this->sql->BuildInsert(this->prefix + s_type->GetName(), obj->id, data); - if (this->imported) - this->RunBackground(insert, new ResultSQLSQLInterface(this, obj)); - else - { - /* We are importing objects from another database module, so don't do asynchronous - * queries in case the core has to shut down, it will cut short the import - */ - Result r = this->sql->RunQuery(insert); - if (r.GetID() > 0) - obj->id = r.GetID(); - } - } - } - - this->updated_items.clear(); - this->imported = true; - } - - void OnReload(Configuration::Conf *conf) anope_override - { - Configuration::Block *block = conf->GetModule(this); - this->sql = ServiceReference<Provider>("SQL::Provider", block->Get<const Anope::string>("engine")); - this->prefix = block->Get<const Anope::string>("prefix", "anope_db_"); - this->import = block->Get<bool>("import"); - } - - void OnShutdown() anope_override - { - this->shutting_down = true; - this->OnNotify(); - } - - void OnRestart() anope_override - { - this->OnShutdown(); - } - - EventReturn OnLoadDatabase() anope_override - { - if (!this->sql) - { - Log(this) << "Unable to load databases, is SQL configured correctly?"; - return EVENT_CONTINUE; - } - - this->loading_databases = true; - - const std::vector<Anope::string> type_order = Serialize::Type::GetTypeOrder(); - for (unsigned i = 0; i < type_order.size(); ++i) - { - Serialize::Type *sb = Serialize::Type::Find(type_order[i]); - this->OnSerializeTypeCreate(sb); - } - - this->loading_databases = false; - this->loaded = true; - - return EVENT_STOP; - } - - void OnSerializableConstruct(Serializable *obj) anope_override - { - if (this->shutting_down || this->loading_databases) - return; - obj->UpdateTS(); - this->updated_items.insert(obj); - this->Notify(); - } - - void OnSerializableDestruct(Serializable *obj) anope_override - { - if (this->shutting_down) - return; - Serialize::Type *s_type = obj->GetSerializableType(); - if (s_type && obj->id > 0) - this->RunBackground("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + stringify(obj->id)); - this->updated_items.erase(obj); - } - - void OnSerializableUpdate(Serializable *obj) anope_override - { - if (this->shutting_down || obj->IsTSCached()) - return; - obj->UpdateTS(); - this->updated_items.insert(obj); - this->Notify(); - } - - void OnSerializeTypeCreate(Serialize::Type *sb) anope_override - { - if (!this->loading_databases && !this->loaded) - return; - - Query query("SELECT * FROM `" + this->prefix + sb->GetName() + "`"); - Result res = this->sql->RunQuery(query); - - for (int j = 0; j < res.Rows(); ++j) - { - Data data; - - const std::map<Anope::string, Anope::string> &row = res.Row(j); - for (std::map<Anope::string, Anope::string>::const_iterator rit = row.begin(), rit_end = row.end(); rit != rit_end; ++rit) - data[rit->first] << rit->second; - - Serializable *obj = sb->Unserialize(NULL, data); - try - { - if (obj) - obj->id = convertTo<unsigned int>(res.Get(j, "id")); - } - catch (const ConvertException &) - { - Log(this) << "Unable to convert id for object #" << j << " of type " << sb->GetName(); - } - - if (obj) - { - /* The Unserialize operation is destructive so rebuild the data for UpdateCache. - * Also the old data may contain columns that we don't use, so we reserialize the - * object to know for sure our cache is consistent - */ - - Data data2; - obj->Serialize(data2); - obj->UpdateCache(data2); /* We know this is the most up to date copy */ - } - } - } -}; - -MODULE_INIT(DBSQL) - diff --git a/modules/database/db_sql_live.cpp b/modules/database/db_sql_live.cpp deleted file mode 100644 index 7dfde3d02..000000000 --- a/modules/database/db_sql_live.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * - * (C) 2012-2016 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - */ - -#include "module.h" -#include "modules/sql.h" - -using namespace SQL; - -class DBMySQL : public Module, public Pipe -{ - private: - Anope::string prefix; - ServiceReference<Provider> SQL; - time_t lastwarn; - bool ro; - bool init; - std::set<Serializable *> updated_items; - - bool CheckSQL() - { - if (SQL) - { - if (Anope::ReadOnly && this->ro) - { - Anope::ReadOnly = this->ro = false; - Log() << "Found SQL again, going out of readonly mode..."; - } - - return true; - } - else - { - if (Anope::CurTime - Config->GetBlock("options")->Get<time_t>("updatetimeout", "5m") > lastwarn) - { - Log() << "Unable to locate SQL reference, going to readonly..."; - Anope::ReadOnly = this->ro = true; - this->lastwarn = Anope::CurTime; - } - - return false; - } - } - - bool CheckInit() - { - return init && SQL; - } - - void RunQuery(const Query &query) - { - /* Can this be threaded? */ - this->RunQueryResult(query); - } - - Result RunQueryResult(const Query &query) - { - if (this->CheckSQL()) - { - Result res = SQL->RunQuery(query); - if (!res.GetError().empty()) - Log(LOG_DEBUG) << "SQL-live got error " << res.GetError() << " for " + res.finished_query; - else - Log(LOG_DEBUG) << "SQL-live got " << res.Rows() << " rows for " << res.finished_query; - return res; - } - throw SQL::Exception("No SQL!"); - } - - public: - DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), SQL("", "") - { - this->lastwarn = 0; - this->ro = false; - this->init = false; - - - if (ModuleManager::FindFirstOf(DATABASE) != this) - throw ModuleException("If db_sql_live is loaded it must be the first database module loaded."); - } - - void OnNotify() anope_override - { - if (!this->CheckInit()) - return; - - for (std::set<Serializable *>::iterator it = this->updated_items.begin(), it_end = this->updated_items.end(); it != it_end; ++it) - { - Serializable *obj = *it; - - if (obj && this->SQL) - { - Data data; - obj->Serialize(data); - - if (obj->IsCached(data)) - continue; - - obj->UpdateCache(data); - - Serialize::Type *s_type = obj->GetSerializableType(); - if (!s_type) - continue; - - std::vector<Query> create = this->SQL->CreateTable(this->prefix + s_type->GetName(), data); - for (unsigned i = 0; i < create.size(); ++i) - this->RunQueryResult(create[i]); - - Result res = this->RunQueryResult(this->SQL->BuildInsert(this->prefix + s_type->GetName(), obj->id, data)); - if (res.GetID() && obj->id != res.GetID()) - { - /* In this case obj is new, so place it into the object map */ - obj->id = res.GetID(); - s_type->objects[obj->id] = obj; - } - } - } - - this->updated_items.clear(); - } - - EventReturn OnLoadDatabase() anope_override - { - init = true; - return EVENT_STOP; - } - - void OnShutdown() anope_override - { - init = false; - } - - void OnRestart() anope_override - { - init = false; - } - - void OnReload(Configuration::Conf *conf) anope_override - { - Configuration::Block *block = conf->GetModule(this); - this->SQL = ServiceReference<Provider>("SQL::Provider", block->Get<const Anope::string>("engine")); - this->prefix = block->Get<const Anope::string>("prefix", "anope_db_"); - } - - void OnSerializableConstruct(Serializable *obj) anope_override - { - if (!this->CheckInit()) - return; - obj->UpdateTS(); - this->updated_items.insert(obj); - this->Notify(); - } - - void OnSerializableDestruct(Serializable *obj) anope_override - { - if (!this->CheckInit()) - return; - Serialize::Type *s_type = obj->GetSerializableType(); - if (s_type) - { - if (obj->id > 0) - this->RunQuery("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + stringify(obj->id)); - s_type->objects.erase(obj->id); - } - this->updated_items.erase(obj); - } - - void OnSerializeCheck(Serialize::Type *obj) anope_override - { - if (!this->CheckInit() || obj->GetTimestamp() == Anope::CurTime) - return; - - Query query("SELECT * FROM `" + this->prefix + obj->GetName() + "` WHERE (`timestamp` >= " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " OR `timestamp` IS NULL)"); - - obj->UpdateTimestamp(); - - Result res = this->RunQueryResult(query); - - bool clear_null = false; - for (int i = 0; i < res.Rows(); ++i) - { - const std::map<Anope::string, Anope::string> &row = res.Row(i); - - unsigned int id; - try - { - id = convertTo<unsigned int>(res.Get(i, "id")); - } - catch (const ConvertException &) - { - Log(LOG_DEBUG) << "Unable to convert id from " << obj->GetName(); - continue; - } - - if (res.Get(i, "timestamp").empty()) - { - clear_null = true; - std::map<uint64_t, Serializable *>::iterator it = obj->objects.find(id); - if (it != obj->objects.end()) - delete it->second; // This also removes this object from the map - } - else - { - Data data; - - for (std::map<Anope::string, Anope::string>::const_iterator it = row.begin(), it_end = row.end(); it != it_end; ++it) - data[it->first] << it->second; - - Serializable *s = NULL; - std::map<uint64_t, Serializable *>::iterator it = obj->objects.find(id); - if (it != obj->objects.end()) - s = it->second; - - Serializable *new_s = obj->Unserialize(s, data); - if (new_s) - { - // If s == new_s then s->id == new_s->id - if (s != new_s) - { - new_s->id = id; - obj->objects[id] = new_s; - - /* The Unserialize operation is destructive so rebuild the data for UpdateCache. - * Also the old data may contain columns that we don't use, so we reserialize the - * object to know for sure our cache is consistent - */ - - Data data2; - new_s->Serialize(data2); - new_s->UpdateCache(data2); /* We know this is the most up to date copy */ - } - } - else - { - if (!s) - this->RunQuery("UPDATE `" + prefix + obj->GetName() + "` SET `timestamp` = " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " WHERE `id` = " + stringify(id)); - else - delete s; - } - } - } - - if (clear_null) - { - query = "DELETE FROM `" + this->prefix + obj->GetName() + "` WHERE `timestamp` IS NULL"; - this->RunQuery(query); - } - } - - void OnSerializableUpdate(Serializable *obj) anope_override - { - if (!this->CheckInit() || obj->IsTSCached()) - return; - obj->UpdateTS(); - this->updated_items.insert(obj); - this->Notify(); - } -}; - -MODULE_INIT(DBMySQL) - diff --git a/modules/database/flatfile.cpp b/modules/database/flatfile.cpp new file mode 100644 index 000000000..ec6911ce2 --- /dev/null +++ b/modules/database/flatfile.cpp @@ -0,0 +1,807 @@ +/* + * Anope IRC Services + * + * Copyright (C) 2011-2016 Anope Team <team@anope.org> + * + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. + */ + +#include "module.h" +#include "modules/botserv/badwords.h" +#include "modules/chanserv/access.h" +#include "modules/chanserv/entrymsg.h" +#include "modules/chanserv/log.h" +#include "modules/chanserv/set_misc.h" +#include "modules/chanserv/suspend.h" +#include "modules/nickserv/access.h" +#include "modules/nickserv/ajoin.h" +#include "modules/nickserv/cert.h" +#include "modules/nickserv/set_misc.h" +#include "modules/nickserv/suspend.h" +#include "modules/operserv/forbid.h" +#include "modules/operserv/news.h" +#include "modules/operserv/info.h" + +class DBFlatFile : public Module + , public EventHook<Event::LoadDatabase> +{ + void LoadAccount(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + NickServ::Account *account = Serialize::New<NickServ::Account *>(); + + if (account == nullptr) + return; + + account->SetDisplay(data["display"]); + account->SetPassword(data["pass"]); + account->SetEmail(data["email"]); + account->SetLanguage(data["language"]); + account->SetOper(Oper::Find(account->GetDisplay())); + + spacesepstream sep = data["access"]; + for (Anope::string token; sep.GetToken(token);) + { + NickAccess *access = Serialize::New<NickAccess *>(); + if (access != nullptr) + { + access->SetAccount(account); + access->SetMask(token); + } + } + + MemoServ::MemoInfo *memos = account->GetMemos(); + if (memos != nullptr) + { + try + { + int16_t memomax = convertTo<int16_t>(data["memomax"]); + memos->SetMemoMax(memomax); + } + catch (const ConvertException &) { } + } + + sep = data["memoignore"]; + for (Anope::string token; memos && sep.GetToken(token);) + { + MemoServ::Ignore *ign = Serialize::New<MemoServ::Ignore *>(); + if (ign != nullptr) + { + ign->SetMemoInfo(memos); + ign->SetMask(token); + } + } + + sep = data["cert"]; + for (Anope::string token; sep.GetToken(token);) + { + NSCertEntry *e = Serialize::New<NSCertEntry *>(); + if (e != nullptr) + { + e->SetAccount(account); + e->SetCert(token); + } + } + + // last_modes + } + + void LoadNick(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + NickServ::Account *acc = NickServ::FindAccount(data["nc"]); + if (acc == nullptr) + return; + + NickServ::Nick *nick = Serialize::New<NickServ::Nick *>(); + + if (nick == nullptr) + return; + + nick->SetNick(data["nick"]); + nick->SetLastQuit(data["last_quit"]); + nick->SetLastRealname(data["last_realname"]); + nick->SetLastUsermask(data["last_usermask"]); + nick->SetLastRealhost(data["last_realhost"]); + try + { + nick->SetTimeRegistered(convertTo<time_t>(data["time_registered"])); + } + catch (const ConvertException &) { } + try + { + nick->SetLastSeen(convertTo<time_t>(data["last_seen"])); + } + catch (const ConvertException &) { } + nick->SetAccount(acc); + + if (data["vhost_host"].empty() == false) + { + HostServ::VHost *vhost = Serialize::New<HostServ::VHost *>(); + if (vhost != nullptr) + { + vhost->SetAccount(acc); + vhost->SetIdent(data["vhost_ident"]); + vhost->SetHost(data["vhost_host"]); + vhost->SetCreator(data["vhost_creator"]); + try + { + vhost->SetCreated(convertTo<time_t>(data["vhost_time"])); + } + catch (const ConvertException &) { } + } + } + } + + void LoadNSSuspend(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + NickServ::Nick *nick = NickServ::FindNick(data["nick"]); + + if (nick == nullptr) + return; + + NSSuspendInfo *si = Serialize::New<NSSuspendInfo *>(); + if (si == nullptr) + return; + + si->SetAccount(nick->GetAccount()); + si->SetBy(data["by"]); + si->SetReason(data["reason"]); + try + { + si->SetWhen(convertTo<time_t>(data["time"])); + } + catch (const ConvertException &) { } + try + { + si->SetExpires(convertTo<time_t>(data["expires"])); + } + catch (const ConvertException &) { } + } + + void LoadAJoin(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + NickServ::Nick *nick = NickServ::FindNick(data["nick"]); + + if (nick == nullptr) + return; + + AutoJoin *entry = Serialize::New<AutoJoin *>(); + if (entry == nullptr) + return; + + entry->SetAccount(nick->GetAccount()); + entry->SetChannel(data["channel"]); + entry->SetKey(data["key"]); + } + + void LoadNSMiscData(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + NickServ::Nick *nick = NickServ::FindNick(data["nc"]); + + if (nick == nullptr) + return; + + NSMiscData *d = Serialize::New<NSMiscData *>(); + if (d == nullptr) + return; + + d->SetAccount(nick->GetAccount()); + d->SetName(data["name"]); + d->SetData(data["data"]); + } + + void LoadChannel(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *chan = Serialize::New<ChanServ::Channel *>(); + + if (chan == nullptr) + return; + + chan->SetName(data["name"]); + chan->SetFounder(NickServ::FindAccount(data["founder"])); + chan->SetSuccessor(NickServ::FindAccount(data["successor"])); + chan->SetDesc(data["description"]); + try + { + chan->SetTimeRegistered(convertTo<time_t>(data["time_registered"])); + } + catch (const ConvertException &) { } + try + { + chan->SetLastUsed(convertTo<time_t>(data["last_used"])); + } + catch (const ConvertException &) { } + chan->SetLastTopic(data["last_topic"]); + chan->SetLastTopicSetter(data["last_topic_setter"]); + try + { + chan->SetLastTopicTime(convertTo<time_t>(data["last_topic_time"])); + } + catch (const ConvertException &) { } + try + { + chan->SetBanType(convertTo<int16_t>(data["bantype"])); + } + catch (const ConvertException &) { } + + spacesepstream sep = data["levels"]; + for (Anope::string lname, lvalue; sep.GetToken(lname) && sep.GetToken(lvalue);) + { + try + { + chan->SetLevel(lname, convertTo<int16_t>(lvalue)); + } + catch (const ConvertException &) { } + } + + if (data["bi"].empty() == false) + { + ServiceBot *sb = ServiceBot::Find(data["bi"], true); + if (sb != nullptr) + chan->SetBI(sb->bi); + } + + try + { + chan->SetBanExpire(convertTo<time_t>(data["banexpire"])); + } + catch (const ConvertException &) { } + + MemoServ::MemoInfo *memos = chan->GetMemos(); + if (memos != nullptr) + { + try + { + int16_t memomax = convertTo<int16_t>(data["memomax"]); + memos->SetMemoMax(memomax); + } + catch (const ConvertException &) { } + } + + sep = data["memoignore"]; + for (Anope::string token; memos && sep.GetToken(token);) + { + MemoServ::Ignore *ign = Serialize::New<MemoServ::Ignore *>(); + if (ign != nullptr) + { + ign->SetMemoInfo(memos); + ign->SetMask(token); + } + } + + // last modes + // kicker data + + // exts + } + + void LoadBot(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + if (ServiceBot::Find(data["nick"], true)) + return; + + BotInfo *bot = Serialize::New<BotInfo *>(); + if (bot == nullptr) + return; + + bot->SetNick(data["nick"]); + bot->SetUser(data["user"]); + bot->SetHost(data["host"]); + bot->SetRealName(data["realname"]); + try + { + bot->SetCreated(convertTo<time_t>(data["created"])); + } + catch (const ConvertException &) { } + bot->SetOperOnly(data["oper_only"] != "0"); + + ServiceBot *sb = new ServiceBot(bot->GetNick(), bot->GetUser(), bot->GetHost(), bot->GetRealName()); + + sb->bi = bot; + bot->bot = sb; + } + + void LoadChanAccess(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + Anope::string mask = data["mask"]; + if (mask.find('#') == 0) + return; + + Anope::string provider = data["provider"]; + ChanServ::ChanAccess *access; + + if (provider == "access/access") + access = Serialize::New<AccessChanAccess *>(); + else if (provider == "access/xop") + access = Serialize::New<XOPChanAccess *>(); + else if (provider == "access/flags") + access = Serialize::New<FlagsChanAccess *>(); + else + return; + + if (access == nullptr) + return; + + access->SetChannel(channel); + access->SetCreator(data["creator"]); + try + { + access->SetLastSeen(convertTo<time_t>(data["last_seen"])); + } + catch (const ConvertException &) { } + try + { + access->SetCreated(convertTo<time_t>(data["created"])); + } + catch (const ConvertException &) { } + access->SetMask(mask); + + NickServ::Nick *nick = NickServ::FindNick(mask); + if (nick != nullptr) + access->SetAccount(nick->GetAccount()); + + access->AccessUnserialize(data["data"]); + } + + void LoadModeLock(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + ModeLock *ml = Serialize::New<ModeLock *>(); + ml->SetChannel(channel); + ml->SetSet(data["set"] == "1"); + ml->SetName(data["name"]); + ml->SetParam(data["param"]); + ml->SetSetter(data["setter"]); + try + { + ml->SetCreated(convertTo<time_t>(data["created"])); + } + catch (const ConvertException &) { } + } + + void LoadAutoKick(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + NickServ::Nick *nick = nullptr; + if (data["nc"].empty() == false) + { + nick = NickServ::FindNick(data["nc"]); + + if (nick == nullptr) + return; + } + + time_t added = 0, lastused = 0; + + try + { + added = convertTo<time_t>(data["addtime"]); + } + catch (const ConvertException &) { } + + try + { + lastused = convertTo<time_t>(data["last_used"]); + } + catch (const ConvertException &) { } + + if (nick != nullptr) + channel->AddAkick(data["creator"], nick->GetAccount(), data["reason"], added, lastused); + else + channel->AddAkick(data["creator"], data["mask"], data["reason"], added, lastused); + } + + void LoadBadWord(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + BadWord *bw = Serialize::New<BadWord *>(); + if (bw == nullptr) + return; + + bw->SetChannel(channel); + bw->SetWord(data["word"]); + try + { + bw->SetType(static_cast<BadWordType>(convertTo<int>(data["type"]))); + } + catch (const ConvertException &) { } + } + + void LoadCSSuspend(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + CSSuspendInfo *si = Serialize::New<CSSuspendInfo *>(); + if (si == nullptr) + return; + + si->SetChannel(channel); + si->SetBy(data["by"]); + si->SetReason(data["reason"]); + try + { + si->SetWhen(convertTo<time_t>(data["time"])); + } + catch (const ConvertException &) { } + try + { + si->SetExpires(convertTo<time_t>(data["expires"])); + } + catch (const ConvertException &) { } + } + + void LoadEntrymsg(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + EntryMsg *msg = Serialize::New<EntryMsg *>(); + if (msg == nullptr) + return; + + msg->SetChannel(channel); + msg->SetCreator(data["creator"]); + msg->SetMessage(data["message"]); + } + + void LoadLogSetting(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + LogSetting *log = Serialize::New<LogSetting *>(); + if (log == nullptr) + return; + + log->SetChannel(channel); + log->SetServiceName(data["service_name"]); + log->SetCommandService(data["command_service"]); + log->SetCommandName(data["command_name"]); + log->SetMethod(data["method"]); + log->SetExtra(data["extra"]); + try + { + log->SetCreated(convertTo<time_t>(data["created"])); + } + catch (const ConvertException &) { } + log->SetCreator(data["creator"]); + } + + void LoadCSMiscData(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ChanServ::Channel *channel = ChanServ::Find(data["ci"]); + if (channel == nullptr) + return; + + CSMiscData *d = Serialize::New<CSMiscData *>(); + if (d == nullptr) + return; + + d->SetChannel(channel); + d->SetName(data["name"]); + d->SetData(data["data"]); + } + + void LoadForbid(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + ForbidData *d = Serialize::New<ForbidData *>(); + if (d == nullptr) + return; + + d->SetMask(data["mask"]); + d->SetCreator(data["creator"]); + d->SetReason(data["reason"]); + try + { + d->SetCreated(convertTo<time_t>(data["created"])); + } + catch (const ConvertException &) { } + try + { + d->SetExpires(convertTo<time_t>(data["expires"])); + } + catch (const ConvertException &) { } + try + { + d->SetType(static_cast<ForbidType>(convertTo<int>(data["type"]))); + } + catch (const ConvertException &) { } + } + + void LoadNews(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + NewsItem *ni = Serialize::New<NewsItem *>(); + if (ni == nullptr) + return; + + try + { + ni->SetNewsType(static_cast<NewsType>(convertTo<int>(data["type"]))); + } + catch (const ConvertException &) { } + ni->SetText(data["text"]); + try + { + ni->SetTime(convertTo<time_t>(data["time"])); + } + catch (const ConvertException &) { } + ni->SetWho(data["who"]); + } + + void LoadOperInfo(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + NickServ::Account *acc = NickServ::FindAccount(data["target"]); + ChanServ::Channel *chan = ChanServ::Find(data["target"]); + + if (acc == nullptr && chan == nullptr) + return; + + OperInfo *o = Serialize::New<OperInfo *>(); + if (o == nullptr) + return; + + o->SetAccount(acc); + o->SetChannel(chan); + o->SetInfo(data["info"]); + o->SetCreator(data["adder"]); + try + { + o->SetCreated(convertTo<time_t>(data["created"])); + } + catch (const ConvertException &) { } + } + + void LoadXLine(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + XLine *x = Serialize::New<XLine *>(); + if (x == nullptr) + return; + + x->SetMask(data["mask"]); + x->SetBy(data["by"]); + try + { + x->SetExpires(convertTo<time_t>(data["expires"])); + } + catch (const ConvertException &) { } + try + { + x->SetCreated(convertTo<time_t>(data["created"])); + } + catch (const ConvertException &) { } + x->SetReason(data["reason"]); + x->SetID(data["uid"]); + x->SetType(data["manager"]); + } + + void LoadOper(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { +#warning "oper needs account ref" +#if 0 + data["name"] << this->name; + data["type"] << this->ot->GetName(); + Oper *o = Serialize::New<Oper *>(); + o->SetName(na->GetAccount()->GetDisplay()); + o->SetType(ot); + o->SetRequireOper(true); +#endif + } + + void LoadDNSZone(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { +#if 0 + DNSZone *z = Serialize::New<DNSZone *>(); + z->SetName(data["name"]); + + unsigned int count = 0; + while (data["server" + stringify(count)].empty() == false) + { + DNSZoneMembership *mem = Serialize::New<DNSZoneMembership *>(); + mem->SetZone(z); + mem->SetServer(s); + + ++count; + } +// data["name"] << name; +// unsigned count = 0; +// for (std::set<Anope::string, ci::less>::iterator it = servers.begin(), it_end = servers.end(); it != it_end; ++it) +// data["server" + stringify(count++)] << *it; +#endif + } + + void LoadDNSServer(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { +#if 0 + s = Serialize::New<DNSServer *>(); + s->SetName(data["server_name"]); + + data["server_name"] << server_name; + for (unsigned i = 0; i < ips.size(); ++i) + data["ip" + stringify(i)] << ips[i]; + try + { + s->SetLimit(convertTo<unsigned>(data["limit"])); + } + catch (const ConvertException &) { } + try + { + s->SetPooled(data["pooled"] == "1"); + } + catch (const ConvertException &) { } + + unsigned int count = 0; + while (data["zone" + stringify(count)].empty() == false) + { + } +// for (std::set<Anope::string, ci::less>::iterator it = zones.begin(), it_end = zones.end(); it != it_end; ++it) +// data["zone" + stringify(count++)] << *it; +#endif + } + + void LoadMemo(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + MemoServ::MemoInfo *mi = nullptr; + + Anope::string owner = data["owner"]; + + NickServ::Nick *nick = NickServ::FindNick(owner); + ChanServ::Channel *chan = ChanServ::Find(owner); + if (nick != nullptr) + mi = nick->GetAccount()->GetMemos(); + else if (chan != nullptr) + mi = chan->GetMemos(); + + if (mi == nullptr) + return; + + MemoServ::Memo *m = Serialize::New<MemoServ::Memo *>(); + if (m == nullptr) + return; + + m->SetMemoInfo(mi); + m->SetSender(data["sender"]); + try + { + m->SetTime(convertTo<time_t>(data["time"])); + } + catch (const ConvertException &) { } + m->SetText(data["text"]); + m->SetUnread(data["unread"] == "1"); + // receipt + } + + void LoadType(const Anope::string &type, std::map<Anope::string, Anope::string> &data) + { + if (type == "NickCore") + LoadAccount(type, data); + else if (type == "NickAlias") + LoadNick(type, data); + else if (type == "NSSuspend") + LoadNSSuspend(type, data); + else if (type == "AJoinEntry") + LoadAJoin(type, data); + else if (type == "NSMiscData") + LoadNSMiscData(type, data); + + else if (type == "BotInfo") + LoadBot(type, data); + else if (type == "BadWord") + LoadBadWord(type, data); + + else if (type == "ChannelInfo") + LoadChannel(type, data); + else if (type == "ChanAccess") + LoadChanAccess(type, data); + else if (type == "ModeLock") + LoadModeLock(type, data); + else if (type == "AutoKick") + LoadAutoKick(type, data); + else if (type == "CSSuspendInfo") + LoadCSSuspend(type, data); + else if (type == "EntryMsg") + LoadEntrymsg(type, data); + else if (type == "LogSetting") + LoadLogSetting(type, data); + else if (type == "CSMiscData") + LoadCSMiscData(type, data); + + else if (type == "ForbidData") + LoadForbid(type, data); + else if (type == "NewsItem") + LoadNews(type, data); + else if (type == "OperInfo") + LoadOperInfo(type, data); + else if (type == "XLine") + LoadXLine(type, data); + else if (type == "Oper") + LoadOper(type, data); + else if (type == "DNSZone") + LoadDNSZone(type, data); + else if (type == "DNSServer") + LoadDNSServer(type, data); + + else if (type == "Memo") + LoadMemo(type, data); + } + + public: + DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) + , EventHook<Event::LoadDatabase>(this) + { + + } + + EventReturn OnLoadDatabase() override + { + const Anope::string &db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<Anope::string>("database", "anope.db"); + + std::fstream fd(db_name.c_str(), std::ios_base::in | std::ios_base::binary); + if (!fd.is_open()) + { + logger.Log("Unable to open {0} for reading!", db_name); + return EVENT_STOP; + } + + Anope::string type; + std::map<Anope::string, Anope::string> data; + for (Anope::string buf; std::getline(fd, buf.str());) + { + if (buf.find("OBJECT ") == 0) + { + type = buf.substr(7); + } + else if (buf.find("DATA ") == 0) + { + size_t sp = buf.find(' ', 5); // Skip DATA + if (sp == Anope::string::npos) + continue; + + Anope::string key = buf.substr(5, sp - 5), value = buf.substr(sp + 1); + + data[key] = value; + } + else if (buf.find("END") == 0) + { + LoadType(type, data); + + type.empty(); + data.empty(); + } + } + + fd.close(); + + return EVENT_STOP; + } +}; + +MODULE_INIT(DBFlatFile) + + diff --git a/modules/database/db_old.cpp b/modules/database/old.cpp index 0c65fb95b..3a2b6ccb6 100644 --- a/modules/database/db_old.cpp +++ b/modules/database/old.cpp @@ -1,23 +1,36 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ +/* Dependencies: anope_chanserv.access */ + #include "module.h" -#include "modules/os_session.h" -#include "modules/bs_kick.h" -#include "modules/cs_mode.h" -#include "modules/bs_badwords.h" -#include "modules/os_news.h" -#include "modules/suspend.h" -#include "modules/os_forbid.h" -#include "modules/cs_entrymsg.h" +#include "modules/operserv/session.h" +#include "modules/botserv/kick.h" +#include "modules/chanserv/mode.h" +#include "modules/botserv/badwords.h" +#include "modules/operserv/news.h" +#include "modules/operserv/forbid.h" +#include "modules/chanserv/entrymsg.h" +#include "modules/nickserv/suspend.h" +#include "modules/chanserv/suspend.h" +#include "modules/chanserv/access.h" +#include "modules/nickserv/access.h" #define READ(x) \ if (true) \ @@ -94,6 +107,18 @@ else \ #define OLD_NEWS_OPER 1 #define OLD_NEWS_RANDOM 2 +enum +{ + TTB_BOLDS, + TTB_COLORS, + TTB_REVERSES, + TTB_UNDERLINES, + TTB_BADWORDS, + TTB_CAPS, + TTB_FLOOD, + TTB_REPEAT, +}; + static struct mlock_info { char c; @@ -143,21 +168,25 @@ enum LANG_PL /* Polish */ }; -static void process_mlock(ChannelInfo *ci, uint32_t lock, bool status, uint32_t *limit, Anope::string *key) +static void process_mlock(ChanServ::Channel *ci, uint32_t lock, bool status, uint32_t *limit, Anope::string *key) { - ModeLocks *ml = ci->Require<ModeLocks>("modelocks"); + ServiceReference<ModeLocks> mlocks; + + if (!mlocks) + return; + for (unsigned i = 0; i < (sizeof(mlock_infos) / sizeof(mlock_info)); ++i) if (lock & mlock_infos[i].m) { ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock_infos[i].c); - if (cm && ml) + if (cm) { if (limit && mlock_infos[i].c == 'l') - ml->SetMLock(cm, status, stringify(*limit)); + mlocks->SetMLock(ci, cm, status, stringify(*limit)); else if (key && mlock_infos[i].c == 'k') - ml->SetMLock(cm, status, *key); + mlocks->SetMLock(ci, cm, status, *key); else - ml->SetMLock(cm, status); + mlocks->SetMLock(ci, cm, status); } } } @@ -326,7 +355,7 @@ static dbFILE *open_db_read(const char *service, const char *filename, int versi fp = fopen(f->filename, "rb"); if (!fp) { - Log() << "Can't read " << service << " database " << f->filename; + Anope::Logger.Log("Can't read {0} database {1}", service, f->filename); delete f; return NULL; } @@ -334,13 +363,13 @@ static dbFILE *open_db_read(const char *service, const char *filename, int versi myversion = fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp); if (feof(fp)) { - Log() << "Error reading version number on " << f->filename << ": End of file detected."; + Anope::Logger.Log("Error reading version number on {0}: End of file detected.", f->filename); delete f; return NULL; } else if (myversion < version) { - Log() << "Unsuported database version (" << myversion << ") on " << f->filename << "."; + Anope::Logger.Log("Unsuported database version ({0}) on {1}.", myversion, f->filename); delete f; return NULL; } @@ -435,7 +464,8 @@ int read_int32(int32_t *ret, dbFILE *f) static void LoadNicks() { - ServiceReference<ForbidService> forbid("ForbidService", "forbid"); + if (!NickServ::service) + return; dbFILE *f = open_db_read("NickServ", "nick.db", 14); if (f == NULL) return; @@ -445,31 +475,37 @@ static void LoadNicks() Anope::string buffer; READ(read_string(buffer, f)); - NickCore *nc = new NickCore(buffer); - const Anope::string settings[] = { "killprotect", "kill_quick", "ns_secure", "ns_private", "hide_email", - "hide_mask", "hide_quit", "memo_signon", "memo_receive", "autoop", "msg", "ns_keepmodes" }; + NickServ::Account *nc = Serialize::New<NickServ::Account *>(); + nc->SetDisplay(buffer); + + const Anope::string settings[] = { "killprotect", "kill_quick", "secure", "private", "hide_email", + "hide_mask", "hide_quit", "memo_signon", "memo_receive", "autoop", "msg", "keepmodes" }; for (unsigned j = 0; j < sizeof(settings) / sizeof(Anope::string); ++j) - nc->Shrink<bool>(settings[j].upper()); + nc->UnsetS<bool>(settings[j]); char pwbuf[32]; READ(read_buffer(pwbuf, f)); if (hashm == "plain") - my_b64_encode(pwbuf, nc->pass); + { + Anope::string p; + my_b64_encode(pwbuf, p); + nc->SetPassword(p); + } else if (hashm == "md5" || hashm == "oldmd5") - nc->pass = Hex(pwbuf, 16); + nc->SetPassword(Hex(pwbuf, 16)); else if (hashm == "sha1") - nc->pass = Hex(pwbuf, 20); + nc->SetPassword(Hex(pwbuf, 20)); else - nc->pass = Hex(pwbuf, strlen(pwbuf)); - nc->pass = hashm + ":" + nc->pass; + nc->SetPassword(Hex(pwbuf, strlen(pwbuf))); + nc->SetPassword(hashm + ":" + nc->GetPassword()); READ(read_string(buffer, f)); - nc->email = buffer; + nc->SetEmail(buffer); READ(read_string(buffer, f)); if (!buffer.empty()) - nc->Extend<Anope::string>("greet", buffer); + nc->SetGreet(buffer); uint32_t u32; READ(read_uint32(&u32, f)); @@ -480,122 +516,135 @@ static void LoadNicks() READ(read_uint32(&u32, f)); if (u32 & OLD_NI_KILLPROTECT) - nc->Extend<bool>("KILLPROTECT"); + nc->SetKillProtect(true); if (u32 & OLD_NI_SECURE) - nc->Extend<bool>("NS_SECURE"); + nc->SetSecure(true); if (u32 & OLD_NI_MSG) - nc->Extend<bool>("MSG"); + nc->SetMsg(true); if (u32 & OLD_NI_MEMO_HARDMAX) - nc->Extend<bool>("MEMO_HARDMAX"); + if (MemoServ::MemoInfo *mi = nc->GetMemos()) + mi->SetHardMax(true); if (u32 & OLD_NI_MEMO_SIGNON) - nc->Extend<bool>("MEMO_SIGNON"); + nc->SetMemoSignon(true); if (u32 & OLD_NI_MEMO_RECEIVE) - nc->Extend<bool>("MEMO_RECEIVE"); + nc->SetMemoReceive(true); if (u32 & OLD_NI_PRIVATE) - nc->Extend<bool>("NS_PRIVATE"); + nc->SetPrivate(true); if (u32 & OLD_NI_HIDE_EMAIL) - nc->Extend<bool>("HIDE_EMAIL"); + nc->SetHideEmail(true); if (u32 & OLD_NI_HIDE_MASK) - nc->Extend<bool>("HIDE_MASK"); + nc->SetHideMask(true); if (u32 & OLD_NI_HIDE_QUIT) - nc->Extend<bool>("HIDE_QUIT"); + nc->SetHideQuit(true); if (u32 & OLD_NI_KILL_QUICK) - nc->Extend<bool>("KILL_QUICK"); + nc->SetKillQuick(true); if (u32 & OLD_NI_KILL_IMMED) - nc->Extend<bool>("KILL_IMMED"); + nc->SetKillImmed(true); if (u32 & OLD_NI_MEMO_MAIL) - nc->Extend<bool>("MEMO_MAIL"); + nc->SetMemoMail(true); if (u32 & OLD_NI_HIDE_STATUS) - nc->Extend<bool>("HIDE_STATUS"); + nc->SetHideStatus(true); if (u32 & OLD_NI_SUSPENDED) { - SuspendInfo si; - si.what = nc->display; - si.when = si.expires = 0; - nc->Extend("NS_SUSPENDED", si); + NSSuspendInfo *si = Serialize::New<NSSuspendInfo *>(); + if (si) + { + si->SetAccount(nc); + } } if (!(u32 & OLD_NI_AUTOOP)) - nc->Extend<bool>("AUTOOP"); + nc->SetAutoOp(true); uint16_t u16; READ(read_uint16(&u16, f)); switch (u16) { case LANG_ES: - nc->language = "es_ES"; + nc->SetLanguage("es_ES"); break; case LANG_PT: - nc->language = "pt_PT"; + nc->SetLanguage("pt_PT"); break; case LANG_FR: - nc->language = "fr_FR"; + nc->SetLanguage("fr_FR"); break; case LANG_TR: - nc->language = "tr_TR"; + nc->SetLanguage("tr_TR"); break; case LANG_IT: - nc->language = "it_IT"; + nc->SetLanguage("it_IT"); break; case LANG_DE: - nc->language = "de_DE"; + nc->SetLanguage("de_DE"); break; case LANG_CAT: - nc->language = "ca_ES"; // yes, iso639 defines catalan as CA + nc->SetLanguage("ca_ES"); // yes, iso639 defines catalan as CA break; case LANG_GR: - nc->language = "el_GR"; + nc->SetLanguage("el_GR"); break; case LANG_NL: - nc->language = "nl_NL"; + nc->SetLanguage("nl_NL"); break; case LANG_RU: - nc->language = "ru_RU"; + nc->SetLanguage("ru_RU"); break; case LANG_HUN: - nc->language = "hu_HU"; + nc->SetLanguage("hu_HU"); break; case LANG_PL: - nc->language = "pl_PL"; + nc->SetLanguage("pl_PL"); break; case LANG_EN_US: case LANG_JA_JIS: case LANG_JA_EUC: case LANG_JA_SJIS: // these seem to be unused default: - nc->language = "en"; + nc->SetLanguage("en"); } READ(read_uint16(&u16, f)); for (uint16_t j = 0; j < u16; ++j) { READ(read_string(buffer, f)); - nc->access.push_back(buffer); + + NickAccess *a = Serialize::New<NickAccess *>(); + if (a) + { + a->SetAccount(nc); + a->SetMask(buffer); + } } int16_t i16; READ(read_int16(&i16, f)); - READ(read_int16(&nc->memos.memomax, f)); + READ(read_int16(&i16, f)); + MemoServ::MemoInfo *mi = nc->GetMemos(); + if (mi) + mi->SetMemoMax(i16); for (int16_t j = 0; j < i16; ++j) { - Memo *m = new Memo; + MemoServ::Memo *m = Serialize::New<MemoServ::Memo *>(); READ(read_uint32(&u32, f)); uint16_t flags; READ(read_uint16(&flags, f)); int32_t tmp32; READ(read_int32(&tmp32, f)); - m->time = tmp32; + if (m) + m->SetTime(tmp32); char sbuf[32]; READ(read_buffer(sbuf, f)); - m->sender = sbuf; - READ(read_string(m->text, f)); - m->owner = nc->display; - nc->memos.memos->push_back(m); - m->mi = &nc->memos; + if (m) + m->SetSender(sbuf); + Anope::string text; + READ(read_string(text, f)); + if (m) + m->SetText(text); } READ(read_uint16(&u16, f)); READ(read_int16(&i16, f)); - Log(LOG_DEBUG) << "Loaded NickCore " << nc->display; + Anope::Logger.Debug("Loaded nickserv account {0}", nc->GetDisplay()); } for (int i = 0; i < 1024; ++i) @@ -620,50 +669,47 @@ static void LoadNicks() Anope::string core; READ(read_string(core, f)); - NickCore *nc = NickCore::Find(core); + NickServ::Account *nc = NickServ::FindAccount(core); if (nc == NULL) { - Log() << "Skipping coreless nick " << nick << " with core " << core; + Anope::Logger.Debug("Skipping coreless nick {0} with core {1}", nick, core); continue; } if (tmpu16 & OLD_NS_VERBOTEN) { - if (!forbid) + if (nc->GetDisplay().find_first_of("?*") != Anope::string::npos) { delete nc; continue; } - if (nc->display.find_first_of("?*") != Anope::string::npos) + ForbidData *d = Serialize::New<ForbidData *>(); + if (d) { - delete nc; - continue; + d->SetMask(nc->GetDisplay()); + d->SetCreator(last_usermask); + d->SetReason(last_realname); + d->SetType(FT_NICK); } - - ForbidData *d = forbid->CreateForbid(); - d->mask = nc->display; - d->creator = last_usermask; - d->reason = last_realname; - d->expires = 0; - d->created = 0; - d->type = FT_NICK; + delete nc; - forbid->AddForbid(d); continue; } - NickAlias *na = new NickAlias(nick, nc); - na->last_usermask = last_usermask; - na->last_realname = last_realname; - na->last_quit = last_quit; - na->time_registered = time_registered; - na->last_seen = last_seen; + NickServ::Nick *na = Serialize::New<NickServ::Nick *>(); + na->SetNick(nick); + na->SetAccount(nc); + na->SetLastUsermask(last_usermask); + na->SetLastRealname(last_realname); + na->SetLastQuit(last_quit); + na->SetTimeRegistered(time_registered); + na->SetLastSeen(last_seen); if (tmpu16 & OLD_NS_NO_EXPIRE) - na->Extend<bool>("NS_NO_EXPIRE"); + na->SetNoExpire(true); - Log(LOG_DEBUG) << "Loaded NickAlias " << na->nick; + Anope::Logger.Debug("Loaded nick {0}", na->GetNick()); } close_db(f); /* End of section Ia */ @@ -686,16 +732,24 @@ static void LoadVHosts() READ(read_string(creator, f)); READ(read_int32(&vtime, f)); - NickAlias *na = NickAlias::Find(nick); + NickServ::Nick *na = NickServ::FindNick(nick); if (na == NULL) { - Log() << "Removing vhost for non-existent nick " << nick; + Anope::Logger.Log("Removing vhost for non-existent nick {0}", nick); continue; } - na->SetVhost(ident, host, creator, vtime); + HostServ::VHost *vhost = Serialize::New<HostServ::VHost *>(); + if (vhost == nullptr) + continue; + + vhost->SetAccount(na->GetAccount()); + vhost->SetIdent(ident); + vhost->SetHost(host); + vhost->SetCreator(creator); + vhost->SetCreated(vtime); - Log() << "Loaded vhost for " << na->nick; + Anope::Logger.Debug("Loaded vhost for {0}", na->GetNick()); } close_db(f); @@ -721,15 +775,19 @@ static void LoadBots() READ(read_int32(&created, f)); READ(read_int16(&chancount, f)); - BotInfo *bi = BotInfo::Find(nick, true); + ServiceBot *bi = ServiceBot::Find(nick, true); if (!bi) - bi = new BotInfo(nick, user, host, real); - bi->created = created; + 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) - bi->oper_only = true; + bi->bi->SetOperOnly(true); - Log(LOG_DEBUG) << "Loaded bot " << bi->nick; + Anope::Logger.Debug("Loaded bot {0}", bi->nick); } close_db(f); @@ -737,7 +795,13 @@ static void LoadBots() static void LoadChannels() { - ServiceReference<ForbidService> forbid("ForbidService", "forbid"); + ServiceReference<BadWords> badwords; + ServiceReference<ChanServ::ChanServService> chanserv; + + if (!chanserv) + return; + + ServiceReference<ForbidService> forbid; dbFILE *f = open_db_read("ChanServ", "chan.db", 16); if (f == NULL) return; @@ -748,87 +812,93 @@ static void LoadChannels() Anope::string buffer; char namebuf[64]; READ(read_buffer(namebuf, f)); - ChannelInfo *ci = new ChannelInfo(namebuf); + ChanServ::Channel *ci = Serialize::New<ChanServ::Channel *>(); + ci->SetName(namebuf); - const Anope::string settings[] = { "keeptopic", "peace", "cs_private", "restricted", "cs_secure", "secureops", "securefounder", - "signkick", "signkick_level", "topiclock", "persist", "noautoop", "cs_keepmodes" }; + const Anope::string settings[] = { "keeptopic", "peace", "private", "restricted", "secure", "secureops", "securefounder", + "signkick", "signkick_level", "topiclock", "persist", "noautoop", "keepmodes" }; for (unsigned j = 0; j < sizeof(settings) / sizeof(Anope::string); ++j) - ci->Shrink<bool>(settings[j].upper()); + ci->UnsetS<bool>(settings[j]); READ(read_string(buffer, f)); - ci->SetFounder(NickCore::Find(buffer)); + ci->SetFounder(NickServ::FindAccount(buffer)); READ(read_string(buffer, f)); - ci->SetSuccessor(NickCore::Find(buffer)); + ci->SetSuccessor(NickServ::FindAccount(buffer)); char pwbuf[32]; READ(read_buffer(pwbuf, f)); - READ(read_string(ci->desc, f)); + Anope::string desc; + READ(read_string(desc, f)); + ci->SetDesc(desc); READ(read_string(buffer, f)); READ(read_string(buffer, f)); int32_t tmp32; READ(read_int32(&tmp32, f)); - ci->time_registered = tmp32; + ci->SetTimeRegistered(tmp32); READ(read_int32(&tmp32, f)); - ci->last_used = tmp32; + ci->SetLastUsed(tmp32); - READ(read_string(ci->last_topic, f)); + Anope::string last_topic; + READ(read_string(last_topic, f)); + ci->SetLastTopic(last_topic); READ(read_buffer(pwbuf, f)); - ci->last_topic_setter = pwbuf; + ci->SetLastTopicSetter(pwbuf); READ(read_int32(&tmp32, f)); - ci->last_topic_time = tmp32; + ci->SetLastTopicTime(tmp32); uint32_t tmpu32; READ(read_uint32(&tmpu32, f)); // Temporary flags cleanup tmpu32 &= ~0x80000000; if (tmpu32 & OLD_CI_KEEPTOPIC) - ci->Extend<bool>("KEEPTOPIC"); + ci->SetKeepTopic(true); if (tmpu32 & OLD_CI_SECUREOPS) - ci->Extend<bool>("SECUREOPS"); + ci->SetSecureOps(true); if (tmpu32 & OLD_CI_PRIVATE) - ci->Extend<bool>("CS_PRIVATE"); + ci->SetPrivate(true); if (tmpu32 & OLD_CI_TOPICLOCK) - ci->Extend<bool>("TOPICLOCK"); + ci->SetTopicLock(true); if (tmpu32 & OLD_CI_RESTRICTED) - ci->Extend<bool>("RESTRICTED"); + ci->SetRestricted(true); if (tmpu32 & OLD_CI_PEACE) - ci->Extend<bool>("PEACE"); + ci->SetPeace(true); if (tmpu32 & OLD_CI_SECURE) - ci->Extend<bool>("CS_SECURE"); + ci->SetSecure(true); if (tmpu32 & OLD_CI_NO_EXPIRE) - ci->Extend<bool>("CS_NO_EXPIRE"); + ci->SetNoExpire(true); if (tmpu32 & OLD_CI_MEMO_HARDMAX) - ci->Extend<bool>("MEMO_HARDMAX"); + if (MemoServ::MemoInfo *mi = ci->GetMemos()) + mi->SetHardMax(true); if (tmpu32 & OLD_CI_SECUREFOUNDER) - ci->Extend<bool>("SECUREFOUNDER"); + ci->SetSecureFounder(true); if (tmpu32 & OLD_CI_SIGNKICK) - ci->Extend<bool>("SIGNKICK"); + ci->SetSignKick(true); if (tmpu32 & OLD_CI_SIGNKICK_LEVEL) - ci->Extend<bool>("SIGNKICK_LEVEL"); + ci->SetSignKickLevel(true); Anope::string forbidby, forbidreason; READ(read_string(forbidby, f)); READ(read_string(forbidreason, f)); if (tmpu32 & OLD_CI_SUSPENDED) { - SuspendInfo si; - si.what = ci->name; - si.by = forbidby; - si.reason = forbidreason; - si.when = si.expires = 0; - ci->Extend("CS_SUSPENDED", si); + CSSuspendInfo *si = Serialize::New<CSSuspendInfo *>(); + if (si) + { + si->SetChannel(ci); + si->SetBy(forbidby); + } } bool forbid_chan = tmpu32 & OLD_CI_VERBOTEN; int16_t tmp16; READ(read_int16(&tmp16, f)); - ci->bantype = tmp16; + ci->SetBanType(tmp16); READ(read_int16(&tmp16, f)); if (tmp16 > 36) @@ -838,17 +908,16 @@ static void LoadChannels() int16_t level; READ(read_int16(&level, f)); - if (level == ACCESS_INVALID) - level = ACCESS_FOUNDER; + if (level == ChanServ::ACCESS_INVALID) + level = ChanServ::ACCESS_FOUNDER; if (j == 10 && level < 0) // NOJOIN - ci->Shrink<bool>("RESTRICTED"); // If CSDefRestricted was enabled this can happen + ci->SetRestricted(false); ci->SetLevel(GetLevelName(j), level); } bool xop = tmpu32 & OLD_CI_XOP; - ServiceReference<AccessProvider> provider_access("AccessProvider", "access/access"), provider_xop("AccessProvider", "access/xop"); uint16_t tmpu16; READ(read_uint16(&tmpu16, f)); for (uint16_t j = 0; j < tmpu16; ++j) @@ -857,19 +926,19 @@ static void LoadChannels() READ(read_uint16(&in_use, f)); if (in_use) { - ChanAccess *access = NULL; - + ChanServ::ChanAccess *access = NULL; + if (xop) { - if (provider_xop) - access = provider_xop->Create(); + access = Serialize::New<XOPChanAccess *>(); } else - if (provider_access) - access = provider_access->Create(); + { + access = Serialize::New<AccessChanAccess *>(); + } if (access) - access->ci = ci; + access->SetChannel(ci); int16_t level; READ(read_int16(&level, f)); @@ -900,16 +969,19 @@ static void LoadChannels() Anope::string mask; READ(read_string(mask, f)); if (access) - access->SetMask(mask, ci); + { + access->SetMask(mask); + NickServ::Nick *na = NickServ::FindNick(mask); + if (na) + na->SetAccount(na->GetAccount()); + } READ(read_int32(&tmp32, f)); if (access) { - access->last_seen = tmp32; - access->creator = "Unknown"; - access->created = Anope::CurTime; - - ci->AddAccess(access); + access->SetLastSeen(tmp32); + access->SetCreator("Unknown"); + access->SetCreated(Anope::CurTime); } } } @@ -943,74 +1015,67 @@ static void LoadChannels() READ(read_string(buffer, f)); // +L READ(read_int16(&tmp16, f)); - READ(read_int16(&ci->memos.memomax, f)); + READ(read_int16(&tmp16, f)); + MemoServ::MemoInfo *mi = ci->GetMemos(); + if (mi) + mi->SetMemoMax(tmp16); for (int16_t j = 0; j < tmp16; ++j) { READ(read_uint32(&tmpu32, f)); READ(read_uint16(&tmpu16, f)); - Memo *m = new Memo; + MemoServ::Memo *m = Serialize::New<MemoServ::Memo *>(); READ(read_int32(&tmp32, f)); - m->time = tmp32; + if (m) + m->SetTime(tmp32); char sbuf[32]; READ(read_buffer(sbuf, f)); - m->sender = sbuf; - READ(read_string(m->text, f)); - m->owner = ci->name; - ci->memos.memos->push_back(m); - m->mi = &ci->memos; + if (m) + m->SetSender(sbuf); + Anope::string text; + READ(read_string(text, f)); + if (m) + m->SetText(text); } READ(read_string(buffer, f)); if (!buffer.empty()) { - EntryMessageList *eml = ci->Require<EntryMessageList>("entrymsg"); - if (eml) + EntryMsg *e = Serialize::New<EntryMsg *>(); + if (e) { - EntryMsg *e = eml->Create(); - - e->chan = ci->name; - e->creator = "Unknown"; - e->message = buffer; - e->when = Anope::CurTime; - - (*eml)->push_back(e); + e->SetChannel(ci); + e->SetCreator("Unknown"); + e->SetMessage(buffer); + e->SetWhen(Anope::CurTime); } } READ(read_string(buffer, f)); - ci->bi = BotInfo::Find(buffer, true); + ci->SetBot(ServiceBot::Find(buffer, true)); READ(read_int32(&tmp32, f)); if (tmp32 & OLD_BS_DONTKICKOPS) - ci->Extend<bool>("BS_DONTKICKOPS"); + ci->SetS<bool>("BS_DONTKICKOPS", true); if (tmp32 & OLD_BS_DONTKICKVOICES) - ci->Extend<bool>("BS_DONTKICKVOICES"); + ci->SetS<bool>("BS_DONTKICKVOICES", true); if (tmp32 & OLD_BS_FANTASY) - ci->Extend<bool>("BS_FANTASY"); + ci->SetFantasy(true); if (tmp32 & OLD_BS_GREET) - ci->Extend<bool>("BS_GREET"); + ci->SetGreet(true); if (tmp32 & OLD_BS_NOBOT) - ci->Extend<bool>("BS_NOBOT"); + ci->SetS<bool>("BS_NOBOT", true); - KickerData *kd = ci->Require<KickerData>("kickerdata"); + KickerData *kd = GetKickerData(ci); if (kd) { - if (tmp32 & OLD_BS_KICK_BOLDS) - kd->bolds = true; - if (tmp32 & OLD_BS_KICK_COLORS) - kd->colors = true; - if (tmp32 & OLD_BS_KICK_REVERSES) - kd->reverses = true; - if (tmp32 & OLD_BS_KICK_UNDERLINES) - kd->underlines = true; - if (tmp32 & OLD_BS_KICK_BADWORDS) - kd->badwords = true; - if (tmp32 & OLD_BS_KICK_CAPS) - kd->caps = true; - if (tmp32 & OLD_BS_KICK_FLOOD) - kd->flood = true; - if (tmp32 & OLD_BS_KICK_REPEAT) - kd->repeat = true; + kd->SetBolds(tmp32 & OLD_BS_KICK_BOLDS); + kd->SetColors(tmp32 & OLD_BS_KICK_COLORS); + kd->SetReverses(tmp32 & OLD_BS_KICK_REVERSES); + kd->SetUnderlines(tmp32 & OLD_BS_KICK_UNDERLINES); + kd->SetBadwords(tmp32 & OLD_BS_KICK_BADWORDS); + kd->SetCaps(tmp32 & OLD_BS_KICK_CAPS); + kd->SetFlood(tmp32 & OLD_BS_KICK_FLOOD); + kd->SetRepeat(tmp32 & OLD_BS_KICK_REPEAT); } READ(read_int16(&tmp16, f)); @@ -1018,27 +1083,51 @@ static void LoadChannels() { int16_t ttb; READ(read_int16(&ttb, f)); - if (j < TTB_SIZE && kd) - kd->ttb[j] = ttb; + switch (j) + { + case TTB_BOLDS: + kd->SetTTBBolds(ttb); + break; + case TTB_COLORS: + kd->SetTTBColors(ttb); + break; + case TTB_REVERSES: + kd->SetTTBReverses(ttb); + break; + case TTB_UNDERLINES: + kd->SetTTBUnderlines(ttb); + break; + case TTB_BADWORDS: + kd->SetTTBBadwords(ttb); + break; + case TTB_CAPS: + kd->SetTTBCaps(ttb); + break; + case TTB_FLOOD: + kd->SetTTBFlood(ttb); + break; + case TTB_REPEAT: + kd->SetTTBRepeat(ttb); + break; + } } READ(read_int16(&tmp16, f)); if (kd) - kd->capsmin = tmp16; + kd->SetCapsMin(tmp16); READ(read_int16(&tmp16, f)); if (kd) - kd->capspercent = tmp16; + kd->SetCapsPercent(tmp16); READ(read_int16(&tmp16, f)); if (kd) - kd->floodlines = tmp16; + kd->SetFloodLines(tmp16); READ(read_int16(&tmp16, f)); if (kd) - kd->floodsecs = tmp16; + kd->SetFloodSecs(tmp16); READ(read_int16(&tmp16, f)); if (kd) - kd->repeattimes = tmp16; + kd->SetRepeatTimes(tmp16); - BadWords *bw = ci->Require<BadWords>("badwords"); READ(read_uint16(&tmpu16, f)); for (uint16_t j = 0; j < tmpu16; ++j) { @@ -1058,38 +1147,33 @@ static void LoadChannels() else if (type == 3) bwtype = BW_END; - if (bw) - bw->AddBadWord(buffer, bwtype); + if (badwords) + badwords->AddBadWord(ci, buffer, bwtype); } } if (forbid_chan) { - if (!forbid) + if (ci->GetName().find_first_of("?*") != Anope::string::npos) { delete ci; continue; } - if (ci->name.find_first_of("?*") != Anope::string::npos) + ForbidData *d = Serialize::New<ForbidData *>(); + if (d) { - delete ci; - continue; + d->SetMask(ci->GetName()); + d->SetCreator(forbidby); + d->SetReason(forbidreason); + d->SetType(FT_CHAN); } - - ForbidData *d = forbid->CreateForbid(); - d->mask = ci->name; - d->creator = forbidby; - d->reason = forbidreason; - d->expires = 0; - d->created = 0; - d->type = FT_CHAN; + delete ci; - forbid->AddForbid(d); continue; } - Log(LOG_DEBUG) << "Loaded channel " << ci->name; + Anope::Logger.Debug("Loaded channel {0}", ci->GetName()); } close_db(f); @@ -1104,9 +1188,8 @@ static void LoadOper() XLineManager *akill, *sqline, *snline, *szline; akill = sqline = snline = szline = NULL; - for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) + for (XLineManager *xl : XLineManager::XLineManagers) { - XLineManager *xl = *it; if (xl->Type() == 'G') akill = xl; else if (xl->Type() == 'Q') @@ -1138,8 +1221,14 @@ static void LoadOper() if (!akill) continue; - XLine *x = new XLine(user + "@" + host, by, expires, reason, XLineManager::GenerateUID()); - x->created = seton; + XLine *x = Serialize::New<XLine *>(); + x->SetMask(user + "@" + host); + x->SetBy(by); + x->SetExpires(expires); + x->SetReason(reason); + x->SetID(XLineManager::GenerateUID()); + x->SetCreated(seton); + akill->AddXLine(x); } @@ -1158,8 +1247,14 @@ static void LoadOper() if (!snline) continue; - XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID()); - x->created = seton; + XLine *x = Serialize::New<XLine *>(); + x->SetMask(mask); + x->SetBy(by); + x->SetExpires(expires); + x->SetReason(reason); + x->SetID(XLineManager::GenerateUID()); + x->SetCreated(seton); + snline->AddXLine(x); } @@ -1178,8 +1273,14 @@ static void LoadOper() if (!sqline) continue; - XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID()); - x->created = seton; + XLine *x = Serialize::New<XLine *>(); + x->SetMask(mask); + x->SetBy(by); + x->SetExpires(expires); + x->SetReason(reason); + x->SetID(XLineManager::GenerateUID()); + x->SetCreated(seton); + sqline->AddXLine(x); } @@ -1198,8 +1299,14 @@ static void LoadOper() if (!szline) continue; - XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID()); - x->created = seton; + XLine *x = Serialize::New<XLine *>(); + x->SetMask(mask); + x->SetBy(by); + x->SetExpires(expires); + x->SetReason(reason); + x->SetID(XLineManager::GenerateUID()); + x->SetCreated(seton); + szline->AddXLine(x); } @@ -1208,13 +1315,10 @@ static void LoadOper() static void LoadExceptions() { - if (!session_service) - return; - dbFILE *f = open_db_read("OperServ", "exception.db", 9); if (f == NULL) return; - + int16_t num; READ(read_int16(&num, f)); for (int i = 0; i < num; ++i) @@ -1231,14 +1335,16 @@ static void LoadExceptions() READ(read_int32(&time, f)); READ(read_int32(&expires, f)); - Exception *exception = session_service->CreateException(); - exception->mask = mask; - exception->limit = limit; - exception->who = who; - exception->time = time; - exception->expires = expires; - exception->reason = reason; - session_service->AddException(exception); + Exception *e = Serialize::New<Exception *>(); + if (e) + { + e->SetMask(mask); + e->SetLimit(limit); + e->SetWho(who); + e->SetTime(time); + e->SetExpires(expires); + e->SetReason(reason); + } } close_db(f); @@ -1246,9 +1352,6 @@ static void LoadExceptions() static void LoadNews() { - if (!news_service) - return; - dbFILE *f = open_db_read("OperServ", "news.db", 9); if (f == NULL) @@ -1260,60 +1363,68 @@ static void LoadNews() for (int16_t i = 0; i < n; i++) { int16_t type; - NewsItem *ni = news_service->CreateNewsItem(); + NewsItem *ni = Serialize::New<NewsItem *>(); + + if (!ni) + break; READ(read_int16(&type, f)); switch (type) { case OLD_NEWS_LOGON: - ni->type = NEWS_LOGON; + ni->SetNewsType(NEWS_LOGON); break; case OLD_NEWS_OPER: - ni->type = NEWS_OPER; + ni->SetNewsType(NEWS_OPER); break; case OLD_NEWS_RANDOM: - ni->type = NEWS_RANDOM; + ni->SetNewsType(NEWS_RANDOM); break; } int32_t unused; READ(read_int32(&unused, f)); - READ(read_string(ni->text, f)); + Anope::string text; + READ(read_string(text, f)); + ni->SetText(text); char who[32]; READ(read_buffer(who, f)); - ni->who = who; + ni->SetWho(who); int32_t tmp; READ(read_int32(&tmp, f)); - ni->time = tmp; - - news_service->AddNewsItem(ni); + ni->SetTime(tmp); } close_db(f); } class DBOld : public Module + , public EventHook<Event::LoadDatabase> + , public EventHook<Event::UplinkSync> { - PrimitiveExtensibleItem<uint32_t> mlock_on, mlock_off, mlock_limit; - PrimitiveExtensibleItem<Anope::string> mlock_key; + ExtensibleItem<uint32_t> mlock_on, mlock_off, mlock_limit; // XXX these are no longer required because of confmodes + ExtensibleItem<Anope::string> mlock_key; public: - DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), - mlock_on(this, "mlock_on"), mlock_off(this, "mlock_off"), mlock_limit(this, "mlock_limit"), mlock_key(this, "mlock_key") + DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) + , EventHook<Event::LoadDatabase>(this) + , EventHook<Event::UplinkSync>(this) + , mlock_on(this, "mlock_on") + , mlock_off(this, "mlock_off") + , mlock_limit(this, "mlock_limit") + , mlock_key(this, "mlock_key") { - - - hashm = Config->GetModule(this)->Get<const Anope::string>("hash"); + hashm = Config->GetModule(this)->Get<Anope::string>("hash"); if (hashm != "md5" && hashm != "oldmd5" && hashm != "sha1" && hashm != "plain" && hashm != "sha256") throw ModuleException("Invalid hash method"); } - EventReturn OnLoadDatabase() anope_override + EventReturn OnLoadDatabase() override { LoadNicks(); LoadVHosts(); @@ -1326,11 +1437,13 @@ class DBOld : public Module return EVENT_STOP; } - void OnUplinkSync(Server *s) anope_override + void OnUplinkSync(Server *s) override { - for (registered_channel_map::iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it) + if (!ChanServ::service) + return; + for (auto& it : ChanServ::service->GetChannels()) { - ChannelInfo *ci = it->second; + ChanServ::Channel *ci = it.second; uint32_t *limit = mlock_limit.Get(ci); Anope::string *key = mlock_key.Get(ci); @@ -1357,5 +1470,10 @@ class DBOld : public Module } }; +template<> void ModuleInfo<DBOld>(ModuleDef *def) +{ + def->Depends("chanserv.access"); +} + MODULE_INIT(DBOld) diff --git a/modules/database/sql.cpp b/modules/database/sql.cpp new file mode 100644 index 000000000..bd5a96b90 --- /dev/null +++ b/modules/database/sql.cpp @@ -0,0 +1,380 @@ +/* + * Anope IRC Services + * + * Copyright (C) 2011-2016 Anope Team <team@anope.org> + * + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. + */ + +#include "module.h" +#include "modules/sql.h" + +using namespace SQL; + +class DBSQL : public Module, public Pipe + , public EventHook<Event::SerializeEvents> +{ + private: + bool transaction = false; + bool inited = false; + Anope::string prefix; + ServiceReference<Provider> SQL; + + Result Run(const Query &query) + { + if (!SQL) + return Result(); + + if (!inited) + { + inited = true; + for (const Query &q : SQL->InitSchema(prefix)) + SQL->RunQuery(q); + } + + return SQL->RunQuery(query); + } + + void StartTransaction() + { + if (!SQL || transaction) + return; + + Run(SQL->BeginTransaction()); + + transaction = true; + Notify(); + } + + void Commit() + { + if (!SQL || !transaction) + return; + + Run(SQL->Commit()); + + transaction = false; + } + + public: + DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) + , EventHook<Event::SerializeEvents>(this) + { + } + + void OnNotify() override + { + Commit(); + Serialize::GC(); + } + + void OnReload(Configuration::Conf *conf) override + { + Configuration::Block *block = conf->GetModule(this); + this->SQL = ServiceReference<Provider>(block->Get<Anope::string>("engine")); + this->prefix = block->Get<Anope::string>("prefix", "anope_"); + inited = false; + } + + EventReturn OnSerializeList(Serialize::TypeBase *type, std::vector<Serialize::ID> &ids) override + { + StartTransaction(); + + ids.clear(); + + Query query = "SELECT `id` FROM `" + prefix + type->GetName() + "`"; + Result res = Run(query); + for (int i = 0; i < res.Rows(); ++i) + { + Serialize::ID id = convertTo<Serialize::ID>(res.Get(i, "id")); + ids.push_back(id); + } + + return EVENT_ALLOW; + } + + EventReturn OnSerializeFind(Serialize::TypeBase *type, Serialize::FieldBase *field, const Anope::string &value, Serialize::ID &id) override + { + if (!SQL) + return EVENT_CONTINUE; + + StartTransaction(); + + for (Query &q : SQL->CreateTable(prefix, type)) + Run(q); + + for (Query &q : SQL->AlterTable(prefix, type, field)) + Run(q); + + for (const Query &q : SQL->CreateIndex(prefix + type->GetName(), field->serialize_name)) + Run(q); + + Query query = SQL->SelectFind(prefix + type->GetName(), field->serialize_name); + + query.SetValue("value", value); + Result res = Run(query); + if (res.Rows()) + try + { + id = convertTo<Serialize::ID>(res.Get(0, "id")); + return EVENT_ALLOW; + } + catch (const ConvertException &) + { + } + + return EVENT_CONTINUE; + } + + private: + bool GetValue(Serialize::Object *object, Serialize::FieldBase *field, SQL::Result::Value &v) + { + StartTransaction(); + + Query query = "SELECT `" + field->serialize_name + "` FROM `" + prefix + object->GetSerializableType()->GetName() + "` WHERE `id` = @id@"; + query.SetValue("id", object->id, false); + Result res = Run(query); + + if (res.Rows() == 0) + return false; + + v = res.GetValue(0, field->serialize_name); + return true; + } + + void GetRefs(Serialize::Object *object, Serialize::TypeBase *type, std::vector<Serialize::Edge> &edges) + { + for (Serialize::FieldBase *field : type->GetFields()) + { + if (field->is_object && object->GetSerializableType()->GetName() == field->GetTypeName()) + { + Anope::string table = prefix + type->GetName(); + + Query query = "SELECT id FROM " + table + + " WHERE " + field->serialize_name + " = @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) + { + Anope::Logger.Debug("Unable to require id {0} type {1}", id, 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 + { + SQL::Result::Value v; + + if (!GetValue(object, field, v)) + return EVENT_CONTINUE; + + value = v.value; + return EVENT_ALLOW; + } + + EventReturn OnSerializeGetRefs(Serialize::Object *object, Serialize::TypeBase *type, std::vector<Serialize::Edge> &edges) override + { + StartTransaction(); + + edges.clear(); + + if (type == nullptr) + { + for (Serialize::TypeBase *type : Serialize::TypeBase::GetTypes()) + GetRefs(object, type, edges); + } + else + { + GetRefs(object, type, edges); + } + + return EVENT_ALLOW; + } + + EventReturn OnSerializeDeref(Serialize::ID id, Serialize::TypeBase *type) override + { + StartTransaction(); + + Query query = "SELECT `id` FROM `" + prefix + type->GetName() + "` WHERE `id` = @id@"; + query.SetValue("id", id, false); + Result res = Run(query); + if (res.Rows() == 0) + return EVENT_CONTINUE; + return EVENT_ALLOW; + } + + EventReturn OnSerializeGetSerializable(Serialize::Object *object, Serialize::FieldBase *field, Anope::string &type, Serialize::ID &value) override + { + StartTransaction(); + + Query query = "SELECT `" + field->serialize_name + "` FROM `" + prefix + object->GetSerializableType()->GetName() + "` " + "WHERE id = @id@"; + query.SetValue("id", object->id, false); + Result res = Run(query); + + if (res.Rows() == 0) + return EVENT_CONTINUE; + + type = field->GetTypeName(); + try + { + value = convertTo<Serialize::ID>(res.Get(0, field->serialize_name)); + } + catch (const ConvertException &ex) + { + return EVENT_STOP; + } + + return EVENT_ALLOW; + } + + private: + void DoSet(Serialize::Object *object, Serialize::FieldBase *field, bool is_object, const Anope::string *value) + { + if (!SQL) + return; + + StartTransaction(); + + for (Query &q : SQL->CreateTable(prefix, object->GetSerializableType())) + Run(q); + + for (Query &q : SQL->AlterTable(prefix, object->GetSerializableType(), field)) + Run(q); + + Query q; + q.SetValue("id", object->id, false); + if (value) + q.SetValue(field->serialize_name, *value, !is_object); + else + q.SetNull(field->serialize_name); + + for (Query &q2 : SQL->Replace(prefix + object->GetSerializableType()->GetName(), q, { "id" })) + Run(q2); + } + + public: + EventReturn OnSerializeSet(Serialize::Object *object, Serialize::FieldBase *field, const Anope::string &value) override + { + DoSet(object, field, false, &value); + return EVENT_STOP; + } + + EventReturn OnSerializeSetSerializable(Serialize::Object *object, Serialize::FieldBase *field, Serialize::Object *value) override + { + if (!SQL) + return EVENT_CONTINUE; + + StartTransaction(); + + if (value) + { + Anope::string v = stringify(value->id); + DoSet(object, field, true, &v); + } + else + { + DoSet(object, field, true, nullptr); + } + + return EVENT_STOP; + } + + EventReturn OnSerializeUnset(Serialize::Object *object, Serialize::FieldBase *field) override + { + DoSet(object, field, false, nullptr); + return EVENT_STOP; + } + + EventReturn OnSerializeUnsetSerializable(Serialize::Object *object, Serialize::FieldBase *field) override + { + DoSet(object, field, true, nullptr); + return EVENT_STOP; + } + + EventReturn OnSerializeHasField(Serialize::Object *object, Serialize::FieldBase *field) override + { + if (field->is_object) + { + Anope::string type; + Serialize::ID id; + + EventReturn er = OnSerializeGetSerializable(object, field, type, id); + + if (er != EVENT_ALLOW) + return EVENT_CONTINUE; + + field->UnserializeFromString(object, type + ":" + stringify(id)); + return EVENT_STOP; + } + else + { + SQL::Result::Value v; + + 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::TypeBase *type, Serialize::ID &id) override + { + if (!SQL) + return EVENT_CONTINUE; + + StartTransaction(); + + for (Query &q : SQL->CreateTable(prefix, type)) + Run(q); + + id = SQL->GetID(prefix, type->GetName()); + return EVENT_ALLOW; + } + + void OnSerializableCreate(Serialize::Object *object) override + { + } + + void OnSerializableDelete(Serialize::Object *object) override + { + StartTransaction(); + + Serialize::TypeBase *type = object->GetSerializableType(); + + Query query("DELETE FROM `" + prefix + type->GetName() + "` WHERE `id` = " + stringify(object->id)); + Run(query); + } +}; + +MODULE_INIT(DBSQL) + |