From 7376831bc8f6dbec8eaf4f4c0a6bba819a0a1e59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?louiz=E2=80=99?= <louiz@louiz.org>
Date: Mon, 7 Nov 2016 14:43:07 +0100
Subject: Add get-irc-connection-info adhoc command

fix #3171
---
 src/xmpp/biboumi_adhoc_commands.cpp | 67 ++++++++++++++++++++++++++++++++++++-
 src/xmpp/biboumi_adhoc_commands.hpp |  2 ++
 src/xmpp/biboumi_component.cpp      |  6 ++++
 src/xmpp/biboumi_component.hpp      |  2 +-
 4 files changed, 75 insertions(+), 2 deletions(-)

(limited to 'src/xmpp')

diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp
index af7e473..87b8d96 100644
--- a/src/xmpp/biboumi_adhoc_commands.cpp
+++ b/src/xmpp/biboumi_adhoc_commands.cpp
@@ -1,10 +1,12 @@
 #include <xmpp/biboumi_adhoc_commands.hpp>
 #include <xmpp/biboumi_component.hpp>
+#include <utils/scopeguard.hpp>
+#include <bridge/bridge.hpp>
 #include <config/config.hpp>
 #include <utils/string.hpp>
 #include <utils/split.hpp>
 #include <xmpp/jid.hpp>
-#include <algorithm>
+#include <iomanip>
 
 #include <biboumi.h>
 
@@ -720,3 +722,66 @@ void DisconnectUserFromServerStep3(XmppComponent& xmpp_component, AdhocSession&
   note.set_inner(msg);
   command_node.add_child(std::move(note));
 }
+
+void GetIrcConnectionInfoStep1(XmppComponent& component, AdhocSession& session, XmlNode& command_node)
+{
+  BiboumiComponent& biboumi_component = static_cast<BiboumiComponent&>(component);
+
+  const Jid owner(session.get_owner_jid());
+  const Jid target(session.get_target_jid());
+
+  std::string message{};
+
+  // As the function is exited, set the message in the response.
+  utils::ScopeGuard sg([&message, &command_node]()
+                       {
+                         command_node.delete_all_children();
+                         XmlNode note("note");
+                         note["type"] = "info";
+                         note.set_inner(message);
+                         command_node.add_child(std::move(note));
+                       });
+
+  Bridge* bridge = biboumi_component.get_user_bridge(owner.bare());
+  if (!bridge)
+    {
+      message = "You are not connected to anything.";
+      return;
+    }
+
+  std::string hostname;
+  if ((hostname = Config::get("fixed_irc_server", "")).empty())
+    hostname = target.local;
+
+  IrcClient* irc = bridge->find_irc_client(hostname);
+  if (!irc || !irc->is_connected())
+    {
+      message = "You are not connected to the IRC server "s + hostname;
+      return;
+    }
+
+  std::ostringstream ss;
+  ss << "Connected to IRC server " << irc->get_hostname() << " on port " << irc->get_port();
+  if (irc->is_using_tls())
+    ss << " (using TLS)";
+  const std::time_t now_c = std::chrono::system_clock::to_time_t(irc->connection_date);
+  ss << " since " << std::put_time(std::localtime(&now_c), "%F %T");
+  ss << " (" << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - irc->connection_date).count() << " seconds ago).";
+
+  for (const auto& it: bridge->resources_in_chan)
+    {
+      const auto& channel_key = it.first;
+      const auto& irc_hostname = std::get<1>(channel_key);
+      const auto& resources = it.second;
+
+      if (irc_hostname == irc->get_hostname() && !resources.empty())
+        {
+          const auto& channel_name = std::get<0>(channel_key);
+          ss << "\n" << channel_name << " from " << resources.size() << " resource" << (resources.size() > 1 ? "s": "") << ": ";
+          for (const auto& resource: resources)
+            ss << resource << " ";
+        }
+    }
+
+  message = ss.str();
+}
diff --git a/src/xmpp/biboumi_adhoc_commands.hpp b/src/xmpp/biboumi_adhoc_commands.hpp
index 7be5509..b5fce61 100644
--- a/src/xmpp/biboumi_adhoc_commands.hpp
+++ b/src/xmpp/biboumi_adhoc_commands.hpp
@@ -22,3 +22,5 @@ void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& co
 void DisconnectUserFromServerStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node);
 void DisconnectUserFromServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node);
 void DisconnectUserFromServerStep3(XmppComponent&, AdhocSession& session, XmlNode& command_node);
+
+void GetIrcConnectionInfoStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node);
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index f3405df..4398562 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -63,6 +63,12 @@ BiboumiComponent::BiboumiComponent(std::shared_ptr<Poller> poller, const std::st
   this->adhoc_commands_handler.add_command("disconnect-from-irc-server", {{&DisconnectUserFromServerStep1, &DisconnectUserFromServerStep2, &DisconnectUserFromServerStep3}, "Disconnect from the selected IRC servers", false});
   this->adhoc_commands_handler.add_command("reload", {{&Reload}, "Reload biboumi’s configuration", true});
 
+  AdhocCommand get_irc_connection_info{{&GetIrcConnectionInfoStep1}, "Returns various information about your connection to this IRC server.", false};
+  if (!Config::get("fixed_irc_server", "").empty())
+    this->adhoc_commands_handler.add_command("get-irc-connection-info", get_irc_connection_info);
+  else
+    this->irc_server_adhoc_commands_handler.add_command("get-irc-connection-info", get_irc_connection_info);
+
 #ifdef USE_DATABASE
   AdhocCommand configure_server_command({&ConfigureIrcServerStep1, &ConfigureIrcServerStep2}, "Configure a few settings for that IRC server", false);
   AdhocCommand configure_global_command({&ConfigureGlobalStep1, &ConfigureGlobalStep2}, "Configure a few settings", false);
diff --git a/src/xmpp/biboumi_component.hpp b/src/xmpp/biboumi_component.hpp
index d5b87e9..999001f 100644
--- a/src/xmpp/biboumi_component.hpp
+++ b/src/xmpp/biboumi_component.hpp
@@ -101,13 +101,13 @@ public:
                              const std::string& queryid);
 #endif
 
-private:
   /**
    * Return the bridge associated with the bare JID. Create a new one
    * if none already exist.
    */
   Bridge* get_user_bridge(const std::string& user_jid);
 
+private:
   /**
    * A map of id -> callback.  When we want to wait for an iq result, we add
    * the callback to this map, with the iq id as the key. When an iq result
-- 
cgit v1.2.3