aboutsummaryrefslogtreecommitdiffstats
path: root/matrix-room.c
diff options
context:
space:
mode:
authorRichard van der Hoff <richard@matrix.org>2015-10-29 20:04:41 +0000
committerRichard van der Hoff <richard@matrix.org>2015-10-29 20:04:41 +0000
commited0c5f6b5ad82df7047296adb081e19102ec4a35 (patch)
treeb2d898e35fef93d08d08efbaf03906bc2a3e1217 /matrix-room.c
parenta6bd56705cd5ef571b5aa4ef420a99fd438d72f8 (diff)
downloadpurple-matrix-ed0c5f6b5ad82df7047296adb081e19102ec4a35.tar.gz
Move the room member table management out to a separate file
Trying to keep the size of matrix-room.c under control, move the membertable management bits out to a separate file. Also do away with the special handling for the first /sync of a room, and instead *always* group together member arrivals/departures until after we've finished handling the state table.
Diffstat (limited to 'matrix-room.c')
-rw-r--r--matrix-room.c386
1 files changed, 101 insertions, 285 deletions
diff --git a/matrix-room.c b/matrix-room.c
index 485c657..edd29ac 100644
--- a/matrix-room.c
+++ b/matrix-room.c
@@ -28,6 +28,7 @@
#include "libmatrix.h"
#include "matrix-api.h"
#include "matrix-json.h"
+#include "matrix-roommembers.h"
/*
* identifiers for purple_conversation_get/set_data
@@ -57,27 +58,6 @@ static MatrixConnectionData *_get_connection_data_from_conversation(
* Members
*/
-/* The MatrixRoomMemberTable is a hashtable from userid to MatrixRoomMember *
- */
-typedef GHashTable MatrixRoomMemberTable;
-
-#define MATRIX_ROOM_MEMBERSHIP_NONE 0
-#define MATRIX_ROOM_MEMBERSHIP_JOIN 1
-#define MATRIX_ROOM_MEMBERSHIP_INVITE 2
-#define MATRIX_ROOM_MEMBERSHIP_LEAVE 3
-
-
-typedef struct _MatrixRoomMember {
- /* the displayname we gave to purple */
- gchar *current_displayname;
-
- /* the current room membership */
- int membership;
-
- /* the displayname from the state table */
- const gchar *state_displayname;
-} MatrixRoomMember;
-
/**
* Get the member table for a room
*/
@@ -87,214 +67,6 @@ MatrixRoomMemberTable *matrix_room_get_member_table(PurpleConversation *conv)
}
-/**
- * calculate the displayname for the given member
- *
- * @returns a string, which should be freed
- */
-static gchar *_calculate_displayname_for_member(const gchar *member_user_id,
- const MatrixRoomMember *member)
-{
- if(member->state_displayname != NULL) {
- return g_strdup(member->state_displayname);
- } else {
- return g_strdup(member_user_id);
- }
-}
-
-
-static int _parse_membership(const gchar *membership)
-{
- if(membership == NULL)
- return MATRIX_ROOM_MEMBERSHIP_NONE;
-
- if(strcmp(membership, "join") == 0)
- return MATRIX_ROOM_MEMBERSHIP_JOIN;
- if(strcmp(membership, "leave") == 0)
- return MATRIX_ROOM_MEMBERSHIP_LEAVE;
- if(strcmp(membership, "invite") == 0)
- return MATRIX_ROOM_MEMBERSHIP_INVITE;
- return MATRIX_ROOM_MEMBERSHIP_NONE;
-}
-
-static MatrixRoomMember *_new_member(MatrixRoomMemberTable *table,
- const gchar *userid)
-{
- MatrixRoomMember *mem = g_new0(MatrixRoomMember, 1);
- g_hash_table_insert(table, g_strdup(userid), mem);
- return mem;
-}
-
-static void _free_member(MatrixRoomMember *member)
-{
- g_assert(member != NULL);
- g_free(member->current_displayname);
- member->current_displayname = NULL;
- g_free(member);
-}
-
-static MatrixRoomMember *_lookup_member(MatrixRoomMemberTable *table,
- const gchar *userid)
-{
- return g_hash_table_lookup(table, userid);
-}
-
-
-static MatrixRoomMemberTable *_new_member_table()
-{
- return g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
- (GDestroyNotify) _free_member);
-}
-
-
-static void _free_member_table(MatrixRoomMemberTable *table)
-{
- g_hash_table_destroy(table);
-}
-
-
-static void _on_member_joined(PurpleConversation *conv,
- const gchar *member_user_id, MatrixRoomMember *member)
-{
- PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
- gchar *displayname;
-
- g_assert(member->current_displayname == NULL);
- displayname = _calculate_displayname_for_member(member_user_id, member);
-
- purple_conv_chat_add_user(chat, displayname, NULL,
- PURPLE_CBFLAGS_NONE, TRUE);
- member->current_displayname = displayname;
-}
-
-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)
-{
- 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;
-}
-
-
-static void _update_member(PurpleConversation *conv,
- MatrixRoomMemberTable *member_table, const gchar *member_user_id,
- const gchar *new_displayname, const gchar *new_membership,
- gboolean suppress_state_update_notifications)
-{
- const gchar *old_displayname = NULL;
- MatrixRoomMember *member;
- int old_membership_val = MATRIX_ROOM_MEMBERSHIP_NONE,
- new_membership_val = _parse_membership(new_membership);
-
- member = _lookup_member(member_table, member_user_id);
-
- if(member != NULL) {
- old_displayname = member -> state_displayname;
- old_membership_val = member -> membership;
- }
-
- if(!member) {
- member = _new_member(member_table, member_user_id);
- }
- member->membership = new_membership_val;
- member->state_displayname = new_displayname;
-
- if(suppress_state_update_notifications)
- return;
-
- purple_debug_info("matrixprpl", "Room %s: member %s change %i->%i, "
- "%s->%s\n", conv -> name, member_user_id,
- old_membership_val, new_membership_val,
- old_displayname, new_displayname);
-
-
- if(new_membership_val == MATRIX_ROOM_MEMBERSHIP_JOIN) {
- if(old_membership_val != MATRIX_ROOM_MEMBERSHIP_JOIN) {
- _on_member_joined(conv, member_user_id, member);
- } else if(g_strcmp0(old_displayname, new_displayname) != 0) {
- _on_member_changed_displayname(conv, member_user_id, member);
- }
- } else {
- if(old_membership_val == MATRIX_ROOM_MEMBERSHIP_JOIN) {
- _on_member_left(conv, member_user_id, member);
- }
- }
-}
-
-
-static void _init_user_list(PurpleConversation *conv)
-{
- GHashTableIter iter;
- gpointer key, value;
- PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
- MatrixRoomMemberTable *member_table = matrix_room_get_member_table(conv);
- GList *users = NULL, *flags = NULL;
-
- purple_debug_info("matrixprpl", "Doing initial member population of %s\n",
- conv->name);
-
- g_hash_table_iter_init (&iter, member_table);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- const gchar *user_id = key;
- gchar *displayname;
- MatrixRoomMember *member = value;
-
- if(member->membership != MATRIX_ROOM_MEMBERSHIP_JOIN)
- continue;
-
- g_assert(member->current_displayname == NULL);
- displayname = _calculate_displayname_for_member(user_id, member);
-
- users = g_list_prepend(users, displayname);
- flags = g_list_prepend(users, GINT_TO_POINTER(PURPLE_CBFLAGS_NONE));
- member->current_displayname = displayname;
- }
-
- purple_conv_chat_add_users(chat, users, NULL, flags, FALSE);
-}
-
-/**
- * Returns a list of user ids. Free the list, but not the string pointers.
- */
-static GList *_get_active_members(MatrixRoomMemberTable *member_table)
-{
- GHashTableIter iter;
- gpointer key, value;
- GList *members = NULL;
-
- g_hash_table_iter_init (&iter, member_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)
- members = g_list_prepend(members, (gpointer)user_id);
- }
- return members;
-}
-
-
/******************************************************************************
*
* Events
@@ -347,6 +119,9 @@ static void _free_room_event(MatrixRoomEvent *event)
*/
typedef GHashTable MatrixRoomStateEventTable;
+
+static void _update_room_alias(PurpleConversation *conv);
+
/**
* create a new, empty, state table
*/
@@ -389,22 +164,14 @@ static MatrixRoomEvent *matrix_room_get_state_event(
* Called when there is a change to the member list
*/
static void _on_member_change(PurpleConversation *conv,
- const gchar *member_user_id,
- MatrixRoomEvent *old_state, MatrixRoomEvent *new_state,
- gboolean suppress_state_update_notifications)
+ const gchar *member_user_id, MatrixRoomEvent *new_state)
{
MatrixRoomMemberTable *member_table;
- const gchar *new_displayname, *new_membership;
member_table = matrix_room_get_member_table(conv);
- new_displayname = matrix_json_object_get_string_member(
- new_state->content, "displayname");
- new_membership = matrix_json_object_get_string_member(
- new_state->content, "membership");
-
- _update_member(conv, member_table, member_user_id, new_displayname,
- new_membership, suppress_state_update_notifications);
+ matrix_roommembers_update_member(member_table, member_user_id,
+ new_state->content);
}
@@ -416,22 +183,24 @@ static void _on_member_change(PurpleConversation *conv,
*/
static void _on_state_update(PurpleConversation *conv,
const gchar *event_type, const gchar *state_key,
- MatrixRoomEvent *old_state, MatrixRoomEvent *new_state,
- gboolean suppress_state_update_notifications)
+ MatrixRoomEvent *old_state, MatrixRoomEvent *new_state)
{
g_assert(new_state != NULL);
- if(strcmp(event_type, "m.room.member") == 0)
- _on_member_change(conv, state_key, old_state, new_state,
- suppress_state_update_notifications);
+ if(strcmp(event_type, "m.room.member") == 0) {
+ _on_member_change(conv, state_key, new_state);
+ }
+ else if(strcmp(event_type, "m.room.alias") == 0 ||
+ strcmp(event_type, "m.room.room_name") == 0) {
+ _update_room_alias(conv);
+ }
}
/**
* Update the state table on a room
*/
void matrix_room_handle_state_event(PurpleConversation *conv,
- const gchar *event_id, JsonObject *json_event_obj,
- gboolean suppress_state_update_notifications)
+ const gchar *event_id, JsonObject *json_event_obj)
{
const gchar *event_type, *state_key;
JsonObject *json_content_obj;
@@ -466,8 +235,7 @@ void matrix_room_handle_state_event(PurpleConversation *conv,
state_key);
}
- _on_state_update(conv, event_type, state_key, old_event, event,
- suppress_state_update_notifications);
+ _on_state_update(conv, event_type, state_key, old_event, event);
g_hash_table_insert(state_table_entry, g_strdup(state_key), event);
}
@@ -487,7 +255,7 @@ static gchar *_get_room_name_from_members(MatrixConnectionData *conn,
MatrixRoomMemberTable *member_table;
member_table = matrix_room_get_member_table(conv);
- members = _get_active_members(member_table);
+ members = matrix_roommembers_get_active_members(member_table);
/* remove ourselves from the list */
tmp = g_list_find_custom(members, conn->user_id, (GCompareFunc)strcmp);
@@ -501,16 +269,16 @@ static gchar *_get_room_name_from_members(MatrixConnectionData *conn,
return g_strdup("invitation");
}
- member1 = _lookup_member(member_table, members->data) ->
- current_displayname;
+ member1 = matrix_roommembers_get_displayname_for_member(
+ member_table, members->data);
if(members->next == NULL) {
/* one other person */
res = g_strdup(member1);
} else if(members->next->next == NULL) {
/* two other people */
- gchar *member2 = _lookup_member(member_table, members->next->data) ->
- current_displayname;
+ const gchar *member2 = matrix_roommembers_get_displayname_for_member(
+ member_table, members->next->data);
res = g_strdup_printf(_("%s and %s"), member1, member2);
} else {
int nmembers = g_list_length(members);
@@ -526,7 +294,7 @@ static gchar *_get_room_name_from_members(MatrixConnectionData *conn,
*
* @returns a string which should be freed
*/
-static char *matrix_room_get_name(MatrixConnectionData *conn,
+static char *_get_room_name(MatrixConnectionData *conn,
PurpleConversation *conv)
{
GHashTable *tmp;
@@ -572,6 +340,28 @@ static char *matrix_room_get_name(MatrixConnectionData *conn,
}
+/**
+ * Update the name of the room in the buddy list (which in turn will update it
+ * in the chat window)
+ *
+ * @param conv: conversation info
+ */
+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);
+
+ /* 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);
+ g_free(room_name);
+}
+
+
+
/******************************************************************************
*
* event queue handling
@@ -717,7 +507,6 @@ 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;
@@ -762,15 +551,14 @@ void matrix_room_handle_timeline_event(PurpleConversation *conv,
return;
}
- if(sender_id != NULL) {
+ if(sender_id == NULL) {
+ sender_display_name = "<unknown>";
+ } else {
MatrixRoomMemberTable *member_table =
matrix_room_get_member_table(conv);
- sender = _lookup_member(member_table, sender_id);
- }
- if(sender != NULL && sender->current_displayname != NULL) {
- sender_display_name = sender->current_displayname;
- } else {
- sender_display_name = sender_id;
+
+ sender_display_name = matrix_roommembers_get_displayname_for_member(
+ member_table, sender_id);
}
flags = PURPLE_MESSAGE_RECV;
@@ -787,7 +575,7 @@ PurpleConversation *matrix_room_create_conversation(
{
PurpleConversation *conv;
MatrixRoomStateEventTable *state_table;
- GHashTable *member_table;
+ MatrixRoomMemberTable *member_table;
purple_debug_info("matrixprpl", "New room %s\n", room_id);
@@ -796,7 +584,7 @@ PurpleConversation *matrix_room_create_conversation(
/* set our data on it */
state_table = _create_state_table();
- member_table = _new_member_table();
+ member_table = matrix_roommembers_new_table();
purple_conversation_set_data(conv, PURPLE_CONV_DATA_EVENT_QUEUE, NULL);
purple_conversation_set_data(conv, PURPLE_CONV_DATA_ACTIVE_SEND, NULL);
purple_conversation_set_data(conv, PURPLE_CONV_DATA_STATE, state_table);
@@ -815,7 +603,7 @@ void matrix_room_leave_chat(PurpleConversation *conv)
{
MatrixRoomStateEventTable *state_table;
GList *event_queue;
- GHashTable *member_table;
+ MatrixRoomMemberTable *member_table;
/* TODO: actually tell the server that we are leaving the chat, and only
* destroy the memory structures once we get a response from that.
@@ -827,7 +615,7 @@ void matrix_room_leave_chat(PurpleConversation *conv)
purple_conversation_set_data(conv, PURPLE_CONV_DATA_STATE, NULL);
member_table = matrix_room_get_member_table(conv);
- _free_member_table(member_table);
+ matrix_roommembers_free_table(member_table);
purple_conversation_set_data(conv, PURPLE_CONV_MEMBER_TABLE, NULL);
event_queue = _get_event_queue(conv);
@@ -838,31 +626,59 @@ void matrix_room_leave_chat(PurpleConversation *conv)
}
-/**
- * Update the name of the room in the buddy list (which in turn will update it
- * in the chat window)
- *
- * @param conv: conversation info
- */
-static void _set_room_alias(PurpleConversation *conv)
+static void _update_user_list(PurpleConversation *conv,
+ gboolean announce_arrivals)
{
- gchar *room_name;
- MatrixConnectionData *conn = _get_connection_data_from_conversation(conv);
- PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
+ PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
+ MatrixRoomMemberTable *table = matrix_room_get_member_table(conv);
+ GList *names = NULL, *flags = NULL, *oldnames = NULL;
+ gboolean updated = FALSE;
- /* we know there should be a buddy list entry for this room */
- g_assert(chat != NULL);
+ purple_debug_info("matrixprpl", "Updating members in %s\n",
+ conv->name);
- room_name = matrix_room_get_name(conn, conv);
- purple_blist_alias_chat(chat, room_name);
- g_free(room_name);
+ 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;
+ }
+
+ 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;
+ }
+
+ if(updated)
+ _update_room_alias(conv);
}
-void matrix_room_handle_initial_state(PurpleConversation *conv)
+void matrix_room_complete_state_update(PurpleConversation *conv,
+ gboolean announce_arrivals)
{
- _init_user_list(conv);
- _set_room_alias(conv);
+ _update_user_list(conv, announce_arrivals);
}