anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

cs_list.cpp (8292B)

      1 /* ChanServ core functions
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "module.h"
     13 #include "modules/cs_mode.h"
     14 
     15 class CommandCSList : public Command
     16 {
     17  public:
     18 	CommandCSList(Module *creator) : Command(creator, "chanserv/list", 1, 2)
     19 	{
     20 		this->SetDesc(_("Lists all registered channels matching the given pattern"));
     21 		this->SetSyntax(_("\037pattern\037 [SUSPENDED] [NOEXPIRE]"));
     22 	}
     23 
     24 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
     25 	{
     26 		Anope::string pattern = params[0];
     27 		unsigned nchans;
     28 		bool is_servadmin = source.HasCommand("chanserv/list");
     29 		int count = 0, from = 0, to = 0;
     30 		bool suspended = false, channoexpire = false;
     31 
     32 		if (pattern[0] == '#')
     33 		{
     34 			Anope::string n1, n2;
     35 			sepstream(pattern.substr(1), '-').GetToken(n1, 0);
     36 			sepstream(pattern, '-').GetToken(n2, 1);
     37 
     38 			try
     39 			{
     40 				from = convertTo<int>(n1);
     41 				to = convertTo<int>(n2);
     42 			}
     43 			catch (const ConvertException &)
     44 			{
     45 				source.Reply(LIST_INCORRECT_RANGE);
     46 				source.Reply(_("To search for channels starting with #, search for the channel\n"
     47 					"name without the #-sign prepended (\002anope\002 instead of \002#anope\002)."));
     48 				return;
     49 			}
     50 
     51 			pattern = "*";
     52 		}
     53 
     54 		nchans = 0;
     55 
     56 		if (is_servadmin && params.size() > 1)
     57 		{
     58 			Anope::string keyword;
     59 			spacesepstream keywords(params[1]);
     60 			while (keywords.GetToken(keyword))
     61 			{
     62 				if (keyword.equals_ci("SUSPENDED"))
     63 					suspended = true;
     64 				if (keyword.equals_ci("NOEXPIRE"))
     65 					channoexpire = true;
     66 			}
     67 		}
     68 
     69 		Anope::string spattern = "#" + pattern;
     70 		unsigned listmax = Config->GetModule(this->owner)->Get<unsigned>("listmax", "50");
     71 
     72 		source.Reply(_("List of entries matching \002%s\002:"), pattern.c_str());
     73 
     74 		ListFormatter list(source.GetAccount());
     75 		list.AddColumn(_("Name")).AddColumn(_("Description"));
     76 
     77 		Anope::map<ChannelInfo *> ordered_map;
     78 		for (registered_channel_map::const_iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it)
     79 			ordered_map[it->first] = it->second;
     80 
     81 		for (Anope::map<ChannelInfo *>::const_iterator it = ordered_map.begin(), it_end = ordered_map.end(); it != it_end; ++it)
     82 		{
     83 			const ChannelInfo *ci = it->second;
     84 
     85 			if (!is_servadmin)
     86 			{
     87 				if (ci->HasExt("CS_PRIVATE") || ci->HasExt("CS_SUSPENDED"))
     88 					continue;
     89 				if (ci->c && ci->c->HasMode("SECRET"))
     90 					continue;
     91 
     92 				ModeLocks *ml = ci->GetExt<ModeLocks>("modelocks");
     93 				const ModeLock *secret = ml ? ml->GetMLock("SECRET") : NULL;
     94 				if (secret && secret->set)
     95 					continue;
     96 			}
     97 
     98 			if (suspended && !ci->HasExt("CS_SUSPENDED"))
     99 				continue;
    100 
    101 			if (channoexpire && !ci->HasExt("CS_NO_EXPIRE"))
    102 				continue;
    103 
    104 			if (pattern.equals_ci(ci->name) || ci->name.equals_ci(spattern) || Anope::Match(ci->name, pattern, false, true) || Anope::Match(ci->name, spattern, false, true) || Anope::Match(ci->desc, pattern, false, true) || Anope::Match(ci->last_topic, pattern, false, true))
    105 			{
    106 				if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nchans <= listmax)
    107 				{
    108 					bool isnoexpire = false;
    109 					if (is_servadmin && (ci->HasExt("CS_NO_EXPIRE")))
    110 						isnoexpire = true;
    111 
    112 					ListFormatter::ListEntry entry;
    113 					entry["Name"] = (isnoexpire ? "!" : "") + ci->name;
    114 					if (ci->HasExt("CS_SUSPENDED"))
    115 						entry["Description"] = Language::Translate(source.GetAccount(), _("[Suspended]"));
    116 					else
    117 						entry["Description"] = ci->desc;
    118 					list.AddEntry(entry);
    119 				}
    120 				++count;
    121 			}
    122 		}
    123 
    124 		std::vector<Anope::string> replies;
    125 		list.Process(replies);
    126 
    127 		for (unsigned i = 0; i < replies.size(); ++i)
    128 			source.Reply(replies[i]);
    129 
    130 		source.Reply(_("End of list - %d/%d matches shown."), nchans > listmax ? listmax : nchans, nchans);
    131 	}
    132 
    133 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    134 	{
    135 		this->SendSyntax(source);
    136 		source.Reply(" ");
    137 		source.Reply(_("Lists all registered channels matching the given pattern.\n"
    138 				"Channels with the \002PRIVATE\002 option set will only be\n"
    139 				"displayed to Services Operators with the proper access.\n"
    140 				"Channels with the \002NOEXPIRE\002 option set will have\n"
    141 				"a \002!\002 prefixed to the channel for Services Operators to see.\n"
    142 				" \n"
    143 				"Note that a preceding '#' specifies a range, channel names\n"
    144 				"are to be written without '#'.\n"
    145 				" \n"
    146 				"If the SUSPENDED or NOEXPIRE options are given, only channels\n"
    147 				"which, respectively, are SUSPENDED or have the NOEXPIRE\n"
    148 				"flag set will be displayed. If multiple options are given,\n"
    149 				"all channels matching at least one option will be displayed.\n"
    150 				"Note that these options are limited to \037Services Operators\037.\n"
    151 				" \n"
    152 				"Examples:\n"
    153 				" \n"
    154 				"    \002LIST *anope*\002\n"
    155 				"        Lists all registered channels with \002anope\002 in their\n"
    156 				"        names (case insensitive).\n"
    157 				" \n"
    158 				"    \002LIST * NOEXPIRE\002\n"
    159 				"        Lists all registered channels which have been set to not expire.\n"
    160 				" \n"
    161 				"    \002LIST #51-100\002\n"
    162 				"        Lists all registered channels within the given range (51-100)."));
    163 
    164 		if (!Config->GetBlock("options")->Get<const Anope::string>("regexengine").empty())
    165 		{
    166 			source.Reply(" ");
    167 			source.Reply(_("Regex matches are also supported using the %s engine.\n"
    168 					"Enclose your pattern in // if this is desired."), Config->GetBlock("options")->Get<const Anope::string>("regexengine").c_str());
    169 		}
    170 
    171 		return true;
    172 	}
    173 };
    174 
    175 class CommandCSSetPrivate : public Command
    176 {
    177  public:
    178 	CommandCSSetPrivate(Module *creator, const Anope::string &cname = "chanserv/set/private") : Command(creator, cname, 2, 2)
    179 	{
    180 		this->SetDesc(_("Hide channel from the LIST command"));
    181 		this->SetSyntax(_("\037channel\037 {ON | OFF}"));
    182 	}
    183 
    184 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    185 	{
    186 		if (Anope::ReadOnly)
    187 		{
    188 			source.Reply(READ_ONLY_MODE);
    189 			return;
    190 		}
    191 
    192 		ChannelInfo *ci = ChannelInfo::Find(params[0]);
    193 		if (ci == NULL)
    194 		{
    195 			source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
    196 			return;
    197 		}
    198 
    199 		EventReturn MOD_RESULT;
    200 		FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1]));
    201 		if (MOD_RESULT == EVENT_STOP)
    202 			return;
    203 
    204 		if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration"))
    205 		{
    206 			source.Reply(ACCESS_DENIED);
    207 			return;
    208 		}
    209 
    210 		if (params[1].equals_ci("ON"))
    211 		{
    212 			Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable private";
    213 			ci->Extend<bool>("CS_PRIVATE");
    214 			source.Reply(_("Private option for %s is now \002on\002."), ci->name.c_str());
    215 		}
    216 		else if (params[1].equals_ci("OFF"))
    217 		{
    218 			Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable private";
    219 			ci->Shrink<bool>("CS_PRIVATE");
    220 			source.Reply(_("Private option for %s is now \002off\002."), ci->name.c_str());
    221 		}
    222 		else
    223 			this->OnSyntaxError(source, "PRIVATE");
    224 
    225 		return;
    226 	}
    227 
    228 	bool OnHelp(CommandSource &source, const Anope::string &) anope_override
    229 	{
    230 		this->SendSyntax(source);
    231 		source.Reply(" ");
    232 		source.Reply(_("Enables or disables the \002private\002 option for a channel."));
    233 
    234 		BotInfo *bi;
    235 		Anope::string cmd;
    236 		if (Command::FindCommandFromService("chanserv/list", bi, cmd))
    237 			source.Reply(_("When \002private\002 is set, the channel will not appear in\n"
    238 				"%s's %s command."), bi->nick.c_str(), cmd.c_str());
    239 		return true;
    240 	}
    241 };
    242 
    243 class CSList : public Module
    244 {
    245 	CommandCSList commandcslist;
    246 	CommandCSSetPrivate commandcssetprivate;
    247 
    248 	SerializableExtensibleItem<bool> priv;
    249 
    250  public:
    251 	CSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
    252 		commandcslist(this), commandcssetprivate(this), priv(this, "CS_PRIVATE")
    253 	{
    254 	}
    255 
    256 	void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override
    257 	{
    258 		if (!show_all)
    259 			return;
    260 
    261 		if (priv.HasExt(ci))
    262 			info.AddOption(_("Private"));
    263 	}
    264 };
    265 
    266 MODULE_INIT(CSList)