Exemple #1
0
	bool MatchLine(Membership* memb, ChannelSettings* rs, std::string message)
	{
		// If the message is larger than whatever size it's set to,
		// let's pretend it isn't. If the first 512 (def. setting) match, it's probably spam.
		if (message.size() > ms.MaxMessageSize)
			message.erase(ms.MaxMessageSize);

		MemberInfo* rp = MemberInfoExt.get(memb);
		if (!rp)
		{
			rp = new MemberInfo;
			MemberInfoExt.set(memb, rp);
		}

		unsigned int matches = 0;
		if (!rs->Backlog)
			matches = rp->Counter;

		RepeatItemList& items = rp->ItemList;
		const unsigned int trigger = (message.size() * rs->Diff / 100);
		const time_t now = ServerInstance->Time();

		std::transform(message.begin(), message.end(), message.begin(), ::tolower);

		for (std::deque<RepeatItem>::iterator it = items.begin(); it != items.end(); ++it)
		{
			if (it->ts < now)
			{
				items.erase(it, items.end());
				matches = 0;
				break;
			}

			if (CompareLines(message, it->line, trigger))
			{
				if (++matches >= rs->Lines)
				{
					if (rs->Action != ChannelSettings::ACT_BLOCK)
						rp->Counter = 0;
					return true;
				}
			}
			else if ((ms.MaxBacklog == 0) || (rs->Backlog == 0))
			{
				matches = 0;
				items.clear();
				break;
			}
		}

		unsigned int max_items = (rs->Backlog ? rs->Backlog : 1);
		if (items.size() >= max_items)
			items.pop_back();

		items.push_front(RepeatItem(now + rs->Seconds, message));
		rp->Counter = matches;
		return false;
	}
Exemple #2
0
	CmdResult add_watch(User* user, const char* nick)
	{
		if (!ServerInstance->IsNick(nick))
		{
			user->WriteNumeric(942, "%s :Invalid nickname", nick);
			return CMD_FAILURE;
		}

		watchlist* wl = ext.get(user);
		if (!wl)
		{
			wl = new watchlist();
			ext.set(user, wl);
		}

		if (wl->size() == MAX_WATCH)
		{
			user->WriteNumeric(512, "%s :Too many WATCH entries", nick);
			return CMD_FAILURE;
		}

		watchlist::iterator n = wl->find(nick);
		if (n == wl->end())
		{
			/* Don't already have the user on my watch list, proceed */
			watchentries::iterator x = whos_watching_me->find(nick);
			if (x != whos_watching_me->end())
			{
				/* People are watching this user, add myself */
				x->second.push_back(user);
			}
			else
			{
				std::deque<User*> newlist;
				newlist.push_back(user);
				(*(whos_watching_me))[nick] = newlist;
			}

			User* target = ServerInstance->FindNick(nick);
			if (target)
			{
				(*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age));
				user->WriteNumeric(604, "%s %s :is online", nick, (*wl)[nick].c_str());
				if (target->IsAway())
				{
					user->WriteNumeric(609, "%s %s %s %lu :is away", target->nick.c_str(), target->ident.c_str(), target->dhost.c_str(), (unsigned long) target->awaytime);
				}
			}
			else
			{
				(*wl)[nick].clear();
				user->WriteNumeric(605, "%s * * 0 :is offline", nick);
			}
		}

		return CMD_SUCCESS;
	}
Exemple #3
0
	virtual void OnUserDisconnect(LocalUser *user)
	{
		/* User disconnect (generic socket detatch event) */
		IdentRequestSocket *isock = ext.get(user);
		if (isock)
		{
			isock->Close();
			ext.unset(user);
		}
	}
Exemple #4
0
	CmdResult remove_watch(User* user, const char* nick)
	{
		// removing an item from the list
		if (!ServerInstance->IsNick(nick))
		{
			user->WriteNumeric(942, "%s :Invalid nickname", nick);
			return CMD_FAILURE;
		}

		watchlist* wl = ext.get(user);
		if (wl)
		{
			/* Yup, is on my list */
			watchlist::iterator n = wl->find(nick);

			if (!wl)
				return CMD_FAILURE;

			if (n != wl->end())
			{
				if (!n->second.empty())
					user->WriteNumeric(602, "%s %s :stopped watching", n->first.c_str(), n->second.c_str());
				else
					user->WriteNumeric(602, "%s * * 0 :stopped watching", nick);

				wl->erase(n);
			}

			if (wl->empty())
			{
				ext.unset(user);
			}

			watchentries::iterator x = whos_watching_me->find(nick);
			if (x != whos_watching_me->end())
			{
				/* People are watching this user, am i one of them? */
				std::deque<User*>::iterator n2 = std::find(x->second.begin(), x->second.end(), user);
				if (n2 != x->second.end())
					/* I'm no longer watching you... */
					x->second.erase(n2);

				if (x->second.empty())
					/* nobody else is, either. */
					whos_watching_me->erase(nick);
			}
		}

		return CMD_SUCCESS;
	}
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		ModeAction rv = ParamChannelModeHandler::OnModeChange(source, dest, channel, parameter, adding);
		if (rv == MODEACTION_ALLOW && !adding)
			ext.unset(channel);
		return rv;
	}
Exemple #6
0
	void OnUnset(User* source, Channel* chan) override
	{
		// Unset the per-membership extension when the mode is removed
		const Channel::MemberMap& users = chan->GetUsers();
		for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
			MemberInfoExt.unset(i->second);
	}
Exemple #7
0
	/* This triggers pretty regularly, we can use it in preference to
	 * creating a Timer object and especially better than creating a
	 * Timer per ident lookup!
	 */
	virtual ModResult OnCheckReady(LocalUser *user)
	{
		/* Does user have an ident socket attached at all? */
		IdentRequestSocket *isock = ext.get(user);
		if (!isock)
		{
			ServerInstance->Logs->Log("m_ident",DEBUG, "No ident socket :(");
			return MOD_RES_PASSTHRU;
		}

		ServerInstance->Logs->Log("m_ident",DEBUG, "Has ident_socket");

		time_t compare = isock->age;
		compare += RequestTimeout;

		/* Check for timeout of the socket */
		if (ServerInstance->Time() >= compare)
		{
			/* Ident timeout */
			user->WriteServ("NOTICE Auth :*** Ident request timed out.");
			ServerInstance->Logs->Log("m_ident",DEBUG, "Timeout");
		}
		else if (!isock->HasResult())
		{
			// time still good, no result yet... hold the registration
			ServerInstance->Logs->Log("m_ident",DEBUG, "No result yet");
			return MOD_RES_DENY;
		}

		ServerInstance->Logs->Log("m_ident",DEBUG, "Yay, result!");

		/* wooo, got a result (it will be good, or bad) */
		if (isock->result.empty())
		{
			user->ident.insert(0, 1, '~');
			user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", user->ident.c_str());
		}
		else
		{
			user->ident = isock->result;
			user->WriteServ("NOTICE Auth :*** Found your ident, '%s'", user->ident.c_str());
		}

		isock->Close();
		ext.unset(user);
		return MOD_RES_PASSTHRU;
	}
Exemple #8
0
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
			{
				source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
				return MODEACTION_DENY;
			}

			/* Set up the flood parameters for this channel */
			unsigned int njoins = ConvToInt(parameter.substr(0, colon));
			unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
			if ((njoins<1) || (nsecs<1))
			{
				source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
				return MODEACTION_DENY;
			}

			joinfloodsettings jfs(nsecs, njoins);
			joinfloodsettings* f = ext.get(channel);
			if ((f) && (*f == jfs))
				// mode params match
				return MODEACTION_DENY;

			ext.set(channel, jfs);
			parameter = ConvToStr(njoins) + ":" + ConvToStr(nsecs);
			channel->SetModeParam(this, parameter);
			return MODEACTION_ALLOW;
		}
		else
		{
			if (!channel->IsModeSet(this))
				return MODEACTION_DENY;

			joinfloodsettings* f = ext.get(channel);
			if (f)
			{
				ext.unset(channel);
				channel->SetModeParam(this, "");
				return MODEACTION_ALLOW;
			}
		}
		return MODEACTION_DENY;
	}
Exemple #9
0
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if (colon == std::string::npos)
				return MODEACTION_DENY;

			std::string duration = parameter.substr(colon+1);
			if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration))))
				return MODEACTION_DENY;

			unsigned int len = ConvToInt(parameter.substr(0, colon));
			int time = InspIRCd::Duration(duration);
			if (len == 0 || time < 0)
				return MODEACTION_DENY;
			if (len > maxlines && IS_LOCAL(source))
				return MODEACTION_DENY;
			if (len > maxlines)
				len = maxlines;
			if (parameter == channel->GetModeParameter(this))
				return MODEACTION_DENY;

			HistoryList* history = ext.get(channel);
			if (history)
			{
				// Shrink the list if the new line number limit is lower than the old one
				if (len < history->lines.size())
					history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len));

				history->maxlen = len;
				history->maxtime = time;
			}
			else
			{
				ext.set(channel, new HistoryList(len, time));
			}
		}
		else
		{
			if (!channel->IsModeSet(this))
				return MODEACTION_DENY;
			ext.unset(channel);
		}
		return MODEACTION_ALLOW;
	}
Exemple #10
0
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
			{
				source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str());
				return MODEACTION_DENY;
			}

			/* Set up the flood parameters for this channel */
			bool ban = (parameter[0] == '*');
			unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon));
			unsigned int nsecs = ConvToInt(parameter.substr(colon+1));

			if ((nlines<2) || (nsecs<1))
			{
				source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str());
				return MODEACTION_DENY;
			}

			floodsettings* f = ext.get(channel);
			if ((f) && (nlines == f->lines) && (nsecs == f->secs) && (ban == f->ban))
				// mode params match
				return MODEACTION_DENY;

			ext.set(channel, new floodsettings(ban, nsecs, nlines));
			parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs);
			return MODEACTION_ALLOW;
		}
		else
		{
			if (!channel->IsModeSet(this))
				return MODEACTION_DENY;

			ext.unset(channel);
			return MODEACTION_ALLOW;
		}
	}
	ModeAction OnModeChange(User* source, User* dest, Channel* chan, std::string& parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if (colon == std::string::npos || parameter.find('-') != std::string::npos)
			{
				source->WriteNumeric(608, "%s %s :Invalid join/part spam parameter", source->nick.c_str(), chan->name.c_str());
				return MODEACTION_DENY;
			}

			unsigned int ncycles = ConvToInt(parameter.substr(0, colon));
			unsigned int nsecs = ConvToInt(parameter.substr(colon+1));

			if (ncycles < 2 || nsecs < 1)
			{
				source->WriteNumeric(608, "%s %s :Invalid join/part spam parameter", source->nick.c_str(), chan->name.c_str());
				return MODEACTION_DENY;
			}

			joinpartspamsettings* jpss = ext.get(chan);
			if (jpss && ncycles == jpss->cycles && nsecs == jpss->secs)
				return MODEACTION_DENY;

			ext.set(chan, new joinpartspamsettings(ncycles, nsecs));
			parameter = ConvToStr(ncycles) + ":" + ConvToStr(nsecs);
			chan->SetModeParam(GetModeChar(), parameter);
			return MODEACTION_ALLOW;
		}
		else
		{
			if (!chan->IsModeSet(GetModeChar()))
				return MODEACTION_DENY;

			ext.unset(chan);
			chan->SetModeParam(GetModeChar(), "");
			return MODEACTION_ALLOW;
		}
	}
	ModResult ProcessMessages(User* user, Channel* dest)
	{
		if (!IS_LOCAL(user) || !dest->IsModeSet(mf.GetModeChar()))
			return MOD_RES_PASSTHRU;

		if (ServerInstance->OnCheckExemption(user, dest, "slowmode") == MOD_RES_ALLOW)
			return MOD_RES_PASSTHRU;

		slowmodesettings *f = ext.get(dest);
		if (f == NULL || !f->addmessage())
			return MOD_RES_PASSTHRU;

		user->WriteNumeric(404, "%s %s :Message throttled due to flood", user->nick.c_str(), dest->name.c_str());
		return MOD_RES_DENY;
	}
Exemple #13
0
	void OnUserInit(LocalUser *user)
	{
		ConfigTag* tag = user->MyClass->config;
		if (!tag->getBool("useident", true))
			return;

		user->WriteServ("NOTICE Auth :*** Looking up your ident...");

		try
		{
			IdentRequestSocket *isock = new IdentRequestSocket(IS_LOCAL(user));
			ext.set(user, isock);
		}
		catch (ModuleException &e)
		{
			ServerInstance->Logs->Log("m_ident",DEBUG,"Ident exception: %s", e.GetReason());
		}
	}
Exemple #14
0
	CmdResult Handle (const std::vector<std::string> &parameters, User *user)
	{
		if (parameters.empty())
		{
			watchlist* wl = ext.get(user);
			if (wl)
			{
				for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
				{
					if (!q->second.empty())
						user->WriteNumeric(604, "%s %s :is online", q->first.c_str(), q->second.c_str());
				}
			}
			user->WriteNumeric(607, ":End of WATCH list");
		}
		else if (parameters.size() > 0)
		{
			for (int x = 0; x < (int)parameters.size(); x++)
			{
				const char *nick = parameters[x].c_str();
				if (!strcasecmp(nick,"C"))
				{
					// watch clear
					watchlist* wl = ext.get(user);
					if (wl)
					{
						for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)
						{
							watchentries::iterator i2 = whos_watching_me->find(i->first);
							if (i2 != whos_watching_me->end())
							{
								/* People are watching this user, am i one of them? */
								std::deque<User*>::iterator n = std::find(i2->second.begin(), i2->second.end(), user);
								if (n != i2->second.end())
									/* I'm no longer watching you... */
									i2->second.erase(n);

								if (i2->second.empty())
									/* nobody else is, either. */
									whos_watching_me->erase(i2);
							}
						}

						ext.unset(user);
					}
				}
				else if (!strcasecmp(nick,"L"))
				{
					watchlist* wl = ext.get(user);
					if (wl)
					{
						for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
						{
							if (!q->second.empty())
							{
								user->WriteNumeric(604, "%s %s :is online", q->first.c_str(), q->second.c_str());
								User *targ = ServerInstance->FindNick(q->first.c_str());
								if (targ->IsAway())
								{
									user->WriteNumeric(609, "%s %s %s %lu :is away", targ->nick.c_str(), targ->ident.c_str(), targ->dhost.c_str(), (unsigned long) targ->awaytime);
								}
							}
							else
								user->WriteNumeric(605, "%s * * 0 :is offline", q->first.c_str());
						}
					}
					user->WriteNumeric(607, ":End of WATCH list");
				}
				else if (!strcasecmp(nick,"S"))
				{
					watchlist* wl = ext.get(user);
					int you_have = 0;
					int youre_on = 0;
					std::string list;

					if (wl)
					{
						for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
							list.append(q->first.c_str()).append(" ");
						you_have = wl->size();
					}

					watchentries::iterator i2 = whos_watching_me->find(user->nick.c_str());
					if (i2 != whos_watching_me->end())
						youre_on = i2->second.size();

					user->WriteNumeric(603, ":You have %d and are on %d WATCH entries", you_have, youre_on);
					user->WriteNumeric(606, ":%s", list.c_str());
					user->WriteNumeric(607, ":End of WATCH S");
				}
				else if (nick[0] == '-')
				{
					nick++;
					remove_watch(user, nick);
				}
				else if (nick[0] == '+')
				{
					nick++;
					add_watch(user, nick);
				}
			}
		}
		return CMD_SUCCESS;
	}
Exemple #15
0
	bool BeforeMode(User* source, User* dest, Channel* channel, std::string &param, bool adding)
	{
		/* nick!ident@host -> nick!ident@host
		 * nick!ident@host#chan -> nick!ident@host#chan
		 * nick@host#chan -> nick!*@host#chan
		 * nick!ident#chan -> nick!ident@*#chan
		 * nick#chan -> nick!*@*#chan
		 */

		if ((channel) && !param.empty())
		{
			BanRedirectList* redirects;

			std::string mask[4];
			enum { NICK, IDENT, HOST, CHAN } current = NICK;
			std::string::iterator start_pos = param.begin();

			if (param.length() >= 2 && param[1] == ':')
				return true;

			if (param.find('#') == std::string::npos)
				return true;

			ListModeBase* banlm = static_cast<ListModeBase*>(*ban);
			unsigned int maxbans = banlm->GetLimit(channel);
			ListModeBase::ModeList* list = banlm->GetList(channel);
			if ((list) && (adding) && (maxbans <= list->size()))
			{
				source->WriteNumeric(ERR_BANLISTFULL, "%s :Channel ban list for %s is full (maximum entries for this channel is %u)", channel->name.c_str(), channel->name.c_str(), maxbans);
				return false;
			}

			for(std::string::iterator curr = start_pos; curr != param.end(); curr++)
			{
				switch(*curr)
				{
					case '!':
						if (current != NICK)
							break;
						mask[current].assign(start_pos, curr);
						current = IDENT;
						start_pos = curr+1;
						break;
					case '@':
						if (current != IDENT)
							break;
						mask[current].assign(start_pos, curr);
						current = HOST;
						start_pos = curr+1;
						break;
					case '#':
						if (current == CHAN)
							break;
						mask[current].assign(start_pos, curr);
						current = CHAN;
						start_pos = curr;
						break;
				}
			}

			if(mask[current].empty())
			{
				mask[current].assign(start_pos, param.end());
			}

			/* nick@host wants to be changed to *!nick@host rather than nick!*@host... */
			if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty())
			{
				/* std::string::swap() is fast - it runs in constant time */
				mask[NICK].swap(mask[IDENT]);
			}

			if (!mask[NICK].empty() && mask[IDENT].empty() && mask[HOST].empty())
			{
				if (mask[NICK].find('.') != std::string::npos || mask[NICK].find(':') != std::string::npos)
				{
					mask[NICK].swap(mask[HOST]);
				}
			}

			for(int i = 0; i < 3; i++)
			{
				if(mask[i].empty())
				{
					mask[i].assign("*");
				}
			}

			param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]);

			if(mask[CHAN].length())
			{
				if (adding && IS_LOCAL(source))
				{
					if (!ServerInstance->IsChannel(mask[CHAN]))
					{
						source->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name in redirection (%s)", channel->name.c_str(), mask[CHAN].c_str());
						return false;
					}

					Channel *c = ServerInstance->FindChan(mask[CHAN]);
					if (!c)
					{
						source->WriteNumeric(690, ":Target channel %s must exist to be set as a redirect.", mask[CHAN].c_str());
						return false;
					}
					else if (adding && c->GetPrefixValue(source) < OP_VALUE)
					{
						source->WriteNumeric(690, ":You must be opped on %s to set it as a redirect.", mask[CHAN].c_str());
						return false;
					}

					if (assign(channel->name) == mask[CHAN])
					{
						source->WriteNumeric(690, "%s :You cannot set a ban redirection to the channel the ban is on", channel->name.c_str());
						return false;
					}
				}

				if(adding)
				{
					/* It's a properly valid redirecting ban, and we're adding it */
					redirects = extItem.get(channel);
					if (!redirects)
					{
						redirects = new BanRedirectList;
						extItem.set(channel, redirects);
					}

					/* Here 'param' doesn't have the channel on it yet */
					redirects->push_back(BanRedirectEntry(mask[CHAN], param));

					/* Now it does */
					param.append(mask[CHAN]);
				}
				else
				{
					/* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */
					redirects = extItem.get(channel);
					if (redirects)
					{
						/* But there were, so we need to remove the matching one if there is one */

						for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
						{
							/* Ugly as f**k */
							if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str())))
							{
								redirects->erase(redir);

								if(redirects->empty())
								{
									extItem.unset(channel);
								}

								break;
							}
						}
					}

					/* Append the channel so the default +b handler can remove the entry too */
					param.append(mask[CHAN]);
				}
			}
		}

		return true;
	}
Exemple #16
0
	CmdResult Handle (const std::vector<std::string>& parameters, User *user)
	{
		if (!parameters.size())
		{
			// no parameters, show the current silence list.
			silencelist* sl = ext.get(user);
			// if the user has a silence list associated with their user record, show it
			if (sl)
			{
				for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
				{
					std::string decomppattern = DecompPattern(c->second);
					user->WriteNumeric(271, "%s %s %s %s",user->nick.c_str(), user->nick.c_str(),c->first.c_str(), decomppattern.c_str());
				}
			}
			user->WriteNumeric(272, "%s :End of Silence List",user->nick.c_str());

			return CMD_SUCCESS;
		}
		else if (parameters.size() > 0)
		{
			// one or more parameters, add or delete entry from the list (only the first parameter is used)
			std::string mask = parameters[0].substr(1);
			char action = parameters[0][0];
			// Default is private and notice so clients do not break
			int pattern = CompilePattern("pn");

			// if pattern supplied, use it
			if (parameters.size() > 1) {
				pattern = CompilePattern(parameters[1].c_str());
			}

			if (pattern == 0)
			{
				user->WriteServ("NOTICE %s :Bad SILENCE pattern",user->nick.c_str());
				return CMD_INVALID;
			}

			if (!mask.length())
			{
				// 'SILENCE +' or 'SILENCE -', assume *!*@*
				mask = "*!*@*";
			}

			ModeParser::CleanMask(mask);

			if (action == '-')
			{
				std::string decomppattern = DecompPattern(pattern);
				// fetch their silence list
				silencelist* sl = ext.get(user);
				// does it contain any entries and does it exist?
				if (sl)
				{
					for (silencelist::iterator i = sl->begin(); i != sl->end(); i++)
					{
						// search through for the item
						irc::string listitem = i->first.c_str();
						if (listitem == mask && i->second == pattern)
						{
							sl->erase(i);
							user->WriteNumeric(950, "%s %s :Removed %s %s from silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
							if (!sl->size())
							{
								ext.unset(user);
							}
							return CMD_SUCCESS;
						}
					}
				}
				user->WriteNumeric(952, "%s %s :%s %s does not exist on your silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
			}
			else if (action == '+')
			{
				// fetch the user's current silence list
				silencelist* sl = ext.get(user);
				if (!sl)
				{
					sl = new silencelist;
					ext.set(user, sl);
				}
				if (sl->size() > maxsilence)
				{
					user->WriteNumeric(952, "%s %s :Your silence list is full",user->nick.c_str(), user->nick.c_str());
					return CMD_FAILURE;
				}

				std::string decomppattern = DecompPattern(pattern);
				for (silencelist::iterator n = sl->begin(); n != sl->end();  n++)
				{
					irc::string listitem = n->first.c_str();
					if (listitem == mask && n->second == pattern)
					{
						user->WriteNumeric(952, "%s %s :%s %s is already on your silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
						return CMD_FAILURE;
					}
				}
				if (((pattern & SILENCE_EXCLUDE) > 0))
				{
					sl->push_front(silenceset(mask,pattern));
				}
				else
				{
					sl->push_back(silenceset(mask,pattern));
				}
				user->WriteNumeric(951, "%s %s :Added %s %s to silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str());
				return CMD_SUCCESS;
			}
		}
		return CMD_SUCCESS;
	}
Exemple #17
0
	virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
	{
		// Don't do anything with unregistered users
		if (user->registered != REG_ALL)
			return MOD_RES_PASSTHRU;

		if ((validated) && (parameters.size() >= 2) && ((command == "PRIVMSG") || (command == "NOTICE")))
		{
			// parameters[0] should have the target(s) in it.
			// I think it will be faster to first check if there are any commas, and if there are then try and parse it out.
			// Most messages have a single target so...

			int targets = 1;
			int userchans = 0;

			if(*parameters[0].c_str() != '#')
			{
				// Decrement if the first target wasn't a channel.
				targets--;
			}

			for(const char* c = parameters[0].c_str(); *c; c++)
				if((*c == ',') && *(c+1) && (*(c+1) == '#'))
					targets++;

			/* targets should now contain the number of channel targets the msg/notice was pointed at.
			 * If the msg/notice was a PM there should be no channel targets and 'targets' should = 0.
			 * We don't want to block PMs so...
			 */
			if(targets == 0)
			{
				return MOD_RES_PASSTHRU;
			}

			userchans = user->chans.size();

			// Check that this message wasn't already sent within a few seconds.
			BlockedMessage* m = blockamsg.get(user);

			// If the message is identical and within the time.
			// We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing...
			// OR
			// The number of target channels is equal to the number of channels the sender is on..a little suspicious.
			// Check it's more than 1 too, or else users on one channel would have fun.
			if((m && (m->message == parameters[1]) && (m->target != parameters[0]) && (ForgetDelay != -1) && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == userchans)))
			{
				// Block it...
				if(action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS)
					ServerInstance->SNO->WriteToSnoMask('a', "%s had an /amsg or /ame denied", user->nick.c_str());

				if(action == IBLOCK_KILL || action == IBLOCK_KILLOPERS)
					ServerInstance->Users->QuitUser(user, "You have been killed for use of /amsg or /ame");
				else if(action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS)
					user->Write(":0ServerNotice@amsg-blocked. NOTICE %s :Global message (/amsg or /ame) denied", user->nick.c_str());

				return MOD_RES_DENY;
			}

			if(m)
			{
				// If there's already a BlockedMessage allocated, use it.
				m->message = parameters[1];
				m->target = parameters[0].c_str();
				m->sent = ServerInstance->Time();
			}
			else
			{
				m = new BlockedMessage(parameters[1], parameters[0].c_str(), ServerInstance->Time());
				blockamsg.set(user, m);
			}
		}
		return MOD_RES_PASSTHRU;
	}