summaryrefslogtreecommitdiff
path: root/modules/database
diff options
context:
space:
mode:
Diffstat (limited to 'modules/database')
-rw-r--r--modules/database/db_atheme.cpp1611
-rw-r--r--modules/database/db_flatfile.cpp134
-rw-r--r--modules/database/db_old.cpp97
-rw-r--r--modules/database/db_redis.cpp233
-rw-r--r--modules/database/db_sql.cpp90
-rw-r--r--modules/database/db_sql_live.cpp55
6 files changed, 1882 insertions, 338 deletions
diff --git a/modules/database/db_atheme.cpp b/modules/database/db_atheme.cpp
new file mode 100644
index 000000000..a62571b4b
--- /dev/null
+++ b/modules/database/db_atheme.cpp
@@ -0,0 +1,1611 @@
+/*
+ *
+ * (C) 2003-2024 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 <functional>
+
+#include "module.h"
+#include "modules/bs_badwords.h"
+#include "modules/bs_kick.h"
+#include "modules/cs_entrymsg.h"
+#include "modules/cs_mode.h"
+#include "modules/hs_request.h"
+#include "modules/info.h"
+#include "modules/ns_cert.h"
+#include "modules/os_forbid.h"
+#include "modules/os_oper.h"
+#include "modules/os_session.h"
+#include "modules/suspend.h"
+
+// Handles reading from an Atheme database row.
+class AthemeRow final
+{
+private:
+ // The number of failed reads.
+ unsigned error = 0;
+
+ // The underlying token stream.
+ spacesepstream stream;
+
+public:
+ AthemeRow(const Anope::string &str)
+ : stream(str)
+ {
+ }
+
+ operator bool() const
+ {
+ return !error;
+ }
+
+ // Retrieves the next parameter.
+ Anope::string Get()
+ {
+ Anope::string token;
+ if (!stream.GetToken(token))
+ error++;
+ return token;
+ }
+
+ // Retrieves the next parameter as a number.
+ template<typename Numeric>
+ std::enable_if_t<std::is_arithmetic_v<Numeric>, Numeric> GetNum()
+ {
+ return Anope::Convert<Numeric>(Get(), 0);
+ }
+
+ // Retrieves the entire row.
+ Anope::string GetRow()
+ {
+ return stream.GetString();
+ }
+
+ // Retrieves the remaining data in the row.
+ Anope::string GetRemaining()
+ {
+ auto remaining = stream.GetRemaining();
+ if (remaining.empty())
+ error++;
+ return remaining;
+ }
+
+ bool LogError(Module *mod)
+ {
+ Log(mod) << "Malformed database line (expected " << error << " fields): " << GetRow();
+ return false;
+ }
+};
+
+struct ModeData final
+{
+ char letter;
+ Anope::string name;
+ Anope::string value;
+ bool set;
+
+ ModeData(const Anope::string &n, bool s, const Anope::string &v = "")
+ : letter(0)
+ , name(n)
+ , value(v)
+ , set(s)
+ {
+ }
+
+ ModeData(char l, const Anope::string &v = "")
+ : letter(l)
+ , value(v)
+ , set(true)
+ {
+ }
+
+ Anope::string str() const
+ {
+ std::stringstream buf;
+ buf << '+' << (name.empty() ? letter : name);
+ if (value.empty())
+ buf << ' ' << value;
+ return buf.str();
+ }
+};
+
+struct ChannelData final
+{
+ Anope::unordered_map<AutoKick *> akicks;
+ Anope::string bot;
+ Anope::string info_adder;
+ Anope::string info_message;
+ time_t info_ts = 0;
+ std::vector<ModeData> mlocks;
+ Anope::string suspend_by;
+ Anope::string suspend_reason;
+ time_t suspend_ts = 0;
+};
+
+struct UserData final
+{
+ bool kill = false;
+ Anope::string info_adder;
+ Anope::string info_message;
+ time_t info_ts = 0;
+ Anope::string last_mask;
+ Anope::string last_quit;
+ Anope::string last_real_mask;
+ bool noexpire = false;
+ Anope::string suspend_by;
+ Anope::string suspend_reason;
+ time_t suspend_ts = 0;
+ Anope::string vhost;
+ Anope::string vhost_creator;
+ Anope::map<Anope::string> vhost_nick;
+ time_t vhost_ts = 0;
+};
+
+namespace
+{
+ // Whether we can safely import clones.
+ bool import_clones = true;
+}
+
+class DBAtheme final
+ : public Module
+{
+private:
+ ServiceReference<AccessProvider> accessprov;
+ PrimitiveExtensibleItem<ChannelData> chandata;
+ std::map<Anope::string, char> flags;
+ PrimitiveExtensibleItem<UserData> userdata;
+ ServiceReference<XLineManager> sglinemgr;
+ ServiceReference<XLineManager> snlinemgr;
+ ServiceReference<XLineManager> sqlinemgr;
+
+ Anope::map<std::function<bool(DBAtheme*,AthemeRow&)>> rowhandlers = {
+ { "AC", &DBAtheme::HandleIgnore },
+ { "AR", &DBAtheme::HandleIgnore },
+ { "BE", &DBAtheme::HandleBE },
+ { "BLE", &DBAtheme::HandleIgnore },
+ { "BOT", &DBAtheme::HandleBOT },
+ { "BOT-COUNT", &DBAtheme::HandleIgnore },
+ { "BW", &DBAtheme::HandleBW },
+ { "CA", &DBAtheme::HandleCA },
+ { "CF", &DBAtheme::HandleIgnore },
+ { "CFCHAN", &DBAtheme::HandleIgnore },
+ { "CFDBV", &DBAtheme::HandleIgnore },
+ { "CFMD", &DBAtheme::HandleIgnore },
+ { "CFOP", &DBAtheme::HandleIgnore },
+ { "CLONES-CD", &DBAtheme::HandleIgnore },
+ { "CLONES-CK", &DBAtheme::HandleIgnore },
+ { "CLONES-DBV", &DBAtheme::HandleCLONESDBV },
+ { "CLONES-EX", &DBAtheme::HandleCLONESEX },
+ { "CLONES-GR", &DBAtheme::HandleIgnore },
+ { "CSREQ", &DBAtheme::HandleIgnore },
+ { "CSREQ", &DBAtheme::HandleIgnore },
+ { "DBV", &DBAtheme::HandleDBV },
+ { "GACL", &DBAtheme::HandleIgnore },
+ { "GDBV", &DBAtheme::HandleIgnore },
+ { "GE", &DBAtheme::HandleIgnore },
+ { "GFA", &DBAtheme::HandleIgnore },
+ { "GRP", &DBAtheme::HandleIgnore },
+ { "GRVER", &DBAtheme::HandleGRVER },
+ { "HE", &DBAtheme::HandleIgnore },
+ { "HO", &DBAtheme::HandleIgnore },
+ { "HR", &DBAtheme::HandleHR },
+ { "JM", &DBAtheme::HandleIgnore },
+ { "KID", &DBAtheme::HandleIgnore },
+ { "KL", &DBAtheme::HandleKL },
+ { "LUID", &DBAtheme::HandleIgnore },
+ { "MC", &DBAtheme::HandleMC },
+ { "MCFP", &DBAtheme::HandleMCFP },
+ { "MDA", &DBAtheme::HandleMDA },
+ { "MDC", &DBAtheme::HandleMDC },
+ { "MDEP", &DBAtheme::HandleIgnore },
+ { "MDG", &DBAtheme::HandleIgnore },
+ { "MDN", &DBAtheme::HandleMDN },
+ { "MDU", &DBAtheme::HandleMDU },
+ { "ME", &DBAtheme::HandleME },
+ { "MI", &DBAtheme::HandleMI },
+ { "MM", &DBAtheme::HandleMM },
+ { "MN", &DBAtheme::HandleMN },
+ { "MU", &DBAtheme::HandleMU },
+ { "NAM", &DBAtheme::HandleNAM },
+ { "QID", &DBAtheme::HandleIgnore },
+ { "QL", &DBAtheme::HandleQL },
+ { "RM", &DBAtheme::HandleIgnore },
+ { "RR", &DBAtheme::HandleIgnore },
+ { "RW", &DBAtheme::HandleIgnore },
+ { "SI", &DBAtheme::HandleIgnore },
+ { "SO", &DBAtheme::HandleSO },
+ { "TS", &DBAtheme::HandleIgnore },
+ { "XID", &DBAtheme::HandleIgnore },
+ { "XL", &DBAtheme::HandleXL },
+ };
+
+ void ApplyAccess(Anope::string &in, char flag, Anope::string &out, std::initializer_list<const char*> privs)
+ {
+ for (const auto *priv : privs)
+ {
+ auto pos = in.find(flag);
+ if (pos != Anope::string::npos)
+ {
+ auto privchar = flags.find(priv);
+ if (privchar != flags.end())
+ {
+ out.push_back(privchar->second);
+ in.erase(pos, 1);
+ }
+ }
+ }
+ }
+
+ void ApplyFlags(Extensible *ext, Anope::string &flags, char flag, const char* extname, bool extend = true)
+ {
+ auto pos = flags.find(flag);
+ auto has_flag = (pos != Anope::string::npos);
+
+ if (has_flag == extend)
+ ext->Extend<bool>(extname);
+ else
+ ext->Shrink<bool>(extname);
+
+ if (has_flag)
+ flags.erase(pos, 1);
+ }
+
+ void ApplyLocks(ChannelInfo *ci, unsigned locks, const Anope::string &limit, const Anope::string &key, bool set)
+ {
+ auto *data = chandata.Require(ci);
+
+ // Start off with the standard mode values.
+ if (locks & 0x1u)
+ data->mlocks.emplace_back("INVITE", set);
+ if (locks & 0x2u)
+ data->mlocks.emplace_back("KEY", set, key);
+ if (locks & 0x4u)
+ data->mlocks.emplace_back("LIMIT", set, limit);
+ if (locks & 0x8u)
+ data->mlocks.emplace_back("MODERATED", set);
+ if (locks & 0x10u)
+ data->mlocks.emplace_back("NOEXTERNAL", set);
+ if (locks & 0x40u)
+ data->mlocks.emplace_back("PRIVATE", set);
+ if (locks & 0x80u)
+ data->mlocks.emplace_back("SECRET", set);
+ if (locks & 0x100u)
+ data->mlocks.emplace_back("TOPIC", set);
+ if (locks & 0x200u)
+ data->mlocks.emplace_back("REGISTERED", set);
+
+ // Atheme also supports per-ircd values here (ew).
+ if (IRCD->owner->name == "bahamut")
+ {
+ if (locks & 0x1000u)
+ data->mlocks.emplace_back("BLOCKCOLOR", set);
+ if (locks & 0x2000u)
+ data->mlocks.emplace_back("REGMODERATED", set);
+ if (locks & 0x4000u)
+ data->mlocks.emplace_back("REGISTEREDONLY", set);
+ if (locks & 0x8000u)
+ data->mlocks.emplace_back("OPERONLY", set);
+
+ // Anope doesn't recognise the following Bahamut modes currently:
+ // - 0x10000u ('A')
+ // - 0x20000u ('P')
+ }
+ else if (IRCD->owner->name == "inspircd")
+ {
+ if (locks & 0x1000u)
+ data->mlocks.emplace_back("BLOCKCOLOR", set);
+ if (locks & 0x2000u)
+ data->mlocks.emplace_back("REGMODERATED", set);
+ if (locks & 0x4000u)
+ data->mlocks.emplace_back("REGISTEREDONLY", set);
+ if (locks & 0x8000u)
+ data->mlocks.emplace_back("OPERONLY", set);
+ if (locks & 0x10000u)
+ data->mlocks.emplace_back("NONOTICE", set);
+ if (locks & 0x20000u)
+ data->mlocks.emplace_back("NOKICK", set);
+ if (locks & 0x40000u)
+ data->mlocks.emplace_back("STRIPCOLOR", set);
+ if (locks & 0x80000u)
+ data->mlocks.emplace_back("NOKNOCK", set);
+ if (locks & 0x100000u)
+ data->mlocks.emplace_back("ALLINVITE", set);
+ if (locks & 0x200000u)
+ data->mlocks.emplace_back("NOCTCP", set);
+ if (locks & 0x400000u)
+ data->mlocks.emplace_back("AUDITORIUM", set);
+ if (locks & 0x800000u)
+ data->mlocks.emplace_back("SSL", set);
+ if (locks & 0x100000u)
+ data->mlocks.emplace_back("NONICK", set);
+ if (locks & 0x200000u)
+ data->mlocks.emplace_back("CENSOR", set);
+ if (locks & 0x400000u)
+ data->mlocks.emplace_back("BLOCKCAPS", set);
+ if (locks & 0x800000u)
+ data->mlocks.emplace_back("PERM", set);
+ if (locks & 0x2000000u)
+ data->mlocks.emplace_back("DELAYEDJOIN", set);
+ }
+ else if (IRCD->owner->name == "ngircd")
+ {
+ if (locks & 0x1000u)
+ data->mlocks.emplace_back("REGISTEREDONLY", set);
+ if (locks & 0x2000u)
+ data->mlocks.emplace_back("OPERONLY", set);
+ if (locks & 0x4000u)
+ data->mlocks.emplace_back("PERM", set);
+ if (locks & 0x8000u)
+ data->mlocks.emplace_back("SSL", set);
+ }
+ else if (IRCD->owner->name == "solanum")
+ {
+ if (locks & 0x1000u)
+ data->mlocks.emplace_back("BLOCKCOLOR", set);
+ if (locks & 0x2000u)
+ data->mlocks.emplace_back("REGISTEREDONLY", set);
+ if (locks & 0x4000u)
+ data->mlocks.emplace_back("OPMODERATED", set);
+ if (locks & 0x8000u)
+ data->mlocks.emplace_back("ALLINVITE", set);
+ if (locks & 0x10000u)
+ data->mlocks.emplace_back("LBAN", set);
+ if (locks & 0x20000u)
+ data->mlocks.emplace_back("PERM", set);
+ if (locks & 0x40000u)
+ data->mlocks.emplace_back("ALLOWFORWARD", set);
+ if (locks & 0x80000u)
+ data->mlocks.emplace_back("NOFORWARD", set);
+ if (locks & 0x100000u)
+ data->mlocks.emplace_back("NOCTCP", set);
+ if (locks & 0x400000u)
+ data->mlocks.emplace_back("SSL", set);
+ if (locks & 0x800000u)
+ data->mlocks.emplace_back("OPERONLY", set);
+ if (locks & 0x1000000u)
+ data->mlocks.emplace_back("ADMINONLY", set);
+ if (locks & 0x2000000u)
+ data->mlocks.emplace_back("NONOTICE", set);
+ if (locks & 0x4000000u)
+ data->mlocks.emplace_back("PROTECTED", set);
+ if (locks & 0x8000000)
+ data->mlocks.emplace_back("NOFILTER", set);
+ if (locks & 0x10000000U)
+ data->mlocks.emplace_back("REGMODERATED", set);
+ }
+ else if (IRCD->owner->name == "unrealircd")
+ {
+ if (locks & 0x1000u)
+ data->mlocks.emplace_back("BLOCKCOLOR", set);
+ if (locks & 0x2000u)
+ data->mlocks.emplace_back("REGMODERATED", set);
+ if (locks & 0x4000u)
+ data->mlocks.emplace_back("REGISTEREDONLY", set);
+ if (locks & 0x8000u)
+ data->mlocks.emplace_back("OPERONLY", set);
+ if (locks & 0x20000u)
+ data->mlocks.emplace_back("NOKICK", set);
+ if (locks & 0x40000u)
+ data->mlocks.emplace_back("STRIPCOLOR", set);
+ if (locks & 0x80000u)
+ data->mlocks.emplace_back("NOKNOCK", set);
+ if (locks & 0x100000u)
+ data->mlocks.emplace_back("NOINVITE", set);
+ if (locks & 0x200000u)
+ data->mlocks.emplace_back("NOCTCP", set);
+ if (locks & 0x800000u)
+ data->mlocks.emplace_back("SSL", set);
+ if (locks & 0x1000000u)
+ data->mlocks.emplace_back("NONICK", set);
+ if (locks & 0x4000000u)
+ data->mlocks.emplace_back("CENSOR", set);
+ if (locks & 0x8000000u)
+ data->mlocks.emplace_back("PERM", set);
+ if (locks & 0x1000000u)
+ data->mlocks.emplace_back("NONOTICE", set);
+ if (locks & 0x2000000u)
+ data->mlocks.emplace_back("DELAYJOIN", set);
+ }
+ else if (IRCD->owner->name != "ratbox")
+ {
+ Log(this) << "Unable to import mode locks for " << IRCD->GetProtocolName();
+ }
+ }
+
+ void ApplyPassword(NickCore *nc, Anope::string &flags, const Anope::string &pass)
+ {
+ auto pos = flags.find('C');
+ if (pos == Anope::string::npos)
+ {
+ // Password is unencrypted so we can use it.
+ Anope::Encrypt(pass, nc->pass);
+ return;
+ }
+
+ // We are processing an encrypted password.
+ flags.erase(pos, 1);
+
+ // Atheme supports several password hashing methods. We can only import
+ // some of them currently.
+ //
+ // anope-enc-sha256 Converted to enc_sha256
+ // argon2 Converted to enc_argon2
+ // base64 Converted to the first encryption algorithm
+ // bcrypt Converted to enc_bcrypt
+ // crypt3-des NO
+ // crypt3-md5 Converted to enc_posix
+ // crypt3-sha2-256 Converted to enc_posix
+ // crypt3-sha2-512 Converted to enc_posix
+ // ircservices Converted to enc_old
+ // pbkdf2 NO
+ // pbkdf2v2 NO
+ // rawmd5 Converted to enc_md5
+ // rawsha1 Converted to enc_sha1
+ // rawsha2-256 Converted to enc_sha2
+ // rawsha2-512 Converted to enc_sha2
+ // scrypt NO
+ if (pass.compare(0, 18, "$anope$enc_sha256$", 18) == 0)
+ {
+ auto sep = pass.find('$', 18);
+ Anope::string iv, pass;
+ Anope::B64Decode(pass.substr(18, sep - 18), iv);
+ Anope::B64Decode(pass.substr(sep + 1), pass);
+ nc->pass = "sha256:" + Anope::Hex(pass) + ":" + Anope::Hex(iv);
+ }
+
+ else if (pass.compare(0, 9, "$argon2d$", 9) == 0)
+ nc->pass = "argon2d:" + pass;
+
+ else if (pass.compare(0, 9, "$argon2i$", 9) == 0)
+ nc->pass = "argon2i:" + pass;
+
+ else if (pass.compare(0, 10, "$argon2id$", 10) == 0)
+ nc->pass = "argon2id:" + pass;
+
+ else if (pass.compare(0, 8, "$base64$", 8) == 0)
+ {
+ Anope::string rawpass;
+ Anope::B64Decode(pass.substr(8), rawpass);
+ Anope::Encrypt(rawpass, nc->pass);
+ }
+
+ else if (pass.compare(0, 13, "$ircservices$", 13) == 0)
+ nc->pass = "oldmd5:" + pass.substr(13);
+
+ else if (pass.compare(0, 8, "$rawmd5$", 8) == 0)
+ nc->pass = "md5:" + pass.substr(8);
+
+ else if (pass.compare(0, 9, "$rawsha1$", 9) == 0)
+ nc->pass = "sha1:" + pass.substr(9);
+
+ else if (pass.compare(0, 11, "$rawsha256$", 11) == 0)
+ nc->pass = "raw-sha256:" + pass.substr(11);
+
+ else if (pass.compare(0, 11, "$rawsha512$", 11) == 0)
+ nc->pass = "raw-sha512:" + pass.substr(11);
+
+ else if (pass.compare(0, 3, "$1$", 3) == 0 || pass.compare(0, 3, "$5", 3) == 0 || pass.compare(0, 3, "$6", 3) == 0)
+ nc->pass = "posix:" + pass;
+
+ else if (pass.compare(0, 4, "$2a$", 4) == 0 || pass.compare(0, 4, "$2b$", 4) == 0)
+ nc->pass = "bcrypt:" + pass;
+
+ else
+ {
+ // Generate a new password as we can't use the old one.
+ auto maxpasslen = Config->GetModule("nickserv")->Get<unsigned>("maxpasslen", "50");
+ Anope::Encrypt(Anope::Random(maxpasslen), nc->pass);
+ Log(this) << "Unable to convert the password for " << nc->display << " as Anope does not support the format!";
+ }
+
+ }
+
+ bool HandleBE(AthemeRow &row)
+ {
+ // BE <email> <created> <creator> <reason>
+ auto email = row.Get();
+ auto created = row.GetNum<time_t>();
+ auto creator = row.Get();
+ auto reason = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ if (!forbid_service)
+ {
+ Log(this) << "Unable to convert forbidden email " << email << " as os_forbid is not loaded";
+ return true;
+ }
+
+ auto *forbid = forbid_service->CreateForbid();
+ forbid->created = created;
+ forbid->creator = creator;
+ forbid->mask = email;
+ forbid->reason = reason;
+ forbid->type = FT_EMAIL;
+ forbid_service->AddForbid(forbid);
+ return true;
+ }
+
+ bool HandleBOT(AthemeRow &row)
+ {
+ // BOT <nick> <user> <host> <operonly> <created> <real>
+ auto nick = row.Get();
+ auto user = row.Get();
+ auto host = row.Get();
+ auto operonly = row.GetNum<unsigned>();
+ auto created = row.GetNum<time_t>();
+ auto real = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *bi = new BotInfo(nick, user, host, real);
+ bi->oper_only = operonly;
+ bi->created = created;
+ return true;
+ }
+
+ bool HandleBW(AthemeRow &row)
+ {
+ // BW <badword> <added> <creator> <channel> <action>
+ auto badword = row.Get();
+ /* auto added = */ row.GetNum<time_t>();
+ /* auto creator = */ row.Get();
+ auto channel = row.Get();
+ /* auto action = */ row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *ci = ChannelInfo::Find(channel);
+ if (!ci)
+ {
+ Log(this) << "Missing ChannelInfo for BW: " << channel;
+ return false;
+ }
+
+ auto *bw = ci->Require<BadWords>("badwords");
+ if (!bw)
+ {
+ Log(this) << "Unable to import badwords for " << ci->name << " as bs_kick is not loaded";
+ return true;
+ }
+
+ auto *kd = ci->Require<KickerData>("kickerdata");
+ if (kd)
+ {
+ kd->badwords = true;
+ kd->ttb[TTB_BADWORDS] = 0;
+ }
+
+ bw->AddBadWord(badword, BW_ANY);
+ return true;
+ }
+
+ bool HandleCA(AthemeRow &row)
+ {
+ // CA <channel> <account/mask> <flags> <modifiedtime> <setter>
+ auto channel = row.Get();
+ auto mask = row.Get();
+ auto flags = row.Get();
+ auto modifiedtime = row.GetNum<time_t>();
+ auto setter = row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *ci = ChannelInfo::Find(channel);
+ if (!ci)
+ {
+ Log(this) << "Missing ChannelInfo for CA: " << channel;
+ return false;
+ }
+
+ auto *nc = NickCore::Find(mask);
+ if (flags.find('b') != Anope::string::npos)
+ {
+ auto *data = chandata.Require(ci);
+ if (nc)
+ data->akicks[mask] = ci->AddAkick(setter, nc, "", modifiedtime, modifiedtime);
+ else
+ data->akicks[mask] = ci->AddAkick(setter, mask, "", modifiedtime, modifiedtime);
+ return true;
+ }
+
+ if (!accessprov)
+ {
+ Log(this) << "Unable to import channel access for " << ci->name << " as cs_flags is not loaded";
+ return true;
+ }
+
+ Anope::string accessflags;
+ ApplyAccess(flags, 'A', accessflags, { "ACCESS_LIST" });
+ ApplyAccess(flags, 'a', accessflags, { "AUTOPROTECT", "PROTECT", "PROTECTME" });
+ ApplyAccess(flags, 'e', accessflags, { "GETKEY", "NOKICK", "UNBANME" });
+ ApplyAccess(flags, 'f', accessflags, { "ACCESS_CHANGE" });
+ ApplyAccess(flags, 'F', accessflags, { "FOUNDER" });
+ ApplyAccess(flags, 'H', accessflags, { "AUTOHALFOP" });
+ ApplyAccess(flags, 'h', accessflags, { "HALFOP", "HALFOPME" });
+ ApplyAccess(flags, 'i', accessflags, { "INVITE" });
+ ApplyAccess(flags, 'O', accessflags, { "AUTOOP" });
+ ApplyAccess(flags, 'o', accessflags, { "OP", "OPME" });
+ ApplyAccess(flags, 'q', accessflags, { "AUTOOWNER", "OWNER", "OWNERME" });
+ ApplyAccess(flags, 'r', accessflags, { "KICK" });
+ ApplyAccess(flags, 's', accessflags, { "SET" });
+ ApplyAccess(flags, 't', accessflags, { "TOPIC" });
+ ApplyAccess(flags, 'V', accessflags, { "AUTOVOICE" });
+ ApplyAccess(flags, 'v', accessflags, { "VOICE", "VOICEME" });
+ if (!accessflags.empty())
+ {
+ auto *access = accessprov->Create();
+ access->SetMask(mask, ci);
+ access->creator = setter;
+ access->description = "Imported from Atheme";
+ access->last_seen = modifiedtime;
+ access->created = modifiedtime;
+ access->AccessUnserialize(accessflags);
+ ci->AddAccess(access);
+ }
+
+ if (flags != "+")
+ Log(this) << "Unable to convert channel access flags " << flags << " for " << mask << " on " << ci->name;
+
+ return true;
+ }
+
+ bool HandleCLONESDBV(AthemeRow &row)
+ {
+ // CLONES-DBV <version>
+ auto version = row.GetNum<unsigned>();
+ if (version != 3)
+ {
+ Log(this) << "Clones database is version " << version << " which is not supported!";
+ import_clones = false;
+ }
+ return true;
+ }
+
+ bool HandleCLONESEX(AthemeRow &row)
+ {
+ if (!import_clones)
+ return HandleIgnore(row);
+
+ // CLONES-EX <ip> <allowed> <warn> <expires> <reason>
+ auto ip = row.Get();
+ auto allowed = row.GetNum<unsigned>();
+ /* auto warn = */ row.GetNum<unsigned>();
+ auto expires = row.GetNum<time_t>();
+ auto reason = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ if (!session_service)
+ {
+ Log(this) << "Unable to import session limit for " << ip << " as os_session is not loaded";
+ return true;
+ }
+
+ auto *exception = session_service->CreateException();
+ exception->mask = ip;
+ exception->limit = allowed;
+ exception->who = "Unknown";
+ exception->time = Anope::CurTime;
+ exception->expires = expires;
+ exception->reason = reason;
+ session_service->AddException(exception);
+ return true;
+ }
+
+ bool HandleDBV(AthemeRow &row)
+ {
+ // DBV <version>
+ auto version = row.GetNum<unsigned>();
+ if (version != 12)
+ {
+ Log(this) << "Database is version " << version << " which is not supported!";
+ return false;
+ }
+ return true;
+ }
+
+ bool HandleGRVER(AthemeRow &row)
+ {
+ // GRVER <version>
+ auto version = row.GetNum<unsigned>();
+ if (version != 1)
+ {
+ Log(this) << "Database grammar is version " << version << " which is not supported!";
+ return false;
+ }
+ return true;
+ }
+
+ bool HandleHR(AthemeRow &row)
+ {
+ // HR <nick> <host> <reqts> <creator>
+ auto nick = row.Get();
+ auto host = row.Get();
+ auto reqts = row.GetNum<time_t>();
+ /* auto creator = */ row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *na = NickAlias::Find(nick);
+ if (!na)
+ {
+ Log(this) << "Missing NickAlias for HR: " << nick;
+ return false;
+ }
+
+ auto *hr = na->Require<HostRequest>("hostrequest");
+ if (!hr)
+ {
+ Log(this) << "Unable to convert host request for " << na->nick << " as hs_request is not loaded";
+ return true;
+ }
+
+ hr->nick = na->nick;
+ hr->ident.clear();
+ hr->host = host;
+ hr->time = reqts;
+ return true;
+ }
+
+ bool HandleKL(AthemeRow &row)
+ {
+ // KL <id> <user> <host> <duration> <settime> <setby> <reason>
+ /* auto id = */ row.GetNum<unsigned>();
+ auto user = row.Get();
+ auto host = row.Get();
+ auto duration = row.GetNum<unsigned>();
+ auto settime = row.GetNum<time_t>();
+ auto setby = row.Get();
+ auto reason = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ if (!sglinemgr)
+ {
+ Log(this) << "Unable to import K-line on " << user << "@" << host << " as operserv is not loaded";
+ return true;
+ }
+
+ auto *xl = new XLine(user + "@" + host, setby, settime + duration, reason);
+ sglinemgr->AddXLine(xl);
+ return true;
+ }
+
+ bool HandleIgnore(AthemeRow &row)
+ {
+ Log(LOG_DEBUG_3) << "Intentionally ignoring Atheme database row: " << row.GetRow();
+ return true;
+ }
+
+ bool HandleIgnoreMetadata(const Anope::string &target, const Anope::string &key, const Anope::string &value)
+ {
+ Log(LOG_DEBUG_3) << "Intentionally ignoring Atheme database metadata for " << target << ": " << key << " = " << value;
+ return true;
+ }
+
+ bool HandleMC(AthemeRow &row)
+ {
+ // MC <channel> <regtime> <used> <flags> <mlock-on> <mlock-off> <mlock-limit> [<mlock-key>]
+ auto channel = row.Get();
+ auto regtime = row.GetNum<time_t>();
+ /* auto used = */ row.GetNum<time_t>();
+ auto flags = row.Get();
+ auto mlock_on = row.GetNum<unsigned>();
+ auto mlock_off = row.GetNum<unsigned>();
+ auto mlock_limit = row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto mlock_key = row.Get(); // May not exist.
+
+ auto *ci = new ChannelInfo(channel);
+ ci->time_registered = regtime;
+
+ // No equivalent: elnv
+ ApplyFlags(ci, flags, 'h', "CS_NO_EXPIRE");
+ ApplyFlags(ci, flags, 'k', "KEEPTOPIC");
+ ApplyFlags(ci, flags, 'o', "NOAUTOOP");
+ ApplyFlags(ci, flags, 'p', "CS_PRIVATE");
+ ApplyFlags(ci, flags, 'r', "RESTRICTED");
+ ApplyFlags(ci, flags, 't', "TOPICLOCK");
+ ApplyFlags(ci, flags, 'z', "SECUREOPS");
+
+ auto pos = flags.find('a');
+ if (pos != Anope::string::npos)
+ {
+ ci->SetLevel("ACCESS_CHANGE", 0);
+ flags.erase(pos, 1);
+ }
+
+ pos = flags.find('f');
+ if (pos != Anope::string::npos)
+ {
+ auto *kd = ci->Require<KickerData>("kickerdata");
+ if (kd)
+ {
+ kd->flood = true;
+ kd->floodlines = 10;
+ kd->floodsecs = 60;
+ kd->ttb[TTB_FLOOD] = 0;
+ flags.erase(pos, 1);
+ }
+ else
+ {
+ Log(this) << "Unable to convert the 'f' flag for " << ci->name << " as bs_kick is not loaded";
+ }
+ }
+
+ pos = flags.find('g');
+ if (pos != Anope::string::npos)
+ {
+ auto *bi = Config->GetClient("ChanServ");
+ if (bi)
+ {
+ bi->Assign(nullptr, ci);
+ flags.erase(pos, 1);
+ }
+ else
+ Log(this) << "Unable to convert the 'g' flag for " << ci->name << " as chanserv is not loaded";
+ }
+
+ if (flags != "+")
+ Log(this) << "Unable to convert channel flags " << flags << " for " << ci->name;
+
+ ApplyLocks(ci, mlock_on, mlock_limit, mlock_key, true);
+ ApplyLocks(ci, mlock_off, mlock_limit, mlock_key, false);
+ return true;
+ }
+
+ bool HandleMCFP(AthemeRow &row)
+ {
+ // MCFP <display> <fingerprint>
+ auto display = row.Get();
+ auto fingerprint = row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = NickCore::Find(display);
+ if (!nc)
+ {
+ Log(this) << "Missing NickCore for MCFP: " << display;
+ return false;
+ }
+
+ auto *cl = nc->Require<NSCertList>("certificates");
+ if (!cl)
+ {
+ Log(this) << "Unable to convert certificate for " << nc->display << " as ns_cert is not loaded";
+ return true;
+ }
+
+ cl->AddCert(fingerprint);
+ return true;
+ }
+
+ bool HandleMDA(AthemeRow &row)
+ {
+ // MDA <channel> <account/mask> <key> <value>
+ auto channel = row.Get();
+ auto mask = row.Get();
+ auto key = row.Get();
+ auto value = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *ci = ChannelInfo::Find(channel);
+ if (!ci)
+ {
+ Log(this) << "Missing ChannelInfo for MDA: " << channel;
+ return false;
+ }
+
+ if (key == "reason")
+ {
+ auto *data = chandata.Require(ci);
+ auto akick = data->akicks.find(mask);
+ if (akick != data->akicks.end())
+ akick->second->reason = value;
+ }
+ else
+ Log(this) << "Unknown channel access metadata for " << mask << " on " << ci->name << ": " << key << " = " << value;
+
+ return true;
+ }
+
+ bool HandleMDC(AthemeRow &row)
+ {
+ // MDC <channel> <key> <value>
+ auto channel = row.Get();
+ auto key = row.Get();
+ auto value = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *ci = ChannelInfo::Find(channel);
+ if (!ci)
+ {
+ Log(this) << "Missing ChannelInfo for MDC: " << channel;
+ return false;
+ }
+
+ auto *data = chandata.Require(ci);
+ if (key == "private:botserv:bot-assigned")
+ data->bot = value;
+ else if (key == "private:botserv:bot-handle-fantasy")
+ ci->Extend<bool>("BS_FANTASY");
+ else if (key == "private:botserv:no-bot")
+ ci->Extend<bool>("BS_NOBOT");
+ else if (key == "private:channelts")
+ return HandleIgnoreMetadata(ci->name, key, value);
+ else if (key == "private:close:closer")
+ data->suspend_by = value;
+ else if (key == "private:close:reason")
+ data->suspend_reason = value;
+ else if (key == "private:close:timestamp")
+ data->suspend_ts = Anope::Convert<time_t>(value, 0);
+ else if (key == "private:entrymsg")
+ {
+ auto *eml = ci->Require<EntryMessageList>("entrymsg");
+ if (!eml)
+ {
+ Log(this) << "Unable to convert entry message for " << ci->name << " as cs_mode is not loaded";
+ return true;
+ }
+
+ auto *msg = eml->Create();
+ msg->chan = ci->name;
+ msg->creator = "Unknown";
+ msg->message = value;
+ msg->when = Anope::CurTime;
+ (*eml)->push_back(msg);
+ }
+ else if (key == "private:klinechan:closer")
+ data->suspend_by = value;
+ else if (key == "private:klinechan:reason")
+ data->suspend_reason = value;
+ else if (key == "private:klinechan:timestamp")
+ data->suspend_ts = Anope::Convert<time_t>(value, 0);
+ else if (key == "private:mark:reason")
+ data->info_message = value;
+ else if (key == "private:mark:setter")
+ data->info_adder = value;
+ else if (key == "private:mark:timestamp")
+ data->info_ts = Anope::Convert<time_t>(value, 0);
+ else if (key == "private:mlockext")
+ {
+ spacesepstream mlocks(value);
+ for (Anope::string mlock; mlocks.GetToken(mlock); )
+ data->mlocks.emplace_back(mlock[0], mlock.substr(1));
+ }
+ else if (key == "private:templates")
+ return HandleIgnoreMetadata(ci->name, key, value);
+ else if (key == "private:topic:setter")
+ ci->last_topic_setter = value;
+ else if (key == "private:topic:text")
+ ci->last_topic = value;
+ else if (key == "private:topic:ts")
+ ci->last_topic_time = Anope::Convert<time_t>(value, 0);
+ else if (key.compare(0, 14, "private:stats:", 14) == 0)
+ return HandleIgnoreMetadata(ci->name, key, value);
+ else
+ Log(this) << "Unknown channel metadata for " << ci->name << ": " << key << " = " << value;
+
+ return true;
+ }
+
+ bool HandleMDN(AthemeRow &row)
+ {
+ // MDN <nick> <key> <value>
+ auto nick = row.Get();
+ auto key = row.Get();
+ auto value = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ if (!forbid_service)
+ {
+ Log(this) << "Unable to convert forbidden nick " << nick << " metadata as os_forbid is not loaded";
+ return true;
+ }
+
+ auto *forbid = forbid_service->FindForbidExact(nick, FT_NICK);
+ if (!forbid)
+ {
+ Log(this) << "Missing forbid for MDN: " << nick;
+ return false;
+ }
+
+ if (key == "private:mark:reason")
+ forbid->reason = value;
+ else if (key == "private:mark:setter")
+ forbid->creator = value;
+ else if (key == "private:mark:timestamp")
+ forbid->created = Anope::Convert<time_t>(value, 0);
+ else
+ Log(this) << "Unknown forbidden nick metadata for " << forbid->mask << ": " << key << " = " << value;
+
+ return true;
+ }
+
+ bool HandleMDU(AthemeRow &row)
+ {
+ // MDU <display> <key> <value>
+ auto display = row.Get();
+ auto key = row.Get();
+ auto value = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = NickCore::Find(display);
+ if (!nc)
+ {
+ Log(this) << "Missing NickCore for MDU: " << display;
+ return false;
+ }
+
+ auto *data = userdata.Require(nc);
+ if (key == "private:autojoin")
+ return true; // TODO
+ else if (key == "private:doenforce")
+ data->kill = true;
+ else if (key == "private:enforcetime")
+ {
+ if (!data->kill)
+ return true; // Don't apply this.
+
+ auto kill = Config->GetModule("nickserv")->Get<time_t>("kill", "60s");
+ auto killquick = Config->GetModule("nickserv")->Get<time_t>("killquick", "20s");
+ auto secs = Anope::Convert<time_t>(value, kill);
+ if (secs >= kill)
+ nc->Extend<bool>("KILLPROTECT");
+ else if (secs >= killquick)
+ nc->Shrink<bool>("KILL_QUICK");
+ else
+ nc->Shrink<bool>("KILL_IMMED");
+ }
+ else if (key == "private:freeze:freezer")
+ data->suspend_by = value;
+ else if (key == "private:freeze:reason")
+ data->suspend_reason = value;
+ else if (key == "private:freeze:timestamp")
+ data->suspend_ts = Anope::Convert<time_t>(value, 0);
+ else if (key == "private:host:actual")
+ data->last_real_mask = value;
+ else if (key == "private:host:vhost")
+ data->last_mask = value;
+ else if (key == "private:lastquit:message")
+ data->last_quit = value;
+ else if (key == "private:loginfail:failnum")
+ return HandleIgnoreMetadata(nc->display, key, value);
+ else if (key == "private:loginfail:lastfailaddr")
+ return HandleIgnoreMetadata(nc->display, key, value);
+ else if (key == "private:loginfail:lastfailtime")
+ return HandleIgnoreMetadata(nc->display, key, value);
+ else if (key == "private:mark:reason")
+ data->info_message = value;
+ else if (key == "private:mark:setter")
+ data->info_adder = value;
+ else if (key == "private:mark:timestamp")
+ data->info_ts = Anope::Convert<time_t>(value, 0);
+ else if (key == "private:swhois")
+ return HandleIgnoreMetadata(nc->display, key, value);
+ else if (key == "private:usercloak")
+ data->vhost = value;
+ else if (key == "private:usercloak-assigner")
+ data->vhost_creator = value;
+ else if (key == "private:usercloak-timestamp")
+ data->vhost_ts = Anope::Convert<time_t>(value, 0);
+ else if (key.compare(0, 18, "private:usercloak:", 18) == 0)
+ data->vhost_nick[key.substr(18)] = value;
+ else
+ Log(this) << "Unknown account metadata for " << nc->display << ": " << key << " = " << value;
+
+ return true;
+ }
+
+ bool HandleME(AthemeRow &row)
+ {
+ // ME <target> <source> <sent> <flags> <text>
+ auto target = row.Get();
+ auto source = row.Get();
+ auto sent = row.GetNum<time_t>();
+ auto flags = row.GetNum<unsigned>();
+ auto text = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = NickCore::Find(target);
+ if (!nc)
+ {
+ Log(this) << "Missing NickCore for ME: " << source;
+ return false;
+ }
+
+ auto *m = new Memo();
+ m->mi = &nc->memos;
+ m->owner = nc->display;
+ m->sender = source;
+ m->time = sent;
+ m->text = text;
+ m->unread = flags & 0x1;
+ nc->memos.memos->push_back(m);
+ return true;
+ }
+
+ bool HandleMI(AthemeRow &row)
+ {
+ // MI <display> <ignored>
+ auto display = row.Get();
+ auto ignored = row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = NickCore::Find(display);
+ if (!nc)
+ {
+ Log(this) << "Missing NickCore for MI: " << display;
+ return false;
+ }
+
+ nc->memos.ignores.push_back(ignored);
+ return true;
+ }
+
+ bool HandleMM(AthemeRow &row)
+ {
+ // MM <id> <setterid> <setteraccount> <markedid> <markedaccount> <setts> <num> <message>
+ /* auto id = */ row.Get();
+ /* auto setterid = */ row.Get();
+ auto setteraccount = row.Get();
+ /* auto markedid = */ row.Get();
+ auto markedaccount = row.Get();
+ auto setts = row.GetNum<time_t>();
+ /* auto num = */ row.Get();
+ auto message = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = NickCore::Find(markedaccount);
+ if (!nc)
+ {
+ Log(this) << "Missing NickCore for MM: " << markedaccount;
+ return false;
+ }
+
+ auto *oil = nc->Require<OperInfoList>("operinfo");
+ if (oil)
+ {
+ auto *info = oil->Create();
+ info->target = nc->display;
+ info->info = message;
+ info->adder = setteraccount;
+ info->created = setts;
+ (*oil)->push_back(info);
+ }
+ else
+ {
+ Log(this) << "Unable to convert oper info for " << nc->display << " as os_info is not loaded";
+ }
+ return true;
+ }
+
+ bool HandleMN(AthemeRow &row)
+ {
+ // MU <display> <nick> <regtime> <lastseen>
+ auto display = row.Get();
+ auto nick = row.Get();
+ auto regtime = row.GetNum<time_t>();
+ auto lastseen = row.GetNum<time_t>();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = NickCore::Find(display);
+ if (!nc)
+ {
+ Log(this) << "Missing NickCore for MN: " << display;
+ return false;
+ }
+
+ auto *na = new NickAlias(nick, nc);
+ na->time_registered = regtime;
+ na->last_seen = lastseen ? regtime : na->time_registered;
+
+ auto *data = userdata.Get(nc);
+ if (data)
+ {
+ if (!data->last_mask.empty())
+ na->last_usermask = data->last_mask;
+
+ if (!data->last_quit.empty())
+ na->last_quit = data->last_quit;
+
+ if (!data->last_real_mask.empty())
+ na->last_realhost = data->last_real_mask;
+
+ if (data->noexpire)
+ na->Extend<bool>("NS_NO_EXPIRE");
+
+ auto vhost = data->vhost;
+ auto nick_vhost = data->vhost_nick.find(nick);
+ if (nick_vhost != data->vhost_nick.end())
+ vhost = nick_vhost->second;
+ if (!vhost.empty())
+ na->SetVHost("", vhost, data->vhost_creator, data->vhost_ts);
+ }
+
+ return true;
+ }
+
+ bool HandleMU(AthemeRow &row)
+ {
+ // MU <id> <display> <pass> <email> <regtime> <lastlogin> <flags> <language>
+ /* auto id = */ row.Get();
+ auto display = row.Get();
+ auto pass = row.Get();
+ auto email = row.Get();
+ auto regtime = row.GetNum<time_t>();
+ /* auto lastlogin = */ row.Get();
+ auto flags = row.Get();
+ auto language = row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = new NickCore(display);
+ nc->email = email;
+ nc->time_registered = regtime;
+ ApplyPassword(nc, flags, pass);
+
+ // No equivalent: bglmNQrS
+ ApplyFlags(nc, flags, 'E', "KILLPROTECT");
+ ApplyFlags(nc, flags, 'e', "MEMO_MAIL");
+ ApplyFlags(nc, flags, 'n', "NEVEROP");
+ ApplyFlags(nc, flags, 'o', "AUTOOP", false);
+ ApplyFlags(nc, flags, 'P', "MSG");
+ ApplyFlags(nc, flags, 'p', "NS_PRIVATE");
+ ApplyFlags(nc, flags, 's', "HIDE_EMAIL");
+ ApplyFlags(nc, flags, 'W', "UNCONFIRMED");
+
+ // If an Atheme account was awaiting confirmation but Anope is not
+ // configured to use confirmation then autoconfirm it.
+ const auto &nsregister = Config->GetModule("ns_register")->Get<const Anope::string>("registration");
+ if (nsregister.equals_ci("none"))
+ nc->Shrink<bool>("UNCONFIRMED");
+
+ auto pos = flags.find('h');
+ if (pos != Anope::string::npos)
+ {
+ userdata.Require(nc)->noexpire = true;
+ flags.erase(pos, 1);
+ }
+
+
+ if (flags != "+")
+ Log(this) << "Unable to convert account flags " << flags << " for " << nc->display;
+
+ // No translations yet: bg, cy, da.
+ if (language == "de")
+ nc->language = "de_DE.UTF-8";
+ else if (language == "en")
+ nc->language = "en_US.UTF-8";
+ else if (language == "es")
+ nc->language = "es_ES.UTF-8";
+ else if (language == "fr")
+ nc->language = "fr_FR.UTF-8";
+ else if (language == "ru")
+ nc->language = "ru_RU.UTF-8";
+ else if (language == "tr")
+ nc->language = "tr_TR.UTF-8";
+ else if (language != "default")
+ {
+ Log(this) << "Unable to convert language " << language << " for " << nc->display;
+ }
+
+ return true;
+ }
+
+ bool HandleNAM(AthemeRow &row)
+ {
+ // NAM <nick>
+ auto nick = row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ if (!forbid_service)
+ {
+ Log(this) << "Unable to convert forbidden nick " << nick << " as os_forbid is not loaded";
+ return true;
+ }
+
+ auto *forbid = forbid_service->CreateForbid();
+ forbid->creator = "Unknown";
+ forbid->mask = nick;
+ forbid->reason = "Unknown";
+ forbid->type = FT_NICK;
+ forbid_service->AddForbid(forbid);
+ return true;
+ }
+
+ bool HandleQL(AthemeRow &row)
+ {
+ // QL <nick> <host> <duration> <settime> <setby> <reason>
+ /* auto id = */ row.GetNum<unsigned>();
+ auto nick = row.Get();
+ auto duration = row.GetNum<unsigned>();
+ auto settime = row.GetNum<time_t>();
+ auto setby = row.Get();
+ auto reason = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ if (!sglinemgr)
+ {
+ Log(this) << "Unable to import Q-line on " << nick << " as operserv is not loaded";
+ return true;
+ }
+
+ auto *xl = new XLine(nick, setby, settime + duration, reason);
+ sqlinemgr->AddXLine(xl);
+ return true;
+ }
+
+ bool HandleSO(AthemeRow &row)
+ {
+ // SO <display> <type> <flags>
+ auto display = row.Get();
+ auto type = row.Get();
+ auto flags = row.Get();
+
+ if (!row)
+ return row.LogError(this);
+
+ auto *nc = NickCore::Find(display);
+ if (!nc)
+ {
+ Log(this) << "Missing NickCore for SO: " << display;
+ return false;
+ }
+
+ auto *ot = OperType::Find(type);
+ if (!ot)
+ {
+ // Attempt to convert oper types.
+ if (type == "sra")
+ ot = OperType::Find("Services Root");
+ else if (type == "ircop")
+ ot = OperType::Find("Services Operator");
+ }
+
+ if (!ot)
+ {
+ Log(this) << "Unable to convert operator status for " << nc->display << " as there is no equivalent oper type: " << type;
+ return true;
+ }
+
+ nc->o = new MyOper(nc->display, ot);
+ return true;
+ }
+
+ bool HandleXL(AthemeRow &row)
+ {
+ // XL <id> <real> <duration> <settime> <setby> <reason>
+ /* auto id = */ row.GetNum<unsigned>();
+ auto real = row.Get();
+ auto duration = row.GetNum<unsigned>();
+ auto settime = row.GetNum<time_t>();
+ auto setby = row.Get();
+ auto reason = row.GetRemaining();
+
+ if (!row)
+ return row.LogError(this);
+
+ if (!sglinemgr)
+ {
+ Log(this) << "Unable to import X-line on " << real << " as operserv is not loaded";
+ return true;
+ }
+
+ auto *xl = new XLine(real, setby, settime + duration, reason);
+ snlinemgr->AddXLine(xl);
+ return true;
+ }
+
+public:
+ DBAtheme(const Anope::string &modname, const Anope::string &creator)
+ : Module(modname, creator, DATABASE | VENDOR)
+ , accessprov("AccessProvider", "access/flags")
+ , chandata(this, "ATHEME_CHANDATA")
+ , userdata(this, "ATHEME_USERDATA")
+ , sglinemgr("XLineManager","xlinemanager/sgline")
+ , snlinemgr("XLineManager","xlinemanager/snline")
+ , sqlinemgr("XLineManager","xlinemanager/sqline")
+ {
+ }
+
+ void OnReload(Configuration::Conf *conf) override
+ {
+ flags.clear();
+ for (int i = 0; i < Config->CountBlock("privilege"); ++i)
+ {
+ Configuration::Block *priv = Config->GetBlock("privilege", i);
+ const Anope::string &name = priv->Get<const Anope::string>("name");
+ const Anope::string &value = priv->Get<const Anope::string>("flag");
+ if (!name.empty() && !value.empty())
+ flags[name] = value[0];
+ }
+ }
+
+ EventReturn OnLoadDatabase() override
+ {
+ const auto dbname = Anope::ExpandData(Config->GetModule(this)->Get<const Anope::string>("database", "atheme.db"));
+ std::ifstream fd(dbname.str());
+ if (!fd.is_open())
+ {
+ Log(this) << "Unable to open " << dbname << " for reading!";
+ return EVENT_STOP;
+ }
+
+ for (Anope::string buf; std::getline(fd, buf.str()); )
+ {
+ AthemeRow row(buf);
+
+ auto rowtype = row.Get();
+ if (!row)
+ continue; // Empty row.
+
+ auto rowhandler = rowhandlers.find(rowtype);
+ if (rowhandler == rowhandlers.end())
+ {
+ Log(this) << "Unknown row type: " << row.GetRow();
+ continue;
+ }
+
+ if (!rowhandler->second(this, row))
+ break;
+ }
+
+ for (const auto &[_, ci] : *RegisteredChannelList)
+ {
+ auto *data = chandata.Get(ci);
+ if (!data)
+ continue;
+
+ if (!data->bot.empty())
+ {
+ auto *bi = BotInfo::Find(data->bot);
+ if (bi)
+ bi->Assign(nullptr, ci);
+ }
+
+ if (!data->info_message.empty())
+ {
+ auto *oil = ci->Require<OperInfoList>("operinfo");
+ if (oil)
+ {
+ auto *info = oil->Create();
+ info->target = ci->name;
+ info->info = data->info_message;
+ info->adder = data->info_adder.empty() ? "Unknown" : data->info_adder;
+ info->created = data->info_ts;
+ (*oil)->push_back(info);
+ }
+ else
+ {
+ Log(this) << "Unable to convert oper info for " << ci->name << " as os_info is not loaded";
+ }
+ }
+
+ if (!data->suspend_reason.empty())
+ {
+ SuspendInfo si;
+ si.by = data->suspend_by.empty() ? "Unknown" : data->suspend_by;
+ si.expires = 0;
+ si.reason = data->suspend_reason;
+ si.what = ci->name;
+ si.when = data->suspend_ts;
+ ci->Extend("CS_SUSPENDED", si);
+ }
+ }
+
+ for (const auto &[_, nc] : *NickCoreList)
+ {
+ auto *data = userdata.Get(nc);
+ if (!data)
+ continue;
+
+ if (!data->info_message.empty())
+ {
+ auto *oil = nc->Require<OperInfoList>("operinfo");
+ if (oil)
+ {
+ auto *info = oil->Create();
+ info->target = nc->display;
+ info->info = data->info_message;
+ info->adder = data->info_adder.empty() ? "Unknown" : data->info_adder;
+ info->created = data->info_ts;
+ (*oil)->push_back(info);
+ }
+ else
+ {
+ Log(this) << "Unable to convert oper info for " << nc->display << " as os_info is not loaded";
+ }
+ }
+
+ if (!data->suspend_reason.empty())
+ {
+ SuspendInfo si;
+ si.by = data->suspend_by.empty() ? "Unknown" : data->suspend_by;
+ si.expires = 0;
+ si.reason = data->suspend_reason;
+ si.what = nc->display;
+ si.when = data->suspend_ts;
+ nc->Extend("NS_SUSPENDED", si);
+ }
+ }
+
+ return EVENT_STOP;
+ }
+
+ void OnUplinkSync(Server *s) override
+ {
+ for (auto &[_, ci] : *RegisteredChannelList)
+ {
+ auto *data = chandata.Get(ci);
+ if (!data)
+ continue;
+
+ auto *ml = ci->Require<ModeLocks>("modelocks");
+ if (!ml)
+ {
+ Log(this) << "Unable to convert mode locks for " << ci->name << " as cs_mode is not loaded";
+ continue;
+ }
+
+ for (const auto &mlock : data->mlocks)
+ {
+ ChannelMode *mh;
+ if (mlock.name.empty())
+ mh = ModeManager::FindChannelModeByChar(mlock.letter);
+ else
+ mh = ModeManager::FindChannelModeByName(mlock.name);
+ if (!mh)
+ {
+ Log(this) << "Unable to find mode while importing mode lock on " << ci->name << ": " << mlock.str();
+ continue;
+ }
+
+ ml->SetMLock(mh, mlock.set, mlock.value, "Unknown");
+ }
+ }
+ Anope::SaveDatabases();
+ }
+};
+
+MODULE_INIT(DBAtheme)
diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp
index 5ccf7772f..a253fe24f 100644
--- a/modules/database/db_flatfile.cpp
+++ b/modules/database/db_flatfile.cpp
@@ -15,15 +15,14 @@
#include <sys/wait.h>
#endif
-class SaveData : public Serialize::Data
+class SaveData final
+ : public Serialize::Data
{
- public:
+public:
Anope::string last;
- std::fstream *fs;
+ std::fstream *fs = nullptr;
- SaveData() : fs(NULL) { }
-
- std::iostream& operator[](const Anope::string &key) anope_override
+ std::iostream &operator[](const Anope::string &key) override
{
if (key != last)
{
@@ -35,18 +34,17 @@ class SaveData : public Serialize::Data
}
};
-class LoadData : public Serialize::Data
+class LoadData final
+ : public Serialize::Data
{
- public:
- std::fstream *fs;
- unsigned int id;
+public:
+ std::fstream *fs = nullptr;
+ unsigned int id = 0;
std::map<Anope::string, Anope::string> data;
std::stringstream ss;
- bool read;
-
- LoadData() : fs(NULL), id(0), read(false) { }
+ bool read = false;
- std::iostream& operator[](const Anope::string &key) anope_override
+ std::iostream &operator[](const Anope::string &key) override
{
if (!read)
{
@@ -54,12 +52,7 @@ class LoadData : public Serialize::Data
{
if (token.find("ID ") == 0)
{
- try
- {
- this->id = convertTo<unsigned int>(token.substr(3));
- }
- catch (const ConvertException &) { }
-
+ this->id = Anope::Convert(token.substr(3), 0);
continue;
}
else if (token.find("DATA ") != 0)
@@ -78,20 +71,12 @@ class LoadData : public Serialize::Data
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() const 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);
+ for (const auto &[_, value] : this->data)
+ if (!value.empty())
+ hash ^= Anope::hash_cs()(value);
return hash;
}
@@ -103,15 +88,17 @@ class LoadData : public Serialize::Data
}
};
-class DBFlatFile : public Module, public Pipe
+class DBFlatFile final
+ : public Module
+ , public Pipe
{
/* Day the last backup was on */
- int last_day;
+ int last_day = 0;
/* Backup file names */
std::map<Anope::string, std::list<Anope::string> > backups;
- bool loaded;
+ bool loaded = false;
- int child_pid;
+ int child_pid = -1;
void BackupDatabase()
{
@@ -121,69 +108,67 @@ class DBFlatFile : public Module, public Pipe
{
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)
+ for (const auto &type_order : Serialize::Type::GetTypeOrder())
{
- Serialize::Type *stype = Serialize::Type::Find(type_order[i]);
+ Serialize::Type *stype = Serialize::Type::Find(type_order);
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)
+ for (const auto &db : dbs)
{
- 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);
+ const auto oldname = Anope::ExpandData(db);
+ const auto newname = Anope::ExpandData("backups/" + db + "-" + Anope::ToString(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;
+ Log(LOG_DEBUG) << "db_flatfile: Attempting to rename " << db << " to " << newname;
if (rename(oldname.c_str(), newname.c_str()))
{
Anope::string err = Anope::LastError();
- Log(this) << "Unable to back up database " << *it << " (" << err << ")!";
+ Log(this) << "Unable to back up database " << db << " (" << err << ")!";
if (!Config->GetModule(this)->Get<bool>("nobackupokay"))
{
Anope::Quitting = true;
- Anope::QuitReason = "Unable to back up database " + *it + " (" + err + ")";
+ Anope::QuitReason = "Unable to back up database " + db + " (" + err + ")";
}
continue;
}
- backups[*it].push_back(newname);
+ backups[db].push_back(newname);
unsigned keepbackups = Config->GetModule(this)->Get<unsigned>("keepbackups");
- if (keepbackups > 0 && backups[*it].size() > keepbackups)
+ if (keepbackups > 0 && backups[db].size() > keepbackups)
{
- unlink(backups[*it].front().c_str());
- backups[*it].pop_front();
+ unlink(backups[db].front().c_str());
+ backups[db].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)
+public:
+ DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR)
{
}
#ifndef _WIN32
- void OnRestart() anope_override
+ void OnRestart() override
{
OnShutdown();
}
- void OnShutdown() anope_override
+ void OnShutdown() override
{
if (child_pid > -1)
{
@@ -197,7 +182,7 @@ class DBFlatFile : public Module, public Pipe
}
#endif
- void OnNotify() anope_override
+ void OnNotify() override
{
char buf[512];
int i = this->Read(buf, sizeof(buf) - 1);
@@ -219,12 +204,11 @@ class DBFlatFile : public Module, public Pipe
Anope::Quitting = true;
}
- EventReturn OnLoadDatabase() anope_override
+ EventReturn OnLoadDatabase() 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");
+ const auto db_name = Anope::ExpandData(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())
@@ -242,18 +226,16 @@ class DBFlatFile : public Module, public Pipe
LoadData ld;
ld.fs = &fd;
- for (unsigned i = 0; i < type_order.size(); ++i)
+ for (const auto &type_order : Serialize::Type::GetTypeOrder())
{
- Serialize::Type *stype = Serialize::Type::Find(type_order[i]);
+ Serialize::Type *stype = Serialize::Type::Find(type_order);
if (!stype || stype->GetOwner())
continue;
- std::vector<std::streampos> &pos = positions[stype->GetName()];
-
- for (unsigned j = 0; j < pos.size(); ++j)
+ for (const auto &position : positions[stype->GetName()])
{
fd.clear();
- fd.seekg(pos[j]);
+ fd.seekg(position);
Serializable *obj = stype->Unserialize(NULL, ld);
if (obj != NULL)
@@ -269,7 +251,7 @@ class DBFlatFile : public Module, public Pipe
}
- void OnSaveDatabase() anope_override
+ void OnSaveDatabase() override
{
if (child_pid > -1)
{
@@ -299,18 +281,16 @@ class DBFlatFile : public Module, public Pipe
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)
+ for (const auto &[_, s_type] : Serialize::Type::GetTypes())
{
- 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";
+ db_name = Anope::ExpandData("module_" + s_type->GetOwner()->name + ".db");
else
- db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<const Anope::string>("database", "anope.db");
+ db_name = Anope::ExpandData(Config->GetModule(this)->Get<const Anope::string>("database", "anope.db"));
std::fstream *fs = databases[s_type->GetOwner()] = new std::fstream((db_name + ".tmp").c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
@@ -320,9 +300,8 @@ class DBFlatFile : public Module, public Pipe
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)
+ for (auto *base : items)
{
- Serializable *base = *it;
Serialize::Type *s_type = base->GetSerializableType();
if (!s_type)
continue;
@@ -338,10 +317,9 @@ class DBFlatFile : public Module, public Pipe
*data.fs << "\nEND\n";
}
- for (std::map<Module *, std::fstream *>::iterator it = databases.begin(), it_end = databases.end(); it != it_end; ++it)
+ for (auto &[mod, f] : databases)
{
- 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"));
+ const auto db_name = Anope::ExpandData((mod ? (mod->name + ".db") : Config->GetModule(this)->Get<const Anope::string>("database", "anope.db")));
if (!f->is_open() || !f->good())
{
@@ -376,16 +354,16 @@ class DBFlatFile : public Module, public Pipe
}
/* Load just one type. Done if a module is reloaded during runtime */
- void OnSerializeTypeCreate(Serialize::Type *stype) anope_override
+ void OnSerializeTypeCreate(Serialize::Type *stype) override
{
if (!loaded)
return;
Anope::string db_name;
if (stype->GetOwner())
- db_name = Anope::DataDir + "/module_" + stype->GetOwner()->name + ".db";
+ db_name = Anope::ExpandData("module_" + stype->GetOwner()->name + ".db");
else
- db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<const Anope::string>("database", "anope.db");
+ db_name = Anope::ExpandData(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())
diff --git a/modules/database/db_old.cpp b/modules/database/db_old.cpp
index 7cd63716d..68ba2ca07 100644
--- a/modules/database/db_old.cpp
+++ b/modules/database/db_old.cpp
@@ -35,13 +35,12 @@ else \
#define OLD_BI_PRIVATE 0x0001
#define OLD_NI_KILLPROTECT 0x00000001 /* Kill others who take this nick */
-#define OLD_NI_SECURE 0x00000002 /* Don't recognize unless IDENTIFY'd */
#define OLD_NI_MSG 0x00000004 /* Use PRIVMSGs instead of NOTICEs */
#define OLD_NI_MEMO_HARDMAX 0x00000008 /* Don't allow user to change memo limit */
#define OLD_NI_MEMO_SIGNON 0x00000010 /* Notify of memos at signon and un-away */
#define OLD_NI_MEMO_RECEIVE 0x00000020 /* Notify of new memos when sent */
#define OLD_NI_PRIVATE 0x00000040 /* Don't show in LIST to non-servadmins */
-#define OLD_NI_HIDE_EMAIL 0x00000080 /* Don't show E-mail in INFO */
+#define OLD_NI_HIDE_EMAIL 0x00000080 /* Don't show email in INFO */
#define OLD_NI_HIDE_MASK 0x00000100 /* Don't show last seen address in INFO */
#define OLD_NI_HIDE_QUIT 0x00000200 /* Don't show last quit message in INFO */
#define OLD_NI_KILL_QUICK 0x00000400 /* Kill in 20 seconds instead of 60 */
@@ -60,7 +59,6 @@ else \
#define OLD_CI_TOPICLOCK 0x00000008
#define OLD_CI_RESTRICTED 0x00000010
#define OLD_CI_PEACE 0x00000020
-#define OLD_CI_SECURE 0x00000040
#define OLD_CI_VERBOTEN 0x00000080
#define OLD_CI_ENCRYPTEDPW 0x00000100
#define OLD_CI_NO_EXPIRE 0x00000200
@@ -94,7 +92,7 @@ else \
#define OLD_NEWS_OPER 1
#define OLD_NEWS_RANDOM 2
-static struct mlock_info
+static struct mlock_info final
{
char c;
uint32_t m;
@@ -146,20 +144,22 @@ enum
static void process_mlock(ChannelInfo *ci, uint32_t lock, bool status, uint32_t *limit, Anope::string *key)
{
ModeLocks *ml = ci->Require<ModeLocks>("modelocks");
- for (unsigned i = 0; i < (sizeof(mlock_infos) / sizeof(mlock_info)); ++i)
- if (lock & mlock_infos[i].m)
+ for (auto &mlock_info : mlock_infos)
+ {
+ if (lock & mlock_info.m)
{
- ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock_infos[i].c);
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock_info.c);
if (cm && ml)
{
- if (limit && mlock_infos[i].c == 'l')
- ml->SetMLock(cm, status, stringify(*limit));
- else if (key && mlock_infos[i].c == 'k')
+ if (limit && mlock_info.c == 'l')
+ ml->SetMLock(cm, status, Anope::ToString(*limit));
+ else if (key && mlock_info.c == 'k')
ml->SetMLock(cm, status, *key);
else
ml->SetMLock(cm, status);
}
}
+ }
}
static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -205,7 +205,7 @@ static Anope::string Hex(const char *data, size_t l)
{
const char hextable[] = "0123456789abcdef";
- std::string rv;
+ Anope::string rv;
for (size_t i = 0; i < l; ++i)
{
unsigned char c = data[i];
@@ -252,7 +252,7 @@ static Anope::string GetLevelName(int level)
case 15:
return "NOKICK";
case 16:
- return "FANTASIA";
+ return "FANTASY";
case 17:
return "SAY";
case 18:
@@ -307,7 +307,7 @@ static char *strscpy(char *d, const char *s, size_t len)
return d_orig;
}
-struct dbFILE
+struct dbFILE final
{
int mode; /* 'r' for reading, 'w' for writing */
FILE *fp; /* The normal file descriptor */
@@ -321,7 +321,7 @@ static dbFILE *open_db_read(const char *service, const char *filename, int versi
int myversion;
f = new dbFILE;
- strscpy(f->filename, (Anope::DataDir + "/" + filename).c_str(), sizeof(f->filename));
+ strscpy(f->filename, Anope::ExpandData(filename).c_str(), sizeof(f->filename));
f->mode = 'r';
fp = fopen(f->filename, "rb");
if (!fp)
@@ -390,7 +390,7 @@ static int read_string(Anope::string &str, dbFILE *f)
return -1;
if (len == 0)
return 0;
- char *s = new char[len];
+ auto *s = new char[len];
if (len != fread(s, 1, len, f->fp))
{
delete [] s;
@@ -445,12 +445,12 @@ static void LoadNicks()
Anope::string buffer;
READ(read_string(buffer, f));
- NickCore *nc = new NickCore(buffer);
+ auto *nc = new NickCore(buffer);
- const Anope::string settings[] = { "killprotect", "kill_quick", "ns_secure", "ns_private", "hide_email",
+ const Anope::string settings[] = { "killprotect", "kill_quick", "ns_private", "hide_email",
"hide_mask", "hide_quit", "memo_signon", "memo_receive", "autoop", "msg", "ns_keepmodes" };
- for (unsigned j = 0; j < sizeof(settings) / sizeof(Anope::string); ++j)
- nc->Shrink<bool>(settings[j].upper());
+ for (const auto &setting : settings)
+ nc->Shrink<bool>(setting.upper());
char pwbuf[32];
READ(read_buffer(pwbuf, f));
@@ -481,8 +481,6 @@ static void LoadNicks()
READ(read_uint32(&u32, f));
if (u32 & OLD_NI_KILLPROTECT)
nc->Extend<bool>("KILLPROTECT");
- if (u32 & OLD_NI_SECURE)
- nc->Extend<bool>("NS_SECURE");
if (u32 & OLD_NI_MSG)
nc->Extend<bool>("MSG");
if (u32 & OLD_NI_MEMO_HARDMAX)
@@ -539,24 +537,18 @@ static void LoadNicks()
case LANG_DE:
nc->language = "de_DE.UTF-8";
break;
- case LANG_CAT:
- nc->language = "ca_ES.UTF-8"; // yes, iso639 defines catalan as CA
- break;
case LANG_GR:
nc->language = "el_GR.UTF-8";
break;
case LANG_NL:
nc->language = "nl_NL.UTF-8";
break;
- case LANG_RU:
- nc->language = "ru_RU.UTF-8";
- break;
- case LANG_HUN:
- nc->language = "hu_HU.UTF-8";
- break;
case LANG_PL:
nc->language = "pl_PL.UTF-8";
break;
+ case LANG_CAT:
+ case LANG_HUN:
+ case LANG_RU:
case LANG_EN_US:
case LANG_JA_JIS:
case LANG_JA_EUC:
@@ -569,7 +561,6 @@ static void LoadNicks()
for (uint16_t j = 0; j < u16; ++j)
{
READ(read_string(buffer, f));
- nc->access.push_back(buffer);
}
int16_t i16;
@@ -577,7 +568,7 @@ static void LoadNicks()
READ(read_int16(&nc->memos.memomax, f));
for (int16_t j = 0; j < i16; ++j)
{
- Memo *m = new Memo;
+ auto *m = new Memo;
READ(read_uint32(&u32, f));
uint16_t flags;
READ(read_uint16(&flags, f));
@@ -653,7 +644,7 @@ static void LoadNicks()
continue;
}
- NickAlias *na = new NickAlias(nick, nc);
+ auto *na = new NickAlias(nick, nc);
na->last_usermask = last_usermask;
na->last_realname = last_realname;
na->last_quit = last_quit;
@@ -693,7 +684,7 @@ static void LoadVHosts()
continue;
}
- na->SetVhost(ident, host, creator, vtime);
+ na->SetVHost(ident, host, creator, vtime);
Log() << "Loaded vhost for " << na->nick;
}
@@ -748,12 +739,12 @@ static void LoadChannels()
Anope::string buffer;
char namebuf[64];
READ(read_buffer(namebuf, f));
- ChannelInfo *ci = new ChannelInfo(namebuf);
+ auto *ci = new ChannelInfo(namebuf);
- const Anope::string settings[] = { "keeptopic", "peace", "cs_private", "restricted", "cs_secure", "secureops", "securefounder",
+ const Anope::string settings[] = { "keeptopic", "peace", "cs_private", "restricted", "secureops", "securefounder",
"signkick", "signkick_level", "topiclock", "persist", "noautoop", "cs_keepmodes" };
- for (unsigned j = 0; j < sizeof(settings) / sizeof(Anope::string); ++j)
- ci->Shrink<bool>(settings[j].upper());
+ for (const auto &setting : settings)
+ ci->Shrink<bool>(setting.upper());
READ(read_string(buffer, f));
ci->SetFounder(NickCore::Find(buffer));
@@ -799,8 +790,6 @@ static void LoadChannels()
ci->Extend<bool>("RESTRICTED");
if (tmpu32 & OLD_CI_PEACE)
ci->Extend<bool>("PEACE");
- if (tmpu32 & OLD_CI_SECURE)
- ci->Extend<bool>("CS_SECURE");
if (tmpu32 & OLD_CI_NO_EXPIRE)
ci->Extend<bool>("CS_NO_EXPIRE");
if (tmpu32 & OLD_CI_MEMO_HARDMAX)
@@ -894,7 +883,7 @@ static void LoadChannels()
}
}
else
- access->AccessUnserialize(stringify(level));
+ access->AccessUnserialize(Anope::ToString(level));
}
Anope::string mask;
@@ -948,7 +937,7 @@ static void LoadChannels()
{
READ(read_uint32(&tmpu32, f));
READ(read_uint16(&tmpu16, f));
- Memo *m = new Memo;
+ auto *m = new Memo;
READ(read_int32(&tmp32, f));
m->time = tmp32;
char sbuf[32];
@@ -1104,9 +1093,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 (auto *xl : XLineManager::XLineManagers)
{
- XLineManager *xl = *it;
if (xl->Type() == 'G')
akill = xl;
else if (xl->Type() == 'Q')
@@ -1138,7 +1126,7 @@ static void LoadOper()
if (!akill)
continue;
- XLine *x = new XLine(user + "@" + host, by, expires, reason, XLineManager::GenerateUID());
+ auto *x = new XLine(user + "@" + host, by, expires, reason, XLineManager::GenerateUID());
x->created = seton;
akill->AddXLine(x);
}
@@ -1158,7 +1146,7 @@ static void LoadOper()
if (!snline)
continue;
- XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
+ auto *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
x->created = seton;
snline->AddXLine(x);
}
@@ -1178,7 +1166,7 @@ static void LoadOper()
if (!sqline)
continue;
- XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
+ auto *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
x->created = seton;
sqline->AddXLine(x);
}
@@ -1198,7 +1186,7 @@ static void LoadOper()
if (!szline)
continue;
- XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
+ auto *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
x->created = seton;
szline->AddXLine(x);
}
@@ -1296,12 +1284,13 @@ static void LoadNews()
close_db(f);
}
-class DBOld : public Module
+class DBOld final
+ : public Module
{
PrimitiveExtensibleItem<uint32_t> mlock_on, mlock_off, mlock_limit;
PrimitiveExtensibleItem<Anope::string> mlock_key;
- public:
+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")
{
@@ -1313,7 +1302,7 @@ class DBOld : public Module
throw ModuleException("Invalid hash method");
}
- EventReturn OnLoadDatabase() anope_override
+ EventReturn OnLoadDatabase() override
{
LoadNicks();
LoadVHosts();
@@ -1326,11 +1315,10 @@ 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)
+ for (auto &[_, ci] : *RegisteredChannelList)
{
- ChannelInfo *ci = it->second;
uint32_t *limit = mlock_limit.Get(ci);
Anope::string *key = mlock_key.Get(ci);
@@ -1354,6 +1342,7 @@ class DBOld : public Module
if (ci->c)
ci->c->CheckModes();
}
+ Anope::SaveDatabases();
}
};
diff --git a/modules/database/db_redis.cpp b/modules/database/db_redis.cpp
index 55843beac..4c633d684 100644
--- a/modules/database/db_redis.cpp
+++ b/modules/database/db_redis.cpp
@@ -14,116 +14,118 @@ using namespace Redis;
class DatabaseRedis;
static DatabaseRedis *me;
-class Data : public Serialize::Data
+class Data final
+ : public Serialize::Data
{
- public:
+public:
std::map<Anope::string, std::stringstream *> data;
- ~Data()
+ ~Data() override
{
- for (std::map<Anope::string, std::stringstream *>::iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
- delete it->second;
+ for (auto &[_, stream] : data)
+ delete stream;
}
- std::iostream& operator[](const Anope::string &key) anope_override
+ std::iostream &operator[](const Anope::string &key) override
{
- std::stringstream* &stream = data[key];
+ 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() const 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());
+ for (const auto &[_, value] : this->data)
+ if (!value->str().empty())
+ hash ^= Anope::hash_cs()(value->str());
return hash;
}
};
-class TypeLoader : public Interface
+class TypeLoader final
+ : public Interface
{
Anope::string type;
- public:
+public:
TypeLoader(Module *creator, const Anope::string &t) : Interface(creator), type(t) { }
- void OnResult(const Reply &r) anope_override;
+ void OnResult(const Reply &r) override;
};
-class ObjectLoader : public Interface
+class ObjectLoader final
+ : public Interface
{
Anope::string type;
int64_t id;
- public:
+public:
ObjectLoader(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
- void OnResult(const Reply &r) anope_override;
+ void OnResult(const Reply &r) override;
};
-class IDInterface : public Interface
+class IDInterface final
+ : public Interface
{
Reference<Serializable> o;
- public:
+public:
IDInterface(Module *creator, Serializable *obj) : Interface(creator), o(obj) { }
- void OnResult(const Reply &r) anope_override;
+ void OnResult(const Reply &r) override;
};
-class Deleter : public Interface
+class Deleter final
+ : public Interface
{
Anope::string type;
int64_t id;
- public:
+public:
Deleter(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
- void OnResult(const Reply &r) anope_override;
+ void OnResult(const Reply &r) override;
};
-class Updater : public Interface
+class Updater final
+ : public Interface
{
Anope::string type;
int64_t id;
- public:
+public:
Updater(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
- void OnResult(const Reply &r) anope_override;
+ void OnResult(const Reply &r) override;
};
-class ModifiedObject : public Interface
+class ModifiedObject final
+ : public Interface
{
Anope::string type;
int64_t id;
- public:
+public:
ModifiedObject(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
- void OnResult(const Reply &r) anope_override;
+ void OnResult(const Reply &r) override;
};
-class SubscriptionListener : public Interface
+class SubscriptionListener final
+ : public Interface
{
- public:
+public:
SubscriptionListener(Module *creator) : Interface(creator) { }
- void OnResult(const Reply &r) anope_override;
+ void OnResult(const Reply &r) override;
};
-class DatabaseRedis : public Module, public Pipe
+class DatabaseRedis final
+ : public Module
+ , public Pipe
{
SubscriptionListener sl;
std::set<Serializable *> updated_items;
- public:
+public:
ServiceReference<Provider> redis;
DatabaseRedis(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), sl(this)
@@ -151,33 +153,31 @@ class DatabaseRedis : public Module, public Pipe
obj->UpdateCache(data);
std::vector<Anope::string> args;
- args.push_back("HGETALL");
- args.push_back("hash:" + t->GetName() + ":" + stringify(obj->id));
+ args.emplace_back("HGETALL");
+ args.push_back("hash:" + t->GetName() + ":" + Anope::ToString(obj->id));
/* Get object attrs to clear before updating */
redis->SendCommand(new Updater(this, t->GetName(), obj->id), args);
}
}
- void OnNotify() anope_override
+ void OnNotify() override
{
- for (std::set<Serializable *>::iterator it = this->updated_items.begin(), it_end = this->updated_items.end(); it != it_end; ++it)
+ for (auto *obj : this->updated_items)
{
- Serializable *s = *it;
-
- this->InsertObject(s);
+ this->InsertObject(obj);
}
this->updated_items.clear();
}
- void OnReload(Configuration::Conf *conf) anope_override
+ void OnReload(Configuration::Conf *conf) 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
+ EventReturn OnLoadDatabase() override
{
if (!redis)
{
@@ -185,10 +185,9 @@ class DatabaseRedis : public Module, public Pipe
return EVENT_CONTINUE;
}
- const std::vector<Anope::string> type_order = Serialize::Type::GetTypeOrder();
- for (unsigned i = 0; i < type_order.size(); ++i)
+ for (const auto &type_order : Serialize::Type::GetTypeOrder())
{
- Serialize::Type *sb = Serialize::Type::Find(type_order[i]);
+ Serialize::Type *sb = Serialize::Type::Find(type_order);
this->OnSerializeTypeCreate(sb);
}
@@ -205,25 +204,25 @@ class DatabaseRedis : public Module, public Pipe
return EVENT_STOP;
}
- void OnSerializeTypeCreate(Serialize::Type *sb) anope_override
+ void OnSerializeTypeCreate(Serialize::Type *sb) override
{
if (!redis)
return;
std::vector<Anope::string> args;
- args.push_back("SMEMBERS");
+ args.emplace_back("SMEMBERS");
args.push_back("ids:" + sb->GetName());
redis->SendCommand(new TypeLoader(this, sb->GetName()), args);
}
- void OnSerializableConstruct(Serializable *obj) anope_override
+ void OnSerializableConstruct(Serializable *obj) override
{
this->updated_items.insert(obj);
this->Notify();
}
- void OnSerializableDestruct(Serializable *obj) anope_override
+ void OnSerializableDestruct(Serializable *obj) override
{
Serialize::Type *t = obj->GetSerializableType();
@@ -240,8 +239,8 @@ class DatabaseRedis : public Module, public Pipe
}
std::vector<Anope::string> args;
- args.push_back("HGETALL");
- args.push_back("hash:" + t->GetName() + ":" + stringify(obj->id));
+ args.emplace_back("HGETALL");
+ args.push_back("hash:" + t->GetName() + ":" + Anope::ToString(obj->id));
/* Get all of the attributes for this object */
redis->SendCommand(new Deleter(this, t->GetName(), obj->id), args);
@@ -251,7 +250,7 @@ class DatabaseRedis : public Module, public Pipe
this->Notify();
}
- void OnSerializableUpdate(Serializable *obj) anope_override
+ void OnSerializableUpdate(Serializable *obj) override
{
this->updated_items.insert(obj);
this->Notify();
@@ -266,26 +265,19 @@ void TypeLoader::OnResult(const Reply &r)
return;
}
- for (unsigned i = 0; i < r.multi_bulk.size(); ++i)
+ for (auto *reply : r.multi_bulk)
{
- 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 &)
- {
+ auto i = Anope::TryConvert<int64_t>(reply->bulk);
+ if (!i)
continue;
- }
+ auto id = i.value();
std::vector<Anope::string> args;
- args.push_back("HGETALL");
- args.push_back("hash:" + this->type + ":" + stringify(id));
+ args.emplace_back("HGETALL");
+ args.push_back("hash:" + this->type + ":" + Anope::ToString(id));
me->redis->SendCommand(new ObjectLoader(me, this->type, id), args);
}
@@ -313,7 +305,7 @@ void ObjectLoader::OnResult(const Reply &r)
data[key->bulk] << value->bulk;
}
- Serializable* &obj = st->objects[this->id];
+ Serializable *&obj = st->objects[this->id];
obj = st->Unserialize(obj, data);
if (obj)
{
@@ -332,7 +324,7 @@ void IDInterface::OnResult(const Reply &r)
return;
}
- Serializable* &obj = o->GetSerializableType()->objects[r.i];
+ Serializable *&obj = o->GetSerializableType()->objects[r.i];
if (obj)
/* This shouldn't be possible */
obj->id = 0;
@@ -358,16 +350,16 @@ void Deleter::OnResult(const Reply &r)
me->redis->StartTransaction();
std::vector<Anope::string> args;
- args.push_back("DEL");
- args.push_back("hash:" + this->type + ":" + stringify(this->id));
+ args.emplace_back("DEL");
+ args.push_back("hash:" + this->type + ":" + Anope::ToString(this->id));
/* Delete hash object */
me->redis->SendCommand(NULL, args);
args.clear();
- args.push_back("SREM");
+ args.emplace_back("SREM");
args.push_back("ids:" + this->type);
- args.push_back(stringify(this->id));
+ args.push_back(Anope::ToString(this->id));
/* Delete id from ids set */
me->redis->SendCommand(NULL, args);
@@ -378,9 +370,9 @@ void Deleter::OnResult(const Reply &r)
*value = r.multi_bulk[i + 1];
args.clear();
- args.push_back("SREM");
+ args.emplace_back("SREM");
args.push_back("value:" + this->type + ":" + key->bulk + ":" + value->bulk);
- args.push_back(stringify(this->id));
+ args.push_back(Anope::ToString(this->id));
/* Delete value -> object id */
me->redis->SendCommand(NULL, args);
@@ -421,9 +413,9 @@ void Updater::OnResult(const Reply &r)
*value = r.multi_bulk[i + 1];
std::vector<Anope::string> args;
- args.push_back("SREM");
+ args.emplace_back("SREM");
args.push_back("value:" + this->type + ":" + key->bulk + ":" + value->bulk);
- args.push_back(stringify(this->id));
+ args.push_back(Anope::ToString(this->id));
/* Delete value -> object id */
me->redis->SendCommand(NULL, args);
@@ -431,29 +423,25 @@ void Updater::OnResult(const Reply &r)
/* Add object id to id set for this type */
std::vector<Anope::string> args;
- args.push_back("SADD");
+ args.emplace_back("SADD");
args.push_back("ids:" + this->type);
- args.push_back(stringify(obj->id));
+ args.push_back(Anope::ToString(obj->id));
me->redis->SendCommand(NULL, args);
args.clear();
- args.push_back("HMSET");
- args.push_back("hash:" + this->type + ":" + stringify(obj->id));
+ args.emplace_back("HMSET");
+ args.push_back("hash:" + this->type + ":" + Anope::ToString(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)
+ for (const auto &[key, value] : data.data)
{
- const Anope::string &key = it->first;
- std::stringstream *value = it->second;
-
args.push_back(key);
- args.push_back(value->str());
+ args.emplace_back(value->str());
std::vector<Anope::string> args2;
- args2.push_back("SADD");
+ args2.emplace_back("SADD");
args2.push_back("value:" + this->type + ":" + key + ":" + value->str());
- args2.push_back(stringify(obj->id));
+ args2.push_back(Anope::ToString(obj->id));
/* Add to value -> object id set */
me->redis->SendCommand(NULL, args2);
@@ -504,16 +492,11 @@ void SubscriptionListener::OnResult(const Reply &r)
if (s_type == NULL)
return;
- uint64_t obj_id;
- try
- {
- obj_id = convertTo<uint64_t>(id);
- }
- catch (const ConvertException &)
- {
+ auto oid = Anope::TryConvert<uint64_t>(id);
+ if (!oid.has_value())
return;
- }
+ auto obj_id = oid.value();
if (op == "hset" || op == "hdel")
{
Serializable *s = s_type->objects[obj_id];
@@ -528,7 +511,7 @@ void SubscriptionListener::OnResult(const Reply &r)
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.emplace_back("HGETALL");
args.push_back("hash:" + type + ":" + id);
me->redis->SendCommand(new ModifiedObject(me, type, obj_id), args);
@@ -536,7 +519,7 @@ void SubscriptionListener::OnResult(const Reply &r)
}
else if (op == "del")
{
- Serializable* &s = s_type->objects[obj_id];
+ Serializable *&s = s_type->objects[obj_id];
if (s == NULL)
return;
@@ -549,14 +532,10 @@ void SubscriptionListener::OnResult(const Reply &r)
/* 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)
+ for (const auto &[k, value] : data.data)
{
- const Anope::string &k = it->first;
- std::stringstream *value = it->second;
-
std::vector<Anope::string> args;
- args.push_back("SREM");
+ args.emplace_back("SREM");
args.push_back("value:" + type + ":" + k + ":" + value->str());
args.push_back(id);
@@ -565,9 +544,9 @@ void SubscriptionListener::OnResult(const Reply &r)
}
std::vector<Anope::string> args;
- args.push_back("SREM");
+ args.emplace_back("SREM");
args.push_back("ids:" + type);
- args.push_back(stringify(s->id));
+ args.push_back(Anope::ToString(s->id));
/* Delete object from id set */
me->redis->SendCommand(NULL, args);
@@ -590,7 +569,7 @@ void ModifiedObject::OnResult(const Reply &r)
return;
}
- Serializable* &obj = st->objects[this->id];
+ Serializable *&obj = st->objects[this->id];
/* Transaction start */
me->redis->StartTransaction();
@@ -602,16 +581,12 @@ void ModifiedObject::OnResult(const Reply &r)
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)
+ for (auto &[key, value] : data.data)
{
- const Anope::string &key = it->first;
- std::stringstream *value = it->second;
-
std::vector<Anope::string> args;
- args.push_back("SREM");
+ args.emplace_back("SREM");
args.push_back("value:" + st->GetName() + ":" + key + ":" + value->str());
- args.push_back(stringify(this->id));
+ args.push_back(Anope::ToString(this->id));
/* Delete value -> object id */
me->redis->SendCommand(NULL, args);
@@ -635,25 +610,21 @@ void ModifiedObject::OnResult(const Reply &r)
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)
+ for (const auto &[key, value] : data.data)
{
- const Anope::string &key = it->first;
- std::stringstream *value = it->second;
-
std::vector<Anope::string> args;
- args.push_back("SADD");
+ args.emplace_back("SADD");
args.push_back("value:" + st->GetName() + ":" + key + ":" + value->str());
- args.push_back(stringify(obj->id));
+ args.push_back(Anope::ToString(obj->id));
/* Add to value -> object id set */
me->redis->SendCommand(NULL, args);
}
std::vector<Anope::string> args;
- args.push_back("SADD");
+ args.emplace_back("SADD");
args.push_back("ids:" + st->GetName());
- args.push_back(stringify(obj->id));
+ args.push_back(Anope::ToString(obj->id));
/* Add to type -> id set */
me->redis->SendCommand(NULL, args);
diff --git a/modules/database/db_sql.cpp b/modules/database/db_sql.cpp
index c02edd8aa..d8fe89972 100644
--- a/modules/database/db_sql.cpp
+++ b/modules/database/db_sql.cpp
@@ -14,17 +14,18 @@
using namespace SQL;
-class SQLSQLInterface : public Interface
+class SQLSQLInterface
+ : public Interface
{
- public:
+public:
SQLSQLInterface(Module *o) : Interface(o) { }
- void OnResult(const Result &r) anope_override
+ void OnResult(const Result &r) override
{
Log(LOG_DEBUG) << "SQL successfully executed query: " << r.finished_query;
}
- void OnError(const Result &r) anope_override
+ void OnError(const Result &r) override
{
if (!r.GetQuery().query.empty())
Log(LOG_DEBUG) << "Error executing query " << r.finished_query << ": " << r.GetError();
@@ -33,14 +34,15 @@ class SQLSQLInterface : public Interface
}
};
-class ResultSQLSQLInterface : public SQLSQLInterface
+class ResultSQLSQLInterface final
+ : public SQLSQLInterface
{
Reference<Serializable> obj;
public:
ResultSQLSQLInterface(Module *o, Serializable *ob) : SQLSQLInterface(o), obj(ob) { }
- void OnResult(const Result &r) anope_override
+ void OnResult(const Result &r) override
{
SQLSQLInterface::OnResult(r);
if (r.GetID() > 0 && this->obj)
@@ -48,14 +50,16 @@ public:
delete this;
}
- void OnError(const Result &r) anope_override
+ void OnError(const Result &r) override
{
SQLSQLInterface::OnError(r);
delete this;
}
};
-class DBSQL : public Module, public Pipe
+class DBSQL final
+ : public Module
+ , public Pipe
{
ServiceReference<Provider> sql;
SQLSQLInterface sqlinterface;
@@ -63,10 +67,10 @@ class DBSQL : public Module, public Pipe
bool import;
std::set<Serializable *> updated_items;
- bool shutting_down;
- bool loading_databases;
- bool loaded;
- bool imported;
+ bool shutting_down = false;
+ bool loading_databases = false;
+ bool loaded = false;
+ bool imported = false;
void RunBackground(const Query &q, Interface *iface = NULL)
{
@@ -89,8 +93,8 @@ class DBSQL : public Module, public Pipe
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)
+public:
+ DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), sql("", ""), sqlinterface(this)
{
@@ -98,12 +102,10 @@ class DBSQL : public Module, public Pipe
throw ModuleException("db_sql can not be loaded after db_sql_live");
}
- void OnNotify() anope_override
+ void OnNotify() override
{
- for (std::set<Serializable *>::iterator it = this->updated_items.begin(), it_end = this->updated_items.end(); it != it_end; ++it)
+ for (auto *obj : this->updated_items)
{
- Serializable *obj = *it;
-
if (this->sql)
{
Data data;
@@ -127,15 +129,15 @@ class DBSQL : public Module, public Pipe
if (this->imported)
{
- for (unsigned i = 0; i < create.size(); ++i)
- this->RunBackground(create[i]);
+ for (const auto &query : create)
+ this->RunBackground(query);
this->RunBackground(insert, new ResultSQLSQLInterface(this, obj));
}
else
{
- for (unsigned i = 0; i < create.size(); ++i)
- this->sql->RunQuery(create[i]);
+ for (const auto &query : create)
+ this->sql->RunQuery(query);
/* 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
@@ -151,7 +153,7 @@ class DBSQL : public Module, public Pipe
this->imported = true;
}
- void OnReload(Configuration::Conf *conf) anope_override
+ void OnReload(Configuration::Conf *conf) override
{
Configuration::Block *block = conf->GetModule(this);
this->sql = ServiceReference<Provider>("SQL::Provider", block->Get<const Anope::string>("engine"));
@@ -159,18 +161,18 @@ class DBSQL : public Module, public Pipe
this->import = block->Get<bool>("import");
}
- void OnShutdown() anope_override
+ void OnShutdown() override
{
this->shutting_down = true;
this->OnNotify();
}
- void OnRestart() anope_override
+ void OnRestart() override
{
this->OnShutdown();
}
- EventReturn OnLoadDatabase() anope_override
+ EventReturn OnLoadDatabase() override
{
if (!this->sql)
{
@@ -180,10 +182,9 @@ class DBSQL : public Module, public Pipe
this->loading_databases = true;
- const std::vector<Anope::string> type_order = Serialize::Type::GetTypeOrder();
- for (unsigned i = 0; i < type_order.size(); ++i)
+ for (const auto &type_order : Serialize::Type::GetTypeOrder())
{
- Serialize::Type *sb = Serialize::Type::Find(type_order[i]);
+ Serialize::Type *sb = Serialize::Type::Find(type_order);
this->OnSerializeTypeCreate(sb);
}
@@ -193,7 +194,7 @@ class DBSQL : public Module, public Pipe
return EVENT_STOP;
}
- void OnSerializableConstruct(Serializable *obj) anope_override
+ void OnSerializableConstruct(Serializable *obj) override
{
if (this->shutting_down || this->loading_databases)
return;
@@ -202,17 +203,17 @@ class DBSQL : public Module, public Pipe
this->Notify();
}
- void OnSerializableDestruct(Serializable *obj) anope_override
+ void OnSerializableDestruct(Serializable *obj) 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->RunBackground("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + Anope::ToString(obj->id));
this->updated_items.erase(obj);
}
- void OnSerializableUpdate(Serializable *obj) anope_override
+ void OnSerializableUpdate(Serializable *obj) override
{
if (this->shutting_down || obj->IsTSCached())
return;
@@ -223,7 +224,7 @@ class DBSQL : public Module, public Pipe
this->Notify();
}
- void OnSerializeTypeCreate(Serialize::Type *sb) anope_override
+ void OnSerializeTypeCreate(Serialize::Type *sb) override
{
if (!this->loading_databases && !this->loaded)
return;
@@ -235,23 +236,18 @@ class DBSQL : public Module, public Pipe
{
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;
+ for (const auto &[key, value] : res.Row(j))
+ data[key] << value;
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)
{
+ auto oid = Anope::TryConvert<unsigned int>(res.Get(j, "id"));
+ if (oid.has_value())
+ obj->id = oid.value();
+ else
+ Log(this) << "Unable to convert id for object #" << j << " of type " << sb->GetName();
+
/* 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
diff --git a/modules/database/db_sql_live.cpp b/modules/database/db_sql_live.cpp
index 407ad6cd2..ea1fb1a27 100644
--- a/modules/database/db_sql_live.cpp
+++ b/modules/database/db_sql_live.cpp
@@ -11,9 +11,11 @@
using namespace SQL;
-class DBMySQL : public Module, public Pipe
+class DBMySQL final
+ : public Module
+ , public Pipe
{
- private:
+private:
Anope::string prefix;
ServiceReference<Provider> SQL;
time_t lastwarn;
@@ -35,7 +37,7 @@ class DBMySQL : public Module, public Pipe
}
else
{
- if (Anope::CurTime - Config->GetBlock("options")->Get<time_t>("updatetimeout", "5m") > lastwarn)
+ if (Anope::CurTime - Config->GetBlock("options")->Get<time_t>("updatetimeout", "2m") > lastwarn)
{
Log() << "Unable to locate SQL reference, going to readonly...";
Anope::ReadOnly = this->ro = true;
@@ -71,7 +73,7 @@ class DBMySQL : public Module, public Pipe
throw SQL::Exception("No SQL!");
}
- public:
+public:
DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), SQL("", "")
{
this->lastwarn = 0;
@@ -83,15 +85,13 @@ class DBMySQL : public Module, public Pipe
throw ModuleException("If db_sql_live is loaded it must be the first database module loaded.");
}
- void OnNotify() anope_override
+ void OnNotify() 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)
+ for (auto *obj : this->updated_items)
{
- Serializable *obj = *it;
-
if (obj && this->SQL)
{
Data data;
@@ -107,8 +107,8 @@ class DBMySQL : public Module, public Pipe
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]);
+ for (const auto &query : create)
+ this->RunQueryResult(query);
Result res = this->RunQueryResult(this->SQL->BuildInsert(this->prefix + s_type->GetName(), obj->id, data));
if (res.GetID() && obj->id != res.GetID())
@@ -123,30 +123,30 @@ class DBMySQL : public Module, public Pipe
this->updated_items.clear();
}
- EventReturn OnLoadDatabase() anope_override
+ EventReturn OnLoadDatabase() override
{
init = true;
return EVENT_STOP;
}
- void OnShutdown() anope_override
+ void OnShutdown() override
{
init = false;
}
- void OnRestart() anope_override
+ void OnRestart() override
{
init = false;
}
- void OnReload(Configuration::Conf *conf) anope_override
+ void OnReload(Configuration::Conf *conf) 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
+ void OnSerializableConstruct(Serializable *obj) override
{
if (!this->CheckInit())
return;
@@ -155,7 +155,7 @@ class DBMySQL : public Module, public Pipe
this->Notify();
}
- void OnSerializableDestruct(Serializable *obj) anope_override
+ void OnSerializableDestruct(Serializable *obj) override
{
if (!this->CheckInit())
return;
@@ -163,13 +163,13 @@ class DBMySQL : public Module, public Pipe
if (s_type)
{
if (obj->id > 0)
- this->RunQuery("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + stringify(obj->id));
+ this->RunQuery("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + Anope::ToString(obj->id));
s_type->objects.erase(obj->id);
}
this->updated_items.erase(obj);
}
- void OnSerializeCheck(Serialize::Type *obj) anope_override
+ void OnSerializeCheck(Serialize::Type *obj) override
{
if (!this->CheckInit() || obj->GetTimestamp() == Anope::CurTime)
return;
@@ -185,17 +185,16 @@ class DBMySQL : public Module, public Pipe
{
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 &)
+
+
+ auto oid = Anope::TryConvert<unsigned int>(res.Get(i, "id"));
+ if (!oid.has_value())
{
Log(LOG_DEBUG) << "Unable to convert id from " << obj->GetName();
continue;
}
+ auto id = oid.value();
if (res.Get(i, "timestamp").empty())
{
clear_null = true;
@@ -207,8 +206,8 @@ class DBMySQL : public Module, public Pipe
{
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;
+ for (const auto &[key, value] : row)
+ data[key] << value;
Serializable *s = NULL;
std::map<uint64_t, Serializable *>::iterator it = obj->objects.find(id);
@@ -237,7 +236,7 @@ class DBMySQL : public Module, public Pipe
else
{
if (!s)
- this->RunQuery("UPDATE `" + prefix + obj->GetName() + "` SET `timestamp` = " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " WHERE `id` = " + stringify(id));
+ this->RunQuery("UPDATE `" + prefix + obj->GetName() + "` SET `timestamp` = " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " WHERE `id` = " + Anope::ToString(id));
else
delete s;
}
@@ -251,7 +250,7 @@ class DBMySQL : public Module, public Pipe
}
}
- void OnSerializableUpdate(Serializable *obj) anope_override
+ void OnSerializableUpdate(Serializable *obj) override
{
if (!this->CheckInit() || obj->IsTSCached())
return;