summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/conf/modules.conf.example7
-rw-r--r--src/modules/m_ircv3_msgid.cpp121
2 files changed, 128 insertions, 0 deletions
diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example
index 8dcdd7d3d..bb8a74dbc 100644
--- a/docs/conf/modules.conf.example
+++ b/docs/conf/modules.conf.example
@@ -1168,6 +1168,13 @@
#<module name="ircv3_invitenotify">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# IRCv3 message id module: Provides the msgid IRCv3 extension which
+# adds a unique identifier to each message when the message-tags cap
+# has been requested. This enables support for modern features such as
+# reactions and replies.
+#<module name="ircv3_msgid">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# IRCv3 server-time module. Adds the 'time' tag which adds a timestamp
# to all messages received from the server.
#<module name="ircv3_servertime">
diff --git a/src/modules/m_ircv3_msgid.cpp b/src/modules/m_ircv3_msgid.cpp
new file mode 100644
index 000000000..4d34455b9
--- /dev/null
+++ b/src/modules/m_ircv3_msgid.cpp
@@ -0,0 +1,121 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2019 Peter Powell <petpow@saberuk.com>
+ * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "modules/cap.h"
+#include "modules/ctctags.h"
+
+class MsgIdTag : public ClientProtocol::MessageTagProvider
+{
+ private:
+ Cap::Reference ctctagcap;
+
+ public:
+ MsgIdTag(Module* mod)
+ : ClientProtocol::MessageTagProvider(mod)
+ , ctctagcap(mod, "message-tags")
+ {
+ }
+
+ ModResult OnProcessTag(User* user, const std::string& tagname, std::string& tagvalue) CXX11_OVERRIDE
+ {
+ if (!irc::equals(tagname, "msgid"))
+ return MOD_RES_PASSTHRU;
+
+ // We should only allow this tag if it is added by a remote server.
+ return IS_LOCAL(user) ? MOD_RES_DENY : MOD_RES_ALLOW;
+ }
+
+ bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE
+ {
+ return ctctagcap.get(user);
+ }
+};
+
+class MsgIdGenerator
+{
+ uint64_t counter;
+ std::string strid;
+ const std::string::size_type baselen;
+
+ public:
+ MsgIdGenerator()
+ : counter(0)
+ , strid(InspIRCd::Format("%s~%lu~", ServerInstance->Config->GetSID().c_str(), ServerInstance->startup_time))
+ , baselen(strid.length())
+ {
+ }
+
+ const std::string& GetNext()
+ {
+ strid.erase(baselen);
+ strid.append(ConvToStr(counter++));
+ return strid;
+ }
+};
+
+class ModuleMsgId
+ : public Module
+ , public CTCTags::EventListener
+{
+ private:
+ MsgIdTag tag;
+ MsgIdGenerator generator;
+
+ ModResult CopyMessageId(const ClientProtocol::TagMap& tags_in, ClientProtocol::TagMap& tags_out)
+ {
+ ClientProtocol::TagMap::const_iterator iter = tags_in.find("msgid");
+ if (iter != tags_in.end())
+ {
+ // If the remote server has sent a message identifier we should use that as
+ // identifiers need to be the same on all sides of the network.
+ tags_out.insert(*iter);
+ return MOD_RES_PASSTHRU;
+ }
+
+ // Otherwise, we can just create a new message identifier.
+ tags_out.insert(std::make_pair("msgid", ClientProtocol::MessageTagData(&tag, generator.GetNext())));
+ return MOD_RES_PASSTHRU;
+ }
+
+ public:
+ ModuleMsgId()
+ : CTCTags::EventListener(this)
+ , tag(this)
+ {
+ }
+
+ ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE
+ {
+ return CopyMessageId(details.tags_in, details.tags_out);
+ }
+
+ ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE
+ {
+ return CopyMessageId(details.tags_in, details.tags_out);
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the msgid IRCv3 tag", VF_VENDOR);
+ }
+};
+
+MODULE_INIT(ModuleMsgId)