/*
*
* (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",
|