Exemplo n.º 1
0
/**
 * Handler for the IRC "PART" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_PART(CLIENT * Client, REQUEST * Req)
{
	CLIENT *target;
	char *chan;

	assert(Client != NULL);
	assert(Req != NULL);

	_IRC_GET_SENDER_OR_RETURN_(target, Req, Client)

	/* Loop over all the given channel names */
	chan = strtok(Req->argv[0], ",");

	/* Make sure that "chan" is not the empty string ("PART :") */
	if (!chan)
		return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					  Client_ID(Client), Req->command);

	while (chan) {
		Channel_Part(target, Client, chan,
			     Req->argc > 1 ? Req->argv[1] : Client_ID(target));
		chan = strtok(NULL, ",");
	}

	/* Update idle time, if local client */
	if (Client_Conn(Client) > NONE)
		Conn_UpdateIdle(Client_Conn(Client));

	return CONNECTED;
} /* IRC_PART */
Exemplo n.º 2
0
/**
 * Handler for the IRC command "KICK".
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_KICK(CLIENT *Client, REQUEST *Req)
{
	CLIENT *from;
	char *itemList = Req->argv[0];
	const char* currentNick, *currentChannel, *reason;
	unsigned int channelCount = 1;
	unsigned int nickCount = 1;

	assert( Client != NULL );
	assert( Req != NULL );

	_IRC_ARGC_BETWEEN_OR_RETURN_(Client, Req, 2, 3)
	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	while (*itemList) {
		if (*itemList == ',') {
			*itemList = '\0';
			channelCount++;
		}
		itemList++;
	}

	itemList = Req->argv[1];
	while (*itemList) {
		if (*itemList == ',') {
			*itemList = '\0';
			nickCount++;
		}
		itemList++;
	}

	reason = Req->argc == 3 ? Req->argv[2] : Client_ID(from);
	currentNick = Req->argv[1];
	currentChannel = Req->argv[0];
	if (channelCount == 1) {
		while (nickCount > 0) {
			if (!try_kick(Client, from, currentNick,
				      currentChannel, reason))
				return false;

			while (*currentNick)
				currentNick++;

			currentNick++;
			nickCount--;
		}
	} else if (channelCount == nickCount) {
		while (nickCount > 0) {
			if (!try_kick(Client, from, currentNick,
				      currentChannel, reason))
				return false;

			while (*currentNick)
				currentNick++;

			while (*currentChannel)
				currentChannel++;

			currentNick++;
			currentChannel++;
			nickCount--;
		}
	} else {
		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					Client_ID(Client), Req->command);
	}
	return true;
} /* IRC_KICK */
Exemplo n.º 3
0
/**
 * Handler for the IRC command "INVITE".
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_INVITE(CLIENT *Client, REQUEST *Req)
{
	CHANNEL *chan;
	CLIENT *target, *from;
	const char *colon_if_necessary;
	bool remember = false;

	assert( Client != NULL );
	assert( Req != NULL );

	_IRC_ARGC_EQ_OR_RETURN_(Client, Req, 2)
	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	/* Search user */
	target = Client_Search(Req->argv[0]);
	if (!target || (Client_Type(target) != CLIENT_USER))
		return IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
				Client_ID(Client), Req->argv[0]);

	chan = Channel_Search(Req->argv[1]);
	if (chan) {
		/* Channel exists. Is the user a valid member of the channel? */
		if (!Channel_IsMemberOf(chan, from))
			return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG, Client_ID(Client), Req->argv[1]);

		/* Is the channel "invite-disallow"? */
		if (strchr(Channel_Modes(chan), 'V'))
			return IRC_WriteStrClient(from, ERR_NOINVITE_MSG,
				Client_ID(from), Channel_Name(chan));

		/* Is the channel "invite-only"? */
		if (strchr(Channel_Modes(chan), 'i')) {
			/* Yes. The user must be channel owner/admin/operator/halfop! */
			if (!strchr(Channel_UserModes(chan, from), 'q') &&
			    !strchr(Channel_UserModes(chan, from), 'a') &&
			    !strchr(Channel_UserModes(chan, from), 'o') &&
			    !strchr(Channel_UserModes(chan, from), 'h'))
				return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(from), Channel_Name(chan));
			remember = true;
		}

		/* Is the target user already member of the channel? */
		if (Channel_IsMemberOf(chan, target))
			return IRC_WriteStrClient(from, ERR_USERONCHANNEL_MSG,
					Client_ID(from), Req->argv[0], Req->argv[1]);

		/* If the target user is banned on that channel: remember invite */
		if (Lists_Check(Channel_GetListBans(chan), target))
			remember = true;

		if (remember) {
			/* We must remember this invite */
			if (!Channel_AddInvite(chan, Client_Mask(target), true))
				return CONNECTED;
		}
	}

	LogDebug("User \"%s\" invites \"%s\" to \"%s\" ...", Client_Mask(from),
		 Req->argv[0], Req->argv[1]);

	/*
	 * RFC 2812 says:
	 * 'There is no requirement that the channel [..] must exist or be a valid channel'
	 * The problem with this is that this allows the "channel" to contain spaces,
	 * in which case we must prefix its name with a colon to make it clear that
	 * it is only a single argument.
	 */
	colon_if_necessary = strchr(Req->argv[1], ' ') ? ":":"";
	/* Inform target client */
	IRC_WriteStrClientPrefix(target, from, "INVITE %s %s%s", Req->argv[0],
					colon_if_necessary, Req->argv[1]);

	if (Client_Conn(target) > NONE) {
		/* The target user is local, so we have to send the status code */
		if (!IRC_WriteStrClientPrefix(from, target, RPL_INVITING_MSG,
			Client_ID(from), Req->argv[0], colon_if_necessary, Req->argv[1]))
			return DISCONNECTED;

		if (strchr(Client_Modes(target), 'a') &&
			!IRC_WriteStrClient(from, RPL_AWAY_MSG, Client_ID(from),
					Client_ID(target), Client_Away(target)))
				return DISCONNECTED;
	}
	return CONNECTED;
} /* IRC_INVITE */
Exemplo n.º 4
0
Arquivo: irc.c Projeto: ngircd/ngircd
/*
 * Handler for the IRC "TRACE" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
 GLOBAL bool
IRC_TRACE(CLIENT *Client, REQUEST *Req)
{
	CLIENT *from, *target, *c;
	CONN_ID idx, idx2;
	char user[CLIENT_USER_LEN];

	assert(Client != NULL);
	assert(Req != NULL);

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
	_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)

	/* Forward command to other server? */
	if (target != Client_ThisServer()) {
		/* Send RPL_TRACELINK back to initiator */
		idx = Client_Conn(Client);
		assert(idx > NONE);
		idx2 = Client_Conn(Client_NextHop(target));
		assert(idx2 > NONE);

		if (!IRC_WriteStrClient(from, RPL_TRACELINK_MSG,
					Client_ID(from), PACKAGE_NAME,
					PACKAGE_VERSION, Client_ID(target),
					Client_ID(Client_NextHop(target)),
					Option_String(idx2),
					(long)(time(NULL) - Conn_StartTime(idx2)),
					Conn_SendQ(idx), Conn_SendQ(idx2)))
			return DISCONNECTED;

		/* Forward command */
		IRC_WriteStrClientPrefix(target, from, "TRACE %s", Req->argv[0]);
		return CONNECTED;
	}

	/* Infos about all connected servers */
	c = Client_First();
	while (c) {
		if (Client_Conn(c) > NONE) {
			/* Local client */
			if (Client_Type(c) == CLIENT_SERVER) {
				/* Server link */
				strlcpy(user, Client_User(c), sizeof(user));
				if (user[0] == '~')
					strlcpy(user, "unknown", sizeof(user));
				if (!IRC_WriteStrClient(from,
						RPL_TRACESERVER_MSG,
						Client_ID(from), Client_ID(c),
						user, Client_Hostname(c),
						Client_Mask(Client_ThisServer()),
						Option_String(Client_Conn(c))))
					return DISCONNECTED;
			}
			if (Client_Type(c) == CLIENT_USER
			    && Client_HasMode(c, 'o')) {
				/* IRC Operator */
				if (!IRC_WriteStrClient(from,
						RPL_TRACEOPERATOR_MSG,
						Client_ID(from), Client_ID(c)))
					return DISCONNECTED;
			}
		}
		c = Client_Next( c );
	}

	return IRC_WriteStrClient(from, RPL_TRACEEND_MSG, Client_ID(from),
				  Conf_ServerName, PACKAGE_NAME,
				  PACKAGE_VERSION, NGIRCd_DebugLevel);
} /* IRC_TRACE */
Exemplo n.º 5
0
/**
 * Handler for the IRC+ "CHANINFO" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
{
	char modes_add[COMMAND_LEN], l[16];
	CLIENT *from;
	CHANNEL *chan;
	int arg_topic;

	assert( Client != NULL );
	assert( Req != NULL );

	/* Bad number of parameters? */
	if (Req->argc < 2 || Req->argc == 4 || Req->argc > 5)
		return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					  Client_ID(Client), Req->command);

	/* Compatibility kludge */
	if (Req->argc == 5)
		arg_topic = 4;
	else if(Req->argc == 3)
		arg_topic = 2;
	else
		arg_topic = -1;

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	/* Search or create channel */
	chan = Channel_Search( Req->argv[0] );
	if (!chan)
		chan = Channel_Create( Req->argv[0] );
	if (!chan)
		return CONNECTED;

	if (Req->argv[1][0] == '+') {
		if (!*Channel_Modes(chan)) {
			/* OK, this channel doesn't have modes yet,
			 * set the received ones: */
			Channel_SetModes(chan, &Req->argv[1][1]);

			if(Req->argc == 5) {
				if(Channel_HasMode(chan, 'k'))
					Channel_SetKey(chan, Req->argv[2]);
				if(Channel_HasMode(chan, 'l'))
					Channel_SetMaxUsers(chan, atol(Req->argv[3]));
			} else {
				/* Delete modes which we never want to inherit */
				Channel_ModeDel(chan, 'l');
				Channel_ModeDel(chan, 'k');
			}

			strcpy(modes_add, "");
			if (Channel_HasMode(chan, 'l'))  {
				snprintf(l, sizeof(l), " %lu",
					 Channel_MaxUsers(chan));
				strlcat(modes_add, l, sizeof(modes_add));
			}
			if (Channel_HasMode(chan, 'k'))  {
				strlcat(modes_add, " ", sizeof(modes_add));
				strlcat(modes_add, Channel_Key(chan),
					sizeof(modes_add));
			}

			/* Inform members of this channel */
			IRC_WriteStrChannelPrefix(Client, chan, from, false,
						  "MODE %s +%s%s", Req->argv[0],
						  Channel_Modes(chan), modes_add);
		}
	}
	else
		Log(LOG_WARNING, "CHANINFO: invalid MODE format ignored!");

	if (arg_topic > 0) {
		/* We got a topic */
		if (!*Channel_Topic(chan) && Req->argv[arg_topic][0]) {
			/* OK, there is no topic jet */
			Channel_SetTopic(chan, Client, Req->argv[arg_topic]);
			IRC_WriteStrChannelPrefix(Client, chan, from, false,
			     "TOPIC %s :%s", Req->argv[0], Channel_Topic(chan));
		}
	}

	/* Forward CHANINFO to other servers */
	if (Req->argc == 5)
		IRC_WriteStrServersPrefixFlag(Client, from, 'C',
					      "CHANINFO %s %s %s %s :%s",
					      Req->argv[0], Req->argv[1],
					      Req->argv[2], Req->argv[3],
					      Req->argv[4]);
	else if (Req->argc == 3)
		IRC_WriteStrServersPrefixFlag(Client, from, 'C',
					      "CHANINFO %s %s :%s",
					      Req->argv[0], Req->argv[1],
					      Req->argv[2]);
	else
		IRC_WriteStrServersPrefixFlag(Client, from, 'C',
					      "CHANINFO %s %s",
					      Req->argv[0], Req->argv[1]);

	return CONNECTED;
} /* IRC_CHANINFO */
Exemplo n.º 6
0
/**
 * Handler for the IRC "TOPIC" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_TOPIC( CLIENT *Client, REQUEST *Req )
{
	CHANNEL *chan;
	CLIENT *from;
	char *topic;
	bool r, topic_power;

	assert( Client != NULL );
	assert( Req != NULL );

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	chan = Channel_Search(Req->argv[0]);
	if (!chan)
		return IRC_WriteErrClient(from, ERR_NOSUCHCHANNEL_MSG,
					  Client_ID(from), Req->argv[0]);

	/* Only remote servers and channel members are allowed to change the
	 * channel topic, and IRC operators when the Conf_OperCanMode option
	 * is set in the server configuration. */
	if (Client_Type(Client) != CLIENT_SERVER) {
		topic_power = Client_HasMode(from, 'o');
		if (!Channel_IsMemberOf(chan, from)
		    && !(Conf_OperCanMode && topic_power))
			return IRC_WriteErrClient(from, ERR_NOTONCHANNEL_MSG,
						  Client_ID(from), Req->argv[0]);
	} else
		topic_power = true;

	if (Req->argc == 1) {
		/* Request actual topic */
		topic = Channel_Topic(chan);
		if (*topic) {
			r = IRC_WriteStrClient(from, RPL_TOPIC_MSG,
					       Client_ID(Client),
					       Channel_Name(chan), topic);
#ifndef STRICT_RFC
			if (!r)
				return r;
			r = IRC_WriteStrClient(from, RPL_TOPICSETBY_MSG,
					       Client_ID(Client),
					       Channel_Name(chan),
					       Channel_TopicWho(chan),
					       Channel_TopicTime(chan));
#endif
			return r;
		}
		else
			return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
						  Client_ID(from),
						  Channel_Name(chan));
	}

	if (Channel_HasMode(chan, 't')) {
		/* Topic Lock. Is the user a channel op or IRC operator? */
		if(!topic_power &&
		   !Channel_UserHasMode(chan, from, 'h') &&
		   !Channel_UserHasMode(chan, from, 'o') &&
		   !Channel_UserHasMode(chan, from, 'a') &&
		   !Channel_UserHasMode(chan, from, 'q'))
			return IRC_WriteErrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
						  Client_ID(from),
						  Channel_Name(chan));
	}

	/* Set new topic */
	Channel_SetTopic(chan, from, Req->argv[1]);
	LogDebug("%s \"%s\" set topic on \"%s\": %s",
		 Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
		 Req->argv[1][0] ? Req->argv[1] : "<none>");

	if (Conf_OperServerMode)
		from = Client_ThisServer();

	/* Update channel and forward new topic to other servers */
	if (!Channel_IsLocal(chan))
		IRC_WriteStrServersPrefix(Client, from, "TOPIC %s :%s",
					  Req->argv[0], Req->argv[1]);
	IRC_WriteStrChannelPrefix(Client, chan, from, false, "TOPIC %s :%s",
				  Req->argv[0], Req->argv[1]);

	if (Client_Type(Client) == CLIENT_USER)
		return IRC_WriteStrClientPrefix(Client, Client, "TOPIC %s :%s",
						Req->argv[0], Req->argv[1]);
	else
		return CONNECTED;
} /* IRC_TOPIC */