Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
louiz’
biboumi
Commits
4e27298b
Commit
4e27298b
authored
May 31, 2014
by
louiz’
Browse files
Add an ad-hoc command to disconnect some users
parent
f5b61f0f
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/xmpp/adhoc_command.cpp
View file @
4e27298b
#include
<xmpp/adhoc_command.hpp>
#include
<xmpp/xmpp_component.hpp>
#include
<bridge/bridge.hpp>
using
namespace
std
::
string_literals
;
...
...
@@ -13,7 +16,12 @@ AdhocCommand::~AdhocCommand()
{
}
void
PingStep1
(
AdhocSession
&
,
XmlNode
&
command_node
)
bool
AdhocCommand
::
is_admin_only
()
const
{
return
this
->
admin_only
;
}
void
PingStep1
(
XmppComponent
*
xmpp_component
,
AdhocSession
&
,
XmlNode
&
command_node
)
{
XmlNode
note
(
"note"
);
note
[
"type"
]
=
"info"
;
...
...
@@ -22,7 +30,7 @@ void PingStep1(AdhocSession&, XmlNode& command_node)
command_node
.
add_child
(
std
::
move
(
note
));
}
void
HelloStep1
(
AdhocSession
&
,
XmlNode
&
command_node
)
void
HelloStep1
(
XmppComponent
*
xmpp_component
,
AdhocSession
&
,
XmlNode
&
command_node
)
{
XmlNode
x
(
"jabber:x:data:x"
);
x
[
"type"
]
=
"form"
;
...
...
@@ -47,7 +55,7 @@ void HelloStep1(AdhocSession&, XmlNode& command_node)
command_node
.
add_child
(
std
::
move
(
x
));
}
void
HelloStep2
(
AdhocSession
&
session
,
XmlNode
&
command_node
)
void
HelloStep2
(
XmppComponent
*
xmpp_component
,
AdhocSession
&
session
,
XmlNode
&
command_node
)
{
// Find out if the name was provided in the form.
XmlNode
*
x
=
command_node
.
get_child
(
"x"
,
"jabber:x:data"
);
...
...
@@ -80,3 +88,101 @@ void HelloStep2(AdhocSession& session, XmlNode& command_node)
// anyway. But this is for the example.
session
.
terminate
();
}
void
DisconnectUserStep1
(
XmppComponent
*
xmpp_component
,
AdhocSession
&
session
,
XmlNode
&
command_node
)
{
XmlNode
x
(
"jabber:x:data:x"
);
x
[
"type"
]
=
"form"
;
XmlNode
title
(
"title"
);
title
.
set_inner
(
"Disconnect a user from the gateway"
);
title
.
close
();
x
.
add_child
(
std
::
move
(
title
));
XmlNode
instructions
(
"instructions"
);
instructions
.
set_inner
(
"Choose a user JID and a quit message"
);
instructions
.
close
();
x
.
add_child
(
std
::
move
(
instructions
));
XmlNode
jids_field
(
"field"
);
jids_field
[
"var"
]
=
"jids"
;
jids_field
[
"type"
]
=
"list-multi"
;
jids_field
[
"label"
]
=
"The JIDs to disconnect"
;
XmlNode
required
(
"required"
);
required
.
close
();
jids_field
.
add_child
(
std
::
move
(
required
));
for
(
Bridge
*
bridge
:
xmpp_component
->
get_bridges
())
{
XmlNode
option
(
"option"
);
option
[
"label"
]
=
bridge
->
get_jid
();
XmlNode
value
(
"value"
);
value
.
set_inner
(
bridge
->
get_jid
());
value
.
close
();
option
.
add_child
(
std
::
move
(
value
));
option
.
close
();
jids_field
.
add_child
(
std
::
move
(
option
));
}
jids_field
.
close
();
x
.
add_child
(
std
::
move
(
jids_field
));
XmlNode
message_field
(
"field"
);
message_field
[
"var"
]
=
"quit-message"
;
message_field
[
"type"
]
=
"text-single"
;
message_field
[
"label"
]
=
"Quit message"
;
XmlNode
message_value
(
"value"
);
message_value
.
set_inner
(
"Disconnected by admin"
);
message_value
.
close
();
message_field
.
add_child
(
std
::
move
(
message_value
));
message_field
.
close
();
x
.
add_child
(
std
::
move
(
message_field
));
x
.
close
();
command_node
.
add_child
(
std
::
move
(
x
));
}
void
DisconnectUserStep2
(
XmppComponent
*
xmpp_component
,
AdhocSession
&
session
,
XmlNode
&
command_node
)
{
// Find out if the jids, and the quit message are provided in the form.
std
::
string
quit_message
;
XmlNode
*
x
=
command_node
.
get_child
(
"x"
,
"jabber:x:data"
);
if
(
x
)
{
XmlNode
*
message_field
=
nullptr
;
XmlNode
*
jids_field
=
nullptr
;
for
(
XmlNode
*
field
:
x
->
get_children
(
"field"
,
"jabber:x:data"
))
if
(
field
->
get_tag
(
"var"
)
==
"jids"
)
jids_field
=
field
;
else
if
(
field
->
get_tag
(
"var"
)
==
"quit-message"
)
message_field
=
field
;
if
(
message_field
)
{
XmlNode
*
value
=
message_field
->
get_child
(
"value"
,
"jabber:x:data"
);
if
(
value
)
quit_message
=
value
->
get_inner
();
}
if
(
jids_field
)
{
std
::
size_t
num
=
0
;
for
(
XmlNode
*
value
:
jids_field
->
get_children
(
"value"
,
"jabber:x:data"
))
{
Bridge
*
bridge
=
xmpp_component
->
find_user_bridge
(
value
->
get_inner
());
if
(
bridge
)
{
bridge
->
shutdown
(
quit_message
);
num
++
;
}
}
command_node
.
delete_all_children
();
XmlNode
note
(
"note"
);
note
[
"type"
]
=
"info"
;
if
(
num
==
0
)
note
.
set_inner
(
"No user were disconnected."
);
else
if
(
num
==
1
)
note
.
set_inner
(
"1 user has been disconnected."
);
else
note
.
set_inner
(
std
::
to_string
(
num
)
+
" users have been disconnected."
);
note
.
close
();
command_node
.
add_child
(
std
::
move
(
note
));
}
}
// TODO insert an error telling the values are missing.
session
.
terminate
();
}
src/xmpp/adhoc_command.hpp
View file @
4e27298b
...
...
@@ -23,6 +23,8 @@ public:
const
std
::
string
name
;
bool
is_admin_only
()
const
;
private:
/**
* A command may have one or more steps. Each step is a different
...
...
@@ -33,8 +35,10 @@ private:
const
bool
admin_only
;
};
void
PingStep1
(
AdhocSession
&
session
,
XmlNode
&
command_node
);
void
HelloStep1
(
AdhocSession
&
session
,
XmlNode
&
command_node
);
void
HelloStep2
(
AdhocSession
&
session
,
XmlNode
&
command_node
);
void
PingStep1
(
XmppComponent
*
,
AdhocSession
&
session
,
XmlNode
&
command_node
);
void
HelloStep1
(
XmppComponent
*
,
AdhocSession
&
session
,
XmlNode
&
command_node
);
void
HelloStep2
(
XmppComponent
*
,
AdhocSession
&
session
,
XmlNode
&
command_node
);
void
DisconnectUserStep1
(
XmppComponent
*
,
AdhocSession
&
session
,
XmlNode
&
command_node
);
void
DisconnectUserStep2
(
XmppComponent
*
,
AdhocSession
&
session
,
XmlNode
&
command_node
);
#endif // ADHOC_COMMAND_HPP
src/xmpp/adhoc_commands_handler.cpp
View file @
4e27298b
...
...
@@ -2,13 +2,17 @@
#include
<xmpp/xmpp_component.hpp>
#include
<logger/logger.hpp>
#include
<config/config.hpp>
#include
<xmpp/jid.hpp>
#include
<iostream>
AdhocCommandsHandler
::
AdhocCommandsHandler
()
:
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
)}
{
"hello"
,
AdhocCommand
({
&
HelloStep1
,
&
HelloStep2
},
"Receive a custom greeting"
,
false
)},
{
"disconnect-user"
,
AdhocCommand
({
&
DisconnectUserStep1
,
&
DisconnectUserStep2
},
"Disconnect a user from the gateway"
,
true
)}
}
{
}
...
...
@@ -31,6 +35,8 @@ XmlNode&& AdhocCommandsHandler::handle_request(const std::string& executor_jid,
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
())
...
...
@@ -43,6 +49,17 @@ XmlNode&& AdhocCommandsHandler::handle_request(const std::string& executor_jid,
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"
);
...
...
@@ -74,7 +91,7 @@ XmlNode&& AdhocCommandsHandler::handle_request(const std::string& executor_jid,
// execute the step
AdhocSession
&
session
=
session_it
->
second
;
const
AdhocStep
&
step
=
session
.
get_next_step
();
step
(
session
,
command_node
);
step
(
this
->
xmpp_component
,
session
,
command_node
);
if
(
session
.
remaining_steps
()
==
0
||
session
.
is_terminated
())
{
...
...
src/xmpp/adhoc_commands_handler.hpp
View file @
4e27298b
...
...
@@ -13,10 +13,12 @@
#include
<string>
#include
<map>
class
XmppComponent
;
class
AdhocCommandsHandler
{
public:
explicit
AdhocCommandsHandler
();
explicit
AdhocCommandsHandler
(
XmppComponent
*
xmpp_component
);
~
AdhocCommandsHandler
();
/**
* Returns the list of available commands.
...
...
@@ -36,6 +38,11 @@ public:
*/
XmlNode
&&
handle_request
(
const
std
::
string
&
executor_jid
,
XmlNode
command_node
);
private:
/**
* A pointer to the XmppComponent, to access to basically anything in the
* gateway.
*/
XmppComponent
*
xmpp_component
;
/**
* The list of all available commands.
*/
...
...
src/xmpp/adhoc_session.hpp
View file @
4e27298b
...
...
@@ -6,6 +6,8 @@
#include
<functional>
#include
<string>
class
XmppComponent
;
class
AdhocCommand
;
class
AdhocSession
;
...
...
@@ -16,7 +18,7 @@ class AdhocSession;
* TODO fix this:
* It also must call one of step_passed(), cancel() etc on the AdhocSession object.
*/
typedef
std
::
function
<
void
(
AdhocSession
&
,
XmlNode
&
)
>
AdhocStep
;
typedef
std
::
function
<
void
(
XmppComponent
*
,
AdhocSession
&
,
XmlNode
&
)
>
AdhocStep
;
class
AdhocSession
{
...
...
src/xmpp/xmpp_component.cpp
View file @
4e27298b
...
...
@@ -41,7 +41,8 @@ XmppComponent::XmppComponent(std::shared_ptr<Poller> poller, const std::string&
served_hostname
(
hostname
),
secret
(
secret
),
authenticated
(
false
),
doc_open
(
false
)
doc_open
(
false
),
adhoc_commands_handler
(
this
)
{
this
->
parser
.
add_stream_open_callback
(
std
::
bind
(
&
XmppComponent
::
on_remote_stream_open
,
this
,
std
::
placeholders
::
_1
));
...
...
@@ -543,6 +544,26 @@ Bridge* XmppComponent::get_user_bridge(const std::string& user_jid)
}
}
Bridge
*
XmppComponent
::
find_user_bridge
(
const
std
::
string
&
user_jid
)
{
try
{
return
this
->
bridges
.
at
(
user_jid
).
get
();
}
catch
(
const
std
::
out_of_range
&
exception
)
{
return
nullptr
;
}
}
std
::
list
<
Bridge
*>
XmppComponent
::
get_bridges
()
const
{
std
::
list
<
Bridge
*>
res
;
for
(
auto
it
=
this
->
bridges
.
begin
();
it
!=
this
->
bridges
.
end
();
++
it
)
res
.
push_back
(
it
->
second
.
get
());
return
res
;
}
void
*
XmppComponent
::
get_receive_buffer
(
const
size_t
size
)
const
{
return
this
->
parser
.
get_buffer
(
size
);
...
...
src/xmpp/xmpp_component.hpp
View file @
4e27298b
...
...
@@ -41,6 +41,16 @@ public:
void
on_connection_close
()
override
final
;
void
parse_in_buffer
(
const
size_t
size
)
override
final
;
/**
* Returns the bridge for the given user. If it does not exist, return
* nullptr.
*/
Bridge
*
find_user_bridge
(
const
std
::
string
&
user_jid
);
/**
* Return a list of all the managed bridges.
*/
std
::
list
<
Bridge
*>
get_bridges
()
const
;
/**
* Returns a unique id, to be used in the 'id' element of our iq stanzas.
*/
...
...
@@ -228,6 +238,7 @@ private:
bool
doc_open
;
std
::
unordered_map
<
std
::
string
,
std
::
function
<
void
(
const
Stanza
&
)
>>
stanza_handlers
;
AdhocCommandsHandler
adhoc_commands_handler
;
/**
* One bridge for each user of the component. Indexed by the user's full
...
...
@@ -235,7 +246,6 @@ private:
*/
std
::
unordered_map
<
std
::
string
,
std
::
unique_ptr
<
Bridge
>>
bridges
;
AdhocCommandsHandler
adhoc_commands_handler
;
XmppComponent
(
const
XmppComponent
&
)
=
delete
;
XmppComponent
(
XmppComponent
&&
)
=
delete
;
XmppComponent
&
operator
=
(
const
XmppComponent
&
)
=
delete
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment