From c3439175d7ced235822bcecb37ff0fdebcdc9f1c Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Tue, 23 Jun 2015 00:14:18 +0200
Subject: degesch: NICK handling cleanup
---
degesch.c | 86 +++++++++++++++++++++++++++++++--------------------------------
1 file changed, 42 insertions(+), 44 deletions(-)
diff --git a/degesch.c b/degesch.c
index 3c560be..acd4856 100644
--- a/degesch.c
+++ b/degesch.c
@@ -4357,27 +4357,6 @@ irc_handle_mode (struct server *s, const struct irc_message *msg)
refresh_prompt (s->ctx);
}
-static struct buffer *
-irc_handle_buffer_collision (struct server *s,
- struct buffer *buffer, const char *new_name)
-{
- struct buffer *collision = str_map_find (&s->irc_buffer_map, new_name);
- if (!collision)
- return buffer;
-
- // TODO: use full weechat-style buffer names
- // to prevent name collisions with the global buffer
- hard_assert (collision->type == buffer->type);
-
- // When there's a collision, there's not much else we can do
- // other than somehow try to merge them
- buffer_merge (s->ctx, collision, buffer);
- if (s->ctx->current_buffer == buffer)
- buffer_activate (s->ctx, collision);
- buffer_remove (s->ctx, buffer);
- return collision;
-}
-
static void
irc_handle_nick (struct server *s, const struct irc_message *msg)
{
@@ -4392,17 +4371,16 @@ irc_handle_nick (struct server *s, const struct irc_message *msg)
if (!user)
return;
- bool lexicographically_identical =
- !irc_server_strcmp (s, user->nickname, new_nickname);
+ bool lexicographically_different =
+ !!irc_server_strcmp (s, user->nickname, new_nickname);
// What the fuck, someone renamed themselves to ourselves
// TODO: probably log a message and force a reconnect
- if (!lexicographically_identical
+ if (lexicographically_different
&& !irc_server_strcmp (s, new_nickname, s->irc_user->nickname))
return;
- // Log a message in any PM buffer and rename it;
- // we may even have one for ourselves
+ // Log a message in any PM buffer (we may even have one for ourselves)
struct buffer *pm_buffer =
str_map_find (&s->irc_buffer_map, user->nickname);
if (pm_buffer)
@@ -4413,21 +4391,45 @@ irc_handle_nick (struct server *s, const struct irc_message *msg)
buffer_send (s->ctx, pm_buffer, BUFFER_LINE_NICK, 0,
.who = who,
.object = irc_to_utf8 (s->ctx, new_nickname));
+ }
- if (!lexicographically_identical)
- {
- // XXX: this code seems a bit ugly (but also necessary)
- user = user_ref (user);
+ // The new nickname may collide with a user referenced by a PM buffer,
+ // or in case of data inconsistency with the server, channels.
+ // In the latter case we need the colliding user to leave all of them.
+ struct user *user_collision = NULL;
+ if (lexicographically_different
+ && (user_collision = str_map_find (&s->irc_users, new_nickname)))
+ LIST_FOR_EACH (struct user_channel, iter, user_collision->channels)
+ irc_remove_user_from_channel (user_collision, iter->channel);
- pm_buffer = irc_handle_buffer_collision
- (s, pm_buffer, new_nickname);
+ struct buffer *buffer_collision = NULL;
+ if (lexicographically_different
+ && (buffer_collision = str_map_find (&s->irc_buffer_map, new_nickname)))
+ {
+ hard_assert (buffer_collision->type == BUFFER_PM);
+ hard_assert (buffer_collision->user == user_collision);
- user_unref (pm_buffer->user);
- pm_buffer->user = user;
+ user_unref (buffer_collision->user);
+ buffer_collision->user = user_ref (user);
- str_map_set (&s->irc_buffer_map, user->nickname, NULL);
- str_map_set (&s->irc_buffer_map, new_nickname, pm_buffer);
- }
+ // There's not much else we can do other than somehow try to merge
+ // one buffer into the other. In our case, the original buffer wins.
+ buffer_merge (s->ctx, buffer_collision, pm_buffer);
+ if (s->ctx->current_buffer == pm_buffer)
+ buffer_activate (s->ctx, buffer_collision);
+ buffer_remove (s->ctx, pm_buffer);
+ pm_buffer = buffer_collision;
+ }
+
+ // The colliding user should be completely destroyed by now
+ if (lexicographically_different)
+ hard_assert (!str_map_find (&s->irc_users, new_nickname));
+
+ // Now we can rename the PM buffer to reflect the new nickname
+ if (pm_buffer)
+ {
+ str_map_set (&s->irc_buffer_map, user->nickname, NULL);
+ str_map_set (&s->irc_buffer_map, new_nickname, pm_buffer);
char *x = xstrdup_printf ("%s.%s", s->name, new_nickname);
buffer_rename (s->ctx, pm_buffer, x);
@@ -4464,13 +4466,9 @@ irc_handle_nick (struct server *s, const struct irc_message *msg)
}
}
- // Finally rename the user
- if (!lexicographically_identical)
- {
- // NOTE: this doesn't dereference anything
- str_map_set (&s->irc_users, user->nickname, NULL);
- str_map_set (&s->irc_users, new_nickname, user);
- }
+ // Finally rename the user as it should be safe now
+ str_map_set (&s->irc_users, user->nickname, NULL);
+ str_map_set (&s->irc_users, new_nickname, user);
free (user->nickname);
user->nickname = xstrdup (new_nickname);
--
cgit v1.2.3-70-g09d2