aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--matrix-room.c285
-rw-r--r--matrix-roommembers.c263
-rw-r--r--matrix-roommembers.h92
-rw-r--r--matrix-sync.c5
4 files changed, 392 insertions, 253 deletions
diff --git a/matrix-room.c b/matrix-room.c
index 96ba838..2d15942 100644
--- a/matrix-room.c
+++ b/matrix-room.c
@@ -63,6 +63,10 @@ static MatrixConnectionData *_get_connection_data_from_conversation(
/* MatrixRoomMemberTable * - see below */
#define PURPLE_CONV_MEMBER_TABLE "member_table"
+/* PURPLE_CONV_FLAG_* */
+#define PURPLE_CONV_FLAGS "flags"
+#define PURPLE_CONV_FLAG_NEEDS_NAME_UPDATE 0x1
+
/**
* Get the member table for a room
@@ -84,6 +88,20 @@ static MatrixRoomStateEventTable *matrix_room_get_state_table(
}
+static guint _get_flags(PurpleConversation *conv)
+{
+ return GPOINTER_TO_UINT(purple_conversation_get_data(conv,
+ PURPLE_CONV_FLAGS));
+}
+
+
+static void _set_flags(PurpleConversation *conv, guint flags)
+{
+ purple_conversation_set_data(conv, PURPLE_CONV_FLAGS,
+ GUINT_TO_POINTER(flags));
+}
+
+
/******************************************************************************
*
* room state handling
@@ -91,8 +109,7 @@ static MatrixRoomStateEventTable *matrix_room_get_state_table(
/**
- * Update the name of the room in the buddy list (which in turn will update it
- * in the chat window)
+ * Update the name of the room in the buddy list and the chat window
*
* @param conv: conversation info
*/
@@ -100,17 +117,38 @@ static void _update_room_alias(PurpleConversation *conv)
{
gchar *room_name;
MatrixConnectionData *conn = _get_connection_data_from_conversation(conv);
- PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
+ PurpleChat *chat;
+ guint flags;
+
+ room_name = _get_room_name(conn, conv);
+ /* update the buddy list entry */
+ chat = purple_blist_find_chat(conv->account, conv->name);
/* we know there should be a buddy list entry for this room */
g_assert(chat != NULL);
-
- room_name = _get_room_name(conn, conv);
purple_blist_alias_chat(chat, room_name);
+
+ /* explicitly update the conversation title. This will tend to happen
+ * anyway, but possibly not until the conversation tab is next activated.
+ */
+ if (strcmp(room_name, purple_conversation_get_title(conv)))
+ purple_conversation_set_title(conv, room_name);
+
g_free(room_name);
+
+ flags = _get_flags(conv);
+ flags &= ~PURPLE_CONV_FLAG_NEEDS_NAME_UPDATE;
+ _set_flags(conv, flags);
}
+static void _schedule_name_update(PurpleConversation *conv)
+{
+ guint flags = _get_flags(conv);
+ flags |= PURPLE_CONV_FLAG_NEEDS_NAME_UPDATE;
+ _set_flags(conv, flags);
+}
+
/**
* Called when there is a change to the member list. Tells the MemberTable
* about it.
@@ -142,10 +180,16 @@ static void _on_state_update(const gchar *event_type,
if(strcmp(event_type, "m.room.member") == 0) {
_on_member_change(conv, state_key, new_state);
+ /* we schedule a room name update here regardless of whether we end up
+ * changing any members, because even changes to invited members can
+ * affect the room name.
+ */
+ _schedule_name_update(conv);
}
else if(strcmp(event_type, "m.room.alias") == 0 ||
+ strcmp(event_type, "m.room.canonical_alias") == 0 ||
strcmp(event_type, "m.room.room_name") == 0) {
- _update_room_alias(conv);
+ _schedule_name_update(conv);
}
}
@@ -158,6 +202,12 @@ void matrix_room_handle_state_event(struct _PurpleConversation *conv,
}
+static gint _compare_member_user_id(const MatrixRoomMember *m,
+ const gchar *user_id)
+{
+ return g_strcmp0(matrix_roommember_get_user_id(m), user_id);
+}
+
/**
* figure out the best name for a room based on its members list
*
@@ -175,7 +225,8 @@ static gchar *_get_room_name_from_members(MatrixConnectionData *conn,
members = matrix_roommembers_get_active_members(member_table, TRUE);
/* remove ourselves from the list */
- tmp = g_list_find_custom(members, conn->user_id, (GCompareFunc)strcmp);
+ tmp = g_list_find_custom(members, conn->user_id,
+ (GCompareFunc)_compare_member_user_id);
if(tmp != NULL) {
members = g_list_delete_link(members, tmp);
}
@@ -185,16 +236,15 @@ static gchar *_get_room_name_from_members(MatrixConnectionData *conn,
return NULL;
}
- member1 = matrix_roommembers_get_displayname_for_member(
- member_table, members->data);
+ member1 = matrix_roommember_get_displayname(members->data);
if(members->next == NULL) {
/* one other person */
res = g_strdup(member1);
} else if(members->next->next == NULL) {
/* two other people */
- const gchar *member2 = matrix_roommembers_get_displayname_for_member(
- member_table, members->next->data);
+ const gchar *member2 = matrix_roommember_get_displayname(
+ members->next->data);
res = g_strdup_printf(_("%s and %s"), member1, member2);
} else {
int nmembers = g_list_length(members);
@@ -396,6 +446,7 @@ void matrix_room_handle_timeline_event(PurpleConversation *conv,
const gchar *room_id, *msg_body;
PurpleMessageFlags flags;
const gchar *sender_display_name;
+ MatrixRoomMember *sender = NULL;
room_id = conv->name;
@@ -440,14 +491,14 @@ void matrix_room_handle_timeline_event(PurpleConversation *conv,
return;
}
- if(sender_id == NULL) {
- sender_display_name = "<unknown>";
+ if(sender_id != NULL) {
+ MatrixRoomMemberTable *table = matrix_room_get_member_table(conv);
+ sender = matrix_roommembers_lookup_member(table, sender_id);
+ }
+ if (sender != NULL) {
+ sender_display_name = matrix_roommember_get_displayname(sender);
} else {
- MatrixRoomMemberTable *member_table =
- matrix_room_get_member_table(conv);
-
- sender_display_name = matrix_roommembers_get_displayname_for_member(
- member_table, sender_id);
+ sender_display_name = "<unknown>";
}
flags = PURPLE_MESSAGE_RECV;
@@ -527,56 +578,181 @@ void matrix_room_leave_chat(PurpleConversation *conv)
}
-static void _update_user_list(PurpleConversation *conv,
+/* *****************************************************************************
+ *
+ * Tracking of member additions/removals.
+ *
+ * We don't tell libpurple about new arrivals immediately, because that is
+ * inefficient and takes ages on a big room like Matrix HQ. Instead, the
+ * MatrixRoomMemberTable builds up a list of changes, and we then go through
+ * those changes after processing all of the state changes in a /sync.
+ *
+ * This introduces a complexity in that we need to track what we've told purple
+ * the displayname of the user is (for instance, member1 leaves a channel,
+ * meaning that there is no longer a clash of displaynames, so member2
+ * can be renamed: we need to know what we previously told libpurple member2 was
+ * called). We do this by setting the member's opaque data to the name we gave
+ * to libpurple.
+ */
+
+
+static void _on_member_deleted(MatrixRoomMember *member)
+{
+ gchar *displayname = matrix_roommember_get_opaque_data(member);
+ g_free(displayname);
+ matrix_roommember_set_opaque_data(member, NULL, NULL);
+}
+
+
+/**
+ * Tell libpurple about newly-arrived members
+ */
+static void _handle_new_members(PurpleConversation *conv,
gboolean announce_arrivals)
{
PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
MatrixRoomMemberTable *table = matrix_room_get_member_table(conv);
- GList *names = NULL, *flags = NULL, *oldnames = NULL;
- gboolean updated = FALSE;
+ GList *names = NULL, *flags = NULL;
+ GSList *members;
+
+ members = matrix_roommembers_get_new_members(table);
+ while(members != NULL) {
+ MatrixRoomMember *member = members->data;
+ const gchar *displayname;
+ GSList *tmp;
+
+ displayname = matrix_roommember_get_opaque_data(member);
+ g_assert(displayname == NULL);
+
+ displayname = matrix_roommember_get_displayname(member);
+ matrix_roommember_set_opaque_data(member, g_strdup(displayname),
+ _on_member_deleted);
+
+ names = g_list_prepend(names, (gpointer)displayname);
+ flags = g_list_prepend(flags, GINT_TO_POINTER(0));
+
+ tmp = members;
+ members = members->next;
+ g_slist_free_1(tmp);
+ }
- matrix_roommembers_get_new_members(table, &names, &flags);
if(names) {
purple_conv_chat_add_users(chat, names, NULL, flags, announce_arrivals);
g_list_free(names);
g_list_free(flags);
- names = NULL;
- flags = NULL;
- updated = TRUE;
}
+}
- matrix_roommembers_get_renamed_members(table, &oldnames, &names);
- if(names) {
- GList *name1 = names, *oldname1 = oldnames;
- while(name1 && oldname1) {
- purple_conv_chat_rename_user(chat, oldname1->data, name1->data);
- name1 = g_list_next(name1);
- oldname1 = g_list_next(oldname1);
- }
- g_list_free_full(oldnames, (GDestroyNotify)g_free);
- g_list_free(names);
- names = NULL;
- oldnames = NULL;
- updated = TRUE;
+
+/**
+ * Tell libpurple about renamed members
+ */
+void _handle_renamed_members(PurpleConversation *conv)
+{
+ PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
+ MatrixRoomMemberTable *table = matrix_room_get_member_table(conv);
+ GSList *members;
+
+ members = matrix_roommembers_get_renamed_members(table);
+ while(members != NULL) {
+ MatrixRoomMember *member = members->data;
+ gchar *current_displayname;
+ const gchar *new_displayname;
+ GSList *tmp;
+
+ current_displayname = matrix_roommember_get_opaque_data(member);
+ g_assert(current_displayname != NULL);
+
+ new_displayname = matrix_roommember_get_displayname(member);
+
+ purple_conv_chat_rename_user(chat, current_displayname,
+ new_displayname);
+
+ matrix_roommember_set_opaque_data(member, g_strdup(new_displayname),
+ _on_member_deleted);
+ g_free(current_displayname);
+
+ tmp = members;
+ members = members->next;
+ g_slist_free_1(tmp);
}
+}
- matrix_roommembers_get_left_members(table, &names);
- if(names) {
- purple_conv_chat_remove_users(chat, names, NULL);
- g_list_free_full(names, (GDestroyNotify)g_free);
- names = NULL;
- updated = TRUE;
+
+/**
+ * Tell libpurple about departed members
+ */
+void _handle_left_members(PurpleConversation *conv)
+{
+ PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
+ MatrixRoomMemberTable *table = matrix_room_get_member_table(conv);
+ GSList *members;
+
+ members = matrix_roommembers_get_left_members(table);
+ while(members != NULL) {
+ MatrixRoomMember *member = members->data;
+ gchar *current_displayname;
+ GSList *tmp;
+
+ current_displayname = matrix_roommember_get_opaque_data(member);
+ g_assert(current_displayname != NULL);
+ purple_conv_chat_remove_user(chat, current_displayname, NULL);
+
+ g_free(current_displayname);
+ matrix_roommember_set_opaque_data(member, NULL, NULL);
+
+ tmp = members;
+ members = members->next;
+ g_slist_free_1(tmp);
}
+}
- if(updated)
- _update_room_alias(conv);
+
+static void _update_user_list(PurpleConversation *conv,
+ gboolean announce_arrivals)
+{
+ _handle_new_members(conv, announce_arrivals);
+ _handle_renamed_members(conv);
+ _handle_left_members(conv);
}
+
+/**
+ * Get the userid of a member of a room, given their displayname
+ *
+ * @returns a string, which will be freed by the caller, or null if not known
+ */
+gchar *matrix_room_displayname_to_userid(struct _PurpleConversation *conv,
+ const gchar *who)
+{
+ /* TODO: make this more efficient */
+ MatrixRoomMemberTable *table = matrix_room_get_member_table(conv);
+ GList *members;
+
+ members = matrix_roommembers_get_active_members(table, TRUE);
+
+ while(members != NULL) {
+ MatrixRoomMember *member = members->data;
+ const gchar *displayname = matrix_roommember_get_opaque_data(member);
+ if(g_strcmp0(displayname, who) == 0) {
+ g_list_free(members);
+ return g_strdup(matrix_roommember_get_user_id(member));
+ }
+ }
+
+ g_list_free(members);
+ return NULL;
+}
+
+/* ************************************************************************** */
+
void matrix_room_complete_state_update(PurpleConversation *conv,
gboolean announce_arrivals)
{
_update_user_list(conv, announce_arrivals);
+ if(_get_flags(conv) & PURPLE_CONV_FLAG_NEEDS_NAME_UPDATE)
+ _update_room_alias(conv);
}
@@ -585,9 +761,13 @@ static const gchar *_get_my_display_name(PurpleConversation *conv)
MatrixConnectionData *conn = _get_connection_data_from_conversation(conv);
MatrixRoomMemberTable *member_table =
matrix_room_get_member_table(conv);
+ MatrixRoomMember *me;
- return matrix_roommembers_get_displayname_for_member(
- member_table, conn->user_id);
+ me = matrix_roommembers_lookup_member(member_table, conn->user_id);
+ if(me == NULL)
+ return NULL;
+ else
+ return matrix_roommember_get_displayname(me);
}
/**
@@ -608,12 +788,3 @@ void matrix_room_send_message(PurpleConversation *conv, const gchar *message)
purple_conv_chat_write(chat, _get_my_display_name(conv),
message, PURPLE_MESSAGE_SEND, g_get_real_time()/1000/1000);
}
-
-
-gchar *matrix_room_displayname_to_userid(struct _PurpleConversation *conv,
- const gchar *who)
-{
- MatrixRoomMemberTable *member_table =
- matrix_room_get_member_table(conv);
- return matrix_roommembers_displayname_to_userid(member_table, who);
-}
diff --git a/matrix-roommembers.c b/matrix-roommembers.c
index 2f68ea0..1f4ed4e 100644
--- a/matrix-roommembers.c
+++ b/matrix-roommembers.c
@@ -35,32 +35,24 @@
*/
typedef struct _MatrixRoomMember {
- gchar *userid;
-
- /* the displayname we gave to purple */
- gchar *current_displayname;
+ gchar *user_id;
/* the current room membership */
int membership;
- /* the displayname from the state table */
+ /* the displayname from the state table (this is a pointer to the actual
+ * string in the state table, so should not be freed here) */
const gchar *state_displayname;
-} MatrixRoomMember;
+ /* data attached to this member (matrix-room.c uses it to track the
+ * name we told libpurple this member had)
+ */
+ gpointer opaque_data;
-/**
- * calculate the displayname for the given member
- *
- * @returns a string, which should be freed
- */
-static gchar *_calculate_displayname_for_member(const MatrixRoomMember *member)
-{
- if(member->state_displayname != NULL) {
- return g_strdup(member->state_displayname);
- } else {
- return g_strdup(member->userid);
- }
-}
+ /* callback to delete the opaque_data. Called with a pointer to the member.
+ */
+ DestroyMemberNotify on_delete;
+} MatrixRoomMember;
static int _parse_membership(const gchar *membership)
@@ -80,21 +72,69 @@ static int _parse_membership(const gchar *membership)
static MatrixRoomMember *_new_member(const gchar *userid)
{
MatrixRoomMember *mem = g_new0(MatrixRoomMember, 1);
- mem->userid = g_strdup(userid);
+ mem->user_id = g_strdup(userid);
return mem;
}
static void _free_member(MatrixRoomMember *member)
{
g_assert(member != NULL);
- g_free(member->userid);
- member->userid = NULL;
- g_free(member->current_displayname);
- member->current_displayname = NULL;
+ if(member->on_delete)
+ member->on_delete(member);
+ g_free(member->user_id);
+ member->user_id = NULL;
g_free(member);
}
+/**
+ * Get the user_id for the given member
+ *
+ * @returns a string, which should *not* be freed
+ */
+const gchar *matrix_roommember_get_user_id(const MatrixRoomMember *member)
+{
+ return member->user_id;
+}
+
+/**
+ * Get the displayname for the given member
+ *
+ * @returns a string, which should *not* be freed
+ */
+const gchar *matrix_roommember_get_displayname(const MatrixRoomMember *member)
+{
+ if(member->state_displayname != NULL) {
+ /* TODO: if there is more than one member with this displayname, we
+ * should return a deduplicated name
+ */
+ return member->state_displayname;
+ } else {
+ return member->user_id;
+ }
+}
+
+
+/**
+ * Get the opaque data associated with the given member
+ */
+gpointer matrix_roommember_get_opaque_data(const MatrixRoomMember *member)
+{
+ return member->opaque_data;
+}
+
+
+/**
+ * Set the opaque data associated with the given member
+ */
+void matrix_roommember_set_opaque_data(MatrixRoomMember *member,
+ gpointer data, DestroyMemberNotify on_delete)
+{
+ member->opaque_data = data;
+ member->on_delete = on_delete;
+}
+
+
/******************************************************************************
*
* member table
@@ -125,120 +165,10 @@ void matrix_roommembers_free_table(MatrixRoomMemberTable *table)
}
-static MatrixRoomMember *_lookup_member(MatrixRoomMemberTable *table,
- const gchar *userid)
-{
- return g_hash_table_lookup(table->hash_table, userid);
-}
-
-
-#if 0
-static void _on_member_changed_displayname(PurpleConversation *conv,
- const gchar *member_user_id, MatrixRoomMember *member)
-{
- PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
- gchar *old_displayname, *new_displayname;
-
- old_displayname = member->current_displayname;
- g_assert(old_displayname != NULL);
- new_displayname = _calculate_displayname_for_member(member_user_id, member);
-
- purple_conv_chat_rename_user(chat, old_displayname, new_displayname);
- g_free(old_displayname);
- member->current_displayname = new_displayname;
-}
-
-
-static void _on_member_left(PurpleConversation *conv,
- const gchar *member_user_id, MatrixRoomMember *member)
+MatrixRoomMember *matrix_roommembers_lookup_member(MatrixRoomMemberTable *table,
+ const gchar *member_user_id)
{
- PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
- gchar *old_displayname;
-
- old_displayname = member->current_displayname;
- g_assert(old_displayname != NULL);
- purple_conv_chat_remove_user(chat, old_displayname, NULL);
- g_free(old_displayname);
- member->current_displayname = NULL;
-}
-#endif
-
-
-const gchar *matrix_roommembers_get_displayname_for_member(
- MatrixRoomMemberTable *table, const gchar *user_id)
-{
- MatrixRoomMember *member = _lookup_member(table, user_id);
- gchar *displayname;
-
- if(member == NULL)
- return user_id;
-
- displayname = member -> current_displayname;
-
- if (displayname != NULL)
- return displayname;
-
- displayname = _calculate_displayname_for_member(member);
- member -> current_displayname = displayname;
- return displayname;
-}
-
-
-void matrix_roommembers_get_new_members(MatrixRoomMemberTable *table,
- GList **display_names, GList **flags)
-{
- while(table->new_members != NULL) {
- MatrixRoomMember *member = table->new_members->data;
- gchar *displayname;
- GSList *tmp;
-
- g_assert(member->current_displayname == NULL);
- displayname = _calculate_displayname_for_member(member);
-
- *display_names = g_list_prepend(*display_names, displayname);
- *flags = g_list_prepend(*flags, GINT_TO_POINTER(0));
-
- tmp = table->new_members;
- table->new_members = tmp->next;
- g_slist_free_1(tmp);
- }
-}
-
-void matrix_roommembers_get_renamed_members(MatrixRoomMemberTable *table,
- GList **old_names, GList **new_names)
-{
- while(table->renamed_members != NULL) {
- MatrixRoomMember *member = table->renamed_members->data;
- gchar *displayname;
- GSList *tmp;
-
- g_assert(member->current_displayname != NULL);
- displayname = _calculate_displayname_for_member(member);
- *old_names = g_list_prepend(*old_names, member->current_displayname);
- *new_names = g_list_prepend(*new_names, displayname);
- member->current_displayname = displayname;
-
- tmp = table->renamed_members;
- table->renamed_members = tmp->next;
- g_slist_free_1(tmp);
- }
-}
-
-void matrix_roommembers_get_left_members(MatrixRoomMemberTable *table,
- GList **names)
-{
- while(table->left_members != NULL) {
- MatrixRoomMember *member = table->left_members->data;
- GSList *tmp;
-
- g_assert(member->current_displayname != NULL);
- *names = g_list_prepend(*names, member->current_displayname);
- member->current_displayname = NULL;
-
- tmp = table->left_members;
- table->left_members = tmp->next;
- g_slist_free_1(tmp);
- }
+ return g_hash_table_lookup(table->hash_table, member_user_id);
}
@@ -258,7 +188,7 @@ void matrix_roommembers_update_member(MatrixRoomMemberTable *table,
new_membership_val = _parse_membership(new_membership);
- member = _lookup_member(table, member_user_id);
+ member = matrix_roommembers_lookup_member(table, member_user_id);
if(member != NULL) {
old_displayname = member -> state_displayname;
@@ -280,17 +210,20 @@ void matrix_roommembers_update_member(MatrixRoomMemberTable *table,
if(new_membership_val == MATRIX_ROOM_MEMBERSHIP_JOIN) {
if(old_membership_val != MATRIX_ROOM_MEMBERSHIP_JOIN) {
- /* new user in this room */
+ purple_debug_info("matrixprpl", "%s (%s) joins\n",
+ member_user_id, new_displayname);
table->new_members = g_slist_append(
table->new_members, member);
} else if(g_strcmp0(old_displayname, new_displayname) != 0) {
- /* user has changed name */
+ purple_debug_info("matrixprpl", "%s (%s) changed name (was %s)\n",
+ member_user_id, new_displayname, old_displayname);
table->renamed_members = g_slist_append(
table->renamed_members, member);
}
} else {
if(old_membership_val == MATRIX_ROOM_MEMBERSHIP_JOIN) {
- /* user has left this room */
+ purple_debug_info("matrixprpl", "%s (%s) leaves\n",
+ member_user_id, old_displayname);
table->left_members = g_slist_append(
table->left_members, member);
}
@@ -299,7 +232,7 @@ void matrix_roommembers_update_member(MatrixRoomMemberTable *table,
/**
- * Returns a list of user ids. Free the list, but not the string pointers.
+ * Returns a list of MatrixRoomMember *s. Free the list, but not the pointers.
*/
GList *matrix_roommembers_get_active_members(
MatrixRoomMemberTable *member_table, gboolean include_invited)
@@ -310,38 +243,40 @@ GList *matrix_roommembers_get_active_members(
g_hash_table_iter_init (&iter, member_table->hash_table);
while (g_hash_table_iter_next (&iter, &key, &value)) {
- const gchar *user_id = key;
MatrixRoomMember *member = value;
if(member->membership == MATRIX_ROOM_MEMBERSHIP_JOIN ||
(include_invited &&
member->membership == MATRIX_ROOM_MEMBERSHIP_INVITE)) {
- members = g_list_prepend(members, (gpointer)user_id);
+ members = g_list_prepend(members, value);
}
}
return members;
}
-/**
- * Get the userid of a member of a room, given their displayname
- *
- * @returns a string, which will be freed by the caller, or null if not known
- */
-gchar *matrix_roommembers_displayname_to_userid(
- MatrixRoomMemberTable *table, const gchar *who)
+GSList *matrix_roommembers_get_new_members(MatrixRoomMemberTable *table)
{
- /* TODO: make this more efficient */
- GHashTableIter iter;
- gpointer key, value;
- g_hash_table_iter_init (&iter, table->hash_table);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- const gchar *user_id = key;
- MatrixRoomMember *member = value;
- if(member->current_displayname != NULL
- && strcmp(who, member->current_displayname) == 0) {
- return g_strdup(user_id);
- }
- }
- return NULL;
+ GSList *members = table->new_members;
+ table->new_members = NULL;
+ return members;
+}
+
+
+GSList *matrix_roommembers_get_renamed_members(MatrixRoomMemberTable *table)
+{
+ GSList *members = table->renamed_members;
+ table->renamed_members = NULL;
+ return members;
+
+}
+
+
+GSList *matrix_roommembers_get_left_members(MatrixRoomMemberTable *table)
+{
+ GSList *members = table->left_members;
+ table->left_members = NULL;
+ return members;
+
}
+
diff --git a/matrix-roommembers.h b/matrix-roommembers.h
index b447034..b5e03a2 100644
--- a/matrix-roommembers.h
+++ b/matrix-roommembers.h
@@ -30,6 +30,54 @@
#define MATRIX_ROOM_MEMBERSHIP_INVITE 2
#define MATRIX_ROOM_MEMBERSHIP_LEAVE 3
+
+
+/* ****************************************************************************
+ *
+ * Handling of individual members
+ */
+
+typedef struct _MatrixRoomMember MatrixRoomMember;
+
+/**
+ * Get the user_id for the given member
+ *
+ * @returns a string, which should *not* be freed
+ */
+const gchar *matrix_roommember_get_user_id(const MatrixRoomMember *member);
+
+/**
+ * Get the displayname for the given member
+ *
+ * @returns a string, which should *not* be freed
+ */
+const gchar *matrix_roommember_get_displayname(const MatrixRoomMember *member);
+
+
+/**
+ * Get the opaque data associated with the given member
+ */
+gpointer matrix_roommember_get_opaque_data(const MatrixRoomMember *member);
+
+
+typedef void (*DestroyMemberNotify)(MatrixRoomMember *member);
+/**
+ * Set the opaque data associated with the given member
+ *
+ * @param on_delete: a callback which will be called when the RoomMember is
+ * deleted (usually when its parent MatrixRoomMemberTable is deleted). It is
+ * passed a pointer to the MatrixRoomMember.
+ */
+void matrix_roommember_set_opaque_data(MatrixRoomMember *member,
+ gpointer data, DestroyMemberNotify on_delete);
+
+
+
+/* ****************************************************************************
+ *
+ * Member table
+ */
+
typedef struct _MatrixRoomMemberTable MatrixRoomMemberTable;
struct _JsonObject;
@@ -56,18 +104,17 @@ void matrix_roommembers_update_member(MatrixRoomMemberTable *table,
/**
- * Get the displayname for the given userid
+ * Look up a room member given the userid
*
- * @returns a string, which should *not* be freed
+ * @returns MatrixRoomMember *, or NULL if unknown
*/
-const gchar *matrix_roommembers_get_displayname_for_member(
- MatrixRoomMemberTable *table, const gchar *user_id);
-
+MatrixRoomMember *matrix_roommembers_lookup_member(MatrixRoomMemberTable *table,
+ const gchar *member_user_id);
/**
* Get a list of the members who have joined this room.
*
- * Returns a list of user ids. Free the list, but not the string pointers.
+ * Returns a list of MatrixRoomMember *s. Free the list, but not the pointers.
*/
GList *matrix_roommembers_get_active_members(
MatrixRoomMemberTable *member_table, gboolean include_invited);
@@ -76,45 +123,30 @@ GList *matrix_roommembers_get_active_members(
/**
* Get a list of the new members since the last time this function was called.
*
- * @param display_names returns the list of display names. Do not free the
- * pointers.
- * @param flags returns a corresponding list of zeros
+ * @returns a list of MatrixRoomMember *s. Free the list when you are done with
+ * it.
*/
-void matrix_roommembers_get_new_members(MatrixRoomMemberTable *table,
- GList **display_names, GList **flags);
+GSList *matrix_roommembers_get_new_members(MatrixRoomMemberTable *table);
/**
* Get a list of the members who have been renamed since the last time this
* function was called.
*
- * @param old_names returns the list of old display names. These are no
- * longer required, so should be freed
- * @param new_names returns the list of new display names. Do *not* free these
- * pointers.
+ * @returns a list of MatrixRoomMember *s. Free the list when you are done with
+ * it.
*/
-void matrix_roommembers_get_renamed_members(MatrixRoomMemberTable *table,
- GList **old_names, GList **new_names);
+GSList *matrix_roommembers_get_renamed_members(MatrixRoomMemberTable *table);
/**
* Get a list of the members who have left the channel since the last time this
* function was called.
*
- * @param new_names returns the list of display names. These are no
- * longer required, so should be freed
- */
-void matrix_roommembers_get_left_members(MatrixRoomMemberTable *table,
- GList **names);
-
-
-/**
- * Get the userid of a member of a room, given their displayname
- *
- * @returns a string, which will be freed by the caller, or null if not known
+ * @returns a list of MatrixRoomMember *s. Free the list when you are done with
+ * it.
*/
-gchar *matrix_roommembers_displayname_to_userid(
- MatrixRoomMemberTable *table, const gchar *who);
+GSList *matrix_roommembers_get_left_members(MatrixRoomMemberTable *table);
#endif /* MATRIX_ROOMMEMBERS_H_ */
diff --git a/matrix-sync.c b/matrix-sync.c
index 599df70..37ecf47 100644
--- a/matrix-sync.c
+++ b/matrix-sync.c
@@ -117,6 +117,8 @@ static PurpleChat *_ensure_blist_entry(PurpleAccount *acct,
purple_blist_node_set_bool(&chat->node, "gtk-persistent", TRUE);
purple_blist_add_chat(chat, group, NULL);
+ purple_debug_info("matrixprpl", "added buddy list entry for room %s\n",
+ room_id);
return chat;
}
@@ -133,8 +135,7 @@ static void matrix_sync_room(const gchar *room_id,
PurpleConversation *conv;
gboolean initial_sync = FALSE;
- /* ensure we have an entry in the buddy list for this room.
- * TODO: We should only do this if the user is actually *in* the room. */
+ /* ensure we have an entry in the buddy list for this room. */
_ensure_blist_entry(pc->account, room_id);
conv = purple_find_conversation_with_account(