From 590fc6cf26f585841f89052e9c9ad6fb0702ba9c Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Mon, 20 Apr 2015 22:51:30 +0200
Subject: degesch: mostly implement NICK handling
Except for the corner case where two buffers merge.
---
degesch.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 76 insertions(+), 16 deletions(-)
diff --git a/degesch.c b/degesch.c
index 6d75532..329ab5d 100644
--- a/degesch.c
+++ b/degesch.c
@@ -403,10 +403,6 @@ struct app_context
// especially for away status polling)
// XXX: there can be buffers for non-existent users
- // TODO: user buffers rename on nick changes
- // TODO: move entries in "irc_buffer_map" and "irc_users" when that happens
- // TODO: user buffers may merge when an existing user renames to match
- // the name of a buffer for a non-existent user
// TODO: initialize key_strxfrm according to server properties;
// note that collisions may arise on reconnecting
// TODO: when disconnected, get rid of all users everywhere;
@@ -1156,6 +1152,49 @@ buffer_activate (struct app_context *ctx, struct buffer *buffer)
refresh_prompt (ctx);
}
+static void
+buffer_merge (struct app_context *ctx,
+ struct buffer *buffer, struct buffer *merged)
+{
+ // TODO: try to merge the buffers as best as we can
+}
+
+static void
+buffer_rename (struct app_context *ctx,
+ struct buffer *buffer, const char *new_name)
+{
+ hard_assert (buffer->type == BUFFER_PM);
+
+ struct buffer *collision =
+ str_map_find (&ctx->irc_buffer_map, new_name);
+ if (collision)
+ {
+ // TODO: use full weechat-style buffer names
+ // to prevent name collisions with the global buffer
+ hard_assert (collision->type == BUFFER_PM);
+
+ // When there's a collision, there's not much else we can do
+ // other than somehow trying to merge them
+ buffer_merge (ctx, collision, buffer);
+ // TODO: log a status message about the merge
+ if (ctx->current_buffer == buffer)
+ buffer_activate (ctx, collision);
+ buffer_remove (ctx, buffer);
+ }
+ else
+ {
+ // Otherwise we just rename the buffer and that's it
+ str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
+ str_map_set (&ctx->buffers_by_name, new_name, buffer);
+
+ free (buffer->name);
+ buffer->name = xstrdup (new_name);
+
+ // We might have renamed the current buffer
+ refresh_prompt (ctx);
+ }
+}
+
static struct buffer *
buffer_at_index (struct app_context *ctx, int n)
{
@@ -1848,13 +1887,31 @@ irc_handle_nick (struct app_context *ctx, const struct irc_message *msg)
if (!msg->prefix || msg->params.len < 1)
return;
+ const char *new_nickname = msg->params.vector[0];
+
char *nickname = irc_cut_nickname (msg->prefix);
struct user *user = str_map_find (&ctx->irc_users, nickname);
free (nickname);
if (!user)
return;
- const char *new_nickname = msg->params.vector[0];
+ // What the fuck
+ // TODO: probably log a message and force a reconnect
+ if (str_map_find (&ctx->irc_users, new_nickname))
+ return;
+
+ // Log a message in any PM buffer and rename it;
+ // we may even have one for ourselves
+ struct buffer *pm_buffer =
+ str_map_find (&ctx->irc_buffer_map, user->nickname);
+ if (pm_buffer)
+ {
+ buffer_send (ctx, pm_buffer, BUFFER_LINE_NICK, 0,
+ msg->prefix, NULL, "%s", new_nickname);
+ // TODO: use a full weechat-style buffer name here
+ buffer_rename (ctx, pm_buffer, new_nickname);
+ }
+
if (irc_is_this_us (ctx, msg->prefix))
{
// Log a message in all open buffers on this server
@@ -1863,26 +1920,21 @@ irc_handle_nick (struct app_context *ctx, const struct irc_message *msg)
struct buffer *buffer;
while ((buffer = str_map_iter_next (&iter)))
{
+ // We've already done that
+ if (buffer == pm_buffer)
+ continue;
+
buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0,
NULL, NULL, "%s", new_nickname);
}
}
else
{
- // Log a message in any PM buffer
- struct buffer *buffer =
- str_map_find (&ctx->irc_buffer_map, user->nickname);
- if (buffer)
- {
- buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0,
- msg->prefix, NULL, "%s", new_nickname);
- // TODO: rename the buffer, and if it collides, merge them
- }
-
// Log a message in all channels the user is in
LIST_FOR_EACH (struct user_channel, iter, user->channels)
{
- buffer = str_map_find (&ctx->irc_buffer_map, iter->channel->name);
+ struct buffer *buffer =
+ str_map_find (&ctx->irc_buffer_map, iter->channel->name);
hard_assert (buffer != NULL);
buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0,
msg->prefix, NULL, "%s", new_nickname);
@@ -1890,6 +1942,9 @@ irc_handle_nick (struct app_context *ctx, const struct irc_message *msg)
}
// Finally rename the user
+ str_map_set (&ctx->irc_users, new_nickname, user_ref (user));
+ str_map_set (&ctx->irc_users, user->nickname, NULL);
+
free (user->nickname);
user->nickname = xstrdup (new_nickname);
@@ -2644,8 +2699,11 @@ on_irc_disconnected (struct app_context *ctx)
xclose (ctx->irc_fd);
ctx->irc_fd = -1;
ctx->irc_ready = false;
+
+ str_map_set (&ctx->irc_users, ctx->irc_user->nickname, NULL);
user_unref (ctx->irc_user);
ctx->irc_user = NULL;
+
free (ctx->irc_user_mode);
ctx->irc_user_mode = NULL;
free (ctx->irc_user_host);
@@ -2815,6 +2873,8 @@ irc_connect (struct app_context *ctx, struct error **e)
// XXX: maybe we should wait for the first message from the server
ctx->irc_user = user_new ();
ctx->irc_user->nickname = xstrdup (nickname);
+ str_map_set (&ctx->irc_users, nickname, user_ref (ctx->irc_user));
+
ctx->irc_user_mode = xstrdup ("");
ctx->irc_user_host = NULL;
return true;
--
cgit v1.2.3-70-g09d2