diff --git a/src/kike.c b/src/kike.c index 3435f6e..d3415e7 100644 --- a/src/kike.c +++ b/src/kike.c @@ -735,6 +735,26 @@ client_in_mask_list (const struct client *c, const struct str_vector *mask) return result; } +static void +irc_initiate_quit (struct server_context *ctx) +{ + print_status ("shutting down"); + + for (struct client *iter = ctx->clients; iter; iter = iter->next) + if (!iter->closing_link) + irc_close_link (iter, "Shutting down"); + + ssize_t i = poller_find_by_fd (&ctx->poller, ctx->listen_fd); + if (soft_assert (i != -1)) + poller_remove_at_index (&ctx->poller, i); + if (ctx->listen_fd != -1) + xclose (ctx->listen_fd); + ctx->listen_fd = -1; + + ctx->quitting = true; + irc_try_finish_quit (ctx); +} + // --- Timers ------------------------------------------------------------------ static void @@ -864,6 +884,7 @@ enum IRC_ERR_BANNEDFROMCHAN = 474, IRC_ERR_BADCHANNELKEY = 475, IRC_ERR_BADCHANMASK = 476, + IRC_ERR_NOPRIVILEGES = 481, IRC_ERR_CHANOPRIVSNEEDED = 482, IRC_ERR_USERSDONTMATCH = 502 @@ -939,6 +960,7 @@ static const char *g_default_replies[] = [IRC_ERR_BANNEDFROMCHAN] = "%s :Cannot join channel (+b)", [IRC_ERR_BADCHANNELKEY] = "%s :Cannot join channel (+k)", [IRC_ERR_BADCHANMASK] = "%s :Bad Channel Mask", + [IRC_ERR_NOPRIVILEGES] = ":Permission Denied- You're not an IRC operator", [IRC_ERR_CHANOPRIVSNEEDED] = "%s :You're not channel operator", [IRC_ERR_USERSDONTMATCH] = ":Cannot change mode for other users", @@ -1958,6 +1980,34 @@ irc_handle_ison (const struct irc_message *msg, struct client *c) str_free (&result); } +static void +irc_handle_kill (const struct irc_message *msg, struct client *c) +{ + if (msg->params.len < 2) + RETURN_WITH_REPLY (c, IRC_ERR_NEEDMOREPARAMS, msg->command); + if (!(c->mode & IRC_USER_MODE_OPERATOR)) + RETURN_WITH_REPLY (c, IRC_ERR_NOPRIVILEGES); + + struct client *target; + if (!(target = str_map_find (&c->ctx->users, msg->params.vector[0]))) + RETURN_WITH_REPLY (c, IRC_ERR_NOSUCHNICK, msg->params.vector[0]); + char *reason = xstrdup_printf ("Killed by %s: %s", + c->nickname, msg->params.vector[1]); + irc_close_link (target, reason); + free (reason); +} + +static void +irc_handle_die (const struct irc_message *msg, struct client *c) +{ + (void) msg; + + if (!(c->mode & IRC_USER_MODE_OPERATOR)) + RETURN_WITH_REPLY (c, IRC_ERR_NOPRIVILEGES); + if (!c->ctx->quitting) + irc_initiate_quit (c->ctx); +} + // ----------------------------------------------------------------------------- struct irc_command @@ -1972,6 +2022,7 @@ irc_register_handlers (struct server_context *ctx) { // TODO: add an index for IRC_ERR_NOSUCHSERVER validation? // TODO: add a minimal parameter count? + // TODO: add a field for oper-only commands? static const struct irc_command message_handlers[] = { { "PASS", false, irc_handle_pass }, @@ -2002,6 +2053,9 @@ irc_register_handlers (struct server_context *ctx) { "WHO", true, irc_handle_who }, { "WHOIS", true, irc_handle_whois }, { "ISON", true, irc_handle_ison }, + + { "KILL", true, irc_handle_kill }, + { "DIE", true, irc_handle_die }, }; for (size_t i = 0; i < N_ELEMENTS (message_handlers); i++) @@ -2639,23 +2693,7 @@ on_signal_pipe_readable (const struct pollfd *fd, struct server_context *ctx) (void) read (fd->fd, &dummy, 1); if (g_termination_requested && !ctx->quitting) - { - print_status ("shutting down"); - - for (struct client *iter = ctx->clients; iter; iter = iter->next) - if (!iter->closing_link) - irc_close_link (iter, "Shutting down"); - - ssize_t i = poller_find_by_fd (&ctx->poller, ctx->listen_fd); - if (soft_assert (i != -1)) - poller_remove_at_index (&ctx->poller, i); - if (ctx->listen_fd != -1) - xclose (ctx->listen_fd); - ctx->listen_fd = -1; - - ctx->quitting = true; - irc_try_finish_quit (ctx); - } + irc_initiate_quit (ctx); } static void