コード例 #1
0
ファイル: channel.c プロジェクト: husemann/ngircd
/**
 * Check if a client is allowed to send to a specific channel.
 *
 * @param Chan The channel to check.
 * @param From The client that wants to send.
 * @return true if the client is allowed to send, false otherwise.
 */
static bool
Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
{
	bool is_member, has_voice, is_halfop, is_op, is_chanadmin, is_owner;

	is_member = has_voice = is_halfop = is_op = is_chanadmin = is_owner = false;

	/* The server itself always can send messages :-) */
	if (Client_ThisServer() == From)
		return true;

	if (Channel_IsMemberOf(Chan, From)) {
		is_member = true;
		if (strchr(Channel_UserModes(Chan, From), 'v'))
			has_voice = true;
		if (strchr(Channel_UserModes(Chan, From), 'h'))
			is_halfop = true;
		if (strchr(Channel_UserModes(Chan, From), 'o'))
			is_op = true;
		if (strchr(Channel_UserModes(Chan, From), 'a'))
			is_chanadmin = true;
		if (strchr(Channel_UserModes(Chan, From), 'q'))
			is_owner = true;
	}

	/*
	 * Is the client allowed to write to channel?
	 *
	 * If channel mode n set: non-members cannot send to channel.
	 * If channel mode m set: need voice.
	 */
	if (strchr(Channel_Modes(Chan), 'n') && !is_member)
		return false;

	if (strchr(Channel_Modes(Chan), 'M') && !Client_HasMode(From, 'R')
	    && !Client_HasMode(From, 'o'))
		return false;

	if (has_voice || is_halfop || is_op || is_chanadmin || is_owner)
		return true;

	if (strchr(Channel_Modes(Chan), 'm'))
		return false;

	if (Lists_Check(&Chan->list_excepts, From))
		return true;

	return !Lists_Check(&Chan->list_bans, From);
}
コード例 #2
0
ファイル: irc-channel.c プロジェクト: andinue/ngircd
/**
 * Forward JOIN command to all servers
 *
 * This function calls cb_join_forward(), which differentiates between
 * protocol implementations (e.g. RFC 2812, RFC 1459).
 *
 * @param Client	Client used to prefix the genrated commands
 * @param target	Forward JOIN (and MODE) command to this peer server
 * @param chan		Channel structure
 * @param channame	Channel name
 */
static void
join_forward(CLIENT *Client, CLIENT *target, CHANNEL *chan,
					const char *channame)
{
	char modes[CHANNEL_MODE_LEN], str[COMMAND_LEN];

	/* RFC 2813, 4.2.1: channel modes are separated from the channel
	 * name with ASCII 7, if any, and not spaces: */
	strlcpy(&modes[1], Channel_UserModes(chan, target), sizeof(modes) - 1);
	if (modes[1])
		modes[0] = 0x7;
	else
		modes[0] = '\0';

	/* forward to other servers (if it is not a local channel) */
	if (!Channel_IsLocal(chan)) {
		snprintf(str, sizeof(str), "%s%s", channame, modes);
		IRC_WriteStrServersPrefixFlag_CB(Client, target, '\0',
						 cb_join_forward, str);
	}

	/* tell users in this channel about the new client */
	IRC_WriteStrChannelPrefix(Client, chan, target, false,
				  "JOIN :%s",  channame);

	/* synchronize channel modes */
	if (modes[1]) {
		IRC_WriteStrChannelPrefix(Client, chan, target, false,
					  "MODE %s +%s %s", channame,
					  &modes[1], Client_ID(target));
	}
} /* join_forward */
コード例 #3
0
ファイル: irc-mode.c プロジェクト: LucentW/ngircd
/**
 * Handle channel mode and channel-user mode changes
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @param Origin The originator of the MODE command (prefix).
 * @param Channel The target channel of this MODE command.
 * @return CONNECTED or DISCONNECTED.
 */
static bool
Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
{
	char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
	    argadd[CLIENT_PASS_LEN], *mode_ptr;
	bool connected, set, skiponce, retval, use_servermode,
	     is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
	int mode_arg, arg_arg, mode_arg_count = 0;
	CLIENT *client;
	long l;
	size_t len;

	is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;

	if (Channel_IsModeless(Channel))
		return IRC_WriteErrClient(Client, ERR_NOCHANMODES_MSG,
				Client_ID(Client), Channel_Name(Channel));

	/* Mode request: let's answer it :-) */
	if (Req->argc <= 1)
		return Channel_Mode_Answer_Request(Origin, Channel);

	/* Check if origin is oper and opers can use mode */
	use_servermode = Conf_OperServerMode;
	if(Client_HasMode(Client, 'o') && Conf_OperCanMode) {
		is_oper = true;
	}

	/* Check if client is a server/service */
	if(Client_Type(Client) == CLIENT_SERVER ||
	   Client_Type(Client) == CLIENT_SERVICE) {
		is_machine = true;
	}

	/* Check if client is member of channel or an oper or an server/service */
	if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
		return IRC_WriteErrClient(Origin, ERR_NOTONCHANNEL_MSG,
					  Client_ID(Origin),
					  Channel_Name(Channel));

	mode_arg = 1;
	mode_ptr = Req->argv[mode_arg];
	if (Req->argc > mode_arg + 1)
		arg_arg = mode_arg + 1;
	else
		arg_arg = -1;

	/* Initial state: set or unset modes? */
	skiponce = false;
	switch (*mode_ptr) {
	case '-':
		set = false;
		break;
	case '+':
		set = true;
		break;
	default:
		set = true;
		skiponce = true;
	}

	/* Prepare reply string */
	strcpy(the_modes, set ? "+" : "-");
	the_args[0] = '\0';

	x[1] = '\0';
	connected = CONNECTED;
	while (mode_ptr) {
		if (!skiponce)
			mode_ptr++;
		if (!*mode_ptr) {
			/* Try next argument if there's any */
			if (arg_arg < 0)
				break;
			if (arg_arg > mode_arg)
				mode_arg = arg_arg;
			else
				mode_arg++;

			if (mode_arg >= Req->argc)
				break;
			mode_ptr = Req->argv[mode_arg];

			if (Req->argc > mode_arg + 1)
				arg_arg = mode_arg + 1;
			else
				arg_arg = -1;
		}
		skiponce = false;

		switch (*mode_ptr) {
		case '+':
		case '-':
			if (((*mode_ptr == '+') && !set)
			    || ((*mode_ptr == '-') && set)) {
				/* Action modifier ("+"/"-") must be changed ... */
				len = strlen(the_modes) - 1;
				if (the_modes[len] == '+' || the_modes[len] == '-') {
					/* Adjust last action modifier in result */
					the_modes[len] = *mode_ptr;
				} else {
					/* Append modifier character to result string */
					x[0] = *mode_ptr;
					strlcat(the_modes, x, sizeof(the_modes));
				}
				set = *mode_ptr == '+';
			}
			continue;
		}

		/* Are there arguments left? */
		if (arg_arg >= Req->argc)
			arg_arg = -1;

		if(!is_machine && !is_oper) {
			if (Channel_UserHasMode(Channel, Client, 'q'))
				is_owner = true;
			if (Channel_UserHasMode(Channel, Client, 'a'))
				is_admin = true;
			if (Channel_UserHasMode(Channel, Client, 'o'))
				is_op = true;
			if (Channel_UserHasMode(Channel, Client, 'h'))
				is_halfop = true;
		}

		/* Validate modes */
		x[0] = '\0';
		argadd[0] = '\0';
		client = NULL;
		switch (*mode_ptr) {
		/* --- Channel modes --- */
		case 'R': /* Registered users only */
		case 's': /* Secret channel */
		case 'z': /* Secure connections only */
			if(!is_oper && !is_machine && !is_owner &&
			   !is_admin && !is_op) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin), Channel_Name(Channel));
				goto chan_exit;
			}
		case 'i': /* Invite only */
		case 'V': /* Invite disallow */
		case 'M': /* Only identified nicks can write */
		case 'm': /* Moderated */
		case 'n': /* Only members can write */
		case 'N': /* Can't change nick while on this channel */
		case 'Q': /* No kicks */
		case 't': /* Topic locked */
			if(is_oper || is_machine || is_owner ||
			   is_admin || is_op || is_halfop)
				x[0] = *mode_ptr;
			else
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin), Channel_Name(Channel));
			break;
		case 'k': /* Channel key */
			if (Mode_Limit_Reached(Client, mode_arg_count++))
				goto chan_exit;
			if (!set) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					x[0] = *mode_ptr;
					if (Channel_HasMode(Channel, 'k'))
						strlcpy(argadd, "*", sizeof(argadd));
					if (arg_arg > mode_arg)
						arg_arg++;
				} else
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				break;
			}
			if (arg_arg > mode_arg) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					Channel_ModeDel(Channel, 'k');
					Channel_SetKey(Channel,
						       Req->argv[arg_arg]);
					strlcpy(argadd, Channel_Key(Channel),
						sizeof(argadd));
					x[0] = *mode_ptr;
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
#ifdef STRICT_RFC
				/* Only send error message in "strict" mode,
				 * this is how ircd2.11 and others behave ... */
				connected = IRC_WriteErrClient(Origin,
					ERR_NEEDMOREPARAMS_MSG,
					Client_ID(Origin), Req->command);
#endif
				goto chan_exit;
			}
			break;
		case 'l': /* Member limit */
			if (Mode_Limit_Reached(Client, mode_arg_count++))
				goto chan_exit;
			if (!set) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop)
					x[0] = *mode_ptr;
				else
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				break;
			}
			if (arg_arg > mode_arg) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					l = atol(Req->argv[arg_arg]);
					if (l > 0 && l < 0xFFFF) {
						Channel_ModeDel(Channel, 'l');
						Channel_SetMaxUsers(Channel, l);
						snprintf(argadd, sizeof(argadd),
							 "%ld", l);
						x[0] = *mode_ptr;
					}
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
#ifdef STRICT_RFC
				/* Only send error message in "strict" mode,
				 * this is how ircd2.11 and others behave ... */
				connected = IRC_WriteErrClient(Origin,
					ERR_NEEDMOREPARAMS_MSG,
					Client_ID(Origin), Req->command);
#endif
				goto chan_exit;
			}
			break;
		case 'O': /* IRC operators only */
			if (set) {
				/* Only IRC operators are allowed to
				 * set the 'O' channel mode! */
				if(is_oper || is_machine)
					x[0] = 'O';
				else
					connected = IRC_WriteErrClient(Origin,
						ERR_NOPRIVILEGES_MSG,
						Client_ID(Origin));
			} else if(is_oper || is_machine || is_owner ||
				  is_admin || is_op)
				x[0] = 'O';
			else
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
			break;
		case 'P': /* Persistent channel */
			if (set) {
				/* Only IRC operators are allowed to
				 * set the 'P' channel mode! */
				if(is_oper || is_machine)
					x[0] = 'P';
				else
					connected = IRC_WriteErrClient(Origin,
						ERR_NOPRIVILEGES_MSG,
						Client_ID(Origin));
			} else if(is_oper || is_machine || is_owner ||
				  is_admin || is_op)
				x[0] = 'P';
			else
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
			break;
		/* --- Channel user modes --- */
		case 'q': /* Owner */
		case 'a': /* Channel admin */
			if(!is_oper && !is_machine && !is_owner && !is_admin) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPPRIVTOOLOW_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
				goto chan_exit;
			}
		case 'o': /* Channel operator */
			if(!is_oper && !is_machine && !is_owner &&
			   !is_admin && !is_op) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
				goto chan_exit;
			}
		case 'h': /* Half Op */
			if(!is_oper && !is_machine && !is_owner &&
			   !is_admin && !is_op) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
				goto chan_exit;
			}
		case 'v': /* Voice */
			if (arg_arg > mode_arg) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					client = Client_Search(Req->argv[arg_arg]);
					if (client)
						x[0] = *mode_ptr;
					else
						connected = IRC_WriteErrClient(Origin,
							ERR_NOSUCHNICK_MSG,
							Client_ID(Origin),
							Req->argv[arg_arg]);
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
#ifdef STRICT_RFC
				/* Report an error to the client, when a user
				 * mode should be changed but no nickname is
				 * given. But don't do it when not in "strict"
				 * mode, because most other servers don't do
				 * it as well and some clients send "wired"
				 * MODE commands like "MODE #chan -ooo nick". */
				connected = IRC_WriteErrClient(Origin,
					ERR_NEEDMOREPARAMS_MSG,
					Client_ID(Origin), Req->command);
#endif
				goto chan_exit;
			}
			break;
		/* --- Channel lists --- */
		case 'I': /* Invite lists */
		case 'b': /* Ban lists */
		case 'e': /* Channel exception lists */
			if (Mode_Limit_Reached(Client, mode_arg_count++))
				goto chan_exit;
			if (arg_arg > mode_arg) {
				/* modify list */
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					connected = set
					   ? Add_To_List(*mode_ptr, Origin,
						Client, Channel,
						Req->argv[arg_arg])
					   : Del_From_List(*mode_ptr, Origin,
						Client, Channel,
						Req->argv[arg_arg]);
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
				switch (*mode_ptr) {
				case 'I':
					Channel_ShowInvites(Origin, Channel);
					break;
				case 'b':
					Channel_ShowBans(Origin, Channel);
					break;
				case 'e':
					Channel_ShowExcepts(Origin, Channel);
					break;
				}
			}
			break;
		default:
			if (Client_Type(Client) != CLIENT_SERVER) {
				Log(LOG_DEBUG,
				    "Unknown mode \"%c%c\" from \"%s\" on %s!?",
				    set ? '+' : '-', *mode_ptr,
				    Client_ID(Origin), Channel_Name(Channel));
				connected = IRC_WriteErrClient(Origin,
					ERR_UNKNOWNMODE_MSG,
					Client_ID(Origin), *mode_ptr,
					Channel_Name(Channel));
				x[0] = '\0';
			} else {
				Log(LOG_DEBUG,
				    "Handling unknown mode \"%c%c\" from \"%s\" on %s ...",
				    set ? '+' : '-', *mode_ptr,
				    Client_ID(Origin), Channel_Name(Channel));
				x[0] = *mode_ptr;
			}
		}

		if (!connected)
			break;

		/* Is there a valid mode change? */
		if (!x[0])
			continue;

		/* Validate target client */
		if (client && (!Channel_IsMemberOf(Channel, client))) {
			if (!IRC_WriteErrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
						Client_ID(Origin),
						Client_ID(client),
						Channel_Name(Channel)))
				break;
			continue;
		}

		if (client) {
			/* Channel-User-Mode */
			retval = set
			       ? Channel_UserModeAdd(Channel, client, x[0])
			       : Channel_UserModeDel(Channel, client, x[0]);
			if (retval) {
				strlcat(the_args, " ", sizeof(the_args));
				strlcat(the_args, Client_ID(client),
					sizeof(the_args));
				strlcat(the_modes, x, sizeof(the_modes));
				LogDebug
				    ("User \"%s\": Mode change on %s, now \"%s\"",
				     Client_Mask(client), Channel_Name(Channel),
				     Channel_UserModes(Channel, client));
			}
		} else {
			/* Channel-Mode */
			retval = set
			       ? Channel_ModeAdd(Channel, x[0])
			       : Channel_ModeDel(Channel, x[0]);
			if (retval) {
				strlcat(the_modes, x, sizeof(the_modes));
				LogDebug("Channel %s: Mode change, now \"%s\".",
					 Channel_Name(Channel),
					 Channel_Modes(Channel));
			}
		}

		/* Are there additional arguments to add? */
		if (argadd[0]) {
			strlcat(the_args, " ", sizeof(the_args));
			strlcat(the_args, argadd, sizeof(the_args));
		}
	}

      chan_exit:
	/* Are there changed modes? */
	if (the_modes[1]) {
		/* Clean up mode string */
		len = strlen(the_modes) - 1;
		if ((the_modes[len] == '+') || (the_modes[len] == '-'))
			the_modes[len] = '\0';

		if (Client_Type(Client) == CLIENT_SERVER) {
			/* MODE requests for local channels from other servers
			 * are definitely invalid! */
			if (Channel_IsLocal(Channel)) {
				Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
				return CONNECTED;
			}

			/* Forward mode changes to channel users and all the
			 * other remote servers: */
			IRC_WriteStrServersPrefix(Client, Origin,
				"MODE %s %s%s", Channel_Name(Channel),
				the_modes, the_args);
			IRC_WriteStrChannelPrefix(Client, Channel, Origin,
				false, "MODE %s %s%s", Channel_Name(Channel),
				the_modes, the_args);
		} else {
			if (use_servermode)
				Origin = Client_ThisServer();
			/* Send reply to client and inform other servers and channel users */
			connected = IRC_WriteStrClientPrefix(Client, Origin,
					"MODE %s %s%s", Channel_Name(Channel),
					the_modes, the_args);
			/* Only forward requests for non-local channels */
			if (!Channel_IsLocal(Channel))
				IRC_WriteStrServersPrefix(Client, Origin,
					"MODE %s %s%s", Channel_Name(Channel),
					the_modes, the_args);
			IRC_WriteStrChannelPrefix(Client, Channel, Origin,
				false, "MODE %s %s%s", Channel_Name(Channel),
				the_modes, the_args);
		}
	}

	return connected;
} /* Channel_Mode */
コード例 #4
0
ファイル: irc-op.c プロジェクト: cofyc/ngircd
/**
 * 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 */
コード例 #5
0
ファイル: channel.c プロジェクト: Flupsy/ngircd
GLOBAL bool
Channel_UserHasMode( CHANNEL *Chan, CLIENT *Client, char Mode )
{
	return strchr(Channel_UserModes(Chan, Client), Mode) != NULL;
} /* Channel_UserHasMode */
コード例 #6
0
ファイル: channel.c プロジェクト: husemann/ngircd
/**
 * Kick user from Channel
 */
GLOBAL void
Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name,
	     const char *Reason )
{
	CHANNEL *chan;
	char *ptr, *target_modes;
	bool can_kick = false;

	assert(Peer != NULL);
	assert(Target != NULL);
	assert(Origin != NULL);
	assert(Name != NULL);
	assert(Reason != NULL);

	/* Check that channel exists */
	chan = Channel_Search( Name );
	if( ! chan )
	{
		IRC_WriteStrClient( Origin, ERR_NOSUCHCHANNEL_MSG, Client_ID( Origin ), Name );
		return;
	}

	if (Client_Type(Peer) != CLIENT_SERVER &&
	    Client_Type(Origin) != CLIENT_SERVICE) {
		/* Check that user is on the specified channel */
		if (!Channel_IsMemberOf(chan, Origin)) {
			IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG,
					    Client_ID(Origin), Name);
			return;
		}
	}

	if(Client_Type(Peer) == CLIENT_USER) {
		/* Channel mode 'Q' and user mode 'q' on target: nobody but
		 * IRC Operators and servers can kick the target user */
		if ((strchr(Channel_Modes(chan), 'Q')
		     || Client_HasMode(Target, 'q')
		     || Client_Type(Target) == CLIENT_SERVICE)
		    && !Client_HasMode(Origin, 'o')) {
			IRC_WriteStrClient(Origin, ERR_KICKDENY_MSG,
					   Client_ID(Origin), Name,
					   Client_ID(Target));
			return;
		}

		/* Check if client has the rights to kick target */
		ptr = Channel_UserModes(chan, Peer);
		target_modes = Channel_UserModes(chan, Target);
		while(*ptr) {
			/* Owner can kick everyone */
			if ( *ptr == 'q') {
				can_kick = true;
				break;
			}
			/* Admin can't kick owner */
			if ( *ptr == 'a' ) {
				if (!strchr(target_modes, 'q')) {
					can_kick = true;
					break;
				}
			}
			/* Op can't kick owner | admin */
			if ( *ptr == 'o' ) {
				if (!strchr(target_modes, 'q') &&
				    !strchr(target_modes, 'a')) {
					can_kick = true;
					break;
				}
			}
			/* Half Op can't kick owner | admin | op */ 
			if ( *ptr == 'h' ) {
				if (!strchr(target_modes, 'q') &&
				    !strchr(target_modes, 'a') &&
				    !strchr(target_modes, 'o')) {
					can_kick = true;
					break;
				}
			}
			ptr++;
		}

		if(!can_kick) {
			IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOOLOW_MSG,
				Client_ID(Origin), Name);
			return;
		}
	}

	/* Check that the client to be kicked is on the specified channel */
	if (!Channel_IsMemberOf(chan, Target)) {
		IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
				   Client_ID(Origin), Client_ID(Target), Name );
		return;
	}

	/* Kick Client from channel */
	Remove_Client( REMOVE_KICK, chan, Target, Origin, Reason, true);
} /* Channel_Kick */
コード例 #7
0
ファイル: numeric.c プロジェクト: LucentW/ngircd
/**
 * Announce a channel and its users in the network.
 */
static bool
Announce_Channel(CLIENT *Client, CHANNEL *Chan)
{
	CL2CHAN *cl2chan;
	CLIENT *cl;
	char str[COMMAND_LEN], *ptr;
	bool njoin, xop;

	/* Check features of remote server */
	njoin = Conn_Options(Client_Conn(Client)) & CONN_RFC1459 ? false : true;
	xop = Client_HasFlag(Client, 'X') ? true : false;

	/* Get all the members of this channel */
	cl2chan = Channel_FirstMember(Chan);
	snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(Chan));
	while (cl2chan) {
		cl = Channel_GetClient(cl2chan);
		assert(cl != NULL);

		if (njoin) {
			/* RFC 2813: send NJOIN with nicknames and modes
			 * (if user is channel operator or has voice) */
			if (str[strlen(str) - 1] != ':')
				strlcat(str, ",", sizeof(str));

			/* Prepare user prefix (ChanOp, voiced, ...) */
			if (xop && Channel_UserHasMode(Chan, cl, 'q'))
				strlcat(str, "~", sizeof(str));
			if (xop && Channel_UserHasMode(Chan, cl, 'a'))
				strlcat(str, "&", sizeof(str));
			if (Channel_UserHasMode(Chan, cl, 'o'))
				strlcat(str, "@", sizeof(str));
			if (xop && Channel_UserHasMode(Chan, cl, 'h'))
				strlcat(str, "%", sizeof(str));
			if (Channel_UserHasMode(Chan, cl, 'v'))
				strlcat(str, "+", sizeof(str));

			strlcat(str, Client_ID(cl), sizeof(str));

			/* Send the data if the buffer is "full" */
			if (strlen(str) > (sizeof(str) - CLIENT_NICK_LEN - 8)) {
				if (!IRC_WriteStrClient(Client, "%s", str))
					return DISCONNECTED;
				snprintf(str, sizeof(str), "NJOIN %s :",
					 Channel_Name(Chan));
			}
		} else {
			/* RFC 1459: no NJOIN, send JOIN and MODE */
			if (!IRC_WriteStrClientPrefix(Client, cl, "JOIN %s",
						Channel_Name(Chan)))
				return DISCONNECTED;
			ptr = Channel_UserModes(Chan, cl);
			while (*ptr) {
				if (!IRC_WriteStrClientPrefix(Client, cl,
						   "MODE %s +%c %s",
						   Channel_Name(Chan), ptr[0],
						   Client_ID(cl)))
					return DISCONNECTED;
				ptr++;
			}
		}

		cl2chan = Channel_NextMember(Chan, cl2chan);
	}

	/* Data left in the buffer? */
	if (str[strlen(str) - 1] != ':') {
		/* Yes, send it ... */
		if (!IRC_WriteStrClient(Client, "%s", str))
			return DISCONNECTED;
	}

	return CONNECTED;
} /* Announce_Channel */
コード例 #8
0
ファイル: irc-server.c プロジェクト: mguindin/ngircd
GLOBAL bool
IRC_NJOIN( CLIENT *Client, REQUEST *Req )
{
	char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8];
	bool is_op, is_voiced;
	CHANNEL *chan;
	CLIENT *c;
	
	assert( Client != NULL );
	assert( Req != NULL );

	if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );

	strlcpy( nick_in, Req->argv[1], sizeof( nick_in ));
	strcpy( nick_out, "" );

	channame = Req->argv[0];
	ptr = strtok( nick_in, "," );
	while( ptr )
	{
		is_op = is_voiced = false;
		
		/* cut off prefixes */
		while(( *ptr == '@' ) || ( *ptr == '+' ))
		{
			if( *ptr == '@' ) is_op = true;
			if( *ptr == '+' ) is_voiced = true;
			ptr++;
		}

		c = Client_Search( ptr );
		if( c )
		{
			Channel_Join( c, channame );
			chan = Channel_Search( channame );
			assert( chan != NULL );
			
			if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
			if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );

			/* announce to channel... */
			IRC_WriteStrChannelPrefix( Client, chan, c, false, "JOIN :%s", channame );

			/* set Channel-User-Modes */
			strlcpy( modes, Channel_UserModes( chan, c ), sizeof( modes ));
			if( modes[0] )
			{
				/* send modes to channel */
				IRC_WriteStrChannelPrefix( Client, chan, Client, false, "MODE %s +%s %s", channame, modes, Client_ID( c ));
			}

			if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out ));
			if( is_op ) strlcat( nick_out, "@", sizeof( nick_out ));
			if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out ));
			strlcat( nick_out, ptr, sizeof( nick_out ));
		}
		else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
		
		/* search for next Nick */
		ptr = strtok( NULL, "," );
	}

	/* forward to other servers */
	if( nick_out[0] != '\0' ) IRC_WriteStrServersPrefix( Client, Client_ThisServer( ), "NJOIN %s :%s", Req->argv[0], nick_out );

	return CONNECTED;
} /* IRC_NJOIN */