X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_ircv3_ctctags.cpp;h=8dd83bd7f525777cdf0c089ee32c9c33f107584a;hb=80e81e3b81b779901fd9d67f8ae030ee30c0bcec;hp=6052051b9a23787f91f3e761522f92885c92af0f;hpb=87b1461e2a4710a38b32186c2582da9fe9bb3804;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_ircv3_ctctags.cpp b/src/modules/m_ircv3_ctctags.cpp index 6052051b9..8dd83bd7f 100644 --- a/src/modules/m_ircv3_ctctags.cpp +++ b/src/modules/m_ircv3_ctctags.cpp @@ -1,8 +1,8 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2019 Peter Powell - * Copyright (C) 2016 Attila Molnar + * Copyright (C) 2019 linuxdaemon + * Copyright (C) 2018-2021 Sadie 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 @@ -26,8 +26,6 @@ class CommandTagMsg : public Command { private: Cap::Capability& cap; - ChanModeReference moderatedmode; - ChanModeReference noextmsgmode; Events::ModuleEventProvider tagevprov; ClientProtocol::EventProvider msgevprov; @@ -43,6 +41,13 @@ class CommandTagMsg : public Command return false; } + // Check whether a module zapped the message tags. + if (msgdetails.tags_out.empty()) + { + source->WriteNumeric(ERR_NOTEXTTOSEND, "No tags to send"); + return false; + } + // Inform modules that a TAGMSG is about to be sent. FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserTagMessage, (source, msgtarget, msgdetails)); return true; @@ -52,7 +57,7 @@ class CommandTagMsg : public Command { // If the source is local then update its idle time. LocalUser* lsource = IS_LOCAL(source); - if (lsource) + if (lsource && msgdetails.update_idle) lsource->idle_lastmsg = ServerInstance->Time(); // Inform modules that a TAGMSG was sent. @@ -70,32 +75,6 @@ class CommandTagMsg : public Command return CMD_FAILURE; } - if (IS_LOCAL(source)) - { - if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(source)) - { - // The noextmsg mode is set and the source is not in the channel. - source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)"); - return CMD_FAILURE; - } - - bool no_chan_priv = chan->GetPrefixValue(source) < VOICE_VALUE; - if (no_chan_priv && chan->IsModeSet(moderatedmode)) - { - // The moderated mode is set and the source has no status rank. - source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m is set)"); - return CMD_FAILURE; - } - - if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(source)) - { - // The source is banned in the channel and restrictbannedusers is enabled. - if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) - source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)"); - return CMD_FAILURE; - } - } - // Fire the pre-message events. MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0); CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); @@ -103,13 +82,14 @@ class CommandTagMsg : public Command return CMD_FAILURE; unsigned int minrank = pm ? pm->GetPrefixRank() : 0; - CTCTags::TagMessage message(source, chan, parameters.GetTags()); + CTCTags::TagMessage message(source, chan, msgdetails.tags_out, msgtarget.status); + message.SetSideEffect(true); const Channel::MemberMap& userlist = chan->GetUsers(); for (Channel::MemberMap::const_iterator iter = userlist.begin(); iter != userlist.end(); ++iter) { LocalUser* luser = IS_LOCAL(iter->first); - // Don't send to remote users or the user who is the source. + // Don't send to remote users or the user who is the source. if (!luser || luser == source) continue; @@ -129,7 +109,10 @@ class CommandTagMsg : public Command // If the source isn't allowed to mass message users then reject // the attempt to mass-message users. if (!source->HasPrivPermission("users/mass-message")) + { + source->WriteNumeric(ERR_NOPRIVILEGES, "Permission Denied - You do not have the required operator privileges"); return CMD_FAILURE; + } // Extract the server glob match from the target parameter. std::string servername(parameters[0], 1); @@ -144,7 +127,8 @@ class CommandTagMsg : public Command // the message out to the local users. if (InspIRCd::Match(ServerInstance->Config->ServerName, servername)) { - CTCTags::TagMessage message(source, "$*", parameters.GetTags()); + CTCTags::TagMessage message(source, "$*", msgdetails.tags_out); + message.SetSideEffect(true); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter) { @@ -211,7 +195,8 @@ class CommandTagMsg : public Command if (localtarget && cap.get(localtarget)) { // Send to the target if they have the capability and are a local user. - CTCTags::TagMessage message(source, localtarget, parameters.GetTags()); + CTCTags::TagMessage message(source, localtarget, msgdetails.tags_out); + message.SetSideEffect(true); localtarget->Send(msgevprov, message); } @@ -223,8 +208,6 @@ class CommandTagMsg : public Command CommandTagMsg(Module* Creator, Cap::Capability& Cap) : Command(Creator, "TAGMSG", 1) , cap(Cap) - , moderatedmode(Creator, "moderated") - , noextmsgmode(Creator, "noextmsg") , tagevprov(Creator, "event/tagmsg") , msgevprov(Creator, "TAGMSG") { @@ -240,19 +223,37 @@ class CommandTagMsg : public Command if (IS_LOCAL(user) && !cap.get(user)) return CMD_FAILURE; + // The specified message tags were empty. + if (parameters.GetTags().empty()) + { + user->WriteNumeric(ERR_NOTEXTTOSEND, "No tags to send"); + return CMD_FAILURE; + } + // The target is a server glob. if (parameters[0][0] == '$') return HandleServerTarget(user, parameters); - // If the message begins with a status character then look it up. + // If the message begins with one or more status characters then look them up. const char* target = parameters[0].c_str(); - PrefixMode* pmh = ServerInstance->Modes->FindPrefix(target[0]); - if (pmh) - target++; + PrefixMode* targetpfx = NULL; + for (PrefixMode* pfx; (pfx = ServerInstance->Modes->FindPrefix(target[0])); ++target) + { + // We want the lowest ranked prefix specified. + if (!targetpfx || pfx->GetPrefixRank() < targetpfx->GetPrefixRank()) + targetpfx = pfx; + } + + if (!target[0]) + { + // The target consisted solely of prefix modes. + user->WriteNumeric(ERR_NORECIPIENT, "No recipient given"); + return CMD_FAILURE; + } // The target is a channel name. if (*target == '#') - return HandleChannelTarget(user, parameters, target, pmh); + return HandleChannelTarget(user, parameters, target, targetpfx); // The target is a nickname. return HandleUserTarget(user, parameters); @@ -260,7 +261,11 @@ class CommandTagMsg : public Command RouteDescriptor GetRouting(User* user, const Params& parameters) CXX11_OVERRIDE { - return ROUTE_MESSAGE(parameters[0]); + if (IS_LOCAL(user)) + // This is handled by the OnUserPostTagMessage hook to split the LoopCall pieces + return ROUTE_LOCALONLY; + else + return ROUTE_MESSAGE(parameters[0]); } }; @@ -270,6 +275,7 @@ class C2CTags : public ClientProtocol::MessageTagProvider Cap::Capability& cap; public: + bool allowclientonlytags; C2CTags(Module* Creator, Cap::Capability& Cap) : ClientProtocol::MessageTagProvider(Creator) , cap(Cap) @@ -280,7 +286,7 @@ class C2CTags : public ClientProtocol::MessageTagProvider { // A client-only tag is prefixed with a plus sign (+) and otherwise conforms // to the format specified in IRCv3.2 tags. - if (tagname[0] != '+' || tagname.length() < 2) + if (tagname[0] != '+' || tagname.length() < 2 || !allowclientonlytags) return MOD_RES_PASSTHRU; // If the user is local then we check whether they have the message-tags cap @@ -307,6 +313,8 @@ class ModuleIRCv3CTCTags Cap::Capability cap; CommandTagMsg cmd; C2CTags c2ctags; + ChanModeReference moderatedmode; + ChanModeReference noextmsgmode; ModResult CopyClientTags(const ClientProtocol::TagMap& tags_in, ClientProtocol::TagMap& tags_out) { @@ -325,7 +333,20 @@ class ModuleIRCv3CTCTags , cap(this, "message-tags") , cmd(this, cap) , c2ctags(this, cap) + , moderatedmode(this, "moderated") + , noextmsgmode(this, "noextmsg") + { + } + + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE + { + c2ctags.allowclientonlytags = ServerInstance->Config->ConfValue("ctctags")->getBool("allowclientonlytags", true); + } + + void On005Numeric(std::map& tokens) CXX11_OVERRIDE { + if (!c2ctags.allowclientonlytags) + tokens["CLIENTTAGDENY"] = "*"; } ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) CXX11_OVERRIDE @@ -335,12 +356,39 @@ class ModuleIRCv3CTCTags ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) CXX11_OVERRIDE { + if (IS_LOCAL(user) && target.type == MessageTarget::TYPE_CHANNEL) + { + Channel* chan = target.Get(); + if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user)) + { + // The noextmsg mode is set and the user is not in the channel. + user->WriteNumeric(Numerics::CannotSendTo(chan, "external messages", *noextmsgmode)); + return MOD_RES_DENY; + } + + bool no_chan_priv = chan->GetPrefixValue(user) < VOICE_VALUE; + if (no_chan_priv && chan->IsModeSet(moderatedmode)) + { + // The moderated mode is set and the user has no status rank. + user->WriteNumeric(Numerics::CannotSendTo(chan, "messages", *noextmsgmode)); + return MOD_RES_DENY; + } + + if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(user)) + { + // The user is banned in the channel and restrictbannedusers is enabled. + if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) + user->WriteNumeric(Numerics::CannotSendTo(chan, "You cannot send messages to this channel whilst banned.")); + return MOD_RES_DENY; + } + } + return CopyClientTags(details.tags_in, details.tags_out); } Version GetVersion() CXX11_OVERRIDE { - return Version("Provides the DRAFT message-tags IRCv3 extension", VF_VENDOR | VF_COMMON); + return Version("Provides the IRCv3 message-tags client capability.", VF_VENDOR | VF_COMMON); } };