diff --git a/degesch.c b/degesch.c index e90d393..fad77f3 100644 --- a/degesch.c +++ b/degesch.c @@ -4679,12 +4679,36 @@ irc_handle_rpl_namreply (struct server *s, const struct irc_message *msg) split_str_ignore_empty (nicks, ' ', &channel->names_buf); } +static void +irc_sync_channel_user (struct server *s, struct channel *channel, + const char *nickname, const char *prefixes) +{ + struct user *user = irc_get_or_make_user (s, nickname); + struct channel_user *channel_user = + irc_channel_get_user (channel, user); + if (!channel_user) + { + irc_channel_link_user (channel, user, prefixes); + return; + } + + user_unref (user); + + // If our idea of the user's modes disagrees with what the server's + // sent us (the most powerful modes differ), use the latter one + if (channel_user->prefixes.str[0] != prefixes[0]) + { + str_reset (&channel_user->prefixes); + str_append (&channel_user->prefixes, prefixes); + } +} + static void irc_process_names (struct server *s, struct channel *channel) { - struct str_map map; - str_map_init (&map); - map.key_xfrm = s->irc_strxfrm; + struct str_map present; + str_map_init (&present); + present.key_xfrm = s->irc_strxfrm; struct str_vector *updates = &channel->names_buf; for (size_t i = 0; i < updates->len; i++) @@ -4694,38 +4718,19 @@ irc_process_names (struct server *s, struct channel *channel) const char *nickname = item + n_prefixes; // Store the nickname in a hashset - str_map_set (&map, nickname, (void *) 1); + str_map_set (&present, nickname, (void *) 1); - char prefixes[n_prefixes + 1]; - memcpy (prefixes, item, n_prefixes); - prefixes[n_prefixes] = '\0'; - - struct user *user = irc_get_or_make_user (s, nickname); - struct channel_user *channel_user = - irc_channel_get_user (channel, user); - if (!channel_user) - { - irc_channel_link_user (channel, user, prefixes); - continue; - } - - user_unref (user); - - // If our idea of the user's modes disagrees with what the server's - // sent us (the most powerful modes differ), use the latter one - if (channel_user->prefixes.str[0] == prefixes[0]) - continue; - - str_reset (&channel_user->prefixes); - str_append (&channel_user->prefixes, prefixes); + char *prefixes = xstrndup (item, n_prefixes); + irc_sync_channel_user (s, channel, nickname, prefixes); + free (prefixes); } // Get rid of channel users missing from "updates" LIST_FOR_EACH (struct channel_user, iter, channel->users) - if (!str_map_find (&map, iter->user->nickname)) + if (!str_map_find (&present, iter->user->nickname)) irc_channel_unlink_user (channel, iter); - str_map_free (&map); + str_map_free (&present); str_vector_reset (&channel->names_buf); struct str_vector v;