anope

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

os_ignore.cpp (10282B)

      1 /* OperServ 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/os_ignore.h"
     14 
     15 struct IgnoreDataImpl : IgnoreData, Serializable
     16 {
     17 	IgnoreDataImpl() : Serializable("IgnoreData") { }
     18 	~IgnoreDataImpl();
     19 	void Serialize(Serialize::Data &data) const anope_override;
     20 	static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
     21 };
     22 
     23 IgnoreDataImpl::~IgnoreDataImpl()
     24 {
     25 	if (ignore_service)
     26 		ignore_service->DelIgnore(this);
     27 }
     28 
     29 void IgnoreDataImpl::Serialize(Serialize::Data &data) const
     30 {
     31 	data["mask"] << this->mask;
     32 	data["creator"] << this->creator;
     33 	data["reason"] << this->reason;
     34 	data["time"] << this->time;
     35 }
     36 
     37 Serializable* IgnoreDataImpl::Unserialize(Serializable *obj, Serialize::Data &data)
     38 {
     39 	if (!ignore_service)
     40 		return NULL;
     41 
     42 	IgnoreDataImpl *ign;
     43 	if (obj)
     44 		ign = anope_dynamic_static_cast<IgnoreDataImpl *>(obj);
     45 	else
     46 	{
     47 		ign = new IgnoreDataImpl();
     48 		ignore_service->AddIgnore(ign);
     49 	}
     50 
     51 	data["mask"] >> ign->mask;
     52 	data["creator"] >> ign->creator;
     53 	data["reason"] >> ign->reason;
     54 	data["time"] >> ign->time;
     55 
     56 	return ign;
     57 }
     58 
     59 
     60 class OSIgnoreService : public IgnoreService
     61 {
     62 	Serialize::Checker<std::vector<IgnoreData *> > ignores;
     63 
     64  public:
     65 	OSIgnoreService(Module *o) : IgnoreService(o), ignores("IgnoreData") { }
     66 
     67 	void AddIgnore(IgnoreData *ign) anope_override
     68 	{
     69 		ignores->push_back(ign);
     70 	}
     71 
     72 	void DelIgnore(IgnoreData *ign) anope_override
     73 	{
     74 		std::vector<IgnoreData *>::iterator it = std::find(ignores->begin(), ignores->end(), ign);
     75 		if (it != ignores->end())
     76 			ignores->erase(it);
     77 	}
     78 
     79 	void ClearIgnores() anope_override
     80 	{
     81 		for (unsigned i = ignores->size(); i > 0; --i)
     82 		{
     83 			IgnoreData *ign = ignores->at(i - 1);
     84 			delete ign;
     85 		}
     86 	}
     87 
     88 	IgnoreData *Create() anope_override
     89 	{
     90 		return new IgnoreDataImpl();
     91 	}
     92 
     93 	IgnoreData *Find(const Anope::string &mask) anope_override
     94 	{
     95 		User *u = User::Find(mask, true);
     96 		std::vector<IgnoreData *>::iterator ign = this->ignores->begin(), ign_end = this->ignores->end();
     97 
     98 		if (u)
     99 		{
    100 			for (; ign != ign_end; ++ign)
    101 			{
    102 				Entry ignore_mask("", (*ign)->mask);
    103 				if (ignore_mask.Matches(u, true))
    104 					break;
    105 			}
    106 		}
    107 		else
    108 		{
    109 			size_t user, host;
    110 			Anope::string tmp;
    111 			/* We didn't get a user.. generate a valid mask. */
    112 			if ((host = mask.find('@')) != Anope::string::npos)
    113 			{
    114 				if ((user = mask.find('!')) != Anope::string::npos)
    115 				{
    116 					/* this should never happen */
    117 					if (user > host)
    118 						return NULL;
    119 					tmp = mask;
    120 				}
    121 				else
    122 					/* We have user@host. Add nick wildcard. */
    123 				tmp = "*!" + mask;
    124 			}
    125 			/* We only got a nick.. */
    126 			else
    127 				tmp = mask + "!*@*";
    128 
    129 			for (; ign != ign_end; ++ign)
    130 				if (Anope::Match(tmp, (*ign)->mask, false, true))
    131 					break;
    132 		}
    133 
    134 		/* Check whether the entry has timed out */
    135 		if (ign != ign_end)
    136 		{
    137 			IgnoreData *id = *ign;
    138 
    139 			if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime)
    140 			{
    141 				Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask;
    142 				delete id;
    143 			}
    144 			else
    145 				return id;
    146 		}
    147 
    148 		return NULL;
    149 	}
    150 
    151 	std::vector<IgnoreData *> &GetIgnores() anope_override
    152 	{
    153 		return *ignores;
    154 	}
    155 };
    156 
    157 class CommandOSIgnore : public Command
    158 {
    159  private:
    160 	Anope::string RealMask(const Anope::string &mask)
    161 	{
    162 		/* If it s an existing user, we ignore the hostmask. */
    163 		User *u = User::Find(mask, true);
    164 		if (u)
    165 			return "*!*@" + u->host;
    166 
    167 		size_t host = mask.find('@');
    168 		/* Determine whether we get a nick or a mask. */
    169 		if (host != Anope::string::npos)
    170 		{
    171 			size_t user = mask.find('!');
    172 			/* Check whether we have a nick too.. */
    173 			if (user != Anope::string::npos)
    174 			{
    175 				if (user > host)
    176 					/* this should never happen */
    177 					return "";
    178 				else
    179 					return mask;
    180 			}
    181 			else
    182 				/* We have user@host. Add nick wildcard. */
    183 				return "*!" + mask;
    184 		}
    185 
    186 		/* We only got a nick.. */
    187 		return mask + "!*@*";
    188 	}
    189 
    190 	void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
    191 	{
    192 		if (!ignore_service)
    193 			return;
    194 
    195 		const Anope::string &time = params.size() > 1 ? params[1] : "";
    196 		const Anope::string &nick = params.size() > 2 ? params[2] : "";
    197 		const Anope::string &reason = params.size() > 3 ? params[3] : "";
    198 
    199 		if (time.empty() || nick.empty())
    200 		{
    201 			this->OnSyntaxError(source, "ADD");
    202 			return;
    203 		}
    204 		else
    205 		{
    206 			time_t t = Anope::DoTime(time);
    207 
    208 			if (t <= -1)
    209 			{
    210 				source.Reply(BAD_EXPIRY_TIME);
    211 				return;
    212 			}
    213 
    214 			Anope::string mask = RealMask(nick);
    215 			if (mask.empty())
    216 			{
    217 				source.Reply(BAD_USERHOST_MASK);
    218 				return;
    219 			}
    220 
    221 			if (Anope::ReadOnly)
    222 				source.Reply(READ_ONLY_MODE);
    223 
    224 			IgnoreData *ign = new IgnoreDataImpl();
    225 			ign->mask = mask;
    226 			ign->creator = source.GetNick();
    227 			ign->reason = reason;
    228 			ign->time = t ? Anope::CurTime + t : 0;
    229 
    230 			ignore_service->AddIgnore(ign);
    231 			if (!t)
    232 			{
    233 				source.Reply(_("\002%s\002 will now permanently be ignored."), mask.c_str());
    234 				Log(LOG_ADMIN, source, this) << "to add a permanent ignore for " << mask;
    235 			}
    236 			else
    237 			{
    238 				source.Reply(_("\002%s\002 will now be ignored for \002%s\002."), mask.c_str(), Anope::Duration(t, source.GetAccount()).c_str());
    239 				Log(LOG_ADMIN, source, this) << "to add an ignore on " << mask << " for " << Anope::Duration(t);
    240 			}
    241 		}
    242 	}
    243 
    244 	void DoList(CommandSource &source)
    245 	{
    246 		if (!ignore_service)
    247 			return;
    248 
    249 		std::vector<IgnoreData *> &ignores = ignore_service->GetIgnores();
    250 		for (unsigned i = ignores.size(); i > 0; --i)
    251 		{
    252 			IgnoreData *id = ignores[i - 1];
    253 
    254 			if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime)
    255 			{
    256 				Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask;
    257 				delete id;
    258 			}
    259 		}
    260 
    261 		if (ignores.empty())
    262 			source.Reply(_("Ignore list is empty."));
    263 		else
    264 		{
    265 			ListFormatter list(source.GetAccount());
    266 			list.AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Reason")).AddColumn(_("Expires"));
    267 
    268 			for (unsigned i = ignores.size(); i > 0; --i)
    269 			{
    270 				const IgnoreData *ignore = ignores[i - 1];
    271 
    272 				ListFormatter::ListEntry entry;
    273 				entry["Mask"] = ignore->mask;
    274 				entry["Creator"] = ignore->creator;
    275 				entry["Reason"] = ignore->reason;
    276 				entry["Expires"] = Anope::Expires(ignore->time, source.GetAccount());
    277 				list.AddEntry(entry);
    278 			}
    279 
    280 			source.Reply(_("Services ignore list:"));
    281 
    282 			std::vector<Anope::string> replies;
    283 			list.Process(replies);
    284 
    285 			for (unsigned i = 0; i < replies.size(); ++i)
    286 				source.Reply(replies[i]);
    287 		}
    288 	}
    289 
    290 	void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
    291 	{
    292 		if (!ignore_service)
    293 			return;
    294 
    295 		const Anope::string nick = params.size() > 1 ? params[1] : "";
    296 		if (nick.empty())
    297 		{
    298 			this->OnSyntaxError(source, "DEL");
    299 			return;
    300 		}
    301 
    302 		Anope::string mask = RealMask(nick);
    303 		if (mask.empty())
    304 		{
    305 			source.Reply(BAD_USERHOST_MASK);
    306 			return;
    307 		}
    308 
    309 		IgnoreData *ign = ignore_service->Find(mask);
    310 		if (ign)
    311 		{
    312 			if (Anope::ReadOnly)
    313 				source.Reply(READ_ONLY_MODE);
    314 
    315 			Log(LOG_ADMIN, source, this) << "to remove an ignore on " << mask;
    316 			source.Reply(_("\002%s\002 will no longer be ignored."), mask.c_str());
    317 			delete ign;
    318 		}
    319 		else
    320 			source.Reply(_("\002%s\002 not found on ignore list."), mask.c_str());
    321 	}
    322 
    323 	void DoClear(CommandSource &source)
    324 	{
    325 		if (!ignore_service)
    326 			return;
    327 
    328 		if (Anope::ReadOnly)
    329 			source.Reply(READ_ONLY_MODE);
    330 
    331 		ignore_service->ClearIgnores();
    332 		Log(LOG_ADMIN, source, this) << "to CLEAR the list";
    333 		source.Reply(_("Ignore list has been cleared."));
    334 
    335 		return;
    336 	}
    337 
    338  public:
    339 	CommandOSIgnore(Module *creator) : Command(creator, "operserv/ignore", 1, 4)
    340 	{
    341 		this->SetDesc(_("Modify the Services ignore list"));
    342 		this->SetSyntax(_("ADD \037expiry\037 {\037nick\037|\037mask\037} [\037reason\037]"));
    343 		this->SetSyntax(_("DEL {\037nick\037|\037mask\037}"));
    344 		this->SetSyntax("LIST");
    345 		this->SetSyntax("CLEAR");
    346 	}
    347 
    348 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    349 	{
    350 		const Anope::string &cmd = params[0];
    351 
    352 		if (cmd.equals_ci("ADD"))
    353 			return this->DoAdd(source, params);
    354 		else if (cmd.equals_ci("LIST"))
    355 			return this->DoList(source);
    356 		else if (cmd.equals_ci("DEL"))
    357 			return this->DoDel(source, params);
    358 		else if (cmd.equals_ci("CLEAR"))
    359 			return this->DoClear(source);
    360 		else
    361 			this->OnSyntaxError(source, "");
    362 
    363 		return;
    364 	}
    365 
    366 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    367 	{
    368 		this->SendSyntax(source);
    369 		source.Reply(" ");
    370 		source.Reply(_("Allows Services Operators to make Services ignore a nick or mask\n"
    371 				"for a certain time or until the next restart. The default\n"
    372 				"time format is seconds. You can specify it by using units.\n"
    373 				"Valid units are: \037s\037 for seconds, \037m\037 for minutes,\n"
    374 				"\037h\037 for hours and \037d\037 for days.\n"
    375 				"Combinations of these units are not permitted.\n"
    376 				"To make Services permanently ignore the user, type 0 as time.\n"
    377 				"When adding a \037mask\037, it should be in the format nick!user@host,\n"
    378 				"everything else will be considered a nick. Wildcards are permitted.\n"
    379 				" \n"
    380 				"Ignores will not be enforced on IRC Operators."));
    381 
    382 		const Anope::string &regexengine = Config->GetBlock("options")->Get<const Anope::string>("regexengine");
    383 		if (!regexengine.empty())
    384 		{
    385 			source.Reply(" ");
    386 			source.Reply(_("Regex matches are also supported using the %s engine.\n"
    387 					"Enclose your pattern in // if this is desired."), regexengine.c_str());
    388 		}
    389 
    390 		return true;
    391 	}
    392 };
    393 
    394 class OSIgnore : public Module
    395 {
    396 	Serialize::Type ignoredata_type;
    397 	OSIgnoreService osignoreservice;
    398 	CommandOSIgnore commandosignore;
    399 
    400  public:
    401 	OSIgnore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
    402 		ignoredata_type("IgnoreData", IgnoreDataImpl::Unserialize), osignoreservice(this), commandosignore(this)
    403 	{
    404 
    405 	}
    406 
    407 	EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) anope_override
    408 	{
    409 		if (!u->HasMode("OPER") && this->osignoreservice.Find(u->nick))
    410 			return EVENT_STOP;
    411 
    412 		return EVENT_CONTINUE;
    413 	}
    414 };
    415 
    416 MODULE_INIT(OSIgnore)