mirror of
https://github.com/anope/anope.git
synced 2026-06-12 17:04:47 +02:00
314 lines
6.7 KiB
C++
314 lines
6.7 KiB
C++
// Anope IRC Services <https://www.anope.org/>
|
|
//
|
|
// Copyright (C) 2003-2026 Anope Contributors
|
|
//
|
|
// Anope is free software. You can use, modify, and/or distribute it under the
|
|
// terms of version 2 of the GNU General Public License. See docs/LICENSE.txt
|
|
// for the complete terms of this license and docs/AUTHORS.txt for a list of
|
|
// contributors.
|
|
//
|
|
// Based on the original code of Epona by Lara
|
|
// Based on the original code of Services by Andy Church
|
|
//
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
#include "module.h"
|
|
#include "modules/info.h"
|
|
|
|
struct OperInfoImpl final
|
|
: OperInfo
|
|
, Serializable
|
|
{
|
|
OperInfoImpl()
|
|
: Serializable("OperInfo")
|
|
{
|
|
}
|
|
|
|
OperInfoImpl(const Anope::string &t, const Anope::string &i, const Anope::string &a, time_t c)
|
|
: OperInfo(t, i, a, c)
|
|
, Serializable("OperInfo")
|
|
{
|
|
}
|
|
|
|
~OperInfoImpl() override;
|
|
};
|
|
|
|
struct OperInfoTypeImpl
|
|
: Serialize::Type
|
|
{
|
|
OperInfoTypeImpl()
|
|
: Serialize::Type("OperInfo")
|
|
{
|
|
}
|
|
|
|
void Serialize(Serializable *obj, Serialize::Data &data) const override
|
|
{
|
|
const auto *oi = static_cast<const OperInfoImpl *>(obj);
|
|
data.Store("target", oi->target);
|
|
data.Store("info", oi->info);
|
|
data.Store("adder", oi->adder);
|
|
data.Store("created", oi->created);
|
|
}
|
|
|
|
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
|
|
};
|
|
|
|
struct OperInfos final
|
|
: OperInfoList
|
|
{
|
|
OperInfos(Extensible *) { }
|
|
|
|
OperInfo *Create() override
|
|
{
|
|
return new OperInfoImpl();
|
|
}
|
|
|
|
static Extensible *Find(const Anope::string &target)
|
|
{
|
|
NickAlias *na = NickAlias::Find(target);
|
|
if (na)
|
|
return na->nc;
|
|
return ChannelInfo::Find(target);
|
|
}
|
|
};
|
|
|
|
OperInfoImpl::~OperInfoImpl()
|
|
{
|
|
Extensible *e = OperInfos::Find(target);
|
|
if (e)
|
|
{
|
|
auto *op = e->GetExt<OperInfos>("operinfo");
|
|
if (op)
|
|
{
|
|
auto it = std::find((*op)->begin(), (*op)->end(), this);
|
|
if (it != (*op)->end())
|
|
(*op)->erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
Serializable *OperInfoTypeImpl::Unserialize(Serializable *obj, Serialize::Data &data) const
|
|
{
|
|
Anope::string starget;
|
|
data["target"] >> starget;
|
|
|
|
Extensible *e = OperInfos::Find(starget);
|
|
if (!e)
|
|
return NULL;
|
|
|
|
auto *oi = e->Require<OperInfos>("operinfo");
|
|
OperInfoImpl *o;
|
|
if (obj)
|
|
o = anope_dynamic_static_cast<OperInfoImpl *>(obj);
|
|
else
|
|
{
|
|
o = new OperInfoImpl();
|
|
o->target = starget;
|
|
}
|
|
data["info"] >> o->info;
|
|
data["adder"] >> o->adder;
|
|
data["created"] >> o->created;
|
|
|
|
if (!obj)
|
|
(*oi)->push_back(o);
|
|
return o;
|
|
}
|
|
|
|
class CommandOSInfo final
|
|
: public Command
|
|
{
|
|
public:
|
|
CommandOSInfo(Module *creator) : Command(creator, "operserv/info", 2, 3)
|
|
{
|
|
this->SetDesc(_("Associate oper info with a nick or channel"));
|
|
this->SetSyntax(_("ADD \037target\037 \037info\037"));
|
|
this->SetSyntax(_("DEL \037target\037 \037info\037"));
|
|
this->SetSyntax(_("CLEAR \037target\037"));
|
|
}
|
|
|
|
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) override
|
|
{
|
|
const Anope::string &cmd = params[0], target = params[1], info = params.size() > 2 ? params[2] : "";
|
|
|
|
Extensible *e;
|
|
if (IRCD->IsChannelValid(target))
|
|
{
|
|
ChannelInfo *ci = ChannelInfo::Find(target);
|
|
if (!ci)
|
|
{
|
|
source.Reply(CHAN_X_NOT_REGISTERED, target.c_str());
|
|
return;
|
|
}
|
|
|
|
e = ci;
|
|
}
|
|
else
|
|
{
|
|
NickAlias *na = NickAlias::Find(target);
|
|
if (!na)
|
|
{
|
|
source.Reply(NICK_X_NOT_REGISTERED, target.c_str());
|
|
return;
|
|
}
|
|
|
|
e = na->nc;
|
|
}
|
|
|
|
if (cmd.equals_ci("ADD"))
|
|
{
|
|
if (info.empty())
|
|
{
|
|
this->OnSyntaxError(source, cmd);
|
|
return;
|
|
}
|
|
|
|
auto *oi = e->Require<OperInfos>("operinfo");
|
|
|
|
if ((*oi)->size() >= Config->GetModule(this->module).Get<unsigned>("max", "10"))
|
|
{
|
|
source.Reply(_("The oper info list for \002%s\002 is full."), target.c_str());
|
|
return;
|
|
}
|
|
|
|
for (auto *o : *(*oi))
|
|
{
|
|
if (o->info.equals_ci(info))
|
|
{
|
|
source.Reply(_("The oper info already exists on \002%s\002."), target.c_str());
|
|
return;
|
|
}
|
|
}
|
|
|
|
(*oi)->push_back(new OperInfoImpl(target, info, source.GetNick(), Anope::CurTime));
|
|
|
|
source.Reply(_("Added info to \002%s\002."), target.c_str());
|
|
Log(LOG_ADMIN, source, this) << "to add information to " << target;
|
|
|
|
if (Anope::ReadOnly)
|
|
source.Reply(READ_ONLY_MODE);
|
|
}
|
|
else if (cmd.equals_ci("DEL"))
|
|
{
|
|
if (info.empty())
|
|
{
|
|
this->OnSyntaxError(source, cmd);
|
|
return;
|
|
}
|
|
|
|
auto *oi = e->GetExt<OperInfos>("operinfo");
|
|
|
|
if (!oi)
|
|
{
|
|
source.Reply(_("Oper info list for \002%s\002 is empty."), target.c_str());
|
|
return;
|
|
}
|
|
|
|
bool found = false;
|
|
for (unsigned i = (*oi)->size(); i > 0; --i)
|
|
{
|
|
OperInfo *o = (*oi)->at(i - 1);
|
|
|
|
if (o->info.equals_ci(info))
|
|
{
|
|
delete o;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
source.Reply(_("No such info \"%s\" on \002%s\002."), info.c_str(), target.c_str());
|
|
}
|
|
else
|
|
{
|
|
if ((*oi)->empty())
|
|
e->Shrink<OperInfos>("operinfo");
|
|
|
|
source.Reply(_("Deleted info from \002%s\002."), target.c_str());
|
|
Log(LOG_ADMIN, source, this) << "to remove information from " << target;
|
|
|
|
if (Anope::ReadOnly)
|
|
source.Reply(READ_ONLY_MODE);
|
|
}
|
|
}
|
|
else if (cmd.equals_ci("CLEAR"))
|
|
{
|
|
auto *oi = e->GetExt<OperInfos>("operinfo");
|
|
|
|
if (!oi)
|
|
{
|
|
source.Reply(_("Oper info list for \002%s\002 is empty."), target.c_str());
|
|
return;
|
|
}
|
|
|
|
e->Shrink<OperInfos>("operinfo");
|
|
|
|
source.Reply(_("Cleared info from \002%s\002."), target.c_str());
|
|
Log(LOG_ADMIN, source, this) << "to clear information for " << target;
|
|
|
|
if (Anope::ReadOnly)
|
|
source.Reply(READ_ONLY_MODE);
|
|
}
|
|
else
|
|
{
|
|
this->OnSyntaxError(source, cmd);
|
|
}
|
|
}
|
|
|
|
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
|
{
|
|
this->SendSyntax(source);
|
|
source.Reply(" ");
|
|
source.Reply(_(
|
|
"Add or delete oper information for a given nick or channel. "
|
|
"This will show to opers in the respective info command for "
|
|
"the nick or channel."
|
|
));
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class OSInfo final
|
|
: public Module
|
|
{
|
|
CommandOSInfo commandosinfo;
|
|
ExtensibleItem<OperInfos> oinfo;
|
|
OperInfoTypeImpl oinfo_type;
|
|
|
|
void OnInfo(CommandSource &source, Extensible *e, InfoFormatter &info)
|
|
{
|
|
if (!source.IsOper())
|
|
return;
|
|
|
|
OperInfos *oi = oinfo.Get(e);
|
|
if (!oi)
|
|
return;
|
|
|
|
for (auto *o : *(*oi))
|
|
{
|
|
info[_("Oper Info")] = Anope::Format(_("(by %s on %s) %s"), o->adder.c_str(), Anope::strftime(o->created, source.GetAccount(), true).c_str(), o->info.c_str());
|
|
}
|
|
}
|
|
|
|
public:
|
|
OSInfo(const Anope::string &modname, const Anope::string &creator)
|
|
: Module(modname, creator, VENDOR)
|
|
, commandosinfo(this)
|
|
, oinfo(this, "operinfo")
|
|
{
|
|
}
|
|
|
|
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) override
|
|
{
|
|
OnInfo(source, na->nc, info);
|
|
}
|
|
|
|
void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_hidden) override
|
|
{
|
|
OnInfo(source, ci, info);
|
|
}
|
|
};
|
|
|
|
MODULE_INIT(OSInfo)
|