degesch: NICK handling cleanup

This commit is contained in:
Přemysl Eric Janouch 2015-06-23 00:14:18 +02:00
parent 9603bae003
commit c3439175d7
1 changed files with 42 additions and 44 deletions

View File

@ -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);