summaryrefslogtreecommitdiff
path: root/louloulibs/xmpp/adhoc_commands_handler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'louloulibs/xmpp/adhoc_commands_handler.cpp')
-rw-r--r--louloulibs/xmpp/adhoc_commands_handler.cpp123
1 files changed, 123 insertions, 0 deletions
diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp
new file mode 100644
index 0000000..17c4e67
--- /dev/null
+++ b/louloulibs/xmpp/adhoc_commands_handler.cpp
@@ -0,0 +1,123 @@
+#include <xmpp/adhoc_commands_handler.hpp>
+#include <xmpp/xmpp_component.hpp>
+
+#include <utils/timed_events.hpp>
+#include <logger/logger.hpp>
+#include <config/config.hpp>
+#include <xmpp/jid.hpp>
+
+#include <iostream>
+
+using namespace std::string_literals;
+
+const std::map<const std::string, const AdhocCommand>& AdhocCommandsHandler::get_commands() const
+{
+ return this->commands;
+}
+
+std::map<const std::string, const AdhocCommand>& AdhocCommandsHandler::get_commands()
+{
+ return this->commands;
+}
+
+XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, const std::string& to, XmlNode command_node)
+{
+ std::string action = command_node.get_tag("action");
+ if (action.empty())
+ action = "execute";
+ command_node.del_tag("action");
+
+ Jid jid(executor_jid);
+
+ const std::string node = command_node.get_tag("node");
+ auto command_it = this->commands.find(node);
+ if (command_it == this->commands.end())
+ {
+ XmlNode error(ADHOC_NS":error");
+ error["type"] = "cancel";
+ XmlNode condition(STANZA_NS":item-not-found");
+ error.add_child(std::move(condition));
+ command_node.add_child(std::move(error));
+ }
+ else if (command_it->second.is_admin_only() &&
+ Config::get("admin", "") != jid.local + "@" + jid.domain)
+ {
+ XmlNode error(ADHOC_NS":error");
+ error["type"] = "cancel";
+ XmlNode condition(STANZA_NS":forbidden");
+ error.add_child(std::move(condition));
+ command_node.add_child(std::move(error));
+ }
+ else
+ {
+ std::string sessionid = command_node.get_tag("sessionid");
+ if (sessionid.empty())
+ { // create a new session, with a new id
+ sessionid = XmppComponent::next_id();
+ command_node["sessionid"] = sessionid;
+ this->sessions.emplace(std::piecewise_construct,
+ std::forward_as_tuple(sessionid, executor_jid),
+ std::forward_as_tuple(command_it->second, executor_jid, to));
+ TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 3600s,
+ std::bind(&AdhocCommandsHandler::remove_session, this, sessionid, executor_jid),
+ "adhocsession"s + sessionid + executor_jid));
+ }
+ auto session_it = this->sessions.find(std::make_pair(sessionid, executor_jid));
+ if (session_it == this->sessions.end())
+ {
+ XmlNode error(ADHOC_NS":error");
+ error["type"] = "modify";
+ XmlNode condition(STANZA_NS":bad-request");
+ error.add_child(std::move(condition));
+ command_node.add_child(std::move(error));
+ }
+ else if (action == "execute" || action == "next" || action == "complete")
+ {
+ // execute the step
+ AdhocSession& session = session_it->second;
+ const AdhocStep& step = session.get_next_step();
+ step(this->xmpp_component, session, command_node);
+ if (session.remaining_steps() == 0 ||
+ session.is_terminated())
+ {
+ this->sessions.erase(session_it);
+ command_node["status"] = "completed";
+ TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid);
+ }
+ else
+ {
+ command_node["status"] = "executing";
+ XmlNode actions("actions");
+ XmlNode next("next");
+ actions.add_child(std::move(next));
+ command_node.add_child(std::move(actions));
+ }
+ }
+ else if (action == "cancel")
+ {
+ this->sessions.erase(session_it);
+ command_node["status"] = "canceled";
+ TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid);
+ }
+ else // unsupported action
+ {
+ XmlNode error(ADHOC_NS":error");
+ error["type"] = "modify";
+ XmlNode condition(STANZA_NS":bad-request");
+ error.add_child(std::move(condition));
+ command_node.add_child(std::move(error));
+ }
+ }
+ return command_node;
+}
+
+void AdhocCommandsHandler::remove_session(const std::string& session_id, const std::string& initiator_jid)
+{
+ auto session_it = this->sessions.find(std::make_pair(session_id, initiator_jid));
+ if (session_it != this->sessions.end())
+ {
+ this->sessions.erase(session_it);
+ return ;
+ }
+ log_error("Tried to remove ad-hoc session for [", session_id, ", ", initiator_jid, "] but none found");
+}