adhoc_commands_handler.cpp 4.41 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#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;
}

18
void AdhocCommandsHandler::add_command(std::string name, AdhocCommand command)
19
{
20 21 22
  const auto found = this->commands.find(name);
  if (found != this->commands.end())
    throw std::runtime_error("Trying to add an ad-hoc command that already exist: "s + name);
23
  this->commands.emplace(std::make_pair(std::move(name), std::move(command)));
24 25
}

26
XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, const std::string& to, XmlNode command_node)
27 28 29 30 31 32 33 34 35 36 37 38
{
  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())
    {
39
      XmlSubNode error(command_node, ADHOC_NS":error");
40
      error["type"] = "cancel";
41
      XmlSubNode condition(error, STANZA_NS":item-not-found");
42 43 44 45
    }
  else if (command_it->second.is_admin_only() &&
           Config::get("admin", "") != jid.local + "@" + jid.domain)
    {
46
      XmlSubNode error(command_node, ADHOC_NS":error");
47
      error["type"] = "cancel";
48
      XmlSubNode condition(error, STANZA_NS":forbidden");
49 50 51 52 53 54 55 56 57 58
    }
  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),
59
                                 std::forward_as_tuple(command_it->second, executor_jid, to));
60 61 62 63 64 65 66
          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())
        {
67
          XmlSubNode error(command_node, ADHOC_NS":error");
68
          error["type"] = "modify";
69
          XmlSubNode condition(error, STANZA_NS":bad-request");
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
        }
      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";
87 88
              XmlSubNode actions(command_node, "actions");
              XmlSubNode next(actions, "next");
89 90 91 92 93 94 95 96 97 98
            }
        }
      else if (action == "cancel")
        {
          this->sessions.erase(session_it);
          command_node["status"] = "canceled";
          TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid);
        }
      else                      // unsupported action
        {
99
          XmlSubNode error(command_node, ADHOC_NS":error");
100
          error["type"] = "modify";
101
          XmlSubNode condition(error, STANZA_NS":bad-request");
102 103 104 105 106 107 108 109 110 111 112 113 114
        }
    }
  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 ;
    }
115
  log_error("Tried to remove ad-hoc session for [", session_id, ", ", initiator_jid, "] but none found");
116
}