From 31be24eb7fe50c02d797ef9d056405734a4be1cb Mon Sep 17 00:00:00 2001
From: Tomatix <post@trollskap.no>
Date: Fri, 9 Jul 2021 23:42:58 +0200
Subject: [PATCH] #102 Added a simple sandbox-implementation of "IRCClient" -
 For testing stuff.

---
 IRCClientSandbox/CMakeLists.txt |   4 +
 IRCClientSandbox/main.cpp       | 277 ++++++++++++++++++++++++++++++++
 2 files changed, 281 insertions(+)
 create mode 100644 IRCClientSandbox/CMakeLists.txt
 create mode 100644 IRCClientSandbox/main.cpp

diff --git a/IRCClientSandbox/CMakeLists.txt b/IRCClientSandbox/CMakeLists.txt
new file mode 100644
index 0000000..fd739d2
--- /dev/null
+++ b/IRCClientSandbox/CMakeLists.txt
@@ -0,0 +1,4 @@
+project(IRCClientSandbox)
+
+add_executable(${PROJECT_NAME} main.cpp)
+target_link_libraries(${PROJECT_NAME} IRCClient)
diff --git a/IRCClientSandbox/main.cpp b/IRCClientSandbox/main.cpp
new file mode 100644
index 0000000..eecd956
--- /dev/null
+++ b/IRCClientSandbox/main.cpp
@@ -0,0 +1,277 @@
+#include "IRCClient/IRCBase.h"
+#include <fmt/format.h>
+
+//#define ENABLE_MESSAGES
+
+
+#ifdef ENABLE_MESSAGES
+template <typename ... Ts>
+void print(const std::string& msg, Ts ... arg)
+{
+    fmt::print(msg, arg...);
+}
+
+void print(const std::string& msg)
+{
+    fmt::print(msg);
+}
+#else
+void print(const std::string&)
+{}
+template <typename ... Ts>
+void print(const std::string&, Ts ...)
+{}
+#endif
+
+class IRCClient : public IRCBase
+{
+    void onConnected() override
+    {
+        print("Connected to {}:{} (ssl={})", getHostname(), getPort(), isSSL());
+    }
+
+    void onConnectedWithSSLExceptions(const std::vector<IRCError>& codes) override
+    {
+        print("Connected (with ssl exceptions) to {}:{} (ssl={})", getHostname(), getPort(), isSSL());
+        for (const auto& code : codes)
+            print("SSL exception: {}", IRCErrorToString(code));
+    }
+
+    void onDisconnected() override
+    {
+        print("Disconnected from {}:{} (ssl={})", getHostname(), getPort(), isSSL());
+        m_running = false;
+    }
+
+    void onRegistered() override
+    {
+        print("Successfully registered with the server");
+    }
+
+    void onConnectionError(IRCError e) override
+    {
+        print("Connection error: ", IRCErrorToString(e));
+    }
+
+    void onMsgNick(const IRCPrefix& sender, const std::string& newNickname, const std::vector<std::string>& channelsAffected) override
+    {
+        print("{} is now known as {}", sender.nickname(), newNickname);
+    }
+
+    void onMsgMode(const IRCPrefix& sender, const std::string& target, const std::string& modes, const std::vector<std::string>& args) override
+    {
+        std::string everything = modes;
+        for (const auto& arg : args)
+            everything.append(fmt::format(" {}", arg));
+
+        if (target == getNickname())
+            print("Own usermode changed: {}", everything);
+        else
+            print("[{}] Mode set: {}", target, everything);
+    }
+
+    void onMsgQuit(const IRCPrefix& sender, const std::string& message, const std::vector<std::string>& channelsAffected) override
+    {
+        print("Quit: {} ({}@{}) ({})", sender.nickname(), sender.user(), sender.host(), message);
+    }
+
+    void onMsgJoin(const IRCPrefix& sender, const std::string& target) override
+    {
+        print("[{}] Join: {} ({}@{})", target, sender.nickname(), sender.user(), sender.host());
+    }
+
+    void onMsgPart(const IRCPrefix& sender, const std::string& target, const std::string& message) override
+    {
+        if (message.empty())
+            print("[{}] Part: {} ({}@{})", target, sender.nickname(), sender.user(), sender.host());
+        else
+            print("[{}] Part: {} ({}@{}) ({})", target, sender.nickname(), sender.user(), sender.host(), message);
+    }
+
+    void onMsgTopic(const IRCPrefix& sender, const std::string& target, const std::string& topic) override
+    {
+        if (topic.empty())
+            print("[{}] {} cleared the topic", target, sender.nickname());
+        else
+            print("[{}] {} set new topic: {}", target, sender.nickname(), topic);
+    }
+
+    void onMsgInvite(const IRCPrefix& sender, const std::string& target) override
+    {
+        print("{} invited you to join {}", sender.nickname(), target);
+    }
+
+    void onMsgKick(const IRCPrefix& sender, const std::string& target, const std::string& who, const std::string& reason) override
+    {
+        if (who == getNickname())
+            print("[{}] You were kicked by {} ({})", target, sender.nickname(), reason);
+        else
+            print("[{}] {} kicked {} ({})", target, sender.nickname(), who, reason);
+    }
+
+    void onMsgPrivmsg(const IRCPrefix& sender, const std::string& target, const std::string& message) override
+    {
+        print("[{}] <{}> {}", target, sender.nickname(), message);
+    }
+
+    void onMsgNotice(const IRCPrefix& sender, const std::string& target, const std::string& message) override
+    {
+        if (target == getNickname())
+            print("-{}- {}", sender.nickname(), message);
+        else
+            print("[{}] -{}- {}", target, sender.nickname(), message);
+    }
+
+    void onMsgKill(const IRCPrefix& sender, const std::string& reason) override
+    {
+        print("You were killed by {} ({})", sender.nickname(), reason);
+    }
+
+    void onMsgPing(const std::string& message) override
+    {
+
+    }
+
+    void onMsgPong(const std::string& message) override
+    {
+
+    }
+
+    void onMsgError(const std::string& message) override
+    {
+        print("Server error: {}", message);
+    }
+
+    void onMsgWallops(const IRCPrefix& sender, const std::string& message) override
+    {
+        print("!{}! {}", sender.nickname(), message);
+    }
+
+    void onMsgNumeric(const IRCPrefix& sender, const std::string& num, const std::vector<std::string>& args, const std::string& message) override
+    {
+        std::string everything;
+
+        for (const auto& arg : args)
+            everything.append(fmt::format("{} ", arg));
+
+        if (!everything.empty())
+            everything.append(": ");
+
+        everything.append(message);
+        print(everything);
+    }
+
+    void onMsgCTCPRequest(const IRCPrefix& sender, const std::string& target, const std::string& command, const std::string& message) override
+    {
+        std::string printmsg;
+        if (message.empty())
+            printmsg = fmt::format("[CTCP {} from {}]", command, sender.nickname());
+        else
+            printmsg = fmt::format("[CTCP {} from {}] {}", command, sender.nickname(), message);
+
+        if (target != getNickname())
+            printmsg = fmt::format("[{}] {}", target, printmsg);
+
+        print(printmsg);
+    }
+
+    void onMsgCTCPResponse(const IRCPrefix& sender, const std::string& target, const std::string& command, const std::string& message) override
+    {
+        std::string printmsg;
+        if (message.empty())
+            printmsg = fmt::format("[CTCP REPLY {} from {}]", command, sender.nickname());
+        else
+            printmsg = fmt::format("[CTCP REPLY {} from {}] {}", command, sender.nickname(), message);
+
+        if (target != getNickname())
+            printmsg = fmt::format("[{}] {}", target, printmsg);
+
+        print(printmsg);
+    }
+
+    void onMsgDCCRequest(std::shared_ptr<DCC> dcc, const IRCPrefix& sender, const std::string& target, const std::string& type, const std::string& message) override
+    {
+
+    }
+
+    void v3onMsgAway(const IRCPrefix& sender, const std::string& message, const std::vector<std::string>& channelsAffected) override
+    {
+        if (message.empty())
+            print("{} is no longer away", sender.nickname());
+        else
+            print("{} is away: {}", sender.nickname(), message);
+    }
+
+    void v3onMsgAccountLogin(const IRCPrefix& sender, const std::string& useraccount) override
+    {
+        print("{} is now logged in as {}", sender.nickname(), useraccount);
+    }
+
+    void v3onMsgAccountLogout(const IRCPrefix& sender) override
+    {
+        print("{} logged out from their account", sender.nickname());
+    }
+
+    /*
+     * Required IRCv3 extensions to implement.
+    */
+    void v3onMsgJoin(const IRCPrefix& sender, const std::string& channel, const std::string& useraccount, const std::string& realname) override
+    {
+        print("[{}] Join: {} (Account: {}) ({}@{})", channel, sender.nickname(), useraccount, sender.user(), sender.host());
+    }
+
+    /*
+     * Catch-all handler. If the message parser cannot match for any of the commands, it will turn up here.
+     * Optional to implement.
+    */
+    void onMsgUnhandled(const IRCPrefix& sender, const std::string& command, const std::vector<std::string>& args, const std::string& message) override
+    {
+        std::string everything = command;
+
+        for (const auto& arg : args)
+            everything.append(fmt::format(" {}", arg));
+
+        if (!message.empty())
+            everything.append(fmt::format(" {}", message));
+
+        print("Unhandled command from {}: {}", sender.nickname(), everything);
+    }
+
+
+    bool m_running{ true };
+
+public:
+    [[nodiscard]] bool isRunning() const { return m_running; }
+};
+
+int main()
+{
+    IRCClient client;
+
+    /*
+     * WARNING
+     * Do not commit any connection details to the source repository!
+    */
+    client.setHostname("");
+    client.setPort("");
+    client.setNickname("");
+    client.setIdent("");
+    client.setRealname("");
+
+    auto connectionStatus = client.tryConnect();
+
+    print("Entering event loop");
+
+    while (true) {
+        if (connectionStatus != IRCError::NoError || !client.isRunning())
+            break;
+
+        client.poll();
+
+        connectionStatus = client.lastErrorCode();
+    }
+
+    print("Leaving event loop");
+
+    return 0;
+}