aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kike.c64
1 files changed, 63 insertions, 1 deletions
diff --git a/src/kike.c b/src/kike.c
index a6ca384..01f7716 100644
--- a/src/kike.c
+++ b/src/kike.c
@@ -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]);
@@ -1666,6 +1668,65 @@ irc_handle_part (const struct irc_message *msg, struct client *c)
}
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)
{
struct channel *chan = str_map_find (&c->ctx->channels, channel_name);
@@ -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 },