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); 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 static void
irc_handle_nick (struct server *s, const struct irc_message *msg) 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) if (!user)
return; return;
bool lexicographically_identical = bool lexicographically_different =
!irc_server_strcmp (s, user->nickname, new_nickname); !!irc_server_strcmp (s, user->nickname, new_nickname);
// What the fuck, someone renamed themselves to ourselves // What the fuck, someone renamed themselves to ourselves
// TODO: probably log a message and force a reconnect // 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)) && !irc_server_strcmp (s, new_nickname, s->irc_user->nickname))
return; return;
// Log a message in any PM buffer and rename it; // Log a message in any PM buffer (we may even have one for ourselves)
// we may even have one for ourselves
struct buffer *pm_buffer = struct buffer *pm_buffer =
str_map_find (&s->irc_buffer_map, user->nickname); str_map_find (&s->irc_buffer_map, user->nickname);
if (pm_buffer) 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, buffer_send (s->ctx, pm_buffer, BUFFER_LINE_NICK, 0,
.who = who, .who = who,
.object = irc_to_utf8 (s->ctx, new_nickname)); .object = irc_to_utf8 (s->ctx, new_nickname));
}
if (!lexicographically_identical) // The new nickname may collide with a user referenced by a PM buffer,
{ // or in case of data inconsistency with the server, channels.
// XXX: this code seems a bit ugly (but also necessary) // In the latter case we need the colliding user to leave all of them.
user = user_ref (user); 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 struct buffer *buffer_collision = NULL;
(s, pm_buffer, new_nickname); 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); user_unref (buffer_collision->user);
pm_buffer->user = user; buffer_collision->user = user_ref (user);
str_map_set (&s->irc_buffer_map, user->nickname, NULL); // There's not much else we can do other than somehow try to merge
str_map_set (&s->irc_buffer_map, new_nickname, pm_buffer); // 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); char *x = xstrdup_printf ("%s.%s", s->name, new_nickname);
buffer_rename (s->ctx, pm_buffer, x); 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 // Finally rename the user as it should be safe now
if (!lexicographically_identical) str_map_set (&s->irc_users, user->nickname, NULL);
{ str_map_set (&s->irc_users, new_nickname, user);
// NOTE: this doesn't dereference anything
str_map_set (&s->irc_users, user->nickname, NULL);
str_map_set (&s->irc_users, new_nickname, user);
}
free (user->nickname); free (user->nickname);
user->nickname = xstrdup (new_nickname); user->nickname = xstrdup (new_nickname);