Exemplo n.º 1
0
/*
 * Reply to a channel mode request.
 *
 * @param Origin The originator of the MODE command (prefix).
 * @param Channel The channel of which the modes should be sent.
 * @return CONNECTED or DISCONNECTED.
 */
static bool
Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
{
	char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
	const char *mode_ptr;

	if (!Channel_IsMemberOf(Channel, Origin)) {
		/* Not a member: "simple" mode reply */
		if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
					Client_ID(Origin), Channel_Name(Channel),
					Channel_Modes(Channel)))
			return DISCONNECTED;
	} else {
		/* The sender is a member: generate extended reply */
		strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
		mode_ptr = the_modes;
		the_args[0] = '\0';

		while(*mode_ptr) {
			switch(*mode_ptr) {
			case 'l':
				snprintf(argadd, sizeof(argadd), " %lu",
					 Channel_MaxUsers(Channel));
				strlcat(the_args, argadd, sizeof(the_args));
				break;
			case 'k':
				strlcat(the_args, " ", sizeof(the_args));
				strlcat(the_args, Channel_Key(Channel),
					sizeof(the_args));
				break;
			}
			mode_ptr++;
		}
		if (the_args[0])
			strlcat(the_modes, the_args, sizeof(the_modes));

		if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
					Client_ID(Origin), Channel_Name(Channel),
					the_modes))
			return DISCONNECTED;
	}

#ifndef STRICT_RFC
	/* Channel creation time */
	if (!IRC_WriteStrClient(Origin, RPL_CREATIONTIME_MSG,
				  Client_ID(Origin), Channel_Name(Channel),
				  Channel_CreationTime(Channel)))
		return DISCONNECTED;
#endif
	return CONNECTED;
}
Exemplo n.º 2
0
/**
 * Send CHANINFO commands to a new server (inform it about existing channels).
 * @param Client New server
 * @param Chan Channel
 */
static bool
Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
{
	char *modes, *topic;
	bool has_k, has_l;

#ifdef DEBUG
	Log(LOG_DEBUG, "Sending CHANINFO commands for \"%s\" ...",
	    Channel_Name(Chan));
#endif

	modes = Channel_Modes(Chan);
	topic = Channel_Topic(Chan);

	if (!*modes && !*topic)
		return CONNECTED;

	has_k = Channel_HasMode(Chan, 'k');
	has_l = Channel_HasMode(Chan, 'l');

	/* send CHANINFO */
	if (!has_k && !has_l) {
		if (!*topic) {
			/* "CHANINFO <chan> +<modes>" */
			return IRC_WriteStrClient(Client, "CHANINFO %s +%s",
						  Channel_Name(Chan), modes);
		}
		/* "CHANINFO <chan> +<modes> :<topic>" */
		return IRC_WriteStrClient(Client, "CHANINFO %s +%s :%s",
					  Channel_Name(Chan), modes, topic);
	}
	/* "CHANINFO <chan> +<modes> <key> <limit> :<topic>" */
	return IRC_WriteStrClient(Client, "CHANINFO %s +%s %s %lu :%s",
				  Channel_Name(Chan), modes,
				  has_k ? Channel_Key(Chan) : "*",
				  has_l ? Channel_MaxUsers(Chan) : 0, topic);
} /* Send_CHANINFO */
Exemplo n.º 3
0
/**
 * Check weather a local client is allowed to join an already existing
 * channel or not.
 *
 * @param Client	Client that sent the JOIN command
 * @param chan		Channel to check
 * @param channame	Name of the channel
 * @param key		Provided channel key (or NULL)
 * @returns		true if client is allowed to join, false otherwise
 */
static bool
join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame,
	     const char *key)
{
	bool is_invited, is_banned, is_exception;

	/* Allow IRC operators to overwrite channel limits */
	if (Client_HasMode(Client, 'o'))
		return true;

	is_banned = Lists_Check(Channel_GetListBans(chan), Client);
	is_exception = Lists_Check(Channel_GetListExcepts(chan), Client);
	is_invited = Lists_Check(Channel_GetListInvites(chan), Client);

	if (is_banned && !is_invited && !is_exception) {
		/* Client is banned from channel (and not on invite list) */
		IRC_WriteErrClient(Client, ERR_BANNEDFROMCHAN_MSG,
				   Client_ID(Client), channame);
		return false;
	}

	if (Channel_HasMode(chan, 'i') && !is_invited) {
		/* Channel is "invite-only" and client is not on invite list */
		IRC_WriteErrClient(Client, ERR_INVITEONLYCHAN_MSG,
				   Client_ID(Client), channame);
		return false;
	}

	if (!Channel_CheckKey(chan, Client, key ? key : "")) {
		/* Channel is protected by a channel key and the client
		 * didn't specify the correct one */
		IRC_WriteErrClient(Client, ERR_BADCHANNELKEY_MSG,
				   Client_ID(Client), channame);
		return false;
	}

	if (Channel_HasMode(chan, 'l') &&
	    (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) {
		/* There are more clints joined to this channel than allowed */
		IRC_WriteErrClient(Client, ERR_CHANNELISFULL_MSG,
				   Client_ID(Client), channame);
		return false;
	}

	if (Channel_HasMode(chan, 'z') && !Conn_UsesSSL(Client_Conn(Client))) {
		/* Only "secure" clients are allowed, but clients doesn't
		 * use SSL encryption */
		IRC_WriteErrClient(Client, ERR_SECURECHANNEL_MSG,
				   Client_ID(Client), channame);
		return false;
	}

	if (Channel_HasMode(chan, 'O') && !Client_HasMode(Client, 'o')) {
		/* Only IRC operators are allowed! */
		IRC_WriteErrClient(Client, ERR_OPONLYCHANNEL_MSG,
				   Client_ID(Client), channame);
		return false;
	}

	if (Channel_HasMode(chan, 'R') && !Client_HasMode(Client, 'R')) {
		/* Only registered users are allowed! */
		IRC_WriteErrClient(Client, ERR_REGONLYCHANNEL_MSG,
				   Client_ID(Client), channame);
		return false;
	}

	return true;
} /* join_allowed */
Exemplo n.º 4
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 */