Exemple #1
0
	void RemoveMode(Channel* channel, irc::modestacker* stack)
	{
		const UserMembList* cl = channel->GetUsers();
		std::vector<std::string> mode_junk;
		mode_junk.push_back(channel->name);
		irc::modestacker modestack(false);
		std::vector<std::string> stackresult;

		for (UserMembCIter i = cl->begin(); i != cl->end(); i++)
		{
			if (i->second->hasMode('Y'))
			{
				if (stack)
					stack->Push(this->GetModeChar(), i->first->nick);
				else
					modestack.Push(this->GetModeChar(), i->first->nick);
			}
		}

		if (stack)
			return;

		while (modestack.GetStackedLine(stackresult))
		{
			mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
			ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
			mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
		}
	}
Exemple #2
0
    void RemoveMode(Channel* channel, char mc, irc::modestacker* stack)
    {
        CUList* cl = channel->GetUsers();
        std::string item = extend + std::string(channel->name);
        std::vector<std::string> mode_junk;
        mode_junk.push_back(channel->name);
        irc::modestacker modestack(MyInstance, false);
        std::deque<std::string> stackresult;

        for (CUList::iterator i = cl->begin(); i != cl->end(); i++)
        {
            if (i->first->GetExt(item))
            {
                if (stack)
                    stack->Push(mc, i->first->nick);
                else
                    modestack.Push(mc, i->first->nick);
            }
        }

        if (stack)
            return;

        while (modestack.GetStackedLine(stackresult))
        {
            mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
            MyInstance->SendMode(mode_junk, MyInstance->FakeClient);
            mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
        }
    }
	void RemoveMode(chanrec* channel, char mc)
	{
		unload_kludge = true;
		CUList* cl = channel->GetUsers();
		std::string item = extend + std::string(channel->name);
		const char* mode_junk[MAXMODES+2];
		userrec* n = new userrec(MyInstance);
		n->SetFd(FD_MAGIC_NUMBER);
		mode_junk[0] = channel->name;
		irc::modestacker modestack(false);
		std::deque<std::string> stackresult;				
		for (CUList::iterator i = cl->begin(); i != cl->end(); i++)
		{
			if (i->first->GetExt(item, dummyptr))
			{
				modestack.Push(mc, i->first->nick);
			}
		}

		while (modestack.GetStackedLine(stackresult))
		{
			for (size_t j = 0; j < stackresult.size(); j++)
			{
				mode_junk[j+1] = stackresult[j].c_str();
			}
			MyInstance->SendMode(mode_junk, stackresult.size() + 1, n);
		}
		
		delete n;
		unload_kludge = false;
	}
	virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
	{
		/* NOTE: If +qa prefix is on, this is propogated by the channel join,
		 * so we dont need to propogate it manually
		 */
		if (!QAPrefixes)
		{
			// this is called when the server is linking into a net and wants to sync channel data.
			// we should send our mode changes for the channel here to ensure that other servers
			// know whos +q/+a on the channel.
			CUList* cl = chan->GetUsers();
			string_list commands;
			std::string founder = "cm_founder_"+std::string(chan->name);
			std::string protect = "cm_protect_"+std::string(chan->name);
			irc::modestacker modestack(true);
			std::deque<std::string> stackresult;
			for (CUList::iterator i = cl->begin(); i != cl->end(); i++)
			{
				if (i->first->GetExt(founder,dummyptr))
				{
					modestack.Push('q',i->first->nick);
				}
				if (i->first->GetExt(protect,dummyptr))
				{
					modestack.Push('a',i->first->nick);
				}
			}
			while (modestack.GetStackedLine(stackresult))
			{
				irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
				std::string line = mode_join.GetJoined();
				proto->ProtoSendMode(opaque,TYPE_CHANNEL,chan, line);
			}
		}
	}
Exemple #5
0
void ListModeBase::DoSyncChannel(Channel* chan, Module* proto, void* opaque)
{
	ChanData* cd = extItem.get(chan);
	if (!cd)
		return;

	irc::modestacker modestack(true);
	std::vector<std::string> stackresult;
	std::vector<TranslateType> types;
	types.push_back(TR_TEXT);

	for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++)
		modestack.Push(mode, it->mask);

	while (modestack.GetStackedLine(stackresult))
	{
		types.assign(stackresult.size(), this->GetTranslateType());
		proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, stackresult, types);
		stackresult.clear();
	}
}
Exemple #6
0
/** FJOIN, almost identical to TS6 SJOIN, except for nicklist handling. */
CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *srcuser)
{
	SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils;
	/* 1.1+ FJOIN works as follows:
	 *
	 * Each FJOIN is sent along with a timestamp, and the side with the lowest
	 * timestamp 'wins'. From this point on we will refer to this side as the
	 * winner. The side with the higher timestamp loses, from this point on we
	 * will call this side the loser or losing side. This should be familiar to
	 * anyone who's dealt with dreamforge or TS6 before.
	 *
	 * When two sides of a split heal and this occurs, the following things
	 * will happen:
	 *
	 * If the timestamps are exactly equal, both sides merge their privilages
	 * and users, as in InspIRCd 1.0 and ircd2.8. The channels have not been
	 * re-created during a split, this is safe to do.
	 *
	 * If the timestamps are NOT equal, the losing side removes all of its
	 * modes from the channel, before introducing new users into the channel
	 * which are listed in the FJOIN command's parameters. The losing side then
	 * LOWERS its timestamp value of the channel to match that of the winning
	 * side, and the modes of the users of the winning side are merged in with
	 * the losing side.
	 *
	 * The winning side on the other hand will ignore all user modes from the
	 * losing side, so only its own modes get applied. Life is simple for those
	 * who succeed at internets. :-)
	 *
	 * Syntax:
	 * :<sid> FJOIN <chan> <TS> <modes> :[[modes,]<uuid> [[modes,]<uuid> ... ]]
	 * The last parameter is a list consisting of zero or more (modelist, uuid)
	 * pairs (permanent channels may have zero users). The mode list for each
	 * user is a concatenation of the mode letters the user has on the channel
	 * (e.g.: "ov" if the user is opped and voiced). The order of the mode letters
	 * are not important but if a server ecounters an unknown mode letter, it will
	 * drop the link to avoid desync.
	 *
	 * InspIRCd 2.0 and older required a comma before the uuid even if the user
	 * had no prefix modes on the channel, InspIRCd 2.2 and later does not require
	 * a comma in this case anymore.
	 *
	 */

	time_t TS = ConvToInt(params[1]);
	if (!TS)
	{
		ServerInstance->Logs->Log("m_spanningtree",LOG_DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
		ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", srcuser->server.c_str());
		return CMD_INVALID;
	}

	const std::string& channel = params[0];
	Channel* chan = ServerInstance->FindChan(channel);
	bool apply_other_sides_modes = true;

	if (!chan)
	{
		chan = new Channel(channel, TS);
	}
	else
	{
		time_t ourTS = chan->age;
		if (TS != ourTS)
		{
			ServerInstance->SNO->WriteToSnoMask('d', "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %lu",
				chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (unsigned long)(ourTS - TS));
			/* If our TS is less than theirs, we dont accept their modes */
			if (ourTS < TS)
			{
				apply_other_sides_modes = false;
			}
			else if (ourTS > TS)
			{
				/* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */
				if (Utils->AnnounceTSChange)
					chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name.c_str(), channel.c_str(), (unsigned long) ourTS, (unsigned long) TS);

				// while the name is equal in case-insensitive compare, it might differ in case; use the remote version
				chan->name = channel;
				chan->age = TS;
				chan->ClearInvites();

				CommandFJoin::RemoveStatus(chan);

				// XXX: If the channel does not exist in the chan hash at this point, create it so the remote modes can be applied on it.
				// This happens to 0-user permanent channels on the losing side, because those are removed (from the chan hash, then
				// deleted later) as soon as the permchan mode is removed from them.
				if (ServerInstance->FindChan(channel) == NULL)
				{
					chan = new Channel(channel, TS);
				}
			}
		}
	}

	/* First up, apply their channel modes if they won the TS war */
	if (apply_other_sides_modes)
	{
		std::vector<std::string> modelist;
		modelist.push_back(channel);

		/* Remember, params[params.size() - 1] is userlist, and we don't want to apply *that* */
		modelist.insert(modelist.end(), params.begin()+2, params.end()-1);
		ServerInstance->SendMode(modelist, srcuser);
	}

	irc::modestacker modestack(true);
	TreeSocket* src_socket = Utils->FindServer(srcuser->server)->GetRoute()->GetSocket();

	/* Now, process every 'modes,uuid' pair */
	irc::tokenstream users(*params.rbegin());
	std::string item;
	irc::modestacker* modestackptr = (apply_other_sides_modes ? &modestack : NULL);
	while (users.GetToken(item))
	{
		if (!ProcessModeUUIDPair(item, src_socket, chan, modestackptr))
			return CMD_INVALID;
	}

	/* Flush mode stacker if we lost the FJOIN or had equal TS */
	if (apply_other_sides_modes)
		CommandFJoin::ApplyModeStack(srcuser, chan, modestack);

	return CMD_SUCCESS;
}
Exemple #7
0
	CmdResult Handle (const std::vector<std::string> &parameters, User *user)
	{
		if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName.c_str())
			return CMD_SUCCESS;

		User *targuser;
		Channel *targchan;
		std::string checkstr;
		std::string chliststr;

		checkstr = ":" + ServerInstance->Config->ServerName + " 304 " + user->nick + " :CHECK";

		targuser = ServerInstance->FindNick(parameters[0]);
		targchan = ServerInstance->FindChan(parameters[0]);

		/*
		 * Syntax of a /check reply:
		 *  :server.name 304 target :CHECK START <target>
		 *  :server.name 304 target :CHECK <field> <value>
		 *  :server.name 304 target :CHECK END
		 */

		user->SendText(checkstr + " START " + parameters[0]);

		if (targuser)
		{
			LocalUser* loctarg = IS_LOCAL(targuser);
			/* /check on a user */
			user->SendText(checkstr + " nuh " + targuser->GetFullHost());
			user->SendText(checkstr + " realnuh " + targuser->GetFullRealHost());
			user->SendText(checkstr + " realname " + targuser->fullname);
			user->SendText(checkstr + " modes +" + targuser->FormatModes());
			user->SendText(checkstr + " snomasks +" + targuser->FormatNoticeMasks());
			user->SendText(checkstr + " server " + targuser->server);
			user->SendText(checkstr + " uid " + targuser->uuid);
			user->SendText(checkstr + " signon " + timestring(targuser->signon));
			user->SendText(checkstr + " nickts " + timestring(targuser->age));
			if (loctarg)
				user->SendText(checkstr + " lastmsg " + timestring(loctarg->idle_lastmsg));

			if (IS_AWAY(targuser))
			{
				/* user is away */
				user->SendText(checkstr + " awaytime " + timestring(targuser->awaytime));
				user->SendText(checkstr + " awaymsg " + targuser->awaymsg);
			}

			if (IS_OPER(targuser))
			{
				OperInfo* oper = targuser->oper;
				/* user is an oper of type ____ */
				user->SendText(checkstr + " opertype " + oper->NameStr());
				if (loctarg)
				{
					std::string umodes;
					std::string cmodes;
					for(char c='A'; c < 'z'; c++)
					{
						ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER);
						if (mh && mh->NeedsOper() && loctarg->HasModePermission(c, MODETYPE_USER))
							umodes.push_back(c);
						mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL);
						if (mh && mh->NeedsOper() && loctarg->HasModePermission(c, MODETYPE_CHANNEL))
							cmodes.push_back(c);
					}
					user->SendText(checkstr + " modeperms user="******" channel=" + cmodes);
					std::string opcmds;
					for(std::set<std::string>::iterator i = oper->AllowedOperCommands.begin(); i != oper->AllowedOperCommands.end(); i++)
					{
						opcmds.push_back(' ');
						opcmds.append(*i);
					}
					std::stringstream opcmddump(opcmds);
					user->SendText(checkstr + " commandperms", opcmddump);
					std::string privs;
					for(std::set<std::string>::iterator i = oper->AllowedPrivs.begin(); i != oper->AllowedPrivs.end(); i++)
					{
						privs.push_back(' ');
						privs.append(*i);
					}
					std::stringstream privdump(privs);
					user->SendText(checkstr + " permissions", privdump);
				}
			}

			if (loctarg)
			{
				user->SendText(checkstr + " clientaddr " + irc::sockets::satouser(loctarg->client_sa));
				user->SendText(checkstr + " serveraddr " + irc::sockets::satouser(loctarg->server_sa));

				std::string classname = loctarg->GetClass()->name;
				if (!classname.empty())
					user->SendText(checkstr + " connectclass " + classname);
			}
			else
				user->SendText(checkstr + " onip " + targuser->GetIPString());

			for (UCListIter i = targuser->chans.begin(); i != targuser->chans.end(); i++)
			{
				Channel* c = *i;
				chliststr.append(c->GetPrefixChar(targuser)).append(c->name).append(" ");
			}

			std::stringstream dump(chliststr);

			user->SendText(checkstr + " onchans", dump);

			dumpExt(user, checkstr, targuser);
		}
		else if (targchan)
		{
			/* /check on a channel */
			user->SendText(checkstr + " timestamp " + timestring(targchan->age));

			if (targchan->topic[0] != 0)
			{
				/* there is a topic, assume topic related information exists */
				user->SendText(checkstr + " topic " + targchan->topic);
				user->SendText(checkstr + " topic_setby " + targchan->setby);
				user->SendText(checkstr + " topic_setat " + timestring(targchan->topicset));
			}

			user->SendText(checkstr + " modes " + targchan->ChanModes(true));
			user->SendText(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter()));

			/* now the ugly bit, spool current members of a channel. :| */

			const UserMembList *ulist= targchan->GetUsers();

			/* note that unlike /names, we do NOT check +i vs in the channel */
			for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++)
			{
				char tmpbuf[MAXBUF];
				/*
				 * Unlike Asuka, I define a clone as coming from the same host. --w00t
				 */
				snprintf(tmpbuf, MAXBUF, "%-3lu %s%s (%s@%s) %s ", ServerInstance->Users->GlobalCloneCount(i->first), targchan->GetAllPrefixChars(i->first), i->first->nick.c_str(), i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str());
				user->SendText(checkstr + " member " + tmpbuf);
			}

			irc::modestacker modestack(true);
			for(BanList::iterator b = targchan->bans.begin(); b != targchan->bans.end(); ++b)
			{
				modestack.Push('b', b->data);
			}
			std::vector<std::string> stackresult;
			std::vector<TranslateType> dummy;
			while (modestack.GetStackedLine(stackresult))
			{
				creator->ProtoSendMode(user, TYPE_CHANNEL, targchan, stackresult, dummy);
				stackresult.clear();
			}
			FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(targchan,creator,user));
			dumpExt(user, checkstr, targchan);
		}
		else
		{
			/*  /check on an IP address, or something that doesn't exist */
			long x = 0;

			/* hostname or other */
			for (user_hash::const_iterator a = ServerInstance->Users->clientlist->begin(); a != ServerInstance->Users->clientlist->end(); a++)
			{
				if (InspIRCd::Match(a->second->host, parameters[0], ascii_case_insensitive_map) || InspIRCd::Match(a->second->dhost, parameters[0], ascii_case_insensitive_map))
				{
					/* host or vhost matches mask */
					user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname);
				}
				/* IP address */
				else if (InspIRCd::MatchCIDR(a->second->GetIPString(), parameters[0]))
				{
					/* same IP. */
					user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname);
				}
			}

			user->SendText(checkstr + " matches " + ConvToStr(x));
		}

		user->SendText(checkstr + " END " + parameters[0]);

		return CMD_SUCCESS;
	}
Exemple #8
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;
	}