diff options
-rw-r--r-- | data/modules.example.conf | 14 | ||||
-rw-r--r-- | docs/RPC/RPC | 2 | ||||
-rw-r--r-- | docs/RPC/jsonrpc.js | 27 | ||||
-rw-r--r-- | docs/RPC/jsonrpc.php | 2 | ||||
-rw-r--r-- | docs/RPC/rpc_message.md | 67 | ||||
-rw-r--r-- | modules/rpc/rpc_main.cpp | 32 | ||||
-rw-r--r-- | modules/rpc/rpc_message.cpp | 155 |
7 files changed, 264 insertions, 35 deletions
diff --git a/data/modules.example.conf b/data/modules.example.conf index bbe14d5ee..df03e8519 100644 --- a/data/modules.example.conf +++ b/data/modules.example.conf @@ -846,6 +846,20 @@ module #module { name = "rpc_main" } /* + * rpc_message + * + * Adds support for the following RPC methods: + * + * anope.messageNetwork anope.messageServer + * anope.messageUser + * + * Requires either the jsonrpc or xmlrpc module. + * + * See docs/RPC/rpc_message.md for API documentation. + */ +#module { name = "rpc_message" } + +/* * rpc_system * * Adds support for the following RPC methods: diff --git a/docs/RPC/RPC b/docs/RPC/RPC index 94c7ba7f7..eee81c632 100644 --- a/docs/RPC/RPC +++ b/docs/RPC/RPC @@ -13,8 +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. -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 database, such as accounts and registered channel information. It is instead used for pulling realtime data such as users and channels currently online. For examples on how to use these calls in PHP, see xmlrpc.php in docs/RPC. diff --git a/docs/RPC/jsonrpc.js b/docs/RPC/jsonrpc.js index 29291ad7d..e6cd07e36 100644 --- a/docs/RPC/jsonrpc.js +++ b/docs/RPC/jsonrpc.js @@ -119,6 +119,33 @@ class AnopeRPC { user(nick) { return this.run("anope.user", nick); } + + /** + * Sends a message to every user on the network. + * @param {...*} messages One or more messages to send. + */ + messageNetwork(...messages) { + return this.run("anope.messageNetwork", ...messages); + } + + /** + * Sends a message to every user on the specified server. + * @param {string} name The name of the server. + * @param {...*} messages One or more messages to send. + */ + messageServer(server, ...messages) { + return this.run("anope.messageServer", server, ...messages); + } + + /** + * Sends a message to the specified user. + * @param {string} source The source pseudoclient to send the message from. + * @param {string} target The target user to send the message to. + * @param {...*} messages One or more messages to send. + */ + messageUser(source, target, ...messages) { + return this.run("anope.messageServer", source, target, ...messages); + } } /* diff --git a/docs/RPC/jsonrpc.php b/docs/RPC/jsonrpc.php index a0a6e9270..4e9b52ba9 100644 --- a/docs/RPC/jsonrpc.php +++ b/docs/RPC/jsonrpc.php @@ -132,7 +132,7 @@ class AnopeRPC */ public function notice($source, $target, $message) { - return $this->run("notice", [$source, $target, $message]); + return $this->run("anope.messageUser", [$source, $target, $message]); } /** diff --git a/docs/RPC/rpc_message.md b/docs/RPC/rpc_message.md new file mode 100644 index 000000000..de91767ae --- /dev/null +++ b/docs/RPC/rpc_message.md @@ -0,0 +1,67 @@ +# Anope `rpc_message` RPC interface + +## `anope.messageNetwork` + +Sends a message to all users on the network. + +### Parameters + +Index | Description +----- | ----------- +0+ | One or more messages to send. + +### Errors + +Code | Description +------ | ----------- +-32099 | The global service is not available. + +### Result + +This procedure returns no result. + +## `anope.messageServer` + +Sends a message to all users on the specified server. + +### Parameters + +Index | Description +----- | ----------- +0 | The name of the server to message users on. +1+ | One or more messages to send. + +### Errors + +Code | Description +------ | ----------- +-32099 | The global service is not available. +-32098 | The specified server does not exist. + +### Result + +This procedure returns no result. + +## `anope.messageUser` + +Sends a message to the specified user. + +### Parameters + +Index | Description +----- | ----------- +0 | The source pseudoclient to send the message from. +1 | The target user to send the message to. +2+ | One or more messages to send. + +### Errors + +Code | Description +------ | ----------- +-32099 | The specified source does not exist. +-32098 | The specified target does not exist. + +### Result + +This procedure returns no result. + diff --git a/modules/rpc/rpc_main.cpp b/modules/rpc/rpc_main.cpp index 0f35de142..a1cad972e 100644 --- a/modules/rpc/rpc_main.cpp +++ b/modules/rpc/rpc_main.cpp @@ -167,35 +167,6 @@ public: } }; -class NoticeRPCEvent final - : public RPC::Event -{ -public: - NoticeRPCEvent() - : RPC::Event("notice") - { - } - - bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override - { - Anope::string from = request.data.size() > 0 ? request.data[0] : ""; - Anope::string to = request.data.size() > 1 ? request.data[1] : ""; - Anope::string message = request.data.size() > 2 ? request.data[2] : ""; - - BotInfo *bi = BotInfo::Find(from, true); - User *u = User::Find(to, true); - - if (!bi || !u || message.empty()) - { - request.Error(RPC::ERR_INVALID_PARAMS, "Invalid parameters"); - return true; - } - - u->SendMessage(bi, message); - return true; - } -}; - class ModuleRPCMain final : public Module { @@ -204,7 +175,6 @@ private: CommandRPCEvent commandrpcevent; CheckAuthenticationRPCEvent checkauthenticationrpcevent; StatsRPCEvent statsrpcevent; - NoticeRPCEvent noticerpcevent; public: ModuleRPCMain(const Anope::string &modname, const Anope::string &creator) @@ -219,7 +189,6 @@ public: rpc->Register(&commandrpcevent); rpc->Register(&checkauthenticationrpcevent); rpc->Register(&statsrpcevent); - rpc->Register(¬icerpcevent); } ~ModuleRPCMain() override @@ -230,7 +199,6 @@ public: rpc->Unregister(&commandrpcevent); rpc->Unregister(&checkauthenticationrpcevent); rpc->Unregister(&statsrpcevent); - rpc->Unregister(¬icerpcevent); } }; diff --git a/modules/rpc/rpc_message.cpp b/modules/rpc/rpc_message.cpp new file mode 100644 index 000000000..237c6f575 --- /dev/null +++ b/modules/rpc/rpc_message.cpp @@ -0,0 +1,155 @@ +/* + * + * (C) 2010-2025 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + */ + +#include "module.h" +#include "modules/global/service.h" +#include "modules/rpc.h" + +enum +{ + // Used by anope.messageNetwork and anope.messageServer + ERR_NO_GLOBAL_SERVICE = RPC::ERR_CUSTOM_START, + + // Used by anope.messageServer + ERR_NO_SUCH_SERVER = RPC::ERR_CUSTOM_START + 1, + + // Used by anope.messageUser + ERR_NO_SUCH_SOURCE = RPC::ERR_CUSTOM_START, + ERR_NO_SUCH_TARGET = RPC::ERR_CUSTOM_START + 1, +}; + +class MessageNetworkRPCEvent final + : public RPC::Event +{ +private: + ServiceReference<GlobalService> &global; + +public: + MessageNetworkRPCEvent(ServiceReference<GlobalService> &g) + : RPC::Event("anope.messageNetwork", 1) + , global(g) + { + } + + bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override + { + if (!global) + { + request.Error(ERR_NO_GLOBAL_SERVICE, "No global service"); + return true; + } + + for (const auto &message : request.data) + global->SendSingle(message); + return true; + } +}; + +class MessageServerRPCEvent final + : public RPC::Event +{ +private: + ServiceReference<GlobalService> &global; + +public: + MessageServerRPCEvent(ServiceReference<GlobalService> &g) + : RPC::Event("anope.messageServer", 2) + , global(g) + { + } + + bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override + { + if (!global) + { + request.Error(ERR_NO_GLOBAL_SERVICE, "No global service"); + return true; + } + + auto *s = Server::Find(request.data[0], true); + if (!s) + { + request.Error(ERR_NO_SUCH_SERVER, "No such server"); + return true; + } + + std::vector<Anope::string> messages(request.data.begin() + 1, request.data.end()); + for (const auto &message : messages) + global->SendSingle(message, nullptr, nullptr, s); + return true; + } +}; + +class MessageUserRPCEvent final + : public RPC::Event +{ +public: + MessageUserRPCEvent() + : RPC::Event("anope.messageUser", 3) + { + } + + bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override + { + auto *bi = BotInfo::Find(request.data[0], true); + if (!bi) + { + request.Error(ERR_NO_SUCH_SOURCE, "No such source"); + return true; + } + + auto *u = User::Find(request.data[1], true); + if (!u) + { + request.Error(ERR_NO_SUCH_TARGET, "No such target"); + return true; + } + + u->SendMessage(bi, request.data[2]); + return true; + } +}; + +class ModuleRPCSystem final + : public Module +{ +private: + ServiceReference<GlobalService> global; + ServiceReference<RPC::ServiceInterface> rpc; + MessageNetworkRPCEvent messagenetworkrpcevent; + MessageServerRPCEvent messageserverrpcevent; + MessageUserRPCEvent messageuserrpcevent; + +public: + ModuleRPCSystem(const Anope::string &modname, const Anope::string &creator) + : Module(modname, creator, EXTRA | VENDOR) + , global("GlobalService", "Global") + , rpc("RPCServiceInterface", "rpc") + , messagenetworkrpcevent(global) + , messageserverrpcevent(global) + { + if (!rpc) + throw ModuleException("Unable to find RPC interface, is jsonrpc/xmlrpc loaded?"); + + rpc->Register(&messagenetworkrpcevent); + rpc->Register(&messageserverrpcevent); + rpc->Register(&messageuserrpcevent); + } + + ~ModuleRPCSystem() override + { + if (!rpc) + return; + + rpc->Unregister(&messagenetworkrpcevent); + rpc->Unregister(&messageserverrpcevent); + rpc->Unregister(&messageuserrpcevent); + } +}; + +MODULE_INIT(ModuleRPCSystem) |