From d3628928b919bd12deb224f5c3db3a7be5e7140b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?=
Date: Wed, 21 Sep 2022 16:32:08 +0200
Subject: [PATCH] xC/xP: relay and render channel modes
---
xC-proto | 4 +-
xC.c | 102 +++++++++++++++++++++++++++++++++---------------
xP/public/xP.js | 7 +++-
3 files changed, 79 insertions(+), 34 deletions(-)
diff --git a/xC-proto b/xC-proto
index 25d48e8..3057404 100644
--- a/xC-proto
+++ b/xC-proto
@@ -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:
diff --git a/xC.c b/xC.c
index 38f2c00..77d2a08 100644
--- a/xC.c
+++ b/xC.c
@@ -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 (¶ms, ' ');
+ str_append (¶ms, param);
+ }
+
+ str_append_str (&modes, ¶ms);
+ str_free (¶ms);
+
+ 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?
diff --git a/xP/public/xP.js b/xP/public/xP.js
index f418d50..7bbf530 100644
--- a/xP/public/xP.js
+++ b/xP/public/xP.js
@@ -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 += `