degesch: naively implement a few user commands

/mode, /topic, /kick, /kickban, /ban, /invite

It's all a bit messy and needs some rewriting.
This commit is contained in:
Přemysl Eric Janouch 2015-05-18 22:04:35 +02:00
parent f2ab9f3937
commit 310b9c31d3

193
degesch.c
View File

@ -4741,6 +4741,25 @@ cut_word (char **s)
return start; 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 static bool
try_handle_buffer_goto (struct app_context *ctx, const char *word) 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; 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 static void
show_buffers_list (struct app_context *ctx) show_buffers_list (struct app_context *ctx)
{ {
@ -5261,6 +5299,131 @@ handle_command_cycle (struct app_context *ctx, char *arguments)
return true; return true;
} }
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 static bool
handle_command_connect (struct app_context *ctx, char *arguments) handle_command_connect (struct app_context *ctx, char *arguments)
{ {
@ -5410,18 +5573,30 @@ g_command_handlers[] =
"[<channel>[,<channel>...]]", "[<channel>[,<channel>...]]",
handle_command_join }, handle_command_join },
{ "part", "Leave channels", { "part", "Leave channels",
"[<channel>[,<channel>...]] [reason]", "[<channel>[,<channel>...]] [<reason>]",
handle_command_part }, handle_command_part },
{ "cycle", "Rejoin channels", { "cycle", "Rejoin channels",
"[<channel>[,<channel>...]] [reason]", "[<channel>[,<channel>...]] [<reason>]",
handle_command_cycle }, handle_command_cycle },
NOT_IMPLEMENTED (mode) { "mode", "Change mode",
NOT_IMPLEMENTED (topic) "[<channel>] [<mode>...]",
NOT_IMPLEMENTED (kick) handle_command_mode },
NOT_IMPLEMENTED (kickban) { "topic", "Change topic",
NOT_IMPLEMENTED (ban) "[<channel>] [<topic>]",
NOT_IMPLEMENTED (invite) 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", { "connect", "Connect to the server",
"[server]", "[server]",
@ -5430,7 +5605,7 @@ g_command_handlers[] =
"[reason]", "[reason]",
handle_command_disconnect }, handle_command_disconnect },
{ "list", "List channels and their topic", { "list", "List channels and their topic",
"[<channel>[,<channel>...]] [server]", "[<channel>[,<channel>...]] [<server>]",
handle_command_list }, handle_command_list },
NOT_IMPLEMENTED (names) NOT_IMPLEMENTED (names)
NOT_IMPLEMENTED (who) NOT_IMPLEMENTED (who)