summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2015-12-03 21:14:24 +0100
committerFlorent Le Coz <louiz@louiz.org>2015-12-03 21:15:22 +0100
commit1f6eea62f46789c0d3ebe7da133ccad2e59c89c8 (patch)
treed84086c52ea913fea84aa33d2ef0f6284c24d8e7 /src
parent700a6c7bc39aa48af5037ecbb9778b20fb6f87df (diff)
downloadbiboumi-1f6eea62f46789c0d3ebe7da133ccad2e59c89c8.tar.gz
biboumi-1f6eea62f46789c0d3ebe7da133ccad2e59c89c8.tar.bz2
biboumi-1f6eea62f46789c0d3ebe7da133ccad2e59c89c8.tar.xz
biboumi-1f6eea62f46789c0d3ebe7da133ccad2e59c89c8.zip
Add an ad-hoc command to disconnect a user from one or more IRC server
fix #3077
Diffstat (limited to 'src')
-rw-r--r--src/bridge/bridge.cpp5
-rw-r--r--src/bridge/bridge.hpp1
-rw-r--r--src/irc/irc_message.hpp6
-rw-r--r--src/xmpp/biboumi_adhoc_commands.cpp166
-rw-r--r--src/xmpp/biboumi_adhoc_commands.hpp4
-rw-r--r--src/xmpp/biboumi_component.cpp3
6 files changed, 181 insertions, 4 deletions
diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp
index 5badb18..a1ba71a 100644
--- a/src/bridge/bridge.cpp
+++ b/src/bridge/bridge.cpp
@@ -690,3 +690,8 @@ void Bridge::trigger_on_irc_message(const std::string& irc_hostname, const IrcMe
++it;
}
}
+
+std::unordered_map<std::string, std::shared_ptr<IrcClient>>& Bridge::get_irc_clients()
+{
+ return this->irc_clients;
+}
diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp
index f1ecf25..7b8df8f 100644
--- a/src/bridge/bridge.hpp
+++ b/src/bridge/bridge.hpp
@@ -187,6 +187,7 @@ public:
* iq_responder_callback_t and remove the callback from the list.
*/
void trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message);
+ std::unordered_map<std::string, std::shared_ptr<IrcClient>>& get_irc_clients();
private:
/**
diff --git a/src/irc/irc_message.hpp b/src/irc/irc_message.hpp
index a0bd772..01e78cf 100644
--- a/src/irc/irc_message.hpp
+++ b/src/irc/irc_message.hpp
@@ -8,9 +8,9 @@
class IrcMessage
{
public:
- explicit IrcMessage(std::string&& line);
- explicit IrcMessage(std::string&& prefix, std::string&& command, std::vector<std::string>&& args);
- explicit IrcMessage(std::string&& command, std::vector<std::string>&& args);
+ IrcMessage(std::string&& line);
+ IrcMessage(std::string&& prefix, std::string&& command, std::vector<std::string>&& args);
+ IrcMessage(std::string&& command, std::vector<std::string>&& args);
~IrcMessage();
std::string prefix;
diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp
index ff0c8d4..84df2b3 100644
--- a/src/xmpp/biboumi_adhoc_commands.cpp
+++ b/src/xmpp/biboumi_adhoc_commands.cpp
@@ -313,3 +313,169 @@ void ConfigureIrcServerStep2(XmppComponent*, AdhocSession& session, XmlNode& com
session.terminate();
}
#endif // USE_DATABASE
+
+void DisconnectUserFromServerStep1(XmppComponent* xmpp_component, AdhocSession& session, XmlNode& command_node)
+{
+ const Jid owner(session.get_owner_jid());
+ if (owner.bare() != Config::get("admin", ""))
+ { // A non-admin is not allowed to disconnect other users, only
+ // him/herself, so we just skip this step
+ auto next_step = session.get_next_step();
+ next_step(xmpp_component, session, command_node);
+ }
+ else
+ { // Send a form to select the user to disconnect
+ auto biboumi_component = static_cast<BiboumiComponent*>(xmpp_component);
+
+ XmlNode x("jabber:x:data:x");
+ x["type"] = "form";
+ XmlNode title("title");
+ title.set_inner("Disconnect a user from selected IRC servers");
+ x.add_child(std::move(title));
+ XmlNode instructions("instructions");
+ instructions.set_inner("Choose a user JID");
+ x.add_child(std::move(instructions));
+ XmlNode jids_field("field");
+ jids_field["var"] = "jid";
+ jids_field["type"] = "list-single";
+ jids_field["label"] = "The JID to disconnect";
+ XmlNode required("required");
+ jids_field.add_child(std::move(required));
+ for (Bridge* bridge: biboumi_component->get_bridges())
+ {
+ XmlNode option("option");
+ option["label"] = bridge->get_jid();
+ XmlNode value("value");
+ value.set_inner(bridge->get_jid());
+ option.add_child(std::move(value));
+ jids_field.add_child(std::move(option));
+ }
+ x.add_child(std::move(jids_field));
+ command_node.add_child(std::move(x));
+ }
+}
+
+void DisconnectUserFromServerStep2(XmppComponent* xmpp_component, AdhocSession& session, XmlNode& command_node)
+{
+ // If no JID is contained in the command node, it means we skipped the
+ // previous stage, and the jid to disconnect is the executor's jid
+ std::string jid_to_disconnect = session.get_owner_jid();
+
+ if (const XmlNode* x = command_node.get_child("x", "jabber:x:data"))
+ {
+ for (const XmlNode* field: x->get_children("field", "jabber:x:data"))
+ if (field->get_tag("var") == "jid")
+ {
+ if (const XmlNode* value = field->get_child("value", "jabber:x:data"))
+ jid_to_disconnect = value->get_inner();
+ }
+ }
+
+ // Save that JID for the last step
+ session.vars["jid"] = jid_to_disconnect;
+
+ // Send a data form to let the user choose which server to disconnect the
+ // user from
+ command_node.delete_all_children();
+ auto biboumi_component = static_cast<BiboumiComponent*>(xmpp_component);
+
+ XmlNode x("jabber:x:data:x");
+ x["type"] = "form";
+ XmlNode title("title");
+ title.set_inner("Disconnect a user from selected IRC servers");
+ x.add_child(std::move(title));
+ XmlNode instructions("instructions");
+ instructions.set_inner("Choose one or more servers to disconnect this JID from");
+ x.add_child(std::move(instructions));
+ XmlNode jids_field("field");
+ jids_field["var"] = "irc-servers";
+ jids_field["type"] = "list-multi";
+ jids_field["label"] = "The servers to disconnect from";
+ XmlNode required("required");
+ jids_field.add_child(std::move(required));
+ Bridge* bridge = biboumi_component->find_user_bridge(jid_to_disconnect);
+
+ if (!bridge || bridge->get_irc_clients().empty())
+ {
+ XmlNode note("note");
+ note["type"] = "info";
+ note.set_inner("User "s + jid_to_disconnect + " is not connected to any IRC server.");
+ command_node.add_child(std::move(note));
+ session.terminate();
+ return ;
+ }
+
+ for (const auto& pair: bridge->get_irc_clients())
+ {
+ XmlNode option("option");
+ option["label"] = pair.first;
+ XmlNode value("value");
+ value.set_inner(pair.first);
+ option.add_child(std::move(value));
+ jids_field.add_child(std::move(option));
+ }
+ 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("Killed by admin");
+ message_field.add_child(std::move(message_value));
+ x.add_child(std::move(message_field));
+
+ command_node.add_child(std::move(x));
+}
+
+void DisconnectUserFromServerStep3(XmppComponent* xmpp_component, AdhocSession& session, XmlNode& command_node)
+{
+ const auto it = session.vars.find("jid");
+ if (it == session.vars.end())
+ return ;
+ const auto jid_to_disconnect = it->second;
+
+ std::vector<std::string> servers;
+ std::string quit_message;
+
+ if (const XmlNode* x = command_node.get_child("x", "jabber:x:data"))
+ {
+ for (const XmlNode* field: x->get_children("field", "jabber:x:data"))
+ {
+ if (field->get_tag("var") == "irc-servers")
+ {
+ for (const XmlNode* value: field->get_children("value", "jabber:x:data"))
+ servers.push_back(value->get_inner());
+ }
+ else if (field->get_tag("var") == "quit-message")
+ if (const XmlNode* value = field->get_child("value", "jabber:x:data"))
+ quit_message = value->get_inner();
+ }
+ }
+
+ auto biboumi_component = static_cast<BiboumiComponent*>(xmpp_component);
+ Bridge* bridge = biboumi_component->find_user_bridge(jid_to_disconnect);
+ auto& clients = bridge->get_irc_clients();
+
+ std::size_t number = 0;
+
+ for (const auto& hostname: servers)
+ {
+ auto it = clients.find(hostname);
+ if (it != clients.end())
+ {
+ it->second->on_error({"ERROR", {quit_message}});
+ clients.erase(it);
+ number++;
+ }
+ }
+ command_node.delete_all_children();
+ XmlNode note("note");
+ note["type"] = "info";
+ std::string msg = jid_to_disconnect + " was disconnected from " + std::to_string(number) + " IRC server";
+ if (number > 1)
+ msg += "s";
+ msg += ".";
+ note.set_inner(msg);
+ command_node.add_child(std::move(note));
+}
diff --git a/src/xmpp/biboumi_adhoc_commands.hpp b/src/xmpp/biboumi_adhoc_commands.hpp
index e530fa7..9377d13 100644
--- a/src/xmpp/biboumi_adhoc_commands.hpp
+++ b/src/xmpp/biboumi_adhoc_commands.hpp
@@ -13,4 +13,8 @@ void DisconnectUserStep2(XmppComponent*, AdhocSession& session, XmlNode& command
void ConfigureIrcServerStep1(XmppComponent*, AdhocSession& session, XmlNode& command_node);
void ConfigureIrcServerStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node);
+void DisconnectUserFromServerStep1(XmppComponent*, AdhocSession& session, XmlNode& command_node);
+void DisconnectUserFromServerStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node);
+void DisconnectUserFromServerStep3(XmppComponent*, AdhocSession& session, XmlNode& command_node);
+
#endif /* BIBOUMI_ADHOC_COMMANDS_HPP_INCLUDED */
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index 6f1e585..72b767f 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -55,7 +55,8 @@ BiboumiComponent::BiboumiComponent(std::shared_ptr<Poller> poller, const std::st
this->adhoc_commands_handler.get_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)},
+ {"disconnect-user", AdhocCommand({&DisconnectUserStep1, &DisconnectUserStep2}, "Disconnect selected users from the gateway", true)},
+ {"disconnect-from-irc-servers", AdhocCommand({&DisconnectUserFromServerStep1, &DisconnectUserFromServerStep2, &DisconnectUserFromServerStep3}, "Disconnect from the selected IRC servers", false)},
{"reload", AdhocCommand({&Reload}, "Reload biboumi’s configuration", true)}
};