示例#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 */
示例#2
0
文件: channel.c 项目: husemann/ngircd
GLOBAL bool
Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command,
	      bool SendErrors, const char *Text)
{
	if (!Can_Send_To_Channel(Chan, From)) {
		if (! SendErrors)
			return CONNECTED;	/* no error, see RFC 2812 */
		if (strchr(Channel_Modes(Chan), 'M'))
			return IRC_WriteStrClient(From, ERR_NEEDREGGEDNICK_MSG,
						  Client_ID(From), Channel_Name(Chan));
		else
			return IRC_WriteStrClient(From, ERR_CANNOTSENDTOCHAN_MSG,
					  Client_ID(From), Channel_Name(Chan));
	}

	if (Client_Conn(From) > NONE)
		Conn_UpdateIdle(Client_Conn(From));

	return IRC_WriteStrChannelPrefix(Client, Chan, From, true,
			"%s %s :%s", Command, Channel_Name(Chan), Text);
}
示例#3
0
文件: irc.c 项目: mguindin/ngircd
static bool
Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
{
	CLIENT *cl, *from;
	CL2CHAN *cl2chan;
	CHANNEL *chan;
	char *currentTarget = Req->argv[0];
	char *lastCurrentTarget = NULL;

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

	if (Req->argc == 0) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG,
					  Client_ID(Client), Req->command);
	}
	if (Req->argc == 1) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG,
					  Client_ID(Client));
	}
	if (Req->argc > 2) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					  Client_ID(Client), Req->command);
	}

	if (Client_Type(Client) == CLIENT_SERVER)
		from = Client_Search(Req->prefix);
	else
		from = Client;
	if (!from)
		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
					  Client_ID(Client), Req->prefix);

	/* handle msgtarget = msgto *("," msgto) */
	currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget);
	ngt_UpperStr(Req->command);

	while (currentTarget) {
		/* Check for and handle valid <msgto> of form:
		 * RFC 2812 2.3.1:
		 *   msgto =  channel / ( user [ "%" host ] "@" servername )
		 *   msgto =/ ( user "%" host ) / targetmask
		 *   msgto =/ nickname / ( nickname "!" user "@" host )
		 */
		if (strchr(currentTarget, '!') == NULL)
			/* nickname */
			cl = Client_Search(currentTarget);
		else
			cl = NULL;

		if (cl == NULL) {
			/* If currentTarget isn't a nickname check for:
			 * user ["%" host] "@" servername
			 * user "%" host
			 * nickname "!" user "@" host
			 */
			char target[COMMAND_LEN];
			char * nick = NULL;
			char * user = NULL;
			char * host = NULL;
			char * server = NULL;

			strlcpy(target, currentTarget, COMMAND_LEN);
			server = strchr(target, '@');
			if (server) {
				*server = '\0';
				server++;
			}
			host = strchr(target, '%');
			if (host) {
				*host = '\0';
				host++;
			}
			user = strchr(target, '!');
			if (user) {
				/* msgto form: nick!user@host */
				*user = '******';
				user++;
				nick = target;
				host = server; /* not "@server" but "@host" */
			} else {
				user = target;
			}

			for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
				if (Client_Type(cl) != CLIENT_USER &&
				    Client_Type(cl) != CLIENT_SERVICE)
					continue;
				if (nick != NULL && host != NULL) {
					if (strcasecmp(nick, Client_ID(cl)) == 0 &&
					    strcasecmp(user, Client_User(cl)) == 0 &&
					    strcasecmp(host, Client_HostnameCloaked(cl)) == 0)
						break;
					else
						continue;
				}
				if (strcasecmp(user, Client_User(cl)) != 0)
					continue;
				if (host != NULL && strcasecmp(host,
						Client_HostnameCloaked(cl)) != 0)
					continue;
				if (server != NULL && strcasecmp(server,
						Client_ID(Client_Introducer(cl))) != 0)
					continue;
				break;
			}
		}

		if (cl) {
			/* Target is a user, enforce type */
#ifndef STRICT_RFC
			if (Client_Type(cl) != ForceType &&
			    !(ForceType == CLIENT_USER &&
			      (Client_Type(cl) == CLIENT_USER ||
			       Client_Type(cl) == CLIENT_SERVICE))) {
#else
			if (Client_Type(cl) != ForceType) {
#endif
				if (SendErrors && !IRC_WriteStrClient(
				    from, ERR_NOSUCHNICK_MSG,Client_ID(from),
				    currentTarget))
					return DISCONNECTED;
				goto send_next_target;
			}

#ifndef STRICT_RFC
			if (ForceType == CLIENT_SERVICE &&
			    (Conn_Options(Client_Conn(Client_NextHop(cl)))
			     & CONN_RFC1459)) {
				/* SQUERY command but RFC 1459 link: convert
				 * request to PRIVMSG command */
				Req->command = "PRIVMSG";
			}
#endif

			if (Client_HasMode(cl, 'C')) {
				cl2chan = Channel_FirstChannelOf(cl);
				while (cl2chan) {
					chan = Channel_GetChannel(cl2chan);
					if (Channel_IsMemberOf(chan, from))
						break;
					cl2chan = Channel_NextChannelOf(cl, cl2chan);
				}
				if (!cl2chan) {
					if (SendErrors && !IRC_WriteStrClient(
					    from, ERR_NOTONSAMECHANNEL_MSG,
					    Client_ID(from), Client_ID(cl)))
						return DISCONNECTED;
					goto send_next_target;
				}
			}

			if (SendErrors && (Client_Type(Client) != CLIENT_SERVER)
			    && strchr(Client_Modes(cl), 'a')) {
				/* Target is away */
				if (!IRC_WriteStrClient(from, RPL_AWAY_MSG,
							Client_ID(from),
							Client_ID(cl),
							Client_Away(cl)))
					return DISCONNECTED;
			}
			if (Client_Conn(from) > NONE) {
				Conn_UpdateIdle(Client_Conn(from));
			}
			if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						      Req->command, Client_ID(cl),
						      Req->argv[1]))
				return DISCONNECTED;
		} else if (ForceType != CLIENT_SERVICE
			   && (chan = Channel_Search(currentTarget))) {
			if (!Channel_Write(chan, from, Client, Req->command,
					   SendErrors, Req->argv[1]))
					return DISCONNECTED;
		} else if (ForceType != CLIENT_SERVICE
			/* $#: server/target mask, RFC 2812, sec. 3.3.1 */
			   && strchr("$#", currentTarget[0])
			   && strchr(currentTarget, '.')) {
			/* targetmask */
			if (!Send_Message_Mask(from, Req->command, currentTarget,
					       Req->argv[1], SendErrors))
				return DISCONNECTED;
		} else {
			if (!SendErrors)
				return CONNECTED;
			if (!IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
						Client_ID(from), currentTarget))
				return DISCONNECTED;
		}

	send_next_target:
		currentTarget = strtok_r(NULL, ",", &lastCurrentTarget);
		if (currentTarget)
			Conn_SetPenalty(Client_Conn(Client), 1);
	}

	return CONNECTED;
} /* Send_Message */


static bool
Send_Message_Mask(CLIENT * from, char * command, char * targetMask,
		  char * message, bool SendErrors)
{
	CLIENT *cl;
	bool client_match;
	char *mask = targetMask + 1;
	const char *check_wildcards;

	cl = NULL;

	if (strchr(Client_Modes(from), 'o') == NULL) {
		if (!SendErrors)
			return true;
		return IRC_WriteStrClient(from, ERR_NOPRIVILEGES_MSG,
					  Client_ID(from));
	}

	/*
	 * RFC 2812, sec. 3.3.1 requires that targetMask have at least one
	 * dot (".") and no wildcards ("*", "?") following the last one.
	 */
	check_wildcards = strrchr(targetMask, '.');
	assert(check_wildcards != NULL);
	if (check_wildcards &&
		check_wildcards[strcspn(check_wildcards, "*?")])
	{
		if (!SendErrors)
			return true;
		return IRC_WriteStrClient(from, ERR_WILDTOPLEVEL, targetMask);
	}

	/* #: hostmask, see RFC 2812, sec. 3.3.1 */
	if (targetMask[0] == '#') {
		for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
			if (Client_Type(cl) != CLIENT_USER)
				continue;
			client_match = MatchCaseInsensitive(mask, Client_Hostname(cl));
			if (client_match)
				if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						command, Client_ID(cl), message))
					return false;
		}
	} else {
		assert(targetMask[0] == '$'); /* $: server mask, see RFC 2812, sec. 3.3.1 */
		for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
			if (Client_Type(cl) != CLIENT_USER)
				continue;
			client_match = MatchCaseInsensitive(mask,
					Client_ID(Client_Introducer(cl)));
			if (client_match)
				if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						command, Client_ID(cl), message))
					return false;
		}
	}
	return CONNECTED;
} /* Send_Message_Mask */
示例#4
0
文件: irc.c 项目: ngircd/ngircd
/**
 * Get pointer to a static string representing the connection "options".
 *
 * @param Idx Connection index.
 * @return Pointer to static (global) string buffer.
 */
static char *
#if defined(SSL_SUPPORT) || defined(ZLIB)
Option_String(CONN_ID Idx)
{
	static char option_txt[8];
	UINT16 options;

	assert(Idx != NONE);

	options = Conn_Options(Idx);
	strcpy(option_txt, "F");	/* No idea what this means, but the
					 * original ircd sends it ... */
#ifdef SSL_SUPPORT
	if(options & CONN_SSL)		/* SSL encrypted link */
		strlcat(option_txt, "s", sizeof(option_txt));
#endif
#ifdef ZLIB
	if(options & CONN_ZIP)		/* zlib compression enabled */
		strlcat(option_txt, "z", sizeof(option_txt));
#endif

	return option_txt;
#else
Option_String(UNUSED CONN_ID Idx)
{
	return "";
#endif
} /* Option_String */

/**
 * Send a message to target(s).
 *
 * This function is used by IRC_{PRIVMSG|NOTICE|SQUERY} to actualy
 * send the message(s).
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @param ForceType Required type of the destination of the message(s).
 * @param SendErrors Whether to report errors back to the client or not.
 * @return CONNECTED or DISCONNECTED.
 */
static bool
Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
{
	CLIENT *cl, *from;
	CL2CHAN *cl2chan;
	CHANNEL *chan;
	char *currentTarget = Req->argv[0];
	char *strtok_last = NULL;
	char *message = NULL;
	char *targets[MAX_HNDL_TARGETS];
	int i, target_nr = 0;

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

	if (Req->argc == 0) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteErrClient(Client, ERR_NORECIPIENT_MSG,
					  Client_ID(Client), Req->command);
	}
	if (Req->argc == 1) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteErrClient(Client, ERR_NOTEXTTOSEND_MSG,
					  Client_ID(Client));
	}
	if (Req->argc > 2) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					  Client_ID(Client), Req->command);
	}

	if (Client_Type(Client) == CLIENT_SERVER && Req->prefix)
		from = Client_Search(Req->prefix);
	else
		from = Client;
	if (!from)
		return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
					  Client_ID(Client), Req->prefix);

#ifdef ICONV
	if (Client_Conn(Client) > NONE)
		message = Conn_EncodingFrom(Client_Conn(Client), Req->argv[1]);
	else
#endif
		message = Req->argv[1];

	/* handle msgtarget = msgto *("," msgto) */
	currentTarget = strtok_r(currentTarget, ",", &strtok_last);
	ngt_UpperStr(Req->command);

	/* Please note that "currentTarget" is NULL when the target contains
	 * the separator character only, e. g. "," or ",,,," etc.! */
	while (currentTarget) {
		/* Make sure that there hasn't been such a target already: */
		targets[target_nr++] = currentTarget;
		for(i = 0; i < target_nr - 1; i++) {
			if (strcasecmp(currentTarget, targets[i]) == 0)
				goto send_next_target;
		}

		/* Check for and handle valid <msgto> of form:
		 * RFC 2812 2.3.1:
		 *   msgto =  channel / ( user [ "%" host ] "@" servername )
		 *   msgto =/ ( user "%" host ) / targetmask
		 *   msgto =/ nickname / ( nickname "!" user "@" host )
		 */
		if (strchr(currentTarget, '!') == NULL)
			/* nickname */
			cl = Client_Search(currentTarget);
		else
			cl = NULL;

		if (cl == NULL) {
			/* If currentTarget isn't a nickname check for:
			 * user ["%" host] "@" servername
			 * user "%" host
			 * nickname "!" user "@" host
			 */
			char target[COMMAND_LEN];
			char * nick = NULL;
			char * user = NULL;
			char * host = NULL;
			char * server = NULL;

			strlcpy(target, currentTarget, COMMAND_LEN);
			server = strchr(target, '@');
			if (server) {
				*server = '\0';
				server++;
			}
			host = strchr(target, '%');
			if (host) {
				*host = '\0';
				host++;
			}
			user = strchr(target, '!');
			if (user) {
				/* msgto form: nick!user@host */
				*user = '******';
				user++;
				nick = target;
				host = server; /* not "@server" but "@host" */
			} else {
				user = target;
			}

			for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
				if (Client_Type(cl) != CLIENT_USER &&
				    Client_Type(cl) != CLIENT_SERVICE)
					continue;
				if (nick != NULL && host != NULL) {
					if (strcasecmp(nick, Client_ID(cl)) == 0 &&
					    strcasecmp(user, Client_User(cl)) == 0 &&
					    strcasecmp(host, Client_HostnameDisplayed(cl)) == 0)
						break;
					else
						continue;
				}
				if (strcasecmp(user, Client_User(cl)) != 0)
					continue;
				if (host != NULL && strcasecmp(host,
						Client_HostnameDisplayed(cl)) != 0)
					continue;
				if (server != NULL && strcasecmp(server,
						Client_ID(Client_Introducer(cl))) != 0)
					continue;
				break;
			}
		}

		if (cl) {
			/* Target is a user, enforce type */
#ifndef STRICT_RFC
			if (Client_Type(cl) != ForceType &&
			    !(ForceType == CLIENT_USER &&
			      (Client_Type(cl) == CLIENT_USER ||
			       Client_Type(cl) == CLIENT_SERVICE))) {
#else
			if (Client_Type(cl) != ForceType) {
#endif
				if (SendErrors && !IRC_WriteErrClient(
				    from, ERR_NOSUCHNICK_MSG,Client_ID(from),
				    currentTarget))
					return DISCONNECTED;
				goto send_next_target;
			}

#ifndef STRICT_RFC
			if (ForceType == CLIENT_SERVICE &&
			    (Conn_Options(Client_Conn(Client_NextHop(cl)))
			     & CONN_RFC1459)) {
				/* SQUERY command but RFC 1459 link: convert
				 * request to PRIVMSG command */
				Req->command = "PRIVMSG";
			}
#endif
			if (Client_HasMode(cl, 'b') &&
			    !Client_HasMode(from, 'R') &&
			    !Client_HasMode(from, 'o') &&
			    !(Client_Type(from) == CLIENT_SERVER) &&
			    !(Client_Type(from) == CLIENT_SERVICE)) {
				if (SendErrors && !IRC_WriteErrClient(from,
						ERR_NONONREG_MSG,
						Client_ID(from), Client_ID(cl)))
					return DISCONNECTED;
				goto send_next_target;
			}

			if (Client_HasMode(cl, 'C') &&
			    !Client_HasMode(from, 'o') &&
			    !(Client_Type(from) == CLIENT_SERVER) &&
			    !(Client_Type(from) == CLIENT_SERVICE)) {
				cl2chan = Channel_FirstChannelOf(cl);
				while (cl2chan) {
					chan = Channel_GetChannel(cl2chan);
					if (Channel_IsMemberOf(chan, from))
						break;
					cl2chan = Channel_NextChannelOf(cl, cl2chan);
				}
				if (!cl2chan) {
					if (SendErrors && !IRC_WriteErrClient(
					    from, ERR_NOTONSAMECHANNEL_MSG,
					    Client_ID(from), Client_ID(cl)))
						return DISCONNECTED;
					goto send_next_target;
				}
			}

			if (SendErrors && (Client_Type(Client) != CLIENT_SERVER)
			    && Client_HasMode(cl, 'a')) {
				/* Target is away */
				if (!IRC_WriteStrClient(from, RPL_AWAY_MSG,
							Client_ID(from),
							Client_ID(cl),
							Client_Away(cl)))
					return DISCONNECTED;
			}
			if (Client_Conn(from) > NONE) {
				Conn_UpdateIdle(Client_Conn(from));
			}
			if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						      Req->command, Client_ID(cl),
						      message))
				return DISCONNECTED;
		} else if (ForceType != CLIENT_SERVICE
			   && (chan = Channel_Search(currentTarget))) {
			/* Target is a channel */
			if (!Channel_Write(chan, from, Client, Req->command,
					   SendErrors, message))
					return DISCONNECTED;
		} else if (ForceType != CLIENT_SERVICE
			   && strchr("$#", currentTarget[0])
			   && strchr(currentTarget, '.')) {
			/* $#: server/host mask, RFC 2812, sec. 3.3.1 */
			if (!Send_Message_Mask(from, Req->command, currentTarget,
					       message, SendErrors))
				return DISCONNECTED;
		} else {
			if (!SendErrors)
				return CONNECTED;
			if (!IRC_WriteErrClient(from, ERR_NOSUCHNICK_MSG,
						Client_ID(from), currentTarget))
				return DISCONNECTED;
		}

	send_next_target:
		currentTarget = strtok_r(NULL, ",", &strtok_last);
		if (!currentTarget)
			break;

		Conn_SetPenalty(Client_Conn(Client), 1);

		if (target_nr >= MAX_HNDL_TARGETS) {
			/* Too many targets given! */
			return IRC_WriteErrClient(Client,
						  ERR_TOOMANYTARGETS_MSG,
						  currentTarget);
		}
	}

	return CONNECTED;
} /* Send_Message */

/**
 * Send a message to "target mask" target(s).
 *
 * See RFC 2812, sec. 3.3.1 for details.
 *
 * @param from The client from which this command has been received.
 * @param command The command to use (PRIVMSG, NOTICE, ...).
 * @param targetMask The "target mask" (will be verified by this function).
 * @param message The message to send.
 * @param SendErrors Whether to report errors back to the client or not.
 * @return CONNECTED or DISCONNECTED.
 */
static bool
Send_Message_Mask(CLIENT * from, char * command, char * targetMask,
		  char * message, bool SendErrors)
{
	CLIENT *cl;
	bool client_match;
	char *mask = targetMask + 1;
	const char *check_wildcards;

	cl = NULL;

	if (!Client_HasMode(from, 'o')) {
		if (!SendErrors)
			return true;
		return IRC_WriteErrClient(from, ERR_NOPRIVILEGES_MSG,
					  Client_ID(from));
	}

	/*
	 * RFC 2812, sec. 3.3.1 requires that targetMask have at least one
	 * dot (".") and no wildcards ("*", "?") following the last one.
	 */
	check_wildcards = strrchr(targetMask, '.');
	if (!check_wildcards || check_wildcards[strcspn(check_wildcards, "*?")]) {
		if (!SendErrors)
			return true;
		return IRC_WriteErrClient(from, ERR_WILDTOPLEVEL_MSG,
					  targetMask);
	}

	if (targetMask[0] == '#') {
		/* #: hostmask, see RFC 2812, sec. 3.3.1 */
		for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
			if (Client_Type(cl) != CLIENT_USER)
				continue;
			client_match = MatchCaseInsensitive(mask, Client_Hostname(cl));
			if (client_match)
				if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						command, Client_ID(cl), message))
					return false;
		}
	} else {
		/* $: server mask, see RFC 2812, sec. 3.3.1 */
		assert(targetMask[0] == '$');
		for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
			if (Client_Type(cl) != CLIENT_USER)
				continue;
			client_match = MatchCaseInsensitive(mask,
					Client_ID(Client_Introducer(cl)));
			if (client_match)
				if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						command, Client_ID(cl), message))
					return false;
		}
	}
	return CONNECTED;
} /* Send_Message_Mask */
示例#5
0
/**
 * Handler for the IRC "JOIN" 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_JOIN( CLIENT *Client, REQUEST *Req )
{
	char *channame, *key = NULL, *flags, *lastkey = NULL, *lastchan = NULL;
	CLIENT *target;
	CHANNEL *chan;

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

	_IRC_GET_SENDER_OR_RETURN_(target, Req, Client)

	/* Is argument "0"? */
	if (Req->argc == 1 && !strncmp("0", Req->argv[0], 2))
		return part_from_all_channels(Client, target);

	/* Are channel keys given? */
	if (Req->argc > 1)
		key = strtok_r(Req->argv[1], ",", &lastkey);

	channame = Req->argv[0];
	channame = strtok_r(channame, ",", &lastchan);

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

	while (channame) {
		flags = NULL;

		/* Did the server include channel-user-modes? */
		if (Client_Type(Client) == CLIENT_SERVER) {
			flags = strchr(channame, 0x7);
			if (flags) {
				*flags = '\0';
				flags++;
			}
		}

		chan = Channel_Search(channame);

		/* Local client? */
		if (Client_Type(Client) == CLIENT_USER) {
			if (chan) {
				/* Already existing channel: already member? */
				if (Channel_IsMemberOf(chan, Client))
				    goto join_next;
			} else {
				/* Channel must be created */
				if (!strchr(Conf_AllowedChannelTypes, channame[0])) {
					/* ... but channel type is not allowed! */
					IRC_WriteErrClient(Client,
						ERR_NOSUCHCHANNEL_MSG,
						Client_ID(Client), channame);
					goto join_next;
				}
			}

			/* Test if the user has reached the channel limit */
			if ((Conf_MaxJoins > 0) &&
			    (Channel_CountForUser(Client) >= Conf_MaxJoins)) {
				if (!IRC_WriteErrClient(Client,
						ERR_TOOMANYCHANNELS_MSG,
						Client_ID(Client), channame))
					return DISCONNECTED;
				goto join_next;
			}

			if (chan) {
				/* Already existing channel: check if the
				 * client is allowed to join */
				if (!join_allowed(Client, chan, channame, key))
					goto join_next;
			} else {
				/* New channel: first user will become channel
				 * operator unless this is a modeless channel */
				if (*channame != '+')
					flags = "o";
			}

			/* Local client: update idle time */
			Conn_UpdateIdle(Client_Conn(Client));
		} else {
			/* Remote server: we don't need to know whether the
			 * client is invited or not, but we have to make sure
			 * that the "one shot" entries (generated by INVITE
			 * commands) in this list become deleted when a user
			 * joins a channel this way. */
			if (chan)
				(void)Lists_Check(Channel_GetListInvites(chan),
						  target);
		}

		/* Join channel (and create channel if it doesn't exist) */
		if (!Channel_Join(target, channame))
			goto join_next;

		if (!chan) { /* channel is new; it has been created above */
			chan = Channel_Search(channame);
			assert(chan != NULL);
			if (Channel_IsModeless(chan)) {
				Channel_ModeAdd(chan, 't'); /* /TOPIC not allowed */
				Channel_ModeAdd(chan, 'n'); /* no external msgs */
			}
		}
		assert(chan != NULL);

		join_set_channelmodes(chan, target, flags);

		join_forward(Client, target, chan, channame);

		if (!join_send_topic(Client, target, chan, channame))
			break; /* write error */

	join_next:
		/* next channel? */
		channame = strtok_r(NULL, ",", &lastchan);
		if (channame && key)
			key = strtok_r(NULL, ",", &lastkey);
	}
	return CONNECTED;
} /* IRC_JOIN */
示例#6
0
/**
 * Handler for the IRC "NICK" command.
 *
 * See RFC 2812, 3.1.2 "Nick message", and RFC 2813, 4.1.3 "Nick".
 *
 * This function implements the IRC command "NICK" which is used to register
 * with the server, to change already registered nicknames and to introduce
 * new users which are connected to other servers.
 *
 * @param Client	The client from which this command has been received.
 * @param Req		Request structure with prefix and all parameters.
 * @returns		CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_NICK( CLIENT *Client, REQUEST *Req )
{
	CLIENT *intr_c, *target, *c;
	char *nick, *user, *hostname, *modes, *info;
	int token, hops;

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

	/* Some IRC clients, for example BitchX, send the NICK and USER
	 * commands in the wrong order ... */
	if(Client_Type(Client) == CLIENT_UNKNOWN
	    || Client_Type(Client) == CLIENT_GOTPASS
	    || Client_Type(Client) == CLIENT_GOTNICK
#ifndef STRICT_RFC
	    || Client_Type(Client) == CLIENT_GOTUSER
#endif
	    || Client_Type(Client) == CLIENT_USER
	    || Client_Type(Client) == CLIENT_SERVICE
	    || (Client_Type(Client) == CLIENT_SERVER && Req->argc == 1))
	{
		/* User registration or change of nickname */

		/* Wrong number of arguments? */
		if( Req->argc != 1 )
			return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
						   Client_ID( Client ),
						   Req->command );

		/* Search "target" client */
		if( Client_Type( Client ) == CLIENT_SERVER )
		{
			target = Client_Search( Req->prefix );
			if( ! target )
				return IRC_WriteStrClient( Client,
							   ERR_NOSUCHNICK_MSG,
							   Client_ID( Client ),
							   Req->argv[0] );
		}
		else
		{
			/* Is this a restricted client? */
			if( Client_HasMode( Client, 'r' ))
				return IRC_WriteStrClient( Client,
							   ERR_RESTRICTED_MSG,
							   Client_ID( Client ));

			target = Client;
		}

#ifndef STRICT_RFC
		/* If the clients tries to change to its own nickname we won't
		 * do anything. This is how the original ircd behaves and some
		 * clients (for example Snak) expect it to be like this.
		 * But I doubt that this is "really the right thing" ... */
		if( strcmp( Client_ID( target ), Req->argv[0] ) == 0 )
			return CONNECTED;
#endif

		/* Check that the new nickname is available. Special case:
		 * the client only changes from/to upper to lower case. */
		if( strcasecmp( Client_ID( target ), Req->argv[0] ) != 0 )
		{
			if( ! Client_CheckNick( target, Req->argv[0] ))
				return CONNECTED;
		}

		if (Client_Type(target) != CLIENT_USER &&
		    Client_Type(target) != CLIENT_SERVICE &&
		    Client_Type(target) != CLIENT_SERVER) {
			/* New client */
			LogDebug("Connection %d: got valid NICK command ...",
			     Client_Conn( Client ));

			/* Register new nickname of this client */
			Client_SetID( target, Req->argv[0] );

#ifndef STRICT_RFC
			if (Conf_AuthPing) {
				Conn_SetAuthPing(Client_Conn(Client), rand());
				IRC_WriteStrClient(Client, "PING :%ld",
					Conn_GetAuthPing(Client_Conn(Client)));
				LogDebug("Connection %d: sent AUTH PING %ld ...",
					Client_Conn(Client),
					Conn_GetAuthPing(Client_Conn(Client)));
			}
#endif

			/* If we received a valid USER command already then
			 * register the new client! */
			if( Client_Type( Client ) == CLIENT_GOTUSER )
				return Login_User( Client );
			else
				Client_SetType( Client, CLIENT_GOTNICK );
		} else {
			/* Nickname change */
			if (Client_Conn(target) > NONE) {
				/* Local client */
				Log(LOG_INFO,
				    "%s \"%s\" changed nick (connection %d): \"%s\" -> \"%s\".",
				    Client_TypeText(target), Client_Mask(target),
				    Client_Conn(target), Client_ID(target),
				    Req->argv[0]);
				Conn_UpdateIdle(Client_Conn(target));
			} else {
				/* Remote client */
				LogDebug("%s \"%s\" changed nick: \"%s\" -> \"%s\".",
					 Client_TypeText(target),
					 Client_Mask(target), Client_ID(target),
					 Req->argv[0]);
			}

			/* Inform all users and servers (which have to know)
			 * of this nickname change */
			if( Client_Type( Client ) == CLIENT_USER )
				IRC_WriteStrClientPrefix( Client, Client,
							  "NICK :%s",
							  Req->argv[0] );
			IRC_WriteStrServersPrefix( Client, target,
						   "NICK :%s", Req->argv[0] );
			IRC_WriteStrRelatedPrefix( target, target, false,
						   "NICK :%s", Req->argv[0] );

			/* Register old nickname for WHOWAS queries */
			Client_RegisterWhowas( target );

			/* Save new nickname */
			Client_SetID( target, Req->argv[0] );

			IRC_SetPenalty( target, 2 );
		}

		return CONNECTED;
	} else if(Client_Type(Client) == CLIENT_SERVER ||
		  Client_Type(Client) == CLIENT_SERVICE) {
		/* Server or service introduces new client */

		/* Bad number of parameters? */
		if (Req->argc != 2 && Req->argc != 7)
			return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
						  Client_ID(Client), Req->command);

		if (Req->argc >= 7) {
			/* RFC 2813 compatible syntax */
			nick = Req->argv[0];
			hops = atoi(Req->argv[1]);
			user = Req->argv[2];
			hostname = Req->argv[3];
			token = atoi(Req->argv[4]);
			modes = Req->argv[5] + 1;
			info = Req->argv[6];
		} else {
			/* RFC 1459 compatible syntax */
			nick = Req->argv[0];
			hops = 1;
			user = Req->argv[0];
			hostname = Client_ID(Client);
			token = atoi(Req->argv[1]);
			modes = "";
			info = Req->argv[0];
		}

		c = Client_Search(nick);
		if(c) {
			/*
			 * the new nick is already present on this server:
			 * the new and the old one have to be disconnected now.
			 */
			Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] );
			Kill_Nick( Req->argv[0], "Nick collision" );
			return CONNECTED;
		}

		/* Find the Server this client is connected to */
		intr_c = Client_GetFromToken(Client, token);
		if( ! intr_c )
		{
			Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] );
			Kill_Nick( Req->argv[0], "Unknown server" );
			return CONNECTED;
		}

		c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname,
					 token, modes, info, true);
		if( ! c )
		{
			/* out of memory, need to disconnect client to keep network state consistent */
			Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client ));
			Kill_Nick( Req->argv[0], "Server error" );
			return CONNECTED;
		}

		/* RFC 2813: client is now fully registered, inform all the
		 * other servers about the new user.
		 * RFC 1459: announce the new client only after receiving the
		 * USER command, first we need more information! */
		if (Req->argc < 7) {
			LogDebug("Client \"%s\" is being registered (RFC 1459) ...",
				 Client_Mask(c));
			Client_SetType(c, CLIENT_GOTNICK);
		} else
			Client_Introduce(Client, c, CLIENT_USER);

		return CONNECTED;
	}
	else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
} /* IRC_NICK */