xC/xP: relay and render channel modes

This commit is contained in:
Přemysl Eric Janouch 2022-09-21 16:32:08 +02:00
parent 1f0e0b1ce4
commit d3628928b9
Signed by: p
GPG Key ID: A0420B94F92B9493
3 changed files with 79 additions and 34 deletions

View File

@ -131,6 +131,8 @@ struct EventMessage {
case CHANNEL:
string server_name;
ItemData topic<>;
// This includes parameters, separated by spaces.
string modes;
case PRIVATE_MESSAGE:
string server_name;
} context;
@ -169,7 +171,7 @@ struct EventMessage {
void;
case REGISTERED:
string user;
string user_mode;
string user_modes;
// Theoretically, we could also send user information in this state,
// but we'd have to duplicate both fields.
case DISCONNECTING:

102
xC.c
View File

@ -1841,7 +1841,7 @@ struct server
struct user *irc_user; ///< Our own user
int nick_counter; ///< Iterates "nicks" when registering
struct str irc_user_mode; ///< Our current user modes
struct str irc_user_modes; ///< Our current user modes
char *irc_user_host; ///< Our current user@host
bool autoaway_active; ///< Autoaway is currently active
@ -1889,7 +1889,7 @@ static struct ispect_field g_server_ispect[] =
// TODO: either rename the underlying field or fix the plugins
{ "user", offsetof (struct server, irc_user),
ISPECT_REF, 0, g_user_ispect, false },
{ "user_mode", offsetof (struct server, irc_user_mode),
{ "user_mode", offsetof (struct server, irc_user_modes),
ISPECT_STR, 0, NULL, false },
{}
@ -1978,7 +1978,7 @@ server_new (struct poller *poller)
self->irc_buffer_map = str_map_make (NULL);
self->irc_buffer_map.key_xfrm = irc_strxfrm;
self->irc_user_mode = str_make ();
self->irc_user_modes = str_make ();
self->outstanding_joins = strv_make ();
self->cap_ls_buf = strv_make ();
@ -2025,7 +2025,7 @@ server_destroy (struct server *self)
if (self->irc_user)
user_unref (self->irc_user);
str_free (&self->irc_user_mode);
str_free (&self->irc_user_modes);
free (self->irc_user_host);
strv_free (&self->outstanding_joins);
@ -2976,6 +2976,45 @@ relay_prepare_buffer_line (struct app_context *ctx, struct buffer *buffer,
// TODO: Consider pushing this whole block of code much further down.
static void formatter_add (struct formatter *self, const char *format, ...);
static char *irc_to_utf8 (const char *text);
static void
relay_prepare_channel_buffer_update (struct app_context *ctx,
struct buffer *buffer, struct relay_buffer_context_channel *e)
{
struct channel *channel = buffer->channel;
struct formatter f = formatter_make (ctx, buffer->server);
if (channel->topic)
formatter_add (&f, "#m", channel->topic);
e->topic = relay_items (ctx, f.items, &e->topic_len);
formatter_free (&f);
// As in make_prompt(), conceal the last known channel modes.
// XXX: This should use irc_channel_is_joined().
if (!channel->users_len)
return;
struct str modes = str_make ();
str_append_str (&modes, &channel->no_param_modes);
struct str params = str_make ();
struct str_map_iter iter = str_map_iter_make (&channel->param_modes);
const char *param;
while ((param = str_map_iter_next (&iter)))
{
str_append_c (&modes, iter.link->key[0]);
str_append_c (&params, ' ');
str_append (&params, param);
}
str_append_str (&modes, &params);
str_free (&params);
char *modes_utf8 = irc_to_utf8 (modes.str);
str_free (&modes);
e->modes = str_from_cstr (modes_utf8);
free (modes_utf8);
}
static void
relay_prepare_buffer_update (struct app_context *ctx, struct buffer *buffer)
@ -2997,18 +3036,10 @@ relay_prepare_buffer_update (struct app_context *ctx, struct buffer *buffer)
server_name = &e->context.server.server_name;
break;
case BUFFER_CHANNEL:
{
e->context.kind = RELAY_BUFFER_KIND_CHANNEL;
server_name = &e->context.channel.server_name;
struct formatter f = formatter_make (ctx, buffer->server);
if (buffer->channel->topic)
formatter_add (&f, "#m", buffer->channel->topic);
e->context.channel.topic =
relay_items (ctx, f.items, &e->context.channel.topic_len);
formatter_free (&f);
relay_prepare_channel_buffer_update (ctx, buffer, &e->context.channel);
break;
}
case BUFFER_PM:
e->context.kind = RELAY_BUFFER_KIND_PRIVATE_MESSAGE;
server_name = &e->context.private_message.server_name;
@ -3086,9 +3117,6 @@ relay_server_state_for_server (struct server *s)
return 0;
}
// TODO: Consider pushing this whole block of code further down.
static char *irc_to_utf8 (const char *text);
static void
relay_prepare_server_update (struct app_context *ctx, struct server *s)
{
@ -3103,9 +3131,9 @@ relay_prepare_server_update (struct app_context *ctx, struct server *s)
e->data.registered.user = str_from_cstr (user_utf8);
free (user_utf8);
char *user_mode_utf8 = irc_to_utf8 (s->irc_user_mode.str);
e->data.registered.user_mode = str_from_cstr (user_mode_utf8);
free (user_mode_utf8);
char *user_modes_utf8 = irc_to_utf8 (s->irc_user_modes.str);
e->data.registered.user_modes = str_from_cstr (user_modes_utf8);
free (user_modes_utf8);
}
}
@ -5311,10 +5339,8 @@ irc_make_channel (struct server *s, char *name)
}
static void
irc_channel_set_topic (struct channel *channel, const char *topic)
irc_channel_broadcast_buffer_update (const struct channel *channel)
{
cstr_set (&channel->topic, xstrdup (topic));
struct server *s = channel->s;
struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel->name);
if (buffer)
@ -5324,6 +5350,13 @@ irc_channel_set_topic (struct channel *channel, const char *topic)
}
}
static void
irc_channel_set_topic (struct channel *channel, const char *topic)
{
cstr_set (&channel->topic, xstrdup (topic));
irc_channel_broadcast_buffer_update (channel);
}
static struct channel_user *
irc_channel_get_user (struct channel *channel, struct user *user)
{
@ -5349,6 +5382,9 @@ irc_left_channel (struct channel *channel)
LIST_FOR_EACH (struct channel_user, iter, channel->users)
irc_channel_unlink_user (channel, iter);
// Send empty channel modes.
irc_channel_broadcast_buffer_update (channel);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -5693,7 +5729,7 @@ irc_destroy_state (struct server *s)
s->irc_user = NULL;
}
str_reset (&s->irc_user_mode);
str_reset (&s->irc_user_modes);
cstr_set (&s->irc_user_host, NULL);
strv_reset (&s->outstanding_joins);
@ -6671,7 +6707,7 @@ make_chanmode_postfix (struct channel *channel, struct str *modes)
str_append (modes, channel->no_param_modes.str);
struct str_map_iter iter = str_map_iter_make (&channel->param_modes);
char *param;
const char *param;
while ((param = str_map_iter_next (&iter)))
str_append_c (modes, iter.link->key[0]);
}
@ -6688,8 +6724,8 @@ make_server_postfix_registered (struct buffer *buffer, struct str *output)
irc_get_channel_user_prefix (s, channel_user, output);
}
str_append (output, s->irc_user->nickname);
if (s->irc_user_mode.len)
str_append_printf (output, "(%s)", s->irc_user_mode.str);
if (s->irc_user_modes.len)
str_append_printf (output, "(%s)", s->irc_user_modes.str);
}
static void
@ -6736,7 +6772,7 @@ make_prompt (struct app_context *ctx, struct str *output)
buffer_get_index (ctx, buffer), buffer->name);
// We remember old modes, don't show them while we're not on the channel
if (buffer->type == BUFFER_CHANNEL
&& buffer->channel->users_len)
&& irc_channel_is_joined (buffer->channel))
{
struct str modes = str_make ();
make_chanmode_postfix (buffer->channel, &modes);
@ -7100,7 +7136,11 @@ irc_handle_mode_channel (struct channel *channel, char **params)
{
struct mode_processor p = { .s = channel->s, .channel = channel };
mode_processor_run (&p, params, mode_processor_apply_channel);
return p.changes == p.usermode_changes;
if (p.changes == p.usermode_changes)
return true;
irc_channel_broadcast_buffer_update (channel);
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -7108,7 +7148,7 @@ irc_handle_mode_channel (struct channel *channel, char **params)
static bool
mode_processor_apply_user (struct mode_processor *self)
{
mode_processor_toggle (self, &self->s->irc_user_mode);
mode_processor_toggle (self, &self->s->irc_user_modes);
return true;
}
@ -8191,7 +8231,7 @@ static void
irc_on_registered (struct server *s, const char *nickname)
{
s->irc_user = irc_get_or_make_user (s, nickname);
str_reset (&s->irc_user_mode);
str_reset (&s->irc_user_modes);
cstr_set (&s->irc_user_host, NULL);
irc_set_state (s, IRC_REGISTERED);
@ -8262,7 +8302,7 @@ irc_handle_rpl_umodeis (struct server *s, const struct irc_message *msg)
if (msg->params.len < 2)
return;
str_reset (&s->irc_user_mode);
str_reset (&s->irc_user_modes);
irc_handle_mode_user (s, msg->params.vector + 1);
// XXX: do we want to log a message?

View File

@ -328,6 +328,7 @@ rpcEventHandlers.set(Relay.Event.BufferUpdate, e => {
b.kind = e.context.kind
b.server = servers.get(e.context.serverName)
b.topic = e.context.topic
b.modes = e.context.modes
})
rpcEventHandlers.set(Relay.Event.BufferStats, e => {
@ -702,6 +703,8 @@ let Status = {
return m('.status', {}, 'Synchronizing...')
let status = `${bufferCurrent}`
if (b.modes)
status += `(+${b.modes})`
if (b.hideUnimportant)
status += `<H>`
return m('.status', {}, [status, m(Toolbar)])
@ -716,8 +719,8 @@ let Prompt = {
if (b.server.data.user !== undefined) {
let user = b.server.data.user
if (b.server.data.userMode)
user += `(${b.server.data.userMode})`
if (b.server.data.userModes)
user += `(${b.server.data.userModes})`
return m('.prompt', {}, `${user}`)
}