aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--degesch.c193
1 files changed, 184 insertions, 9 deletions
diff --git a/degesch.c b/degesch.c
index da80577..52414de 100644
--- a/degesch.c
+++ b/degesch.c
@@ -4741,6 +4741,25 @@ cut_word (char **s)
return start;
}
+static char *
+maybe_cut_word (char **s, bool (*validator) (void *, char *), void *user_data)
+{
+ char *start = *s;
+ size_t word_len = strcspn (*s, WORD_BREAKING_CHARS);
+
+ char *word = xstrndup (start, word_len);
+ bool ok = validator (user_data, word);
+ free (word);
+
+ if (!ok)
+ return NULL;
+
+ char *end = start + word_len;
+ *s = end + strspn (end, WORD_BREAKING_CHARS);
+ *end = '\0';
+ return start;
+}
+
static bool
try_handle_buffer_goto (struct app_context *ctx, const char *word)
{
@@ -4790,6 +4809,25 @@ server_command_check (struct app_context *ctx, const char *action,
return false;
}
+static bool
+validate_channel_name (void *user_data, char *word)
+{
+ struct server *s = user_data;
+ return irc_is_channel (s, word);
+}
+
+static char *
+try_get_channel (struct app_context *ctx, char **arguments)
+{
+ struct server *s = ctx->current_buffer->server;
+ char *channel_name = maybe_cut_word (arguments, validate_channel_name, s);
+ if (channel_name)
+ return channel_name;
+ if (ctx->current_buffer->type == BUFFER_CHANNEL)
+ return ctx->current_buffer->channel->name;
+ return NULL;
+}
+
static void
show_buffers_list (struct app_context *ctx)
{
@@ -5262,6 +5300,131 @@ handle_command_cycle (struct app_context *ctx, char *arguments)
}
static bool
+handle_command_mode (struct app_context *ctx, char *arguments)
+{
+ if (!server_command_check (ctx, "mode", true))
+ return true;
+
+ // FIXME: allow usernames as well, not only channels
+ // FIXME: +channels collide with setting modes
+ struct server *s = ctx->current_buffer->server;
+ char *channel_name = try_get_channel (ctx, &arguments);
+ if (!channel_name)
+ buffer_send_error (ctx, ctx->current_buffer,
+ "%s: %s", "Can't set mode",
+ "no channel name given and this buffer is not a channel");
+ else if (*arguments)
+ irc_send (s, "MODE %s %s", channel_name, arguments);
+ else
+ irc_send (s, "MODE %s", channel_name);
+ return true;
+}
+
+static bool
+handle_command_topic (struct app_context *ctx, char *arguments)
+{
+ if (!server_command_check (ctx, "topic", true))
+ return true;
+
+ // FIXME: currently the topic can't start with a channel name
+ struct server *s = ctx->current_buffer->server;
+ char *channel_name = try_get_channel (ctx, &arguments);
+ if (!channel_name)
+ buffer_send_error (ctx, ctx->current_buffer,
+ "%s: %s", "Can't change topic",
+ "no channel name given and this buffer is not a channel");
+ else if (*arguments)
+ // FIXME: there's no way to unset the topic
+ irc_send (s, "TOPIC %s :%s", channel_name, arguments);
+ else
+ irc_send (s, "TOPIC %s", channel_name);
+ return true;
+}
+
+static bool
+handle_command_kick (struct app_context *ctx, char *arguments)
+{
+ if (!server_command_check (ctx, "kick", true))
+ return true;
+
+ struct server *s = ctx->current_buffer->server;
+ char *channel_name = try_get_channel (ctx, &arguments);
+ if (!channel_name)
+ buffer_send_error (ctx, ctx->current_buffer,
+ "%s: %s", "Can't kick",
+ "no channel name given and this buffer is not a channel");
+ else if (*arguments)
+ // FIXME: the reason should be one argument
+ irc_send (s, "KICK %s %s", channel_name, arguments);
+ else
+ return false;
+ return true;
+}
+
+static bool
+handle_command_kickban (struct app_context *ctx, char *arguments)
+{
+ if (!server_command_check (ctx, "kickban", true))
+ return true;
+
+ struct server *s = ctx->current_buffer->server;
+ char *channel_name = try_get_channel (ctx, &arguments);
+ if (!channel_name)
+ buffer_send_error (ctx, ctx->current_buffer,
+ "%s: %s", "Can't kickban",
+ "no channel name given and this buffer is not a channel");
+ else if (*arguments)
+ {
+ // FIXME: don't include the reason
+ irc_send (s, "MODE %s +b %s", channel_name, arguments);
+ // FIXME: the reason should be one argument
+ irc_send (s, "KICK %s %s", channel_name, arguments);
+ }
+ else
+ return false;
+ return true;
+}
+
+static bool
+handle_command_ban (struct app_context *ctx, char *arguments)
+{
+ if (!server_command_check (ctx, "ban", true))
+ return true;
+
+ struct server *s = ctx->current_buffer->server;
+ char *channel_name = try_get_channel (ctx, &arguments);
+ if (!channel_name)
+ buffer_send_error (ctx, ctx->current_buffer,
+ "%s: %s", "Can't ban",
+ "no channel name given and this buffer is not a channel");
+ else if (*arguments)
+ irc_send (s, "MODE %s +b %s", channel_name, arguments);
+ else
+ return false;
+ return true;
+}
+
+static bool
+handle_command_invite (struct app_context *ctx, char *arguments)
+{
+ if (!server_command_check (ctx, "invite", true))
+ return true;
+
+ // XXX: the order of arguments should probably be reverse
+ struct server *s = ctx->current_buffer->server;
+ char *channel_name = try_get_channel (ctx, &arguments);
+ if (!channel_name)
+ buffer_send_error (ctx, ctx->current_buffer,
+ "%s: %s", "Can't invite",
+ "no channel name given and this buffer is not a channel");
+ else if (*arguments)
+ irc_send (s, "INVITE %s %s", arguments, channel_name);
+ else
+ return false;
+ return true;
+}
+
+static bool
handle_command_connect (struct app_context *ctx, char *arguments)
{
struct server *s = NULL;
@@ -5410,18 +5573,30 @@ g_command_handlers[] =
"[<channel>[,<channel>...]]",
handle_command_join },
{ "part", "Leave channels",
- "[<channel>[,<channel>...]] [reason]",
+ "[<channel>[,<channel>...]] [<reason>]",
handle_command_part },
{ "cycle", "Rejoin channels",
- "[<channel>[,<channel>...]] [reason]",
+ "[<channel>[,<channel>...]] [<reason>]",
handle_command_cycle },
- NOT_IMPLEMENTED (mode)
- NOT_IMPLEMENTED (topic)
- NOT_IMPLEMENTED (kick)
- NOT_IMPLEMENTED (kickban)
- NOT_IMPLEMENTED (ban)
- NOT_IMPLEMENTED (invite)
+ { "mode", "Change mode",
+ "[<channel>] [<mode>...]",
+ handle_command_mode },
+ { "topic", "Change topic",
+ "[<channel>] [<topic>]",
+ handle_command_topic },
+ { "kick", "Kick user from channel",
+ "[<channel>] <user> [<reason>]",
+ handle_command_kick },
+ { "kickban", "Kick and ban user from channel",
+ "[<channel>] <user> [<reason>]",
+ handle_command_kickban },
+ { "ban", "Ban user from channel",
+ "[<channel>] <mask>",
+ handle_command_ban },
+ { "invite", "Invite user to channel",
+ "[<channel>] <user>",
+ handle_command_invite },
{ "connect", "Connect to the server",
"[server]",
@@ -5430,7 +5605,7 @@ g_command_handlers[] =
"[reason]",
handle_command_disconnect },
{ "list", "List channels and their topic",
- "[<channel>[,<channel>...]] [server]",
+ "[<channel>[,<channel>...]] [<server>]",
handle_command_list },
NOT_IMPLEMENTED (names)
NOT_IMPLEMENTED (who)