degesch: mostly implement NICK handling

Except for the corner case where two buffers merge.
This commit is contained in:
Přemysl Eric Janouch 2015-04-20 22:51:30 +02:00
parent 3fa9a67a59
commit 590fc6cf26

View File

@ -403,10 +403,6 @@ struct app_context
// especially for away status polling) // especially for away status polling)
// XXX: there can be buffers for non-existent users // 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; // TODO: initialize key_strxfrm according to server properties;
// note that collisions may arise on reconnecting // note that collisions may arise on reconnecting
// TODO: when disconnected, get rid of all users everywhere; // 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); 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 * static struct buffer *
buffer_at_index (struct app_context *ctx, int n) 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) if (!msg->prefix || msg->params.len < 1)
return; return;
const char *new_nickname = msg->params.vector[0];
char *nickname = irc_cut_nickname (msg->prefix); char *nickname = irc_cut_nickname (msg->prefix);
struct user *user = str_map_find (&ctx->irc_users, nickname); struct user *user = str_map_find (&ctx->irc_users, nickname);
free (nickname); free (nickname);
if (!user) if (!user)
return; 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)) if (irc_is_this_us (ctx, msg->prefix))
{ {
// Log a message in all open buffers on this server // 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; struct buffer *buffer;
while ((buffer = str_map_iter_next (&iter))) 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, buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0,
NULL, NULL, "%s", new_nickname); NULL, NULL, "%s", new_nickname);
} }
} }
else 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 // Log a message in all channels the user is in
LIST_FOR_EACH (struct user_channel, iter, user->channels) 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); hard_assert (buffer != NULL);
buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0, buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0,
msg->prefix, NULL, "%s", new_nickname); 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 // 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); free (user->nickname);
user->nickname = xstrdup (new_nickname); user->nickname = xstrdup (new_nickname);
@ -2644,8 +2699,11 @@ on_irc_disconnected (struct app_context *ctx)
xclose (ctx->irc_fd); xclose (ctx->irc_fd);
ctx->irc_fd = -1; ctx->irc_fd = -1;
ctx->irc_ready = false; ctx->irc_ready = false;
str_map_set (&ctx->irc_users, ctx->irc_user->nickname, NULL);
user_unref (ctx->irc_user); user_unref (ctx->irc_user);
ctx->irc_user = NULL; ctx->irc_user = NULL;
free (ctx->irc_user_mode); free (ctx->irc_user_mode);
ctx->irc_user_mode = NULL; ctx->irc_user_mode = NULL;
free (ctx->irc_user_host); 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 // XXX: maybe we should wait for the first message from the server
ctx->irc_user = user_new (); ctx->irc_user = user_new ();
ctx->irc_user->nickname = xstrdup (nickname); 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_mode = xstrdup ("");
ctx->irc_user_host = NULL; ctx->irc_user_host = NULL;
return true; return true;