From 7f57bed5638b4e9e7f3a4fdfabfe3eb72135f7dc Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Fri, 5 Jun 2015 00:57:39 +0200 Subject: degesch: correctly update user prefixes --- degesch.c | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/degesch.c b/degesch.c index 0baac98..3533658 100644 --- a/degesch.c +++ b/degesch.c @@ -820,13 +820,14 @@ struct channel_user LIST_HEADER (struct channel_user) struct user *user; ///< Reference to user - char *modes; ///< Ordered @+... characters + struct str prefixes; ///< Ordered @+... characters }; static struct channel_user * channel_user_new (void) { struct channel_user *self = xcalloc (1, sizeof *self); + str_init (&self->prefixes); return self; } @@ -834,7 +835,7 @@ static void channel_user_destroy (struct channel_user *self) { user_unref (self->user); - free (self->modes); + str_free (&self->prefixes); free (self); } @@ -3878,7 +3879,6 @@ irc_handle_join (struct server *s, const struct irc_message *msg) struct channel_user *channel_user = channel_user_new (); channel_user->user = user; - channel_user->modes = xstrdup (""); LIST_PREPEND (channel->users, channel_user); // Finally log the message @@ -3938,8 +3938,8 @@ struct mode_processor char **params; ///< Mode string parameters - struct server *s; ///< Who does the changes - struct channel *channel; ///< The channel we're modifying + struct server *s; ///< Server + struct channel *channel; ///< The channel being modified // Internals: @@ -3978,24 +3978,27 @@ mode_processor_do_user (struct mode_processor *self) if (!channel_user) return; - char prefix = self->s->irc_chanuser_prefixes - [strchr (self->s->irc_chanuser_modes, self->mode_char) - - self->s->irc_chanuser_modes]; + const char *all_prefixes = self->s->irc_chanuser_prefixes; + const char *all_modes = self->s->irc_chanuser_modes; + char prefix = all_prefixes[strchr (all_modes, self->mode_char) - all_modes]; - // XXX: shouldn't this rather be a "struct str"? - char *modes = channel_user->modes; - char *pos = strchr (modes, self->mode_char); + struct str *prefixes = &channel_user->prefixes; + const char *pos = strchr (prefixes->str, prefix); if (self->adding == !!pos) return; if (self->adding) { - // FIXME: this doesn't give two fucks about the correct order - channel_user->modes = xstrdup_printf ("%s%c", modes, prefix); - free (modes); + // Add the new mode prefix while retaining the right order + char *old_prefixes = str_steal (prefixes); + str_init (prefixes); + for (const char *p = all_prefixes; *p; p++) + if (*p == prefix || strchr (old_prefixes, *p)) + str_append_c (prefixes, *p); + free (old_prefixes); } else - memmove (pos, pos + 1, strlen (pos + 1)); + str_remove_slice (prefixes, pos - prefixes->str, 1); } static void @@ -4689,26 +4692,27 @@ irc_process_names (struct server *s, struct channel *channel) for (size_t i = 0; i < updates->len; i++) { const char *item = updates->vector[i]; - const char *nick = item + strspn (item, s->irc_chanuser_prefixes); - char *modes = xstrndup (item, nick - item); + size_t n_prefixes = strspn (item, s->irc_chanuser_prefixes); + const char *nick = item + n_prefixes; + + char prefixes[n_prefixes + 1]; + memcpy (prefixes, item, n_prefixes); + prefixes[n_prefixes] = '\0'; struct channel_user *channel_user = str_map_find (&map, nick); if (!channel_user) { channel_user = channel_user_new (); channel_user->user = irc_get_or_make_user (s, nick); - channel_user->modes = modes; LIST_PREPEND (channel->users, channel_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 - else if (channel_user->modes[0] != modes[0]) - { - free (channel_user->modes); - channel_user->modes = modes; - } - else - free (modes); + else if (channel_user->prefixes.str[0] == prefixes[0]) + continue; + + str_reset (&channel_user->prefixes); + str_append (&channel_user->prefixes, prefixes); } // TODO: get rid of channel users missing from "updates": @@ -4721,7 +4725,7 @@ irc_process_names (struct server *s, struct channel *channel) str_vector_init (&v); LIST_FOR_EACH (struct channel_user, iter, channel->users) str_vector_add_owned (&v, - xstrdup_printf ("%s%s", iter->modes, iter->user->nickname)); + xstrdup_printf ("%s%s", iter->prefixes.str, iter->user->nickname)); char *all_users = join_str_vector (&v, ' '); str_vector_free (&v); -- cgit v1.2.3-70-g09d2