kike: implement the KICK command

This commit is contained in:
Přemysl Eric Janouch 2014-08-05 01:38:49 +02:00
parent c386592d70
commit 08b93c3a71
1 changed files with 63 additions and 1 deletions

View File

@ -836,6 +836,7 @@ enum
IRC_ERR_NONICKNAMEGIVEN = 431,
IRC_ERR_ERRONEOUSNICKNAME = 432,
IRC_ERR_NICKNAMEINUSE = 433,
IRC_ERR_USERNOTINCHANNEL = 441,
IRC_ERR_NOTONCHANNEL = 442,
IRC_ERR_SUMMONDISABLED = 445,
IRC_ERR_USERSDISABLED = 446,
@ -903,6 +904,7 @@ static const char *g_default_replies[] =
[IRC_ERR_NONICKNAMEGIVEN] = ":No nickname given",
[IRC_ERR_ERRONEOUSNICKNAME] = "%s :Erroneous nickname",
[IRC_ERR_NICKNAMEINUSE] = "%s :Nickname is already in use",
[IRC_ERR_USERNOTINCHANNEL] = "%s %s :They aren't on that channel",
[IRC_ERR_NOTONCHANNEL] = "%s :You're not on that channel",
[IRC_ERR_SUMMONDISABLED] = ":SUMMON has been disabled",
[IRC_ERR_USERSDISABLED] = ":USERS has been disabled",
@ -1597,7 +1599,7 @@ irc_handle_topic (const struct irc_message *msg, struct client *c)
if ((chan->modes & IRC_CHAN_MODE_PROTECTED_TOPIC)
&& !(user->modes & IRC_CHAN_MODE_OPERATOR))
RETURN_WITH_REPLY (c, IRC_ERR_CHANOPRIVSNEEDED);
RETURN_WITH_REPLY (c, IRC_ERR_CHANOPRIVSNEEDED, target);
free (chan->topic);
chan->topic = xstrdup (msg->params.vector[1]);
@ -1665,6 +1667,65 @@ irc_handle_part (const struct irc_message *msg, struct client *c)
str_vector_free (&channels);
}
static void
irc_try_kick (struct client *c, const char *channel_name, const char *nick,
const char *reason)
{
struct channel *chan;
if (!(chan = str_map_find (&c->ctx->channels, channel_name)))
RETURN_WITH_REPLY (c, IRC_ERR_NOSUCHCHANNEL, channel_name);
struct channel_user *user;
if (!(user = channel_get_user (chan, c)))
RETURN_WITH_REPLY (c, IRC_ERR_NOTONCHANNEL, channel_name);
if (!(user->modes & IRC_CHAN_MODE_OPERATOR))
RETURN_WITH_REPLY (c, IRC_ERR_CHANOPRIVSNEEDED, channel_name);
struct client *client;
if (!(client = str_map_find (&c->ctx->users, nick))
|| !(user = channel_get_user (chan, client)))
RETURN_WITH_REPLY (c, IRC_ERR_USERNOTINCHANNEL, nick, channel_name);
char *message = xstrdup_printf (":%s!%s@%s KICK %s %s :%s",
c->nickname, c->username, c->hostname, channel_name, nick, reason);
if (!(chan->modes & IRC_CHAN_MODE_QUIET))
irc_channel_multicast (chan, message);
else
irc_send (c, "%s", message);
free (message);
channel_remove_user (chan, user);
channel_destroy_if_empty (c->ctx, chan);
}
static void
irc_handle_kick (const struct irc_message *msg, struct client *c)
{
if (msg->params.len < 2)
RETURN_WITH_REPLY (c, IRC_ERR_NEEDMOREPARAMS, msg->command);
const char *reason = c->nickname;
if (msg->params.len > 2)
reason = msg->params.vector[2];
struct str_vector channels;
struct str_vector users;
str_vector_init (&channels);
str_vector_init (&users);
split_str_ignore_empty (msg->params.vector[0], ',', &channels);
split_str_ignore_empty (msg->params.vector[1], ',', &users);
if (channels.len == 1)
for (size_t i = 0; i < users.len; i++)
irc_try_kick (c, channels.vector[0], users.vector[i], reason);
else
for (size_t i = 0; i < channels.len && i < users.len; i++)
irc_try_kick (c, channels.vector[i], users.vector[i], reason);
str_vector_free (&channels);
str_vector_free (&users);
}
static void
irc_try_join (struct client *c, const char *channel_name, const char *key)
{
@ -1804,6 +1865,7 @@ irc_register_handlers (struct server_context *ctx)
{ "NOTICE", true, irc_handle_notice },
{ "JOIN", true, irc_handle_join },
{ "PART", true, irc_handle_part },
{ "KICK", true, irc_handle_kick },
{ "TOPIC", true, irc_handle_topic },
{ "LIST", true, irc_handle_list },
{ "NAMES", true, irc_handle_names },