X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fcoremods%2Fcore_list.cpp;h=28ea91ce154a174a62a5ad56d69b67ff16c26e40;hb=7b1ab06a9551d8db141ebc9213836af6b5369284;hp=278e6044d0e31fd2792d14a6ad89229849b0bbe6;hpb=bd1471bc08be28bc2554d35fdaeb078338b14266;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/coremods/core_list.cpp b/src/coremods/core_list.cpp index 278e6044d..28ea91ce1 100644 --- a/src/coremods/core_list.cpp +++ b/src/coremods/core_list.cpp @@ -1,8 +1,14 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2017-2020 Sadie Powell + * Copyright (C) 2015 Daniel Vassdal + * Copyright (C) 2013-2016 Attila Molnar + * Copyright (C) 2012 Robby * Copyright (C) 2009 Daniel De Graaf - * Copyright (C) 2007 Robin Burchell + * Copyright (C) 2008 Robin Burchell + * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2005-2007, 2010 Craig Edwards * * 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 @@ -24,17 +30,32 @@ */ class CommandList : public Command { + private: ChanModeReference secretmode; ChanModeReference privatemode; - public: - /** Constructor for list. + /** Parses the creation time or topic set time out of a LIST parameter. + * @param value The parameter containing a minute count. + * @return The UNIX time at \p value minutes ago. */ + time_t ParseMinutes(const std::string& value) + { + time_t minutes = ConvToNum(value.c_str() + 2); + if (!minutes) + return 0; + return ServerInstance->Time() - (minutes * 60); + } + + public: + // Whether to show modes in the LIST response. + bool showmodes; + CommandList(Module* parent) : Command(parent,"LIST", 0, 0) , secretmode(creator, "secret") , privatemode(creator, "private") { + allow_empty_last_param = false; Penalty = 5; } @@ -43,51 +64,114 @@ class CommandList : public Command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector& parameters, User *user); + CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; /** Handle /LIST */ -CmdResult CommandList::Handle (const std::vector& parameters, User *user) +CmdResult CommandList::Handle(User* user, const Params& parameters) { - int minusers = 0, maxusers = 0; - - user->WriteNumeric(RPL_LISTSTART, "Channel :Users Name"); - - /* Work around mIRC suckyness. YOU SUCK, KHALED! */ - if (parameters.size() == 1) + // C: Searching based on creation time, via the "Cval" modifiers + // to search for a channel creation time that is lower or higher than val + // respectively. + time_t mincreationtime = 0; + time_t maxcreationtime = 0; + + // M: Searching based on mask. + // N: Searching based on !mask. + bool match_name_topic = false; + bool match_inverted = false; + const char* match = NULL; + + // T: Searching based on topic time, via the "Tval" modifiers to + // search for a topic time that is lower or higher than val respectively. + time_t mintopictime = 0; + time_t maxtopictime = 0; + + // U: Searching based on user count within the channel, via the "val" modifiers to search for a channel that has less than or more than + // val users respectively. + size_t minusers = 0; + size_t maxusers = 0; + + for (Params::const_iterator iter = parameters.begin(); iter != parameters.end(); ++iter) { - if (parameters[0][0] == '<') + const std::string& constraint = *iter; + if (constraint[0] == '<') + { + maxusers = ConvToNum(constraint.c_str() + 1); + } + else if (constraint[0] == '>') + { + minusers = ConvToNum(constraint.c_str() + 1); + } + else if (!constraint.compare(0, 2, "C<", 2) || !constraint.compare(0, 2, "c<", 2)) + { + mincreationtime = ParseMinutes(constraint); + } + else if (!constraint.compare(0, 2, "C>", 2) || !constraint.compare(0, 2, "c>", 2)) { - maxusers = atoi((parameters[0].c_str())+1); + maxcreationtime = ParseMinutes(constraint); } - else if (parameters[0][0] == '>') + else if (!constraint.compare(0, 2, "T<", 2) || !constraint.compare(0, 2, "t<", 2)) { - minusers = atoi((parameters[0].c_str())+1); + mintopictime = ParseMinutes(constraint); + } + else if (!constraint.compare(0, 2, "T>", 2) || !constraint.compare(0, 2, "t>", 2)) + { + maxtopictime = ParseMinutes(constraint); + } + else + { + // If the glob is prefixed with ! it is inverted. + match = constraint.c_str(); + if (match[0] == '!') + { + match_inverted = true; + match += 1; + } + + // Ensure that the user didn't just run "LIST !". + if (match[0]) + match_name_topic = true; } } const bool has_privs = user->HasPrivPermission("channels/auspex"); - const bool match_name_topic = ((!parameters.empty()) && (!parameters[0].empty()) && (parameters[0][0] != '<') && (parameters[0][0] != '>')); + user->WriteNumeric(RPL_LISTSTART, "Channel", "Users Name"); const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) { Channel* const chan = i->second; - // attempt to match a glob pattern - long users = chan->GetUserCounter(); + // Check the user count if a search has been specified. + const size_t users = chan->GetUserCounter(); + if ((minusers && users <= minusers) || (maxusers && users >= maxusers)) + continue; - bool too_few = (minusers && (users <= minusers)); - bool too_many = (maxusers && (users >= maxusers)); + // Check the creation ts if a search has been specified. + const time_t creationtime = chan->age; + if ((mincreationtime && creationtime <= mincreationtime) || (maxcreationtime && creationtime >= maxcreationtime)) + continue; - if (too_many || too_few) + // Check the topic ts if a search has been specified. + const time_t topictime = chan->topicset; + if ((mintopictime && (!topictime || topictime <= mintopictime)) || (maxtopictime && (!topictime || topictime >= maxtopictime))) continue; + // Attempt to match a glob pattern. if (match_name_topic) { - if (!InspIRCd::Match(chan->name, parameters[0]) && !InspIRCd::Match(chan->topic, parameters[0])) + bool matches = InspIRCd::Match(chan->name, match) || InspIRCd::Match(chan->topic, match); + + // The user specified an match that we did not match. + if (!matches && !match_inverted) + continue; + + // The user specified an inverted match that we did match. + if (matches && match_inverted) continue; } @@ -100,19 +184,52 @@ CmdResult CommandList::Handle (const std::vector& parameters, User if ((!n) && (chan->IsModeSet(privatemode))) { // Channel is private (+p) and user is outside/not privileged - user->WriteNumeric(RPL_LIST, "* %ld :", users); + user->WriteNumeric(RPL_LIST, '*', users, ""); + } + else if (showmodes) + { + // Show the list response with the modes and topic. + user->WriteNumeric(RPL_LIST, chan->name, users, InspIRCd::Format("[+%s] %s", chan->ChanModes(n), chan->topic.c_str())); } else { - /* User is in the channel/privileged, channel is not +s */ - user->WriteNumeric(RPL_LIST, "%s %ld :[+%s] %s", chan->name.c_str(), users, chan->ChanModes(n), chan->topic.c_str()); + // Show the list response with just the modes. + user->WriteNumeric(RPL_LIST, chan->name, users, chan->topic); } } } - user->WriteNumeric(RPL_LISTEND, ":End of channel list."); + user->WriteNumeric(RPL_LISTEND, "End of channel list."); return CMD_SUCCESS; } +class CoreModList : public Module +{ + private: + CommandList cmd; + + public: + CoreModList() + : cmd(this) + { + } + + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE + { + ConfigTag* tag = ServerInstance->Config->ConfValue("options"); + cmd.showmodes = tag->getBool("modesinlist", true); + } + + void On005Numeric(std::map& tokens) CXX11_OVERRIDE + { + tokens["ELIST"] = "CMNTU"; + tokens["SAFELIST"]; + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Provides the LIST command", VF_VENDOR|VF_CORE); + } +}; -COMMAND_INIT(CommandList) +MODULE_INIT(CoreModList)