1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#include <xmpp/adhoc_commands_handler.hpp>
#include <xmpp/xmpp_component.hpp>
#include <logger/logger.hpp>
#include <config/config.hpp>
#include <xmpp/jid.hpp>
#include <iostream>
AdhocCommandsHandler::AdhocCommandsHandler(XmppComponent* xmpp_component):
xmpp_component(xmpp_component),
commands{
{"ping", AdhocCommand({&PingStep1}, "Do a ping", false)},
{"hello", AdhocCommand({&HelloStep1, &HelloStep2}, "Receive a custom greeting", false)},
{"disconnect-user", AdhocCommand({&DisconnectUserStep1, &DisconnectUserStep2}, "Disconnect a user from the gateway", true)}
}
{
}
AdhocCommandsHandler::~AdhocCommandsHandler()
{
}
const std::map<const std::string, const AdhocCommand>& AdhocCommandsHandler::get_commands() const
{
return this->commands;
}
XmlNode&& AdhocCommandsHandler::handle_request(const std::string& executor_jid, XmlNode command_node)
{
// TODO check the type of action. Currently it assumes it is always
// 'execute'.
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");
condition.close();
error.add_child(std::move(condition));
error.close();
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");
condition.close();
error.add_child(std::move(condition));
error.close();
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));
// TODO add a timed event to have an expiration date that deletes
// this session. We could have a nasty client starting commands
// but never finishing the last step, and that would fill the map
// with dummy sessions.
}
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");
condition.close();
error.add_child(std::move(condition));
error.close();
command_node.add_child(std::move(error));
}
else
{
// 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";
}
else
{
command_node["status"] = "executing";
XmlNode actions("actions");
XmlNode next("next");
next.close();
actions.add_child(std::move(next));
actions.close();
command_node.add_child(std::move(actions));
}
}
}
// TODO remove that once we make sure so session can stay there for ever,
// by mistake.
log_debug("Number of existing sessions: " << this->sessions.size());
return std::move(command_node);
}
|