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