Example #1
0
/**
 * Acknowledge user JOIN request and send "channel info" numerics.
 *
 * @param Client	Client used to prefix the genrated commands
 * @param target	Forward commands/numerics to this user
 * @param chan		Channel structure
 * @param channame	Channel name
 */
static bool
join_send_topic(CLIENT *Client, CLIENT *target, CHANNEL *chan,
					const char *channame)
{
	const char *topic;

	if (Client_Type(Client) != CLIENT_USER)
		return true;
	/* acknowledge join */
	if (!IRC_WriteStrClientPrefix(Client, target, "JOIN :%s", channame))
		return false;

	/* Send topic to client, if any */
	topic = Channel_Topic(chan);
	assert(topic != NULL);
	if (*topic) {
		if (!IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
			Client_ID(Client), channame, topic))
				return false;
#ifndef STRICT_RFC
		if (!IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
			Client_ID(Client), channame,
			Channel_TopicWho(chan),
			Channel_TopicTime(chan)))
				return false;
#endif
	}
	/* send list of channel members to client */
	if (!IRC_Send_NAMES(Client, chan))
		return false;
	return IRC_WriteStrClient(Client, RPL_ENDOFNAMES_MSG, Client_ID(Client),
				  Channel_Name(chan));
} /* join_send_topic */
Example #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 */
Example #3
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 */
Example #4
0
/**
 * Handler for the IRC "LIST" 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_LIST( CLIENT *Client, REQUEST *Req )
{
	char *pattern;
	CHANNEL *chan;
	CLIENT *from, *target;
	int count = 0;

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

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	if (Req->argc > 0)
		pattern = strtok(Req->argv[0], ",");
	else
		pattern = "*";

	if (Req->argc == 2) {
		/* Forward to other server? */
		target = Client_Search(Req->argv[1]);
		if (! target || Client_Type(target) != CLIENT_SERVER)
			return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
						  Client_ID(Client),
						  Req->argv[1]);

		if (target != Client_ThisServer()) {
			/* Target is indeed an other server, forward it! */
			return IRC_WriteStrClientPrefix(target, from,
							"LIST %s :%s",
							Req->argv[0],
							Req->argv[1]);
		}
	}

	while (pattern) {
		/* Loop through all the channels */
		if (Req->argc > 0)
			ngt_LowerStr(pattern);
		chan = Channel_First();
		while (chan) {
			/* Check search pattern */
			if (MatchCaseInsensitive(pattern, Channel_Name(chan))) {
				/* Gotcha! */
				if (!Channel_HasMode(chan, 's')
				    || Channel_IsMemberOf(chan, from)
				    || (!Conf_MorePrivacy
					&& Client_HasMode(Client, 'o')
					&& Client_Conn(Client) > NONE))
				{
					if ((Conf_MaxListSize > 0)
					    && IRC_CheckListTooBig(from, count,
								   Conf_MaxListSize,
								   "LIST"))
						break;
					if (!IRC_WriteStrClient(from,
					     RPL_LIST_MSG, Client_ID(from),
					     Channel_Name(chan),
					     Channel_MemberCount(chan),
					     Channel_Topic( chan )))
						return DISCONNECTED;
					count++;
				}
			}
			chan = Channel_Next(chan);
		}

		/* Get next name ... */
		if(Req->argc > 0)
			pattern = strtok(NULL, ",");
		else
			pattern = NULL;
	}

	return IRC_WriteStrClient(from, RPL_LISTEND_MSG, Client_ID(from));
} /* IRC_LIST */
Example #5
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 */