From c495b5d9cf8bed4f07c0b77a1f9e98dcc1f62068 Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Thu, 6 Sep 2018 10:09:09 +0100 Subject: Implement support for IRCv3 client-to-client tags. --- include/modules/ctctags.h | 135 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 include/modules/ctctags.h (limited to 'include/modules') diff --git a/include/modules/ctctags.h b/include/modules/ctctags.h new file mode 100644 index 000000000..d8798de54 --- /dev/null +++ b/include/modules/ctctags.h @@ -0,0 +1,135 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2019 Peter Powell + * + * 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 . + */ + + +#pragma once + +#include "event.h" + +namespace CTCTags +{ + class EventListener; + class TagMessage; + class TagMessageDetails; +} + +class CTCTags::TagMessage : public ClientProtocol::Message +{ + public: + TagMessage(User* source, const Channel* targetchan, const ClientProtocol::TagMap& Tags) + : ClientProtocol::Message("TAGMSG", source) + { + PushParamRef(targetchan->name); + AddTags(Tags); + SetSideEffect(true); + } + + TagMessage(User* source, const User* targetuser, const ClientProtocol::TagMap& Tags) + : ClientProtocol::Message("TAGMSG", source) + { + if (targetuser->registered & REG_NICK) + PushParamRef(targetuser->nick); + else + PushParam("*"); + AddTags(Tags); + SetSideEffect(true); + } + + TagMessage(User* source, const char* targetstr, const ClientProtocol::TagMap& Tags) + : ClientProtocol::Message("TAGMSG", source) + { + PushParam(targetstr); + AddTags(Tags); + SetSideEffect(true); + } +}; + +class CTCTags::TagMessageDetails +{ + public: + /** Whether to echo the tags at all. */ + bool echo; + + /* Whether to send the original tags back to clients with echo-message support. */ + bool echo_original; + + /** The users who are exempted from receiving this message. */ + CUList exemptions; + + /** IRCv3 message tags sent to the server by the user. */ + const ClientProtocol::TagMap tags_in; + + /** IRCv3 message tags sent out to users who get this message. */ + ClientProtocol::TagMap tags_out; + + TagMessageDetails(const ClientProtocol::TagMap& tags) + : echo(true) + , echo_original(false) + , tags_in(tags) + { + } +}; + +class CTCTags::EventListener + : public Events::ModuleEventListener +{ + protected: + EventListener(Module* mod, unsigned int eventprio = DefaultPriority) + : ModuleEventListener(mod, "event/tagmsg", eventprio) + { + } + + public: + /** Called before a user sends a tag message to a channel, a user, or a server glob mask. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + * @return MOD_RES_ALLOW to explicitly allow the message, MOD_RES_DENY to explicitly deny the + * message, or MOD_RES_PASSTHRU to let another module handle the event. + */ + virtual ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, TagMessageDetails& details) { return MOD_RES_PASSTHRU; } + + /** Called immediately after a user sends a tag message to a channel, a user, or a server glob mask. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + */ + virtual void OnUserPostTagMessage(User* user, const MessageTarget& target, const TagMessageDetails& details) { } + + /** Called immediately before a user sends a tag message to a channel, a user, or a server glob mask. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + */ + virtual void OnUserTagMessage(User* user, const MessageTarget& target, const TagMessageDetails& details) { } + + /** Called when a tag message sent by a user to a channel, a user, or a server glob mask is blocked. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + */ + virtual void OnUserTagMessageBlocked(User* user, const MessageTarget& target, const TagMessageDetails& details) { } +}; -- cgit v1.3.1-10-gc9f91 From dfb1e0da7823641ad648f9fbd19b43d2e6b0d7ad Mon Sep 17 00:00:00 2001 From: linuxdaemon Date: Tue, 12 Mar 2019 09:48:28 -0500 Subject: Add Who::Request::GetFlagIndex to get field index Replaces the dirty logic in m_hideoper and m_namesx --- include/modules/who.h | 11 +++++++++++ src/coremods/core_who.cpp | 22 ++++++++++++++++++++++ src/modules/m_hideoper.cpp | 19 +++---------------- src/modules/m_namesx.cpp | 19 +++---------------- 4 files changed, 39 insertions(+), 32 deletions(-) (limited to 'include/modules') diff --git a/include/modules/who.h b/include/modules/who.h index 4fcbe5f91..8fd2dab08 100644 --- a/include/modules/who.h +++ b/include/modules/who.h @@ -71,6 +71,17 @@ class Who::Request /** A user specified label for the WHOX response. */ std::string whox_querytype; + /** Get the index in the response parameters for the different data fields + * + * The fields 'r' (realname) and 'd' (hops) will always be missing in a non-WHOX + * query, because WHOX splits them to 2 fields, where old WHO has them as one. + * + * @param flag The field name to look for + * @param out The index will be stored in this value + * @return True if the field is available, false otherwise + */ + virtual bool GetFlagIndex(char flag, size_t& out) const = 0; + protected: Request() : fuzzy_match(false) diff --git a/src/coremods/core_who.cpp b/src/coremods/core_who.cpp index bf00b741f..f32ef77b3 100644 --- a/src/coremods/core_who.cpp +++ b/src/coremods/core_who.cpp @@ -34,8 +34,19 @@ enum RPL_WHOSPCRPL = 354 }; +static const char whox_field_order[] = "tcuihsnfdlaor"; +static const char who_field_order[] = "cuhsnf"; + struct WhoData : public Who::Request { + std::string query_flag_order; + + bool GetFlagIndex(char flag, size_t& out) const CXX11_OVERRIDE + { + out = query_flag_order.find(flag); + return out != std::string::npos; + } + WhoData(const CommandBase::Params& parameters) { // Find the matchtext and swap the 0 for a * so we can use InspIRCd::Match on it. @@ -74,6 +85,17 @@ struct WhoData : public Who::Request current_bitset->set(chr); } } + + if (whox) + { + for (const char *c = whox_field_order; c; c++) + { + if (whox_fields[*c]) + query_flag_order.push_back(*c); + } + } + else + query_flag_order = who_field_order; } }; diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index f04d88809..8feb1a852 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -123,22 +123,9 @@ class ModuleHideOper if (request.flags['o']) return MOD_RES_DENY; - size_t flag_index = 5; - if (request.whox) - { - // We only need to fiddle with the flags if they are present. - if (!request.whox_fields['f']) - return MOD_RES_PASSTHRU; - - // WHOX makes this a bit tricky as we need to work out the parameter which the flags are in. - flag_index = 0; - static const char* flags = "tcuihsn"; - for (size_t i = 0; i < strlen(flags); ++i) - { - if (request.whox_fields[flags[i]]) - flag_index += 1; - } - } + size_t flag_index; + if (!request.GetFlagIndex('f', flag_index)) + return MOD_RES_PASSTHRU; // hide the "*" that marks the user as an oper from the /WHO line // #chan ident localhost insp22.test nick H@ :0 Attila diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp index defb66b78..1e051e75c 100644 --- a/src/modules/m_namesx.cpp +++ b/src/modules/m_namesx.cpp @@ -84,22 +84,9 @@ class ModuleNamesX if (prefixes.length() <= 1) return MOD_RES_PASSTHRU; - size_t flag_index = 5; - if (request.whox) - { - // We only need to fiddle with the flags if they are present. - if (!request.whox_fields['f']) - return MOD_RES_PASSTHRU; - - // WHOX makes this a bit tricky as we need to work out the parameter which the flags are in. - flag_index = 0; - static const char* flags = "tcuihsn"; - for (size_t i = 0; i < strlen(flags); ++i) - { - if (request.whox_fields[flags[i]]) - flag_index += 1; - } - } + size_t flag_index; + if (!request.GetFlagIndex('f', flag_index)) + return MOD_RES_PASSTHRU; // #chan ident localhost insp22.test nick H@ :0 Attila if (numeric.GetParams().size() <= flag_index) -- cgit v1.3.1-10-gc9f91 From 1003c593bfd455734a8f39f137d4ce68e7e87ca8 Mon Sep 17 00:00:00 2001 From: linuxdaemon Date: Tue, 12 Mar 2019 12:04:01 -0500 Subject: Rename GetFlagIndex -> GetFieldIndex --- include/modules/who.h | 2 +- src/coremods/core_who.cpp | 2 +- src/modules/m_hideoper.cpp | 2 +- src/modules/m_namesx.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/modules') diff --git a/include/modules/who.h b/include/modules/who.h index 8fd2dab08..983cece46 100644 --- a/include/modules/who.h +++ b/include/modules/who.h @@ -80,7 +80,7 @@ class Who::Request * @param out The index will be stored in this value * @return True if the field is available, false otherwise */ - virtual bool GetFlagIndex(char flag, size_t& out) const = 0; + virtual bool GetFieldIndex(char flag, size_t& out) const = 0; protected: Request() diff --git a/src/coremods/core_who.cpp b/src/coremods/core_who.cpp index 52af2d2ce..d6df6de20 100644 --- a/src/coremods/core_who.cpp +++ b/src/coremods/core_who.cpp @@ -39,7 +39,7 @@ static const char who_field_order[] = "cuhsnf"; struct WhoData : public Who::Request { - bool GetFlagIndex(char flag, size_t& out) const CXX11_OVERRIDE + bool GetFieldIndex(char flag, size_t& out) const CXX11_OVERRIDE { if (!whox) { diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index 8feb1a852..d78ed538b 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -124,7 +124,7 @@ class ModuleHideOper return MOD_RES_DENY; size_t flag_index; - if (!request.GetFlagIndex('f', flag_index)) + if (!request.GetFieldIndex('f', flag_index)) return MOD_RES_PASSTHRU; // hide the "*" that marks the user as an oper from the /WHO line diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp index 1e051e75c..ac15c9723 100644 --- a/src/modules/m_namesx.cpp +++ b/src/modules/m_namesx.cpp @@ -85,7 +85,7 @@ class ModuleNamesX return MOD_RES_PASSTHRU; size_t flag_index; - if (!request.GetFlagIndex('f', flag_index)) + if (!request.GetFieldIndex('f', flag_index)) return MOD_RES_PASSTHRU; // #chan ident localhost insp22.test nick H@ :0 Attila -- cgit v1.3.1-10-gc9f91 From bdded70ac222c997aea8e8fefb029571398c611e Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Sat, 30 Mar 2019 11:53:51 +0000 Subject: Rename OnClientProtocolPopulateTags to OnPopulateTags. --- include/clientprotocol.h | 2 +- include/modules/ircv3.h | 2 +- src/clientprotocol.cpp | 2 +- src/modules/m_botmode.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/modules') diff --git a/include/clientprotocol.h b/include/clientprotocol.h index ec033e166..44896a3a3 100644 --- a/include/clientprotocol.h +++ b/include/clientprotocol.h @@ -537,7 +537,7 @@ class ClientProtocol::MessageTagProvider : public Events::ModuleEventListener * The default implementation does nothing. * @param msg Message to be populated with tags. */ - virtual void OnClientProtocolPopulateTags(ClientProtocol::Message& msg) + virtual void OnPopulateTags(ClientProtocol::Message& msg) { } diff --git a/include/modules/ircv3.h b/include/modules/ircv3.h index 9729e8ed5..ce2b70da7 100644 --- a/include/modules/ircv3.h +++ b/include/modules/ircv3.h @@ -75,7 +75,7 @@ class IRCv3::CapTag : public ClientProtocol::MessageTagProvider return cap.get(user); } - void OnClientProtocolPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE + void OnPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE { T& tag = static_cast(*this); const std::string* const val = tag.GetValue(msg); diff --git a/src/clientprotocol.cpp b/src/clientprotocol.cpp index 212d65d6b..ee3909fbf 100644 --- a/src/clientprotocol.cpp +++ b/src/clientprotocol.cpp @@ -63,7 +63,7 @@ const ClientProtocol::SerializedMessage& ClientProtocol::Serializer::SerializeFo if (!msg.msginit_done) { msg.msginit_done = true; - FOREACH_MOD_CUSTOM(evprov, MessageTagProvider, OnClientProtocolPopulateTags, (msg)); + FOREACH_MOD_CUSTOM(evprov, MessageTagProvider, OnPopulateTags, (msg)); } return msg.GetSerialized(Message::SerializedInfo(this, MakeTagWhitelist(user, msg.GetTags()))); } diff --git a/src/modules/m_botmode.cpp b/src/modules/m_botmode.cpp index 1007f7ca1..44241e82c 100644 --- a/src/modules/m_botmode.cpp +++ b/src/modules/m_botmode.cpp @@ -43,7 +43,7 @@ class BotTag : public ClientProtocol::MessageTagProvider { } - void OnClientProtocolPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE + void OnPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE { User* const user = msg.GetSourceUser(); if (user && user->IsModeSet(botmode)) -- cgit v1.3.1-10-gc9f91