mirror of
https://github.com/anope/anope.git
synced 2026-06-30 09:16:38 +02:00
Add the rpc_data module.
- Add rewritten and namespaced versions of the channel, oper, user events. - Add the following new events: * anope.listChannels * anope.listOpers * anope.listServers * anope.listUsers * anope.server
This commit is contained in:
@@ -817,6 +817,22 @@ module { name = "sasl" }
|
||||
server = "httpd/main"
|
||||
}
|
||||
|
||||
/*
|
||||
* rpc_data
|
||||
*
|
||||
* Adds support for the following RPC methods:
|
||||
*
|
||||
* anope.listChannels anope.channel
|
||||
* anope.listOpers anope.oper
|
||||
* anope.listServers anope.server
|
||||
* anope.listUsers anope.user
|
||||
*
|
||||
* Requires either the jsonrpc or xmlrpc module.
|
||||
*
|
||||
* See docs/RPC/rpc_data.md for API documentation.
|
||||
*/
|
||||
#module { name = "rpc_data" }
|
||||
|
||||
/*
|
||||
* rpc_main
|
||||
*
|
||||
|
||||
@@ -13,13 +13,6 @@ command - Takes three parameters, a service name (BotServ, ChanServ, NickServ),
|
||||
|
||||
stats - Takes no parameters, returns miscellaneous stats that can be found in the /operserv stats command.
|
||||
|
||||
channel - Takes one parameter, a channel name, and returns real time information regarding that channel, such as users, modes
|
||||
(ban lists and such), topic etc.
|
||||
|
||||
user - Takes one parameter, a user name, and returns real time information regarding that user.
|
||||
|
||||
opers - Takes no parameters, returns opertypes, their privileges and commands.
|
||||
|
||||
notice - Takes three parameters, source user, target user, and message. Sends a message to the user.
|
||||
|
||||
RPC was designed to be used with db_sql, and will not return any information that can be pulled from the SQL
|
||||
|
||||
@@ -117,7 +117,7 @@ class AnopeRPC
|
||||
*/
|
||||
public function channel($channel)
|
||||
{
|
||||
return $this->run("channel", [$channel]);
|
||||
return $this->run("anope.channel", [$channel]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +143,7 @@ class AnopeRPC
|
||||
*/
|
||||
public function user($user)
|
||||
{
|
||||
return $this->run("user", [$user]);
|
||||
return $this->run("anope.user", [$user]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
# Anope `rpc_data` RPC interface
|
||||
|
||||
## `anope.listChannels`
|
||||
|
||||
Lists all channels that exist on the network.
|
||||
|
||||
### Parameters
|
||||
|
||||
*None*
|
||||
|
||||
### Errors
|
||||
|
||||
*Only standard RPC errors*
|
||||
|
||||
### Result
|
||||
|
||||
Returns an array of channel names.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
["#chan1", "#chan2", "#chan3"]
|
||||
```
|
||||
|
||||
## `anope.channel`
|
||||
|
||||
Retrieves information about the specified channel.
|
||||
|
||||
### Parameters
|
||||
|
||||
Index | Description
|
||||
----- | -----------
|
||||
0 | The name of the channel.
|
||||
|
||||
### Errors
|
||||
|
||||
Code | Description
|
||||
------ | -----------
|
||||
-32099 | The specified channel does not exist.
|
||||
|
||||
### Result
|
||||
|
||||
Returns a map containing information about the channel.
|
||||
|
||||
Key | Type | Description
|
||||
--- | ---- | -----------
|
||||
created | uint | The UNIX time at which the channel was originally created.
|
||||
listmodes | map | List modes which are set on the channel keyed by the mode character.
|
||||
modes | array[string] | Flag and parameter modes which are set on the channel.
|
||||
name | string | The name of the channel.
|
||||
registered | boolean | Whether the channel is registered.
|
||||
topic | map or null | The channel topic or null if no topic is set.
|
||||
topic.setat | uint | The time at which the topic was set.
|
||||
topic.setby | string | The nick or nuh of the user who set the topic.
|
||||
topic.value | string | The text of the topic.
|
||||
users | array[string] | The users that are current in the channel prefixed by their status mode prefixes.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"created": 1740402691,
|
||||
"listmodes": {
|
||||
"b": ["foo!bar@baz", "account:bax"],
|
||||
},
|
||||
"modes": ["+knrt", "secret"],
|
||||
"name": "#chan1",
|
||||
"registered": true,
|
||||
"topic": {
|
||||
"setat": 1740404706,
|
||||
"setby": "nick1",
|
||||
"value": "Example channel topic"
|
||||
},
|
||||
"users": ["@nick1", "nick2"]
|
||||
}
|
||||
```
|
||||
|
||||
## `anope.listOpers`
|
||||
|
||||
Lists all services operators that exist on the network.
|
||||
|
||||
### Parameters
|
||||
|
||||
*None*
|
||||
|
||||
### Errors
|
||||
|
||||
*Only standard RPC errors*
|
||||
|
||||
### Result
|
||||
|
||||
Returns an array of services operator names.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
["nick1", "nick2", "nick3"]
|
||||
```
|
||||
|
||||
## `anope.oper`
|
||||
|
||||
Retrieves information about the specified services operator.
|
||||
|
||||
### Parameters
|
||||
|
||||
Index | Description
|
||||
----- | -----------
|
||||
0 | The name of the services operator.
|
||||
|
||||
### Errors
|
||||
|
||||
Code | Description
|
||||
------ | -----------
|
||||
-32099 | The specified services operator does not exist.
|
||||
|
||||
### Result
|
||||
|
||||
Returns a map containing information about the services operator.
|
||||
|
||||
Key | Type | Description
|
||||
--- | ---- | -----------
|
||||
fingerprints | array[string] or null | The client certificate fingerprints that a user must be using to log in as this services operator or null if there are no client certificate restrictions.
|
||||
hosts | array[string] or null | The user@ip and user@ip masks that a user must be connecting from to log in as this services operator or null if there are no host restrictions.
|
||||
name | string | The name of the services operator.
|
||||
operonly | boolean | Whether a user has to be a server operator to log in as this services operator.
|
||||
opertype | map | The oper type associated with the services operator opertype.
|
||||
opertype.commands | array[string] | The commands that the services operator type can use.
|
||||
opertype.name | string | The name of the services operator type.
|
||||
opertype.privileges | array[string] | The privileges that the services operator type has.
|
||||
password | boolean | Whether a user has to specify a password to log in as the services operator.
|
||||
vhost | string or null | The vhost of the services operator or null if there is no vhost.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"fingerprints": null,
|
||||
"hosts": ["*@*.example.com"],
|
||||
"name": "stest",
|
||||
"operonly": true,
|
||||
"opertype": {
|
||||
"commands": ["hostserv/*", "operserv/session"],
|
||||
"name": "Helper",
|
||||
"privileges": ["chanserv/no-register-limit"]
|
||||
},
|
||||
"password": false,
|
||||
"vhost": null
|
||||
}
|
||||
```
|
||||
|
||||
## `anope.listServers`
|
||||
|
||||
Lists all servers that exist on the network.
|
||||
|
||||
### Parameters
|
||||
|
||||
*None*
|
||||
|
||||
### Errors
|
||||
|
||||
*Only standard RPC errors*
|
||||
|
||||
### Result
|
||||
|
||||
Returns an array of server names.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
["irc1.example.com", "irc2.example.com", "services.example.com"]
|
||||
```
|
||||
|
||||
## `anope.server`
|
||||
|
||||
Retrieves information about the specified server.
|
||||
|
||||
### Parameters
|
||||
|
||||
Index | Description
|
||||
----- | -----------
|
||||
0 | The name of the server.
|
||||
|
||||
### Errors
|
||||
|
||||
Code | Description
|
||||
------ | -----------
|
||||
-32099 | The specified server does not exist.
|
||||
|
||||
### Result
|
||||
|
||||
Returns a map containing information about the server.
|
||||
|
||||
Key | Type | Description
|
||||
--- | ---- | -----------
|
||||
description | string | The description of the server.
|
||||
downlinks | array[string] | The servers which are behind this server
|
||||
juped | boolean | Whether the server has been juped.
|
||||
name | string | The name of the server.
|
||||
sid | string or null | The unique immutable identifier of the server or null if the IRCd does not use SIDs.
|
||||
synced | boolean | Whether the server has finished syncing.
|
||||
ulined | boolean | Whether the server is U-lined.
|
||||
uplink | string or null | The server in front of this server or null if it is the services server.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"description": "Anope IRC Services",
|
||||
"downlinks": ["irc.example.com"],
|
||||
"juped": false,
|
||||
"name": "services.example.com",
|
||||
"sid": "00B",
|
||||
"synced": true,
|
||||
"ulined": true,
|
||||
"uplink": null
|
||||
}
|
||||
```
|
||||
|
||||
## `anope.listUsers`
|
||||
|
||||
Lists all users that exist on the network.
|
||||
|
||||
### Parameters
|
||||
|
||||
*None*
|
||||
|
||||
### Errors
|
||||
|
||||
*Only standard RPC errors*
|
||||
|
||||
### Result
|
||||
|
||||
Returns an array of user nicknames.
|
||||
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
["nick1", "nick2", "nick3"]
|
||||
```
|
||||
|
||||
## `anope.user`
|
||||
|
||||
Retrieves information about the specified user.
|
||||
|
||||
### Parameters
|
||||
|
||||
Index | Description
|
||||
----- | -----------
|
||||
0 | The nickname of the user.
|
||||
|
||||
### Errors
|
||||
|
||||
Code | Description
|
||||
------ | -----------
|
||||
-32099 | The specified user does not exist.
|
||||
|
||||
### Result
|
||||
|
||||
Returns a map containing information about the user.
|
||||
|
||||
Key | Type | Description
|
||||
--- | ---- | -----------
|
||||
account | map or null | The user's account or null if they are not logged in to an account.
|
||||
account.display | string | The display nickname of the account.
|
||||
account.opertype | string or null | The account's oper type or null if the account is not a services operator.
|
||||
account.uniqueid | uint | The unique immutable identifier of the account.
|
||||
address | string | The IP address the user is connecting from.
|
||||
channels | array[string] | The channels that the user is in prefixed by their status mode prefixes.
|
||||
chost | string or null | The cloaked hostname of the user or null if they have no cloak.
|
||||
fingerprint | string or null | The fingerprint of the user's client certificate or null if they are not using one.
|
||||
host | string | The real hostname of the user.
|
||||
ident | string | The username (ident) of the user.
|
||||
modes | array[string] | Flag and parameter modes which are set on the user.
|
||||
nick | string | The nickname of the user.
|
||||
nickchanged | uint | The time at which the user last changed their nickname.
|
||||
real | string | The real name of the user.
|
||||
server | string | The server that the user is connected to.
|
||||
signon | uint | The time at which the user connected to the network.
|
||||
uid | string or null | The unique immutable identifier of the user or null if the IRCd does not use UIDs.
|
||||
vhost | string or null | The virtual host of the user or null if they have no vhost.
|
||||
vident | string or null | The virtual ident (username) of the user or null if they have no vident.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"account": {
|
||||
"display": "nick1",
|
||||
"opertype": "Services Root",
|
||||
"uniqueid": "17183514657819486040"
|
||||
},
|
||||
"address": "127.0.0.1",
|
||||
"channels": ["@#chan1", "#chan2"],
|
||||
"chost": "localhost",
|
||||
"fingerprint": null,
|
||||
"host": "localhost",
|
||||
"id": "9TSAAAAAA",
|
||||
"ident": "user1",
|
||||
"modes": ["+r"],
|
||||
"nick": "nick1",
|
||||
"nickchanged": 1740408318,
|
||||
"real": "An IRC User",
|
||||
"server": "irc.example.com",
|
||||
"signon": 1740408296,
|
||||
"vhost": "staff.example.com",
|
||||
"vident": null,
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2010-2025 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/rpc.h"
|
||||
|
||||
enum
|
||||
{
|
||||
// Used by anope.channel, anope.oper, anope.server, and anope.user
|
||||
ERR_NO_SUCH_TARGET = RPC::ERR_CUSTOM_START,
|
||||
};
|
||||
|
||||
class AnopeListChannelsRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeListChannelsRPCEvent()
|
||||
: RPC::Event("anope.listChannels")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
auto &root = request.Root<RPC::Array>();
|
||||
for (auto &[_, c] : ChannelList)
|
||||
root.Reply(c->name);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class AnopeChannelRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeChannelRPCEvent()
|
||||
: RPC::Event("anope.channel")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
if (request.data.empty())
|
||||
{
|
||||
request.Error(RPC::ERR_INVALID_PARAMS, "Not enough parameters");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto *c = Channel::Find(request.data[0]);
|
||||
if (!c)
|
||||
{
|
||||
request.Error(ERR_NO_SUCH_TARGET, "No such channel");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto &root = request.Root();
|
||||
root.Reply("created", c->creation_time)
|
||||
.Reply("name", c->name)
|
||||
.Reply("registered", !!c->ci);
|
||||
|
||||
std::map<char, RPC::Array&> modemap;
|
||||
auto &listmodes = root.ReplyMap("listmodes");
|
||||
for (auto *cm : ModeManager::GetChannelModes())
|
||||
{
|
||||
if (cm->type != MODE_LIST)
|
||||
continue;
|
||||
|
||||
for (auto &entry : c->GetModeList(cm->name))
|
||||
{
|
||||
auto *wcm = cm->Wrap(entry);
|
||||
|
||||
auto it = modemap.find(wcm->mchar);
|
||||
if (it == modemap.end())
|
||||
it = modemap.emplace(wcm->mchar, listmodes.ReplyArray(wcm->mchar)).first;
|
||||
|
||||
it->second.Reply(entry);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Anope::string> modelist = { "+" };
|
||||
for (const auto &[mname, mvalue] : c->GetModes())
|
||||
{
|
||||
auto *cm = ModeManager::FindChannelModeByName(mname);
|
||||
if (!cm || cm->type == MODE_LIST)
|
||||
continue;
|
||||
|
||||
modelist.front().push_back(cm->mchar);
|
||||
if (!mvalue.empty())
|
||||
modelist.push_back(mvalue);
|
||||
}
|
||||
auto &modes = root.ReplyArray("modes");
|
||||
for (const auto &modeparam : modelist)
|
||||
modes.Reply(modeparam);
|
||||
|
||||
if (c->topic.empty())
|
||||
root.Reply("topic", nullptr);
|
||||
else
|
||||
{
|
||||
auto &topic = root.ReplyMap("topic");
|
||||
topic.Reply("setat", c->topic_ts)
|
||||
.Reply("setby", c->topic_setter)
|
||||
.Reply("value", c->topic);
|
||||
}
|
||||
|
||||
auto &users = root.ReplyArray("users");
|
||||
for (const auto &[_, uc] : c->users)
|
||||
users.Reply(uc->status.BuildModePrefixList() + uc->user->nick);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class AnopeListOpersRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeListOpersRPCEvent()
|
||||
: RPC::Event("anope.listOpers")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
auto &root = request.Root<RPC::Array>();
|
||||
for (auto *oper : Oper::opers)
|
||||
root.Reply(oper->name);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class AnopeOperRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeOperRPCEvent()
|
||||
: RPC::Event("anope.oper")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
if (request.data.empty())
|
||||
{
|
||||
request.Error(RPC::ERR_INVALID_PARAMS, "Not enough parameters");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto *o = Oper::Find(request.data[0]);
|
||||
if (!o)
|
||||
{
|
||||
request.Error(ERR_NO_SUCH_TARGET, "No such oper");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto &root = request.Root();
|
||||
root
|
||||
.Reply("name", o->name)
|
||||
.Reply("operonly", o->require_oper)
|
||||
.Reply("password", !o->password.empty());
|
||||
|
||||
if (o->certfp.empty())
|
||||
root.Reply("fingerprints", nullptr);
|
||||
else
|
||||
{
|
||||
auto &fingerprints = root.ReplyArray("fingerprints");
|
||||
for (const auto &fingerprint : o->certfp)
|
||||
fingerprints.Reply(fingerprint);
|
||||
}
|
||||
|
||||
if (o->hosts.empty())
|
||||
root.Reply("hosts", nullptr);
|
||||
else
|
||||
{
|
||||
auto &hosts = root.ReplyArray("hosts");
|
||||
for (const auto &host : o->hosts)
|
||||
hosts.Reply(host);
|
||||
}
|
||||
|
||||
auto &opertype = root.ReplyMap("opertype");
|
||||
opertype.Reply("name", o->ot->GetName());
|
||||
{
|
||||
auto &commands = opertype.ReplyArray("commands");
|
||||
for (const auto &command : o->ot->GetCommands())
|
||||
commands.Reply(command);
|
||||
|
||||
auto &privileges = opertype.ReplyArray("privileges");
|
||||
for (const auto &privilege : o->ot->GetPrivs())
|
||||
privileges.Reply(privilege);
|
||||
}
|
||||
|
||||
if (o->vhost.empty())
|
||||
root.Reply("vhost", nullptr);
|
||||
else
|
||||
root.Reply("vhost", o->vhost);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class AnopeListServersRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeListServersRPCEvent()
|
||||
: RPC::Event("anope.listServers")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
auto &root = request.Root<RPC::Array>();
|
||||
for (auto &[_, s] : Servers::ByName)
|
||||
root.Reply(s->GetName());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class AnopeServerRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeServerRPCEvent()
|
||||
: RPC::Event("anope.server")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
if (request.data.empty())
|
||||
{
|
||||
request.Error(RPC::ERR_INVALID_PARAMS, "Not enough parameters");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto *s = Server::Find(request.data[0]);
|
||||
if (!s)
|
||||
{
|
||||
request.Error(ERR_NO_SUCH_TARGET, "No such server");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto &root = request.Root();
|
||||
root.Reply("description", s->GetDescription())
|
||||
.Reply("juped", s->IsJuped())
|
||||
.Reply("name", s->GetName())
|
||||
.Reply("synced", s->IsSynced())
|
||||
.Reply("ulined", s->IsULined());
|
||||
|
||||
auto &downlinks = root.ReplyArray("downlinks");
|
||||
for (const auto *s : s->GetLinks())
|
||||
downlinks.Reply(s->GetName());
|
||||
|
||||
if (IRCD->RequiresID)
|
||||
root.Reply("sid", s->GetSID());
|
||||
else
|
||||
root.Reply("sid", nullptr);
|
||||
|
||||
if (s->GetUplink())
|
||||
root.Reply("uplink", s->GetUplink()->GetName());
|
||||
else
|
||||
root.Reply("uplink", nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class AnopeListUsersRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeListUsersRPCEvent()
|
||||
: RPC::Event("anope.listUsers")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
auto &root = request.Root<RPC::Array>();
|
||||
for (auto &[_, u] : UserListByNick)
|
||||
root.Reply(u->nick);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class AnopeUserRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
AnopeUserRPCEvent()
|
||||
: RPC::Event("anope.user")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
if (request.data.empty())
|
||||
{
|
||||
request.Error(RPC::ERR_INVALID_PARAMS, "Not enough parameters");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto *u = User::Find(request.data[0]);
|
||||
if (!u)
|
||||
{
|
||||
request.Error(ERR_NO_SUCH_TARGET, "No such user");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto &root = request.Root();
|
||||
root.Reply("address", u->ip.addr())
|
||||
.Reply("host", u->host)
|
||||
.Reply("ident", u->GetIdent())
|
||||
.Reply("nick", u->nick)
|
||||
.Reply("nickchanged", u->timestamp)
|
||||
.Reply("real", u->realname)
|
||||
.Reply("server", u->server->GetName())
|
||||
.Reply("signon", u->signon);
|
||||
|
||||
if (u->IsIdentified())
|
||||
{
|
||||
auto &account = root.ReplyMap("account");
|
||||
account.Reply("display", u->Account()->display)
|
||||
.Reply("uniqueid", u->Account()->GetId());
|
||||
|
||||
if (u->Account()->o)
|
||||
account.Reply("opertype", u->Account()->o->ot->GetName());
|
||||
else
|
||||
account.Reply("opertype", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
root.Reply("account", nullptr);
|
||||
}
|
||||
|
||||
auto &channels = root.ReplyArray("channels");
|
||||
for (const auto &[_, cc] : u->chans)
|
||||
channels.Reply(cc->status.BuildModePrefixList() + cc->chan->name);
|
||||
|
||||
if (u->chost.empty())
|
||||
root.Reply("chost", nullptr);
|
||||
else
|
||||
root.Reply("chost", u->chost);
|
||||
|
||||
if (u->fingerprint.empty())
|
||||
root.Reply("fingerprint", nullptr);
|
||||
else
|
||||
root.Reply("fingerprint", u->fingerprint);
|
||||
|
||||
std::vector<Anope::string> modelist = { "+" };
|
||||
for (const auto &[mname, mvalue] : u->GetModeList())
|
||||
{
|
||||
auto *um = ModeManager::FindUserModeByName(mname);
|
||||
if (!um || um->type == MODE_LIST)
|
||||
continue;
|
||||
|
||||
modelist.front().push_back(um->mchar);
|
||||
if (!mvalue.empty())
|
||||
modelist.push_back(mvalue);
|
||||
}
|
||||
auto &modes = root.ReplyArray("modes");
|
||||
for (const auto &modeparam : modelist)
|
||||
modes.Reply(modeparam);
|
||||
|
||||
if (IRCD->RequiresID)
|
||||
root.Reply("uid", u->GetUID());
|
||||
else
|
||||
root.Reply("uid", nullptr);
|
||||
|
||||
if (u->vhost.empty() || u->vhost.equals_cs(u->host))
|
||||
root.Reply("vhost", nullptr);
|
||||
else
|
||||
root.Reply("vhost", u->vhost);
|
||||
|
||||
if (u->GetVIdent().equals_cs(u->GetIdent()))
|
||||
root.Reply("vident", nullptr);
|
||||
else
|
||||
root.Reply("vident", u->GetIdent());
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleRPCData final
|
||||
: public Module
|
||||
{
|
||||
private:
|
||||
ServiceReference<RPC::ServiceInterface> rpc;
|
||||
|
||||
AnopeListChannelsRPCEvent anopelistchannelsrpcevent;
|
||||
AnopeChannelRPCEvent anopechannelrpcevent;
|
||||
|
||||
AnopeListOpersRPCEvent anopelistopersrpcevent;
|
||||
AnopeOperRPCEvent anopeoperrpcevent;
|
||||
|
||||
AnopeListServersRPCEvent anopelistserversrpcevent;
|
||||
AnopeServerRPCEvent anopeserverrpcevent;
|
||||
|
||||
AnopeListUsersRPCEvent anopelistusersrpcevent;
|
||||
AnopeUserRPCEvent anopeuserrpcevent;
|
||||
|
||||
public:
|
||||
ModuleRPCData(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, EXTRA | VENDOR)
|
||||
, rpc("RPCServiceInterface", "rpc")
|
||||
{
|
||||
if (!rpc)
|
||||
throw ModuleException("Unable to find RPC interface, is jsonrpc/xmlrpc loaded?");
|
||||
|
||||
rpc->Register(&anopelistchannelsrpcevent);
|
||||
rpc->Register(&anopechannelrpcevent);
|
||||
|
||||
rpc->Register(&anopelistopersrpcevent);
|
||||
rpc->Register(&anopeoperrpcevent);
|
||||
|
||||
rpc->Register(&anopelistserversrpcevent);
|
||||
rpc->Register(&anopeserverrpcevent);
|
||||
|
||||
rpc->Register(&anopelistusersrpcevent);
|
||||
rpc->Register(&anopeuserrpcevent);
|
||||
|
||||
}
|
||||
|
||||
~ModuleRPCData() override
|
||||
{
|
||||
if (!rpc)
|
||||
return;
|
||||
|
||||
rpc->Unregister(&anopelistchannelsrpcevent);
|
||||
rpc->Unregister(&anopechannelrpcevent);
|
||||
|
||||
rpc->Unregister(&anopelistopersrpcevent);
|
||||
rpc->Unregister(&anopeoperrpcevent);
|
||||
|
||||
rpc->Unregister(&anopelistserversrpcevent);
|
||||
rpc->Unregister(&anopeserverrpcevent);
|
||||
|
||||
rpc->Unregister(&anopelistusersrpcevent);
|
||||
rpc->Unregister(&anopeuserrpcevent);
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(ModuleRPCData)
|
||||
@@ -167,136 +167,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ChannelRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
ChannelRPCEvent()
|
||||
: RPC::Event("channel")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
if (request.data.empty())
|
||||
{
|
||||
request.Error(RPC::ERR_INVALID_PARAMS, "Invalid parameters");
|
||||
return true;
|
||||
}
|
||||
|
||||
Channel *c = Channel::Find(request.data[0]);
|
||||
|
||||
auto &root = request.Root();
|
||||
root.Reply("name", c ? c->name : request.data[0]);
|
||||
|
||||
if (c)
|
||||
{
|
||||
root.Reply("bancount", c->HasMode("BAN"));
|
||||
auto &bans = root.ReplyArray("bans");
|
||||
for (auto &ban : c->GetModeList("BAN"))
|
||||
bans.Reply(ban);
|
||||
|
||||
root.Reply("exceptcount", c->HasMode("EXCEPT"));
|
||||
auto &excepts = root.ReplyArray("excepts");
|
||||
for (auto &except : c->GetModeList("EXCEPT"))
|
||||
excepts.Reply(except);
|
||||
|
||||
root.Reply("invitecount", c->HasMode("INVITEOVERRIDE"));
|
||||
auto &invites = root.ReplyArray("invites");
|
||||
for (auto &invite : c->GetModeList("INVITEOVERRIDE"))
|
||||
invites.Reply(invite);
|
||||
|
||||
auto &users = root.ReplyArray("users");
|
||||
for (const auto &[_, uc] : c->users)
|
||||
users.Reply(uc->status.BuildModePrefixList() + uc->user->nick);
|
||||
|
||||
if (!c->topic.empty())
|
||||
root.Reply("topic", c->topic);
|
||||
|
||||
if (!c->topic_setter.empty())
|
||||
root.Reply("topicsetter", c->topic_setter);
|
||||
|
||||
root.Reply("topictime", c->topic_time);
|
||||
root.Reply("topicts", c->topic_ts);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class UserRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
UserRPCEvent()
|
||||
: RPC::Event("user")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
if (request.data.empty())
|
||||
{
|
||||
request.Error(RPC::ERR_INVALID_PARAMS, "Invalid parameters");
|
||||
return true;
|
||||
}
|
||||
|
||||
User *u = User::Find(request.data[0]);
|
||||
|
||||
auto &root = request.Root();
|
||||
root.Reply("nick", u ? u->nick : request.data[0]);
|
||||
|
||||
if (u)
|
||||
{
|
||||
root.Reply("ident", u->GetIdent());
|
||||
root.Reply("vident", u->GetVIdent());
|
||||
root.Reply("host", u->host);
|
||||
if (!u->vhost.empty())
|
||||
root.Reply("vhost", u->vhost);
|
||||
if (!u->chost.empty())
|
||||
root.Reply("chost", u->chost);
|
||||
root.Reply("ip", u->ip.addr());
|
||||
root.Reply("timestamp", u->timestamp);
|
||||
root.Reply("signon", u->signon);
|
||||
if (u->IsIdentified())
|
||||
{
|
||||
root.Reply("account", u->Account()->display);
|
||||
if (u->Account()->o)
|
||||
root.Reply("opertype", u->Account()->o->ot->GetName());
|
||||
}
|
||||
|
||||
auto &channels = root.ReplyArray("channels");
|
||||
for (const auto &[_, cc] : u->chans)
|
||||
channels.Reply(cc->status.BuildModePrefixList() + cc->chan->name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class OpersRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
public:
|
||||
OpersRPCEvent()
|
||||
: RPC::Event("opers")
|
||||
{
|
||||
}
|
||||
|
||||
bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override
|
||||
{
|
||||
auto &root = request.Root();
|
||||
for (auto *ot : Config->MyOperTypes)
|
||||
{
|
||||
Anope::string perms;
|
||||
for (const auto &priv : ot->GetPrivs())
|
||||
perms += " " + priv;
|
||||
for (const auto &command : ot->GetCommands())
|
||||
perms += " " + command;
|
||||
root.Reply(ot->GetName(), perms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class NoticeRPCEvent final
|
||||
: public RPC::Event
|
||||
{
|
||||
@@ -334,9 +204,6 @@ private:
|
||||
CommandRPCEvent commandrpcevent;
|
||||
CheckAuthenticationRPCEvent checkauthenticationrpcevent;
|
||||
StatsRPCEvent statsrpcevent;
|
||||
ChannelRPCEvent channelrpcevent;
|
||||
UserRPCEvent userrpcevent;
|
||||
OpersRPCEvent opersrpcevent;
|
||||
NoticeRPCEvent noticerpcevent;
|
||||
|
||||
public:
|
||||
@@ -352,9 +219,6 @@ public:
|
||||
rpc->Register(&commandrpcevent);
|
||||
rpc->Register(&checkauthenticationrpcevent);
|
||||
rpc->Register(&statsrpcevent);
|
||||
rpc->Register(&channelrpcevent);
|
||||
rpc->Register(&userrpcevent);
|
||||
rpc->Register(&opersrpcevent);
|
||||
rpc->Register(¬icerpcevent);
|
||||
}
|
||||
|
||||
@@ -366,9 +230,6 @@ public:
|
||||
rpc->Unregister(&commandrpcevent);
|
||||
rpc->Unregister(&checkauthenticationrpcevent);
|
||||
rpc->Unregister(&statsrpcevent);
|
||||
rpc->Unregister(&channelrpcevent);
|
||||
rpc->Unregister(&userrpcevent);
|
||||
rpc->Unregister(&opersrpcevent);
|
||||
rpc->Unregister(¬icerpcevent);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user