Exemple #1
0
CmdResult CommandTopic::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
{
	Channel* c = ServerInstance->FindChan(parameters[0]);
	if (!c)
	{
		user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
		return CMD_FAILURE;
	}

	if (parameters.size() == 1)
	{
		if (c)
		{
			if ((c->IsModeSet(secretmode)) && (!c->HasUser(user)))
			{
				user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c->name.c_str());
				return CMD_FAILURE;
			}

			if (c->topic.length())
			{
				user->WriteNumeric(RPL_TOPIC, "%s :%s", c->name.c_str(), c->topic.c_str());
				user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", c->name.c_str(), c->setby.c_str(), (unsigned long)c->topicset);
			}
			else
			{
				user->WriteNumeric(RPL_NOTOPICSET, "%s :No topic is set.", c->name.c_str());
			}
		}
		return CMD_SUCCESS;
	}

	std::string t = parameters[1]; // needed, in case a module wants to change it
	ModResult res;
	FIRST_MOD_RESULT(OnPreTopicChange, res, (user,c,t));

	if (res == MOD_RES_DENY)
		return CMD_FAILURE;
	if (res != MOD_RES_ALLOW)
	{
		if (!c->HasUser(user))
		{
			user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", c->name.c_str());
			return CMD_FAILURE;
		}
		if (c->IsModeSet(topiclockmode) && !ServerInstance->OnCheckExemption(user, c, "topiclock").check(c->GetPrefixValue(user) >= HALFOP_VALUE))
		{
			user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You do not have access to change the topic on this channel", c->name.c_str());
			return CMD_FAILURE;
		}
	}

	c->SetTopic(user, t);
	return CMD_SUCCESS;
}
Exemple #2
0
/** Handle /NAMES
 */
CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User *user)
{
	Channel* c;

	if (!parameters.size())
	{
		user->WriteNumeric(366, "%s * :End of /NAMES list.",user->nick.c_str());
		return CMD_SUCCESS;
	}

	if (CommandParser::LoopCall(user, this, parameters, 0))
		return CMD_SUCCESS;

	c = ServerInstance->FindChan(parameters[0]);
	if (c)
	{
		if ((c->IsModeSet('s')) && (!c->HasUser(user)))
		{
		      user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), c->name.c_str());
		      return CMD_FAILURE;
		}
		c->UserList(user);
	}
	else
	{
		user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
	}

	return CMD_SUCCESS;
}
Exemple #3
0
std::string User::ChannelList(User* source, bool spy)
{
	std::string list;

	for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
	{
		Channel* c = *i;
		/* If the target is the sender, neither +p nor +s is set, or
		 * the channel contains the user, it is not a spy channel
		 */
		if (spy != (source == this || !(c->IsModeSet('p') || c->IsModeSet('s')) || c->HasUser(source)))
			list.append(c->GetPrefixChar(this)).append(c->name).append(" ");
	}

	return list;
}
	ModResult DoMsg(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list, bool privmsg)
	{
		if (!IS_LOCAL(user) || target_type != TYPE_CHANNEL || status)
			return MOD_RES_PASSTHRU;

		Channel* chan = static_cast<Channel*>(dest);
		ModResult res = ServerInstance->OnCheckExemption(user,chan,"opmoderated");
		if (res == MOD_RES_ALLOW)
			return MOD_RES_PASSTHRU;
		if (!chan->GetExtBanStatus(user, 'u').check(!chan->IsModeSet(&mh)) && chan->GetPrefixValue(user) < VOICE_VALUE)
		{
			FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list));
			chan->WriteAllExcept(user, false, '@', exempt_list, "%s @%s :%s",
				privmsg ? "PRIVMSG" : "NOTICE", chan->name.c_str(), text.c_str());
			if (privmsg)
			{
				FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,text,'@',exempt_list));
			}
			else
				FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,'@',exempt_list));

			return MOD_RES_DENY;
		}

		return MOD_RES_PASSTHRU;
	}
Exemple #5
0
	ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override
	{
		if (!IS_LOCAL(user))
			return MOD_RES_PASSTHRU;

		std::string ctcpname;
		if (!details.IsCTCP(ctcpname) || irc::equals(ctcpname, "ACTION"))
			return MOD_RES_PASSTHRU;

		if (target.type == MessageTarget::TYPE_CHANNEL)
		{
			Channel* c = target.Get<Channel>();
			ModResult res = CheckExemption::Call(exemptionprov, user, c, "noctcp");
			if (res == MOD_RES_ALLOW)
				return MOD_RES_PASSTHRU;

			if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet(nc)))
			{
				user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send CTCP to channel (+C set)");
				return MOD_RES_DENY;
			}
		}
		else if (target.type == MessageTarget::TYPE_USER)
		{
			User* u = target.Get<User>();
			if (u->IsModeSet(ncu))
			{
				user->WriteNumeric(ERR_CANTSENDTOUSER, u->nick, "Can't send CTCP to user (+T set)");
				return MOD_RES_PASSTHRU;
			}
		}
		return MOD_RES_PASSTHRU;
	}
    ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
    {
        if (!IS_LOCAL(user))
            return MOD_RES_PASSTHRU;

        std::string *account = accountname.get(user);
        bool is_registered = account && !account->empty();

        if (target_type == TYPE_CHANNEL)
        {
            Channel* c = (Channel*)dest;
            ModResult res = ServerInstance->OnCheckExemption(user,c,"regmoderated");

            if (c->IsModeSet('M') && !is_registered && res != MOD_RES_ALLOW)
            {
                // user messaging a +M channel and is not registered
                user->WriteNumeric(477, user->nick+" "+c->name+" :You need to be identified to a registered account to message this channel");
                return MOD_RES_DENY;
            }
        }
        else if (target_type == TYPE_USER)
        {
            User* u = (User*)dest;

            if (u->IsModeSet('R') && !is_registered)
            {
                // user messaging a +R user and is not registered
                user->WriteNumeric(477, ""+ user->nick +" "+ u->nick +" :You need to be identified to a registered account to message this user");
                return MOD_RES_DENY;
            }
        }
        return MOD_RES_PASSTHRU;
    }
Exemple #7
0
	virtual ModResult OnUserPreNick(User* user, const std::string &newnick)
	{
		if (!IS_LOCAL(user))
			return MOD_RES_PASSTHRU;

		// Allow forced nick changes.
		if (ServerInstance->NICKForced.get(user))
			return MOD_RES_PASSTHRU;

		for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
		{
			Channel* curr = *i;

			ModResult res = ServerInstance->OnCheckExemption(user,curr,"nonick");

			if (res == MOD_RES_ALLOW)
				continue;

			if (override && IS_OPER(user))
				continue;

			if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet('N')))
			{
				user->WriteNumeric(ERR_CANTCHANGENICK, "%s :Can't change nickname while on %s (+N is set)",
					user->nick.c_str(), curr->name.c_str());
				return MOD_RES_DENY;
			}
		}

		return MOD_RES_PASSTHRU;
	}
Exemple #8
0
std::string CommandWhois::ChannelList(User* source, User* dest, bool spy)
{
	std::string list;

	for (UCListIter i = dest->chans.begin(); i != dest->chans.end(); i++)
	{
		Channel* c = *i;
		/* If the target is the sender, neither +p nor +s is set, or
		 * the channel contains the user, it is not a spy channel
		 */
		if (spy != (source == dest || !(c->IsModeSet(privatemode) || c->IsModeSet(secretmode)) || c->HasUser(source)))
			list.append(c->GetPrefixChar(dest)).append(c->name).append(" ");
	}

	return list;
}
Exemple #9
0
	Channel* get_first_visible_channel(User *u)
	{
		UCListIter i = u->chans.begin();
		while (i != u->chans.end())
		{
			Channel* c = *i++;
			if (!c->IsModeSet(secretmode))
				return c;
		}
		return NULL;
	}
std::string CommandWhois::ChannelList(User* source, User* dest, bool spy)
{
	std::string list;

	for (User::ChanList::iterator i = dest->chans.begin(); i != dest->chans.end(); i++)
	{
		Membership* memb = *i;
		Channel* c = memb->chan;
		/* If the target is the sender, neither +p nor +s is set, or
		 * the channel contains the user, it is not a spy channel
		 */
		if (spy != (source == dest || !(c->IsModeSet(privatemode) || c->IsModeSet(secretmode)) || c->HasUser(source)))
		{
			char prefix = memb->GetPrefixChar();
			if (prefix)
				list.push_back(prefix);
			list.append(c->name).push_back(' ');
		}
	}

	return list;
}
Exemple #11
0
	CmdResult Handle (const std::vector<std::string> &parameters, User *user)
	{
		Channel* c = ServerInstance->FindChan(parameters[0]);
		if (!c)
		{
			user->WriteNumeric(Numerics::NoSuchNick(parameters[0]));
			return CMD_FAILURE;
		}

		if (c->HasUser(user))
		{
			user->WriteNumeric(ERR_KNOCKONCHAN, c->name, InspIRCd::Format("Can't KNOCK on %s, you are already on that channel.", c->name.c_str()));
			return CMD_FAILURE;
		}

		if (c->IsModeSet(noknockmode))
		{
			user->WriteNumeric(480, InspIRCd::Format("Can't KNOCK on %s, +K is set.", c->name.c_str()));
			return CMD_FAILURE;
		}

		if (!c->IsModeSet(inviteonlymode))
		{
			user->WriteNumeric(ERR_CHANOPEN, c->name, InspIRCd::Format("Can't KNOCK on %s, channel is not invite only so knocking is pointless!", c->name.c_str()));
			return CMD_FAILURE;
		}

		if (sendnotice)
			c->WriteNotice(InspIRCd::Format("User %s is KNOCKing on %s (%s)", user->nick.c_str(), c->name.c_str(), parameters[1].c_str()));

		if (sendnumeric)
			c->WriteChannelWithServ(ServerInstance->Config->ServerName, "710 %s %s %s :is KNOCKing: %s", c->name.c_str(), c->name.c_str(), user->GetFullHost().c_str(), parameters[1].c_str());

		user->WriteNotice("KNOCKing on " + c->name);
		return CMD_SUCCESS;
	}
Exemple #12
0
	CmdResult Handle (const std::vector<std::string> &parameters, User *user)
	{
		Channel* c = ServerInstance->FindChan(parameters[0]);
		if (!c)
		{
			user->WriteNumeric(401, "%s %s :No such channel",user->nick.c_str(), parameters[0].c_str());
			return CMD_FAILURE;
		}

		if (c->HasUser(user))
		{
			user->WriteNumeric(480, "%s :Can't KNOCK on %s, you are already on that channel.", user->nick.c_str(), c->name.c_str());
			return CMD_FAILURE;
		}

		if (c->IsModeSet('K'))
		{
			user->WriteNumeric(480, "%s :Can't KNOCK on %s, +K is set.",user->nick.c_str(), c->name.c_str());
			return CMD_FAILURE;
		}

		if (!c->IsModeSet('i'))
		{
			user->WriteNumeric(480, "%s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick.c_str(), c->name.c_str());
			return CMD_FAILURE;
		}

		if (sendnotice)
			c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name.c_str(), user->nick.c_str(), c->name.c_str(), parameters[1].c_str());

		if (sendnumeric)
			c->WriteChannelWithServ(ServerInstance->Config->ServerName, "710 %s %s %s :is KNOCKing: %s", c->name.c_str(), c->name.c_str(), user->GetFullHost().c_str(), parameters[1].c_str());

		user->WriteNotice("KNOCKing on " + c->name);
		return CMD_SUCCESS;
	}
Exemple #13
0
	virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
	{
		ModResult res;
		if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
		{
			Channel* c = (Channel*)dest;
			if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet('T')))
			{
				res = ServerInstance->OnCheckExemption(user,c,"nonotice");
				if (res == MOD_RES_ALLOW)
					return MOD_RES_PASSTHRU;
				else
				{
					user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Can't send NOTICE to channel (+T set)",user->nick.c_str(), c->name.c_str());
					return MOD_RES_DENY;
				}
			}
		}
		return MOD_RES_PASSTHRU;
	}
Exemple #14
0
	virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
	{
		if (target_type == TYPE_CHANNEL)
		{
			if ((!IS_LOCAL(user)) || (text.length() < minlen))
				return MOD_RES_PASSTHRU;

			Channel* c = (Channel*)dest;
			ModResult res = ServerInstance->OnCheckExemption(user,c,"blockcaps");

			if (res == MOD_RES_ALLOW)
				return MOD_RES_PASSTHRU;

			if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet('B')))
			{
				int caps = 0;
				const char* actstr = "\1ACTION ";
				int act = 0;

				for (std::string::iterator i = text.begin(); i != text.end(); i++)
				{
					/* Smart fix for suggestion from Jobe, ignore CTCP ACTION (part of /ME) */
					if (*actstr && *i == *actstr++ && act != -1)
					{
						act++;
						continue;
					}
					else
						act = -1;

					caps += capsmap[(unsigned char)*i];
				}
				if ( ((caps*100)/(int)text.length()) >= percent )
				{
					user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Your message cannot contain more than %d%% capital letters if it's longer than %d characters", user->nick.c_str(), c->name.c_str(), percent, minlen);
					return MOD_RES_DENY;
				}
			}
		}
		return MOD_RES_PASSTHRU;
	}
Exemple #15
0
	void ValidateChans()
	{
		Modes::ChangeList removepermchan;

		badchan = true;
		const chan_hash& chans = ServerInstance->GetChans();
		for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); )
		{
			Channel* c = i->second;
			// Move iterator before we begin kicking
			++i;
			if (ServerInstance->IsChannel(c->name))
				continue; // The name of this channel is still valid

			if (c->IsModeSet(permchannelmode) && c->GetUserCounter())
			{
				removepermchan.clear();
				removepermchan.push_remove(*permchannelmode);
				ServerInstance->Modes.Process(ServerInstance->FakeClient, c, NULL, removepermchan);
			}

			Channel::MemberMap& users = c->userlist;
			for (Channel::MemberMap::iterator j = users.begin(); j != users.end(); )
			{
				if (IS_LOCAL(j->first))
				{
					// KickUser invalidates the iterator
					Channel::MemberMap::iterator it = j++;
					c->KickUser(ServerInstance->FakeClient, it, "Channel name no longer valid");
				}
				else
					++j;
			}
		}
		badchan = false;
	}
Exemple #16
0
	void ValidateChans()
	{
		badchan = true;
		std::vector<Channel*> chanvec;
		for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); ++i)
		{
			if (!ServerInstance->IsChannel(i->second->name))
				chanvec.push_back(i->second);
		}
		std::vector<Channel*>::reverse_iterator c2 = chanvec.rbegin();
		while (c2 != chanvec.rend())
		{
			Channel* c = *c2++;
			if (c->IsModeSet(permchannelmode) && c->GetUserCounter())
			{
				std::vector<std::string> modes;
				modes.push_back(c->name);
				modes.push_back(std::string("-") + permchannelmode->GetModeChar());

				ServerInstance->Modes->Process(modes, ServerInstance->FakeClient);
			}
			const UserMembList* users = c->GetUsers();
			for(UserMembCIter j = users->begin(); j != users->end(); )
			{
				if (IS_LOCAL(j->first))
				{
					// KickUser invalidates the iterator
					UserMembCIter it = j++;
					c->KickUser(ServerInstance->FakeClient, it->first, "Channel name no longer valid");
				}
				else
					++j;
			}
		}
		badchan = false;
	}
Exemple #17
0
static bool WriteDatabase(PermChannel& permchanmode, Module* mod, bool save_listmodes)
{
	ChanModeReference ban(mod, "ban");
	/*
	 * We need to perform an atomic write so as not to f**k things up.
	 * So, let's write to a temporary file, flush it, then rename the file..
	 *     -- w00t
	 */

	// If the user has not specified a configuration file then we don't write one.
	if (permchannelsconf.empty())
		return true;

	std::string permchannelsnewconf = permchannelsconf + ".tmp";
	std::ofstream stream(permchannelsnewconf.c_str());
	if (!stream.is_open())
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot create database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno);
		return false;
	}

	stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl
		<< "<config format=\"xml\">" << std::endl;

	for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
	{
		Channel* chan = i->second;
		if (!chan->IsModeSet(permchanmode))
			continue;

		std::string chanmodes = chan->ChanModes(true);
		if (save_listmodes)
		{
			std::string modes;
			std::string params;

			const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
			for (ModeParser::ListModeList::const_iterator j = listmodes.begin(); j != listmodes.end(); ++j)
			{
				ListModeBase* lm = *j;
				ListModeBase::ModeList* list = lm->GetList(chan);
				if (!list || list->empty())
					continue;

				size_t n = 0;
				// Append the parameters
				for (ListModeBase::ModeList::const_iterator k = list->begin(); k != list->end(); ++k, n++)
				{
					params += k->mask;
					params += ' ';
				}

				// Append the mode letters (for example "IIII", "gg")
				modes.append(n, lm->GetModeChar());
			}

			if (!params.empty())
			{
				// Remove the last space
				params.erase(params.end()-1);

				// If there is at least a space in chanmodes (that is, a non-listmode has a parameter)
				// insert the listmode mode letters before the space. Otherwise just append them.
				std::string::size_type p = chanmodes.find(' ');
				if (p == std::string::npos)
					chanmodes += modes;
				else
					chanmodes.insert(p, modes);

				// Append the listmode parameters (the masks themselves)
				chanmodes += ' ';
				chanmodes += params;
			}
		}

		stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name)
			<< "\" ts=\"" << chan->age
			<< "\" topic=\"" << ServerConfig::Escape(chan->topic)
			<< "\" topicts=\"" << chan->topicset
			<< "\" topicsetby=\"" << ServerConfig::Escape(chan->setby)
			<< "\" modes=\"" << ServerConfig::Escape(chanmodes)
			<< "\">" << std::endl;
	}

	if (stream.fail())
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot write to new database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno);
		return false;
	}
	stream.close();

#ifdef _WIN32
	if (remove(permchannelsconf.c_str()))
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot remove old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno);
		return false;
	}
#endif
	// Use rename to move temporary to new db - this is guarenteed not to f**k up, even in case of a crash.
	if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0)
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot move new to old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno);
		return false;
	}

	return true;
}
Exemple #18
0
	CmdResult Handle(User* user, const Params& parameters) override
	{
		ModeHandler* mh;
		Channel* chan = ServerInstance->FindChan(parameters[0]);
		char modeletter = parameters[1][0];

		if (chan == NULL)
		{
			user->WriteNotice("The channel " + parameters[0] + " does not exist.");
			return CMD_FAILURE;
		}

		mh = ServerInstance->Modes.FindMode(modeletter, MODETYPE_CHANNEL);
		if (mh == NULL || parameters[1].size() > 1)
		{
			user->WriteNotice(parameters[1] + " is not a valid channel mode.");
			return CMD_FAILURE;
		}

		if (chan->GetPrefixValue(user) < mh->GetLevelRequired(false))
		{
			user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " +  chan->name + ".");
			return CMD_FAILURE;
		}

		std::string pattern = parameters.size() > 2 ? parameters[2] : "*";
		PrefixMode* pm;
		ListModeBase* lm;
		ListModeBase::ModeList* ml;
		Modes::ChangeList changelist;

		if ((pm = mh->IsPrefixMode()))
		{
			// As user prefix modes don't have a GetList() method, let's iterate through the channel's users.
			const Channel::MemberMap& users = chan->GetUsers();
			for (Channel::MemberMap::const_iterator it = users.begin(); it != users.end(); ++it)
			{
				if (!InspIRCd::Match(it->first->nick, pattern))
					continue;
				if (it->second->HasMode(pm) && !((it->first == user) && (pm->GetPrefixRank() > VOICE_VALUE)))
					changelist.push_remove(mh, it->first->nick);
			}
		}
		else if ((lm = mh->IsListModeBase()) && ((ml = lm->GetList(chan)) != NULL))
		{
			for (ListModeBase::ModeList::iterator it = ml->begin(); it != ml->end(); ++it)
			{
				if (!InspIRCd::Match(it->mask, pattern))
					continue;
				changelist.push_remove(mh, it->mask);
			}
		}
		else
		{
			if (chan->IsModeSet(mh))
				changelist.push_remove(mh);
		}

		ServerInstance->Modes.Process(user, chan, NULL, changelist);
		return CMD_SUCCESS;
	}
Exemple #19
0
	CmdResult HandleChannelTarget(User* source, const Params& parameters, const char* target, PrefixMode* pm)
	{
		Channel* chan = ServerInstance->FindChan(target);
		if (!chan)
		{
			// The target channel does not exist.
			source->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
			return CMD_FAILURE;
		}

		if (IS_LOCAL(source))
		{
			if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(source))
			{
				// The noextmsg mode is set and the source is not in the channel.
				source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)");
				return CMD_FAILURE;
			}

			bool no_chan_priv = chan->GetPrefixValue(source) < VOICE_VALUE;
			if (no_chan_priv && chan->IsModeSet(moderatedmode))
			{
				// The moderated mode is set and the source has no status rank.
				source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m)");
				return CMD_FAILURE;
			}

			if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(source))
			{
				// The source is banned in the channel and restrictbannedusers is enabled.
				if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY)
					source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)");
				return CMD_FAILURE;
			}
		}

		// Fire the pre-message events.
		MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0);
		CTCTags::TagMessageDetails msgdetails(parameters.GetTags());
		if (!FirePreEvents(source, msgtarget, msgdetails))
			return CMD_FAILURE;

		unsigned int minrank = pm ? pm->GetPrefixRank() : 0;
		CTCTags::TagMessage message(source, chan, parameters.GetTags());
		const Channel::MemberMap& userlist = chan->GetUsers();
		for (Channel::MemberMap::const_iterator iter = userlist.begin(); iter != userlist.end(); ++iter)
		{
			LocalUser* luser = IS_LOCAL(iter->first);

			// Don't send to remote users or the user who is the source. 
			if (!luser || luser == source)
				continue;

			// Don't send to unprivileged or exempt users.
			if (iter->second->getRank() < minrank || msgdetails.exemptions.count(luser))
				continue;

			// Send to users if they have the capability.
			if (cap.get(luser))
				luser->Send(msgevprov, message);
		}
		return FirePostEvent(source, msgtarget, msgdetails);
	}
Exemple #20
0
	CmdResult HandleRMB(User* user, const CommandBase::Params& parameters,  bool fpart)
	{
		User* target;
		Channel* channel;
		std::string reason;

		// If the command is a /REMOVE then detect the parameter order
		bool neworder = ((fpart) || (parameters[0][0] == '#'));

		/* Set these to the parameters needed, the new version of this module switches it's parameters around
		 * supplying a new command with the new order while keeping the old /remove with the older order.
		 * /remove <nick> <channel> [reason ...]
		 * /fpart <channel> <nick> [reason ...]
		 */
		const std::string& channame = parameters[neworder ? 0 : 1];
		const std::string& username = parameters[neworder ? 1 : 0];

		/* Look up the user we're meant to be removing from the channel */
		if (IS_LOCAL(user))
			target = ServerInstance->FindNickOnly(username);
		else
			target = ServerInstance->FindNick(username);

		/* And the channel we're meant to be removing them from */
		channel = ServerInstance->FindChan(channame);

		/* Fix by brain - someone needs to learn to validate their input! */
		if (!channel)
		{
			user->WriteNumeric(Numerics::NoSuchChannel(channame));
			return CMD_FAILURE;
		}
		if ((!target) || (target->registered != REG_ALL))
		{
			user->WriteNumeric(Numerics::NoSuchNick(username));
			return CMD_FAILURE;
		}

		if (!channel->HasUser(target))
		{
			user->WriteNotice(InspIRCd::Format("*** The user %s is not on channel %s", target->nick.c_str(), channel->name.c_str()));
			return CMD_FAILURE;
		}

		if (target->server->IsULine())
		{
			user->WriteNumeric(ERR_CHANOPRIVSNEEDED, channame, "Only a u-line may remove a u-line from a channel.");
			return CMD_FAILURE;
		}

		/* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */
		if ((!IS_LOCAL(user)) || (!supportnokicks) || (!channel->IsModeSet(nokicksmode)))
		{
			/* We'll let everyone remove their level and below, eg:
			 * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1)
			  a ulined target will get a higher level than it's possible for a /remover to get..so they're safe.
			 * Nobody may remove people with >= protectedrank rank.
			 */
			unsigned int ulevel = channel->GetPrefixValue(user);
			unsigned int tlevel = channel->GetPrefixValue(target);
			if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && ((protectedrank == 0) || (tlevel < protectedrank))))
			{
				// REMOVE will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command)
				if (!IS_LOCAL(target))
				{
					// Send an ENCAP REMOVE with parameters being in the old <user> <chan> order which is
					// compatible with both 2.0 and 3.0. This also turns FPART into REMOVE.
					CommandBase::Params p;
					p.push_back(target->uuid);
					p.push_back(channel->name);
					if (parameters.size() > 2)
						p.push_back(":" + parameters[2]);
					ServerInstance->PI->SendEncapsulatedData(target->server->GetName(), "REMOVE", p, user);

					return CMD_SUCCESS;
				}

				std::string reasonparam;

				/* If a reason is given, use it */
				if(parameters.size() > 2)
					reasonparam = parameters[2];
				else
					reasonparam = "No reason given";

				/* Build up the part reason string. */
				reason = "Removed by " + user->nick + ": " + reasonparam;

				channel->WriteNotice(InspIRCd::Format("%s removed %s from the channel", user->nick.c_str(), target->nick.c_str()));
				target->WriteNotice("*** " + user->nick + " removed you from " + channel->name + " with the message: " + reasonparam);

				channel->PartUser(target, reason);
			}
			else
			{
				user->WriteNotice(InspIRCd::Format("*** You do not have access to /remove %s from %s", target->nick.c_str(), channel->name.c_str()));
				return CMD_FAILURE;
			}
		}
		else
		{
			/* m_nokicks.so was loaded and +Q was set, block! */
			user->WriteNumeric(ERR_RESTRICTED, channel->name, InspIRCd::Format("Can't remove user %s from channel (nokicks mode is set)", target->nick.c_str()));
			return CMD_FAILURE;
		}

		return CMD_SUCCESS;
	}
Exemple #21
0
void ModeParser::Process(const std::vector<std::string>& parameters, User* user, ModeProcessFlag flags)
{
	std::string target = parameters[0];
	Channel* targetchannel = ServerInstance->FindChan(target);
	User* targetuser  = ServerInstance->FindNick(target);
	ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;

	LastParse.clear();
	LastParseParams.clear();
	LastParseTranslate.clear();

	if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser))))
	{
		user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
		return;
	}
	if (parameters.size() == 1)
	{
		this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
		return;
	}

	ModResult MOD_RESULT;
	FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));

	bool SkipAccessChecks = false;

	if (!IS_LOCAL(user) || ServerInstance->ULine(user->server) || MOD_RESULT == MOD_RES_ALLOW)
		SkipAccessChecks = true;
	else if (MOD_RESULT == MOD_RES_DENY)
		return;

	if (targetuser && !SkipAccessChecks && user != targetuser)
	{
		user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
		return;
	}

	std::string mode_sequence = parameters[1];

	std::string output_mode;
	std::ostringstream output_parameters;
	LastParseParams.push_back(output_mode);
	LastParseTranslate.push_back(TR_TEXT);

	bool adding = true;
	char output_pm = '\0'; // current output state, '+' or '-'
	unsigned int param_at = 2;

	for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
	{
		unsigned char modechar = *letter;
		if (modechar == '+' || modechar == '-')
		{
			adding = (modechar == '+');
			continue;
		}

		ModeHandler *mh = this->FindMode(modechar, type);
		if (!mh)
		{
			/* No mode handler? Unknown mode character then. */
			user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
			continue;
		}

		std::string parameter;
		int pcnt = mh->GetNumParams(adding);
		if (pcnt && param_at == parameters.size())
		{
			/* No parameter, continue to the next mode */
			mh->OnParameterMissing(user, targetuser, targetchannel);
			continue;
		}
		else if (pcnt)
		{
			parameter = parameters[param_at++];
			/* Make sure the user isn't trying to slip in an invalid parameter */
			if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
				continue;
			if ((flags & MODE_MERGE) && targetchannel && targetchannel->IsModeSet(mh) && !mh->IsListMode())
			{
				std::string ours = targetchannel->GetModeParameter(mh);
				if (!mh->ResolveModeConflict(parameter, ours, targetchannel))
					/* we won the mode merge, don't apply this mode */
					continue;
			}
		}

		ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);

		if (ma != MODEACTION_ALLOW)
			continue;

		char needed_pm = adding ? '+' : '-';
		if (needed_pm != output_pm)
		{
			output_pm = needed_pm;
			output_mode.append(1, output_pm);
		}
		output_mode.append(1, modechar);

		if (pcnt)
		{
			output_parameters << " " << parameter;
			LastParseParams.push_back(parameter);
			LastParseTranslate.push_back(mh->GetTranslateType());
		}

		if ( (output_mode.length() + output_parameters.str().length() > 450)
				|| (output_mode.length() > 100)
				|| (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
		{
			/* mode sequence is getting too long */
			break;
		}
	}

	LastParseParams[0] = output_mode;

	if (!output_mode.empty())
	{
		LastParse = targetchannel ? targetchannel->name : targetuser->nick;
		LastParse.append(" ");
		LastParse.append(output_mode);
		LastParse.append(output_parameters.str());

		if (!(flags & MODE_LOCALONLY))
			ServerInstance->PI->SendMode(user, targetuser, targetchannel, LastParseParams, LastParseTranslate);

		if (targetchannel)
			targetchannel->WriteChannel(user, "MODE " + LastParse);
		else
			targetuser->WriteFrom(user, "MODE " + LastParse);

		FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastParseParams, LastParseTranslate));
	}
	else if (targetchannel && parameters.size() == 2)
	{
		/* Special case for displaying the list for listmodes,
		 * e.g. MODE #chan b, or MODE #chan +b without a parameter
		 */
		this->DisplayListModes(user, targetchannel, mode_sequence);
	}
}
static bool WriteDatabase(PermChannel& permchanmode, Module* mod, bool save_listmodes)
{
	ChanModeReference ban(mod, "ban");
	/*
	 * We need to perform an atomic write so as not to f**k things up.
	 * So, let's write to a temporary file, flush it, then rename the file..
	 *     -- w00t
	 */
	
	// If the user has not specified a configuration file then we don't write one.
	if (permchannelsconf.empty())
		return true;

	std::string permchannelsnewconf = permchannelsconf + ".tmp";
	std::ofstream stream(permchannelsnewconf.c_str());
	if (!stream.is_open())
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot create database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno);
		return false;
	}
	
	stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl
		<< "<config format=\"xml\">" << std::endl;

	for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
	{
		Channel* chan = i->second;
		if (!chan->IsModeSet(permchanmode))
			continue;

		std::string chanmodes = chan->ChanModes(true);
		if (save_listmodes)
		{
			ListModeData lm;

			// Bans are managed by the core, so we have to process them separately
			static_cast<ListModeBase*>(*ban)->DoSyncChannel(chan, mod, &lm);

			// All other listmodes are managed by modules, so we need to ask them (call their
			// OnSyncChannel() handler) to give our ProtoSendMode() a list of modes that are
			// set on the channel. The ListModeData struct is passed as an opaque pointer
			// that will be passed back to us by the module handling the mode.
			FOREACH_MOD(OnSyncChannel, (chan, mod, &lm));

			if (!lm.modes.empty())
			{
				// Remove the last space
				lm.params.erase(lm.params.end()-1);

				// If there is at least a space in chanmodes (that is, a non-listmode has a parameter)
				// insert the listmode mode letters before the space. Otherwise just append them.
				std::string::size_type p = chanmodes.find(' ');
				if (p == std::string::npos)
					chanmodes += lm.modes;
				else
					chanmodes.insert(p, lm.modes);

				// Append the listmode parameters (the masks themselves)
				chanmodes += ' ';
				chanmodes += lm.params;
			}
		}

		stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name)
			<< "\" ts=\"" << chan->age
			<< "\" topic=\"" << ServerConfig::Escape(chan->topic)
			<< "\" topicts=\"" << chan->topicset
			<< "\" topicsetby=\"" << ServerConfig::Escape(chan->setby)
			<< "\" modes=\"" << ServerConfig::Escape(chanmodes)
			<< "\">" << std::endl;
	}

	if (stream.fail())
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot write to new database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno);
		return false;
	}
	stream.close();

#ifdef _WIN32
	if (remove(permchannelsconf.c_str()))
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot remove old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno);
		return false;
	}
#endif
	// Use rename to move temporary to new db - this is guarenteed not to f**k up, even in case of a crash.
	if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0)
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot move new to old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno);
		return false;
	}

	return true;
}
Exemple #23
0
static bool WriteDatabase()
{
	/*
	 * We need to perform an atomic write so as not to f**k things up.
	 * So, let's write to a temporary file, flush it, then rename the file..
	 *     -- w00t
	 */
	
	// If the user has not specified a configuration file then we don't write one.
	if (permchannelsconf.empty())
		return true;

	std::string permchannelsnewconf = permchannelsconf + ".tmp";
	std::ofstream stream(permchannelsnewconf.c_str());
	if (!stream.is_open())
	{
		ServerInstance->Logs->Log("m_permchannels", LOG_DEFAULT, "permchannels: Cannot create database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno);
		return false;
	}
	
	stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl
		<< "<config format=\"xml\">" << std::endl;

	for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
	{
		Channel* chan = i->second;
		if (!chan->IsModeSet('P'))
			continue;

		stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name)
			<< "\" topic=\"" << ServerConfig::Escape(chan->topic)
			<< "\" modes=\"" << ServerConfig::Escape(chan->ChanModes(true))
			<< "\">" << std::endl;
	}

	if (stream.fail())
	{
		ServerInstance->Logs->Log("m_permchannels", LOG_DEFAULT, "permchannels: Cannot write to new database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno);
		return false;
	}
	stream.close();

#ifdef _WIN32
	if (remove(permchannelsconf.c_str()))
	{
		ServerInstance->Logs->Log("m_permchannels", LOG_DEFAULT, "permchannels: Cannot remove old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno);
		return false;
	}
#endif
	// Use rename to move temporary to new db - this is guarenteed not to f**k up, even in case of a crash.
	if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0)
	{
		ServerInstance->Logs->Log("m_permchannels", LOG_DEFAULT, "permchannels: Cannot move new to old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno);
		return false;
	}

	return true;
}
Exemple #24
0
CmdResult CommandNotice::Handle (const std::vector<std::string>& parameters, User *user)
{
    User *dest;
    Channel *chan;

    CUList exempt_list;

    user->idle_lastmsg = ServerInstance->Time();

    if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
        return CMD_SUCCESS;
    if (parameters[0][0] == '$')
    {
        if (!user->HasPrivPermission("users/mass-message"))
            return CMD_SUCCESS;

        int MOD_RESULT = 0;
        std::string temp = parameters[1];
        FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, exempt_list));
        if (MOD_RESULT)
            return CMD_FAILURE;
        const char* text = temp.c_str();
        const char* servermask = (parameters[0].c_str()) + 1;

        FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list));
        if (InspIRCd::Match(ServerInstance->Config->ServerName,servermask, NULL))
        {
            user->SendAll("NOTICE", "%s", text);
        }
        FOREACH_MOD(I_OnUserNotice,OnUserNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list));
        return CMD_SUCCESS;
    }
    char status = 0;
    const char* target = parameters[0].c_str();

    if (ServerInstance->Modes->FindPrefix(*target))
    {
        status = *target;
        target++;
    }
    if (*target == '#')
    {
        chan = ServerInstance->FindChan(target);

        exempt_list[user] = user->nick;

        if (chan)
        {
            if (IS_LOCAL(user))
            {
                if ((chan->IsModeSet('n')) && (!chan->HasUser(user)))
                {
                    user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str());
                    return CMD_FAILURE;
                }
                if ((chan->IsModeSet('m')) && (chan->GetStatus(user) < STATUS_VOICE))
                {
                    user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str());
                    return CMD_FAILURE;
                }
            }
            int MOD_RESULT = 0;

            std::string temp = parameters[1];
            FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,chan,TYPE_CHANNEL,temp,status, exempt_list));
            if (MOD_RESULT) {
                return CMD_FAILURE;
            }
            const char* text = temp.c_str();

            if (temp.empty())
            {
                user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
                return CMD_FAILURE;
            }

            FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list));

            if (status)
            {
                if (ServerInstance->Config->UndernetMsgPrefix)
                {
                    chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name.c_str(), status, text);
                }
                else
                {
                    chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name.c_str(), text);
                }
            }
            else
            {
                chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name.c_str(), text);
            }

            FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,status,exempt_list));
        }
        else
        {
            /* no such nick/channel */
            user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target);
            return CMD_FAILURE;
        }
        return CMD_SUCCESS;
    }

    const char* destnick = parameters[0].c_str();

    if (IS_LOCAL(user))
    {
        const char* targetserver = strchr(destnick, '@');

        if (targetserver)
        {
            std::string nickonly;

            nickonly.assign(destnick, 0, targetserver - destnick);
            dest = ServerInstance->FindNickOnly(nickonly);
            if (dest && strcasecmp(dest->server, targetserver + 1))
            {
                /* Incorrect server for user */
                user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
                return CMD_FAILURE;
            }
        }
        else
            dest = ServerInstance->FindNickOnly(destnick);
    }
    else
        dest = ServerInstance->FindNick(destnick);

    if (dest)
    {
        if (parameters[1].empty())
        {
            user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
            return CMD_FAILURE;
        }

        int MOD_RESULT = 0;
        std::string temp = parameters[1];
        FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,dest,TYPE_USER,temp,0,exempt_list));
        if (MOD_RESULT) {
            return CMD_FAILURE;
        }
        const char* text = temp.c_str();

        FOREACH_MOD(I_OnText,OnText(user,dest,TYPE_USER,text,0,exempt_list));

        if (IS_LOCAL(dest))
        {
            // direct write, same server
            user->WriteTo(dest, "NOTICE %s :%s", dest->nick.c_str(), text);
        }

        FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,text,0,exempt_list));
    }
    else
    {
        /* no such nick/channel */
        user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
        return CMD_FAILURE;
    }

    return CMD_SUCCESS;

}
Exemple #25
0
static bool WriteDatabase()
{
	FILE *f;

	if (permchannelsconf.empty())
	{
		// Fake success.
		return true;
	}

	std::string tempname = permchannelsconf + ".tmp";

	/*
	 * We need to perform an atomic write so as not to f**k things up.
	 * So, let's write to a temporary file, flush and sync the FD, then rename the file..
	 *		-- w00t
	 */
	f = fopen(tempname.c_str(), "w");
	if (!f)
	{
		ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: Cannot create database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno);
		return false;
	}

	fputs("# Permchannels DB\n# This file is autogenerated; any changes will be overwritten!\n<config format=\"compat\">\n", f);
	// Now, let's write.
	for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
	{
		Channel* chan = i->second;
		if (!chan->IsModeSet('P'))
			continue;

		char line[1024];
		const char* items[] =
		{
			"<permchannels channel=",
			chan->name.c_str(),
			" topic=",
			chan->topic.c_str(),
			" modes=",
			chan->ChanModes(true),
			">\n"
		};

		int lpos = 0, item = 0, ipos = 0;
		while (lpos < 1022 && item < 7)
		{
			char c = items[item][ipos++];
			if (c == 0)
			{
				// end of this string; hop to next string, insert a quote
				item++;
				ipos = 0;
				c = '"';
			}
			else if (c == '\\' || c == '"')
			{
				line[lpos++] = '\\';
			}
			line[lpos++] = c;
		}
		line[--lpos] = 0;
		fputs(line, f);
	}

	int write_error = 0;
	write_error = ferror(f);
	write_error |= fclose(f);
	if (write_error)
	{
		ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: Cannot write to new database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno);
		return false;
	}

#ifdef _WIN32
	if (remove(permchannelsconf.c_str()))
	{
		ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: Cannot remove old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno);
		return false;
	}
#endif
	// Use rename to move temporary to new db - this is guarenteed not to f**k up, even in case of a crash.
	if (rename(tempname.c_str(), permchannelsconf.c_str()) < 0)
	{
		ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: Cannot move new to old database! %s (%d)", strerror(errno), errno);
		ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno);
		return false;
	}

	return true;
}
Exemple #26
0
	CmdResult HandleRMB(const std::vector<std::string>& parameters, User *user, bool neworder)
	{
		User* target;
		Channel* channel;
		std::string reason;
		std::string protectkey;
		std::string founderkey;
		bool hasnokicks;

		/* Set these to the parameters needed, the new version of this module switches it's parameters around
		 * supplying a new command with the new order while keeping the old /remove with the older order.
		 * /remove <nick> <channel> [reason ...]
		 * /fpart <channel> <nick> [reason ...]
		 */
		const std::string& channame = parameters[neworder ? 0 : 1];
		const std::string& username = parameters[neworder ? 1 : 0];

		/* Look up the user we're meant to be removing from the channel */
		target = ServerInstance->FindNick(username);

		/* And the channel we're meant to be removing them from */
		channel = ServerInstance->FindChan(channame);

		/* Fix by brain - someone needs to learn to validate their input! */
		if ((!target) || (target->registered != REG_ALL) || (!channel))
		{
			user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), !channel ? channame.c_str() : username.c_str());
			return CMD_FAILURE;
		}

		if (!channel->HasUser(target))
		{
			user->WriteServ( "NOTICE %s :*** The user %s is not on channel %s", user->nick.c_str(), target->nick.c_str(), channel->name.c_str());
			return CMD_FAILURE;
		}

		int ulevel = channel->GetPrefixValue(user);
		int tlevel = channel->GetPrefixValue(target);

		hasnokicks = (ServerInstance->Modules->Find("m_nokicks.so") && channel->IsModeSet('Q'));

		if (ServerInstance->ULine(target->server))
		{
			user->WriteNumeric(482, "%s %s :Only a u-line may remove a u-line from a channel.", user->nick.c_str(), channame.c_str());
			return CMD_FAILURE;
		}

		/* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */
		if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks))
		{
			/* We'll let everyone remove their level and below, eg:
			 * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1)
			 * a ulined target will get a higher level than it's possible for a /remover to get..so they're safe.
			 * Nobody may remove a founder.
			 */
			if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && (tlevel != 50000)))
			{
				// REMOVE/FPART will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command)
				if (!IS_LOCAL(target))
					return CMD_SUCCESS;

				std::string reasonparam;

				/* If a reason is given, use it */
				if(parameters.size() > 2)
					reasonparam = parameters[2];
				else
					reasonparam = "No reason given";

				/* Build up the part reason string. */
				reason = "Removed by " + user->nick + ": " + reasonparam;

				channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name.c_str(), user->nick.c_str(), target->nick.c_str());
				target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick.c_str(), user->nick.c_str(), channel->name.c_str(), reasonparam.c_str());

				channel->PartUser(target, reason);
			}
			else
			{
				user->WriteServ( "NOTICE %s :*** You do not have access to /remove %s from %s", user->nick.c_str(), target->nick.c_str(), channel->name.c_str());
				return CMD_FAILURE;
			}
		}
		else
		{
			/* m_nokicks.so was loaded and +Q was set, block! */
			user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick.c_str(), channel->name.c_str(), target->nick.c_str());
			return CMD_FAILURE;
		}

		return CMD_SUCCESS;
	}
Exemple #27
0
CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, User *user)
{
	User *dest;
	Channel *chan;
	CUList except_list;

	LocalUser* localuser = IS_LOCAL(user);
	if (localuser)
		localuser->idle_lastmsg = ServerInstance->Time();

	if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
		return CMD_SUCCESS;

	if (parameters[0][0] == '$')
	{
		if (!user->HasPrivPermission("users/mass-message"))
			return CMD_SUCCESS;

		ModResult MOD_RESULT;
		std::string temp = parameters[1];
		FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list, MSG_PRIVMSG));
		if (MOD_RESULT == MOD_RES_DENY)
			return CMD_FAILURE;

		const char* text = temp.c_str();
		const char* servermask = (parameters[0].c_str()) + 1;

		FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list));
		if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL))
		{
			user->SendAll("PRIVMSG", "%s", text);
		}
		FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list, MSG_PRIVMSG));
		return CMD_SUCCESS;
	}
	char status = 0;
	const char* target = parameters[0].c_str();

	if (ServerInstance->Modes->FindPrefix(*target))
	{
		status = *target;
		target++;
	}
	if (*target == '#')
	{
		chan = ServerInstance->FindChan(target);

		except_list.insert(user);

		if (chan)
		{
			if (localuser && chan->GetPrefixValue(user) < VOICE_VALUE)
			{
				if (chan->IsModeSet('n') && !chan->HasUser(user))
				{
					user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str());
					return CMD_FAILURE;
				}

				if (chan->IsModeSet('m'))
				{
					user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str());
					return CMD_FAILURE;
				}

				if (ServerInstance->Config->RestrictBannedUsers)
				{
					if (chan->IsBanned(user))
					{
						user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str());
						return CMD_FAILURE;
					}
				}
			}
			ModResult MOD_RESULT;

			std::string temp = parameters[1];
			FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, chan, TYPE_CHANNEL, temp, status, except_list, MSG_PRIVMSG));
			if (MOD_RESULT == MOD_RES_DENY)
				return CMD_FAILURE;

			const char* text = temp.c_str();

			/* Check again, a module may have zapped the input string */
			if (temp.empty())
			{
				user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
				return CMD_FAILURE;
			}

			FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,except_list));

			if (status)
			{
				if (ServerInstance->Config->UndernetMsgPrefix)
				{
					chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name.c_str(), status, text);
				}
				else
				{
					chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name.c_str(), text);
				}
			}
			else
			{
				chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name.c_str(), text);
			}

			FOREACH_MOD(I_OnUserMessage, OnUserMessage(user,chan, TYPE_CHANNEL, text, status, except_list, MSG_PRIVMSG));
		}
		else
		{
			/* no such nick/channel */
			user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), target);
			return CMD_FAILURE;
		}
		return CMD_SUCCESS;
	}

	const char* destnick = parameters[0].c_str();

	if (localuser)
	{
		const char* targetserver = strchr(destnick, '@');

		if (targetserver)
		{
			std::string nickonly;

			nickonly.assign(destnick, 0, targetserver - destnick);
			dest = ServerInstance->FindNickOnly(nickonly);
			if (dest && strcasecmp(dest->server.c_str(), targetserver + 1))
			{
				/* Incorrect server for user */
				user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
				return CMD_FAILURE;
			}
		}
		else
			dest = ServerInstance->FindNickOnly(destnick);
	}
	else
		dest = ServerInstance->FindNick(destnick);

	if ((dest) && (dest->registered == REG_ALL))
	{
		if (parameters[1].empty())
		{
			user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
			return CMD_FAILURE;
		}

		if (dest->IsAway())
		{
			/* auto respond with aweh msg */
			user->WriteNumeric(301, "%s %s :%s", user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str());
		}

		ModResult MOD_RESULT;

		std::string temp = parameters[1];
		FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list, MSG_PRIVMSG));
		if (MOD_RESULT == MOD_RES_DENY)
			return CMD_FAILURE;

		const char* text = temp.c_str();

		FOREACH_MOD(I_OnText,OnText(user, dest, TYPE_USER, text, 0, except_list));

		if (IS_LOCAL(dest))
		{
			// direct write, same server
			user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick.c_str(), text);
		}

		FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, dest, TYPE_USER, text, 0, except_list, MSG_PRIVMSG));
	}
	else
	{
		/* no such nick/channel */
		user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
		return CMD_FAILURE;
	}
	return CMD_SUCCESS;
}
Exemple #28
0
	CmdResult Handle(const std::vector<std::string> &parameters, User *user)
	{
		ModeHandler* mh;
		Channel* chan = ServerInstance->FindChan(parameters[0]);
		char modeletter = parameters[1][0];

		if (chan == NULL)
		{
			user->WriteNotice("The channel " + parameters[0] + " does not exist.");
			return CMD_FAILURE;
		}

		mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);
		if (mh == NULL || parameters[1].size() > 1)
		{
			user->WriteNotice(parameters[1] + " is not a valid channel mode.");
			return CMD_FAILURE;
		}

		if (chan->GetPrefixValue(user) < mh->GetLevelRequired())
		{
			user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " +  chan->name + ".");
			return CMD_FAILURE;
		}

		unsigned int prefixrank;
		char prefixchar;
		std::string pattern = parameters.size() > 2 ? parameters[2] : "*";
		ListModeBase* lm;
		ListModeBase::ModeList* ml;
		irc::modestacker modestack(false);

		if (!mh->IsListMode())
		{
			if (chan->IsModeSet(mh))
				modestack.Push(modeletter);
		}
		else if (((prefixrank = mh->GetPrefixRank()) && (prefixchar = mh->GetPrefix())))
		{
			// As user prefix modes don't have a GetList() method, let's iterate through the channel's users.
			for (UserMembIter it = chan->userlist.begin(); it != chan->userlist.end(); ++it)
			{
				if (!InspIRCd::Match(it->first->nick, pattern))
					continue;
				if (((strchr(chan->GetAllPrefixChars(user), prefixchar)) != NULL) && !(it->first == user && prefixrank > VOICE_VALUE))
					modestack.Push(modeletter, it->first->nick);
			}
		}
		else if (((lm = dynamic_cast<ListModeBase*>(mh)) != NULL) && ((ml = lm->GetList(chan)) != NULL))
		{
			for (ListModeBase::ModeList::iterator it = ml->begin(); it != ml->end(); ++it)
			{
				if (!InspIRCd::Match(it->mask, pattern))
					continue;
				modestack.Push(modeletter, it->mask);
			}
		}
		else
		{
			user->WriteNotice("Could not remove channel mode " + ConvToStr(modeletter));
			return CMD_FAILURE;
		}

		parameterlist stackresult;
		stackresult.push_back(chan->name);
		while (modestack.GetStackedLine(stackresult))
		{
			ServerInstance->Modes->Process(stackresult, user);
			stackresult.erase(stackresult.begin() + 1, stackresult.end());
		}

		return CMD_SUCCESS;
	}