Ejemplo n.º 1
0
void ModeParser::AddMode(ModeHandler* mh)
{
	/* Yes, i know, this might let people declare modes like '_' or '^'.
	 * If they do that, thats their problem, and if i ever EVER see an
	 * official InspIRCd developer do that, i'll beat them with a paddle!
	 */
	if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
		throw ModuleException("Invalid letter for mode " + mh->name);

	/* A mode prefix of ',' is not acceptable, it would f**k up server to server.
	 * A mode prefix of ':' will f**k up both server to server, and client to server.
	 * A mode prefix of '#' will mess up /whois and /privmsg
	 */
	PrefixMode* pm = mh->IsPrefixMode();
	if (pm)
	{
		if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#'))
			throw ModuleException("Invalid prefix for mode " + mh->name);

		if (FindPrefix(pm->GetPrefix()))
			throw ModuleException("Prefix already exists for mode " + mh->name);
	}

	ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65];
	if (slot)
		throw ModuleException("Letter is already in use for mode " + mh->name);

	// The mode needs an id if it is either a user mode, a simple mode (flag) or a parameter mode.
	// Otherwise (for listmodes and prefix modes) the id remains MODEID_MAX, which is invalid.
	ModeHandler::Id modeid = MODEID_MAX;
	if ((mh->GetModeType() == MODETYPE_USER) || (mh->IsParameterMode()) || (!mh->IsListMode()))
		modeid = AllocateModeId(mh->GetModeType());

	if (!modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh)).second)
		throw ModuleException("Mode name already in use: " + mh->name);

	// Everything is fine, add the mode

	// If we allocated an id for this mode then save it and put the mode handler into the slot
	if (modeid != MODEID_MAX)
	{
		mh->modeid = modeid;
		modehandlersbyid[mh->GetModeType()][modeid] = mh;
	}

	slot = mh;
	if (pm)
		mhlist.prefix.push_back(pm);
	else if (mh->IsListModeBase())
		mhlist.list.push_back(mh->IsListModeBase());

	RecreateModeListFor004Numeric();
}
Ejemplo n.º 2
0
	CmdResult Handle(User* user, const Params& parameters) override
	{
		Channel* channel = ServerInstance->FindChan(parameters[0]);
		if (!channel)
		{
			user->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
			return CMD_FAILURE;
		}
		unsigned int cm = channel->GetPrefixValue(user);
		if (cm < HALFOP_VALUE)
		{
			user->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, "You do not have permission to set bans on this channel");
			return CMD_FAILURE;
		}

		TimedBan T;
		unsigned long duration;
		if (!InspIRCd::Duration(parameters[1], duration))
		{
			user->WriteNotice("Invalid ban time");
			return CMD_FAILURE;
		}
		unsigned long expire = duration + ServerInstance->Time();
		std::string mask = parameters[2];
		bool isextban = ((mask.size() > 2) && (mask[1] == ':'));
		if (!isextban && !InspIRCd::IsValidMask(mask))
			mask.append("!*@*");

		if (IsBanSet(channel, mask))
		{
			user->WriteNotice("Ban already set");
			return CMD_FAILURE;
		}

		Modes::ChangeList setban;
		setban.push_add(ServerInstance->Modes.FindMode('b', MODETYPE_CHANNEL), mask);
		// Pass the user (instead of ServerInstance->FakeClient) to ModeHandler::Process() to
		// make it so that the user sets the mode themselves
		ServerInstance->Modes.Process(user, channel, NULL, setban);
		if (ServerInstance->Modes.GetLastChangeList().empty())
		{
			user->WriteNotice("Invalid ban mask");
			return CMD_FAILURE;
		}

		T.mask = mask;
		T.expire = expire + (IS_REMOTE(user) ? 5 : 0);
		T.chan = channel;
		TimedBanList.push_back(T);

		const std::string addban = user->nick + " added a timed ban on " + mask + " lasting for " + InspIRCd::DurationString(duration) + ".";
		// If halfop is loaded, send notice to halfops and above, otherwise send to ops and above
		PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
		char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';

		ClientProtocol::Messages::Privmsg notice(ServerInstance->FakeClient, channel, addban, MSG_NOTICE);
		channel->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar);
		ServerInstance->PI->SendChannelNotice(channel, pfxchar, addban);
		return CMD_SUCCESS;
	}
Ejemplo n.º 3
0
	void OnBackgroundTimer(time_t curtime) override
	{
		timedbans expired;
		for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end();)
		{
			if (curtime > i->expire)
			{
				expired.push_back(*i);
				i = TimedBanList.erase(i);
			}
			else
				++i;
		}

		for (timedbans::iterator i = expired.begin(); i != expired.end(); i++)
		{
			std::string mask = i->mask;
			Channel* cr = i->chan;
			{
				const std::string expiry = "*** Timed ban on " + cr->name + " expired.";
				// If halfop is loaded, send notice to halfops and above, otherwise send to ops and above
				PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
				char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';

				ClientProtocol::Messages::Privmsg notice(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, cr, expiry, MSG_NOTICE);
				cr->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar);
				ServerInstance->PI->SendChannelNotice(cr, pfxchar, expiry);

				Modes::ChangeList setban;
				setban.push_remove(ServerInstance->Modes.FindMode('b', MODETYPE_CHANNEL), mask);
				ServerInstance->Modes.Process(ServerInstance->FakeClient, cr, NULL, setban);
			}
		}
	}
Ejemplo n.º 4
0
bool ModeParser::AddMode(ModeHandler* mh)
{
	unsigned char mask = 0;
	unsigned char pos = 0;

	/* Yes, i know, this might let people declare modes like '_' or '^'.
	 * If they do that, thats their problem, and if i ever EVER see an
	 * official InspIRCd developer do that, i'll beat them with a paddle!
	 */
	if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
		return false;

	/* A mode prefix of ',' is not acceptable, it would f**k up server to server.
	 * A mode prefix of ':' will f**k up both server to server, and client to server.
	 * A mode prefix of '#' will mess up /whois and /privmsg
	 */
	PrefixMode* pm = mh->IsPrefixMode();
	if (pm)
	{
		if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#'))
			return false;

		if (FindPrefix(pm->GetPrefix()))
			return false;
	}

	mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
	pos = (mh->GetModeChar()-65) | mask;

	if (modehandlers[pos])
		return false;

	// Everything is fine, add the mode
	modehandlers[pos] = mh;
	if (pm)
		mhlist.prefix.push_back(pm);
	else if (mh->IsListModeBase())
		mhlist.list.push_back(mh->IsListModeBase());

	RecreateModeListFor004Numeric();
	return true;
}
Ejemplo n.º 5
0
PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter)
{
	const PrefixModeList& list = GetPrefixModes();
	for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i)
	{
		PrefixMode* pm = *i;
		if (pm->GetPrefix() == pfxletter)
			return pm;
	}
	return NULL;
}
Ejemplo n.º 6
0
std::string ModeParser::BuildPrefixes(bool lettersAndModes)
{
	std::string mletters;
	std::string mprefixes;
	std::map<int,std::pair<char,char> > prefixes;

	const PrefixModeList& list = GetPrefixModes();
	for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i)
	{
		PrefixMode* pm = *i;
		if (pm->GetPrefix())
			prefixes[pm->GetPrefixRank()] = std::make_pair(pm->GetPrefix(), pm->GetModeChar());
	}

	for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
	{
		mletters = mletters + n->second.first;
		mprefixes = mprefixes + n->second.second;
	}

	return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters;
}
Ejemplo n.º 7
0
std::string ModeParser::GiveModeList(ModeMasks m)
{
	std::string type1;	/* Listmodes EXCEPT those with a prefix */
	std::string type2;	/* Modes that take a param when adding or removing */
	std::string type3;	/* Modes that only take a param when adding */
	std::string type4;	/* Modes that dont take a param */

	for (unsigned char mode = 'A'; mode <= 'z'; mode++)
	{
		unsigned char pos = (mode-65) | m;
		 /* One parameter when adding */
		if (modehandlers[pos])
		{
			if (modehandlers[pos]->GetNumParams(true))
			{
				PrefixMode* pm = modehandlers[pos]->IsPrefixMode();
				if ((modehandlers[pos]->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0)))
				{
					type1 += modehandlers[pos]->GetModeChar();
				}
				else
				{
					/* ... and one parameter when removing */
					if (modehandlers[pos]->GetNumParams(false))
					{
						/* But not a list mode */
						if (!pm)
						{
							type2 += modehandlers[pos]->GetModeChar();
						}
					}
					else
					{
						/* No parameters when removing */
						type3 += modehandlers[pos]->GetModeChar();
					}
				}
			}
			else
			{
				type4 += modehandlers[pos]->GetModeChar();
			}
		}
	}

	return type1 + "," + type2 + "," + type3 + "," + type4;
}
Ejemplo n.º 8
0
/** Handle /INVITE
 */
CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, User *user)
{
	ModResult MOD_RESULT;

	if (parameters.size() >= 2)
	{
		User* u;
		if (IS_LOCAL(user))
			u = ServerInstance->FindNickOnly(parameters[0]);
		else
			u = ServerInstance->FindNick(parameters[0]);

		Channel* c = ServerInstance->FindChan(parameters[1]);
		time_t timeout = 0;
		if (parameters.size() >= 3)
		{
			if (IS_LOCAL(user))
				timeout = ServerInstance->Time() + InspIRCd::Duration(parameters[2]);
			else if (parameters.size() > 3)
				timeout = ConvToInt(parameters[3]);
		}

		if ((!c) || (!u) || (u->registered != REG_ALL))
		{
			user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c ? parameters[0].c_str() : parameters[1].c_str());
			return CMD_FAILURE;
		}

		// Verify channel timestamp if the INVITE is coming from a remote server
		if (!IS_LOCAL(user))
		{
			// Remote INVITE commands must carry a channel timestamp
			if (parameters.size() < 3)
				return CMD_INVALID;

			// Drop the invite if our channel TS is lower
			time_t RemoteTS = ConvToInt(parameters[2]);
			if (c->age < RemoteTS)
				return CMD_FAILURE;
		}

		if ((IS_LOCAL(user)) && (!c->HasUser(user)))
		{
			user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", c->name.c_str());
			return CMD_FAILURE;
		}

		if (c->HasUser(u))
		{
			user->WriteNumeric(ERR_USERONCHANNEL, "%s %s :is already on channel", u->nick.c_str(), c->name.c_str());
			return CMD_FAILURE;
		}

		FIRST_MOD_RESULT(OnUserPreInvite, MOD_RESULT, (user,u,c,timeout));

		if (MOD_RESULT == MOD_RES_DENY)
		{
			return CMD_FAILURE;
		}
		else if (MOD_RESULT == MOD_RES_PASSTHRU)
		{
			if (IS_LOCAL(user))
			{
				unsigned int rank = c->GetPrefixValue(user);
				if (rank < HALFOP_VALUE)
				{
					// Check whether halfop mode is available and phrase error message accordingly
					ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL);
					user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must be a channel %soperator",
						c->name.c_str(), (mh && mh->name == "halfop" ? "half-" : ""));
					return CMD_FAILURE;
				}
			}
		}

		if (IS_LOCAL(u))
		{
			Invitation::Create(c, IS_LOCAL(u), timeout);
			u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str());
		}

		if (IS_LOCAL(user))
			user->WriteNumeric(RPL_INVITING, "%s %s", u->nick.c_str(),c->name.c_str());

		if (ServerInstance->Config->AnnounceInvites != ServerConfig::INVITE_ANNOUNCE_NONE)
		{
			char prefix;
			switch (ServerInstance->Config->AnnounceInvites)
			{
				case ServerConfig::INVITE_ANNOUNCE_OPS:
				{
					prefix = '@';
					break;
				}
				case ServerConfig::INVITE_ANNOUNCE_DYNAMIC:
				{
					PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h');
					prefix = (mh && mh->name == "halfop" ? mh->GetPrefix() : '@');
					break;
				}
				default:
				{
					prefix = 0;
					break;
				}
			}
			c->WriteAllExceptSender(user, true, prefix, "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str());
		}
		FOREACH_MOD(OnUserInvite, (user,u,c,timeout));
	}
	else if (IS_LOCAL(user))
	{
		// pinched from ircu - invite with not enough parameters shows channels
		// youve been invited to but haven't joined yet.
		InviteList& il = IS_LOCAL(user)->GetInviteList();
		for (InviteList::const_iterator i = il.begin(); i != il.end(); ++i)
		{
			user->WriteNumeric(RPL_INVITELIST, ":%s", (*i)->chan->name.c_str());
		}
		user->WriteNumeric(RPL_ENDOFINVITELIST, ":End of INVITE list");
	}
	return CMD_SUCCESS;
}