2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2017-2019 Sadie Powell <sadie@witchery.services>
5 * Copyright (C) 2015 Daniel Vassdal <shutter@canternet.org>
6 * Copyright (C) 2013-2016 Attila Molnar <attilamolnar@hush.com>
7 * Copyright (C) 2012 Robby <robby@chatbelgie.be>
8 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
9 * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
10 * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
11 * Copyright (C) 2006-2007, 2010 Craig Edwards <brain@inspircd.org>
13 * This file is part of InspIRCd. InspIRCd is free software: you can
14 * redistribute it and/or modify it under the terms of the GNU General Public
15 * License as published by the Free Software Foundation, version 2.
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 class CommandList : public Command
34 ChanModeReference secretmode;
35 ChanModeReference privatemode;
37 /** Parses the creation time or topic set time out of a LIST parameter.
38 * @param value The parameter containing a minute count.
39 * @return The UNIX time at \p value minutes ago.
41 time_t ParseMinutes(const std::string& value)
43 time_t minutes = ConvToNum<time_t>(value.c_str() + 2);
46 return ServerInstance->Time() - (minutes * 60);
50 /** Constructor for list.
52 CommandList(Module* parent)
53 : Command(parent,"LIST", 0, 0)
54 , secretmode(creator, "secret")
55 , privatemode(creator, "private")
57 allow_empty_last_param = false;
62 * @param parameters The parameters to the command
63 * @param user The user issuing the command
64 * @return A value from CmdResult to indicate command success or failure.
66 CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
72 CmdResult CommandList::Handle(User* user, const Params& parameters)
74 // C: Searching based on creation time, via the "C<val" and "C>val" modifiers
75 // to search for a channel creation time that is lower or higher than val
77 time_t mincreationtime = 0;
78 time_t maxcreationtime = 0;
80 // M: Searching based on mask.
81 // N: Searching based on !mask.
82 bool match_name_topic = false;
83 bool match_inverted = false;
84 const char* match = NULL;
86 // T: Searching based on topic time, via the "T<val" and "T>val" modifiers to
87 // search for a topic time that is lower or higher than val respectively.
88 time_t mintopictime = 0;
89 time_t maxtopictime = 0;
91 // U: Searching based on user count within the channel, via the "<val" and
92 // ">val" modifiers to search for a channel that has less than or more than
93 // val users respectively.
97 for (Params::const_iterator iter = parameters.begin(); iter != parameters.end(); ++iter)
99 const std::string& constraint = *iter;
100 if (constraint[0] == '<')
102 maxusers = ConvToNum<size_t>(constraint.c_str() + 1);
104 else if (constraint[0] == '>')
106 minusers = ConvToNum<size_t>(constraint.c_str() + 1);
108 else if (!constraint.compare(0, 2, "C<", 2) || !constraint.compare(0, 2, "c<", 2))
110 mincreationtime = ParseMinutes(constraint);
112 else if (!constraint.compare(0, 2, "C>", 2) || !constraint.compare(0, 2, "c>", 2))
114 maxcreationtime = ParseMinutes(constraint);
116 else if (!constraint.compare(0, 2, "T<", 2) || !constraint.compare(0, 2, "t<", 2))
118 mintopictime = ParseMinutes(constraint);
120 else if (!constraint.compare(0, 2, "T>", 2) || !constraint.compare(0, 2, "t>", 2))
122 maxtopictime = ParseMinutes(constraint);
126 // If the glob is prefixed with ! it is inverted.
127 match = constraint.c_str();
130 match_inverted = true;
134 // Ensure that the user didn't just run "LIST !".
136 match_name_topic = true;
140 const bool has_privs = user->HasPrivPermission("channels/auspex");
142 user->WriteNumeric(RPL_LISTSTART, "Channel", "Users Name");
143 const chan_hash& chans = ServerInstance->GetChans();
144 for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
146 Channel* const chan = i->second;
148 // Check the user count if a search has been specified.
149 const size_t users = chan->GetUserCounter();
150 if ((minusers && users <= minusers) || (maxusers && users >= maxusers))
153 // Check the creation ts if a search has been specified.
154 const time_t creationtime = chan->age;
155 if ((mincreationtime && creationtime <= mincreationtime) || (maxcreationtime && creationtime >= maxcreationtime))
158 // Check the topic ts if a search has been specified.
159 const time_t topictime = chan->topicset;
160 if ((mintopictime && (!topictime || topictime <= mintopictime)) || (maxtopictime && (!topictime || topictime >= maxtopictime)))
163 // Attempt to match a glob pattern.
164 if (match_name_topic)
166 bool matches = InspIRCd::Match(chan->name, match) || InspIRCd::Match(chan->topic, match);
168 // The user specified an match that we did not match.
169 if (!matches && !match_inverted)
172 // The user specified an inverted match that we did match.
173 if (matches && match_inverted)
177 // if the channel is not private/secret, OR the user is on the channel anyway
178 bool n = (has_privs || chan->HasUser(user));
180 // If we're not in the channel and +s is set on it, we want to ignore it
181 if ((n) || (!chan->IsModeSet(secretmode)))
183 if ((!n) && (chan->IsModeSet(privatemode)))
185 // Channel is private (+p) and user is outside/not privileged
186 user->WriteNumeric(RPL_LIST, '*', users, "");
190 /* User is in the channel/privileged, channel is not +s */
191 user->WriteNumeric(RPL_LIST, chan->name, users, InspIRCd::Format("[+%s] %s", chan->ChanModes(n), chan->topic.c_str()));
195 user->WriteNumeric(RPL_LISTEND, "End of channel list.");
200 class CoreModList : public Module
211 void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
213 tokens["ELIST"] = "CMNTU";
217 Version GetVersion() CXX11_OVERRIDE
219 return Version("Provides the LIST command", VF_VENDOR|VF_CORE);
223 MODULE_INIT(CoreModList)