summaryrefslogtreecommitdiff
path: root/degesch.c
diff options
context:
space:
mode:
Diffstat (limited to 'degesch.c')
-rw-r--r--degesch.c77
1 files changed, 74 insertions, 3 deletions
diff --git a/degesch.c b/degesch.c
index f997471..a1920cb 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1059,6 +1059,8 @@ struct server
// TODO: an output queue to prevent excess floods (this will be needed
// especially for away status polling)
+ bool rehashing; ///< Rehashing IRC identifiers
+
struct str_map irc_users; ///< IRC user data
struct str_map irc_channels; ///< IRC channel data
struct str_map irc_buffer_map; ///< Maps IRC identifiers to buffers
@@ -2791,7 +2793,8 @@ irc_user_on_destroy (void *object, void *user_data)
{
struct user *user = object;
struct server *s = user_data;
- str_map_set (&s->irc_users, user->nickname, NULL);
+ if (!s->rehashing)
+ str_map_set (&s->irc_users, user->nickname, NULL);
}
static struct user *
@@ -2877,7 +2880,8 @@ irc_channel_on_destroy (void *object, void *user_data)
struct server *s = user_data;
LIST_FOR_EACH (struct channel_user, iter, channel->users)
irc_channel_unlink_user (channel, iter);
- str_map_set (&s->irc_channels, channel->name, NULL);
+ if (!s->rehashing)
+ str_map_set (&s->irc_channels, channel->name, NULL);
}
static struct channel *
@@ -2924,7 +2928,74 @@ irc_left_channel (struct channel *channel)
static void
irc_rehash_and_fix_conflicts (struct server *s)
{
- // TODO
+ // Save the old maps and initialize new ones
+ struct str_map old_users = s->irc_users;
+ struct str_map old_channels = s->irc_channels;
+ struct str_map old_buffer_map = s->irc_buffer_map;
+
+ str_map_init (&s->irc_users);
+ str_map_init (&s->irc_channels);
+ str_map_init (&s->irc_buffer_map);
+
+ s->irc_users .free = old_users .free;
+ s->irc_channels .free = old_channels .free;
+ s->irc_buffer_map.free = old_buffer_map.free;
+
+ s->irc_users .key_xfrm = s->irc_strxfrm;
+ s->irc_channels .key_xfrm = s->irc_strxfrm;
+ s->irc_buffer_map.key_xfrm = s->irc_strxfrm;
+
+ // Prevent channels and users from unsetting themselves
+ // from server maps upon removing the last reference to them
+ s->rehashing = true;
+
+ // TODO: "Removed similarly named buffer %s because of casemapping conflict"
+ // XXX: to be perfectly sure, we should also check
+ // whether any users collide with channels and vice versa
+
+ struct str_map_iter iter;
+ str_map_iter_init (&iter, &old_users);
+ struct user *user;
+ while ((user = str_map_iter_next (&iter)))
+ {
+ // FIXME: don't remove ourselves!
+ if (str_map_find (&s->irc_users, user->nickname))
+ {
+ // TODO: move or merge any PM buffer and remove
+ // the user from channels and altogether
+ }
+ else
+ {
+ str_map_set (&s->irc_users, user->nickname, user);
+ str_map_set (&s->irc_buffer_map, user->nickname,
+ str_map_find (&old_buffer_map, user->nickname));
+ }
+ }
+
+ str_map_iter_init (&iter, &old_channels);
+ struct channel *channel;
+ while ((channel = str_map_iter_next (&iter)))
+ {
+ if (str_map_find (&s->irc_channels, channel->name))
+ {
+ // TODO: remove all users from the buffer
+ // and probably issue NAMES if registered and on the channel,
+ // and of course remove the colliding channel
+ }
+ else
+ {
+ str_map_set (&s->irc_channels, channel->name, user);
+ str_map_set (&s->irc_buffer_map, user->nickname,
+ str_map_find (&old_buffer_map, user->nickname));
+ }
+ }
+
+ // Hopefully we've either moved or destroyed all the old content
+ s->rehashing = false;
+
+ str_map_free (&old_users);
+ str_map_free (&old_channels);
+ str_map_free (&old_buffer_map);
}
static void