X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fcoremods%2Fcore_privmsg.cpp;h=692a661b3aea7cd9368df2a0b2259a9fd203df3a;hb=a032cd90ad5582914759e226085efee5aae1a1ef;hp=2daeef3ad6636ac6d852b1b1df4596eb111c7c42;hpb=58a0a7e01422e62de1565a8eb0a1febdc463d04d;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/coremods/core_privmsg.cpp b/src/coremods/core_privmsg.cpp index 2daeef3ad..692a661b3 100644 --- a/src/coremods/core_privmsg.cpp +++ b/src/coremods/core_privmsg.cpp @@ -21,18 +21,98 @@ #include "inspircd.h" +class MessageDetailsImpl : public MessageDetails +{ +public: + MessageDetailsImpl(MessageType mt, const std::string& msg, const ClientProtocol::TagMap& tags) + : MessageDetails(mt, msg, tags) + { + } + + bool IsCTCP(std::string& name, std::string& body) const CXX11_OVERRIDE + { + if (!this->IsCTCP()) + return false; + + size_t end_of_name = text.find(' ', 2); + size_t end_of_ctcp = *text.rbegin() == '\x1' ? 1 : 0; + if (end_of_name == std::string::npos) + { + // The CTCP only contains a name. + name.assign(text, 1, text.length() - 1 - end_of_ctcp); + body.clear(); + return true; + } + + // The CTCP contains a name and a body. + name.assign(text, 1, end_of_name - 1); + + size_t start_of_body = text.find_first_not_of(' ', end_of_name + 1); + if (start_of_body == std::string::npos) + { + // The CTCP body is provided but empty. + body.clear(); + return true; + } + + // The CTCP body provided was non-empty. + body.assign(text, start_of_body, text.length() - start_of_body - end_of_ctcp); + return true; + } + + bool IsCTCP(std::string& name) const CXX11_OVERRIDE + { + if (!this->IsCTCP()) + return false; + + size_t end_of_name = text.find(' ', 2); + if (end_of_name == std::string::npos) + { + // The CTCP only contains a name. + size_t end_of_ctcp = *text.rbegin() == '\x1' ? 1 : 0; + name.assign(text, 1, text.length() - 1 - end_of_ctcp); + return true; + } + + // The CTCP contains a name and a body. + name.assign(text, 1, end_of_name - 1); + return true; + } + + bool IsCTCP() const CXX11_OVERRIDE + { + // According to draft-oakley-irc-ctcp-02 a valid CTCP must begin with SOH and + // contain at least one octet which is not NUL, SOH, CR, LF, or SPACE. As most + // of these are restricted at the protocol level we only need to check for SOH + // and SPACE. + return (text.length() >= 2) && (text[0] == '\x1') && (text[1] != '\x1') && (text[1] != ' '); + } +}; + class MessageCommandBase : public Command { ChanModeReference moderatedmode; ChanModeReference noextmsgmode; /** Send a PRIVMSG or NOTICE message to all local users from the given user - * @param user User sending the message - * @param msg The message to send - * @param mt Type of the message (MSG_PRIVMSG or MSG_NOTICE) - * @param tags Message tags to include in the outgoing protocol message + * @param source The user sending the message. + * @param msg The details of the message to send. */ - static void SendAll(User* user, const std::string& msg, MessageType mt, const ClientProtocol::TagMap& tags); + static void SendAll(User* source, const MessageDetails& details) + { + ClientProtocol::Messages::Privmsg message(ClientProtocol::Messages::Privmsg::nocopy, source, "$*", details.text, details.type); + message.AddTags(details.tags_out); + message.SetSideEffect(true); + ClientProtocol::Event messageevent(ServerInstance->GetRFCEvents().privmsg, message); + + const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); + for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) + { + LocalUser* user = *i; + if ((user->registered == REG_ALL) && (!details.exemptions.count(user))) + user->Send(messageevent); + } + } public: MessageCommandBase(Module* parent, MessageType mt) @@ -60,30 +140,11 @@ class MessageCommandBase : public Command } }; -void MessageCommandBase::SendAll(User* user, const std::string& msg, MessageType mt, const ClientProtocol::TagMap& tags) -{ - ClientProtocol::Messages::Privmsg message(ClientProtocol::Messages::Privmsg::nocopy, user, "$*", msg, mt); - message.AddTags(tags); - message.SetSideEffect(true); - ClientProtocol::Event messageevent(ServerInstance->GetRFCEvents().privmsg, message); - - const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); - for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) - { - if ((*i)->registered == REG_ALL) - (*i)->Send(messageevent); - } -} - CmdResult MessageCommandBase::HandleMessage(User* user, const Params& parameters, MessageType mt) { User *dest; Channel *chan; - LocalUser* localuser = IS_LOCAL(user); - if (localuser) - localuser->idle_lastmsg = ServerInstance->Time(); - if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; @@ -94,7 +155,7 @@ CmdResult MessageCommandBase::HandleMessage(User* user, const Params& parameters std::string servername(parameters[0], 1); MessageTarget msgtarget(&servername); - MessageDetails msgdetails(mt, parameters[1], parameters.GetTags()); + MessageDetailsImpl msgdetails(mt, parameters[1], parameters.GetTags()); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, msgtarget, msgdetails)); @@ -107,7 +168,7 @@ CmdResult MessageCommandBase::HandleMessage(User* user, const Params& parameters FOREACH_MOD(OnUserMessage, (user, msgtarget, msgdetails)); if (InspIRCd::Match(ServerInstance->Config->ServerName, servername, NULL)) { - SendAll(user, msgdetails.text, mt, msgdetails.tags_out); + SendAll(user, msgdetails); } FOREACH_MOD(OnUserPostMessage, (user, msgtarget, msgdetails)); return CMD_SUCCESS; @@ -127,7 +188,7 @@ CmdResult MessageCommandBase::HandleMessage(User* user, const Params& parameters if (chan) { - if (localuser && chan->GetPrefixValue(user) < VOICE_VALUE) + if (IS_LOCAL(user) && chan->GetPrefixValue(user) < VOICE_VALUE) { if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user)) { @@ -153,7 +214,7 @@ CmdResult MessageCommandBase::HandleMessage(User* user, const Params& parameters } MessageTarget msgtarget(chan, status); - MessageDetails msgdetails(mt, parameters[1], parameters.GetTags()); + MessageDetailsImpl msgdetails(mt, parameters[1], parameters.GetTags()); msgdetails.exemptions.insert(user); ModResult MOD_RESULT; @@ -191,7 +252,7 @@ CmdResult MessageCommandBase::HandleMessage(User* user, const Params& parameters const char* destnick = parameters[0].c_str(); - if (localuser) + if (IS_LOCAL(user)) { const char* targetserver = strchr(destnick, '@'); @@ -229,7 +290,7 @@ CmdResult MessageCommandBase::HandleMessage(User* user, const Params& parameters } MessageTarget msgtarget(dest); - MessageDetails msgdetails(mt, parameters[1], parameters.GetTags()); + MessageDetailsImpl msgdetails(mt, parameters[1], parameters.GetTags()); ModResult MOD_RESULT; @@ -289,6 +350,20 @@ class ModuleCoreMessage : public Module { } + void OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details) CXX11_OVERRIDE + { + // We only handle the idle times of local users. + LocalUser* luser = IS_LOCAL(user); + if (!luser) + return; + + // We don't update the idle time when a CTCP reply is sent. + if (details.type == MSG_NOTICE && details.IsCTCP()) + return; + + luser->idle_lastmsg = ServerInstance->Time(); + } + Version GetVersion() CXX11_OVERRIDE { return Version("PRIVMSG, NOTICE", VF_CORE|VF_VENDOR);