diff options
author | Richard van der Hoff <richard@matrix.org> | 2015-10-30 17:10:15 +0000 |
---|---|---|
committer | Richard van der Hoff <richard@matrix.org> | 2015-10-30 17:10:15 +0000 |
commit | 2ed95f49507a2fa528df6eeacdf8954df473a75e (patch) | |
tree | 87a44f0a7ab85ebce37735d891b975b1f7272ffe /matrix-room.c | |
parent | e354189a87d01942a0abe782583f0b30eb7f8839 (diff) | |
download | purple-matrix-2ed95f49507a2fa528df6eeacdf8954df473a75e.tar.gz |
Refactor the statetable out to a separate file
Apart from generally being cleaner, we're going to want to use the statetable
in isolation of rooms, to handle invites.
Diffstat (limited to 'matrix-room.c')
-rw-r--r-- | matrix-room.c | 260 |
1 files changed, 65 insertions, 195 deletions
diff --git a/matrix-room.c b/matrix-room.c index 30c20c7..58d249b 100644 --- a/matrix-room.c +++ b/matrix-room.c @@ -27,8 +27,25 @@ #include "libmatrix.h" #include "matrix-api.h" +#include "matrix-event.h" #include "matrix-json.h" #include "matrix-roommembers.h" +#include "matrix-statetable.h" + + +static gchar *_get_room_name(MatrixConnectionData *conn, + PurpleConversation *conv); + +static MatrixConnectionData *_get_connection_data_from_conversation( + PurpleConversation *conv) +{ + return conv->account->gc->proto_data; +} + +/****************************************************************************** + * + * conversation data + */ /* * identifiers for purple_conversation_get/set_data @@ -47,121 +64,56 @@ #define PURPLE_CONV_MEMBER_TABLE "member_table" -static MatrixConnectionData *_get_connection_data_from_conversation( - PurpleConversation *conv) -{ - return conv->account->gc->proto_data; -} - -/****************************************************************************** - * - * Members - */ - /** * Get the member table for a room */ -MatrixRoomMemberTable *matrix_room_get_member_table(PurpleConversation *conv) +static MatrixRoomMemberTable *matrix_room_get_member_table( + PurpleConversation *conv) { return purple_conversation_get_data(conv, PURPLE_CONV_MEMBER_TABLE); } -/****************************************************************************** - * - * Events - */ - -typedef struct _MatrixRoomEvent { - /* for outgoing events, our made-up transaction id. NULL for incoming - * events. - */ - gchar *txn_id; - gchar *event_type; - JsonObject *content; -} MatrixRoomEvent; - /** - * Allocate a new MatrixRoomEvent. - * - * @param event_type the type of the event. this is copied into the event - * @param content the content of the event. This is used direct, but the - * reference count is incremented. + * Get the state table for a room */ -static MatrixRoomEvent *_alloc_room_event(const gchar *event_type, - JsonObject *content) +static MatrixRoomStateEventTable *matrix_room_get_state_table( + PurpleConversation *conv) { - MatrixRoomEvent *event; - event = g_new0(MatrixRoomEvent, 1); - event->content = json_object_ref(content); - event->event_type = g_strdup(event_type); - return event; + return purple_conversation_get_data(conv, PURPLE_CONV_DATA_STATE); } -static void _free_room_event(MatrixRoomEvent *event) -{ - if(event->content) - json_object_unref(event->content); - g_free(event->txn_id); - g_free(event->event_type); - g_free(event); -} /****************************************************************************** * * room state handling */ -/* The state event table is a hashtable which maps from event type to - * another hashtable, which maps from state key to content, which is itself a - * MatrixRoomEvent. - * - */ -typedef GHashTable MatrixRoomStateEventTable; - - -static void _update_room_alias(PurpleConversation *conv); - -/** - * create a new, empty, state table - */ -static MatrixRoomStateEventTable *_create_state_table() -{ - return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify) g_hash_table_destroy); -} - /** - * Get the state table for a room - */ -MatrixRoomStateEventTable *matrix_room_get_state_table(PurpleConversation *conv) -{ - return purple_conversation_get_data(conv, PURPLE_CONV_DATA_STATE); -} - - -/** - * look up a particular bit of state + * Update the name of the room in the buddy list (which in turn will update it + * in the chat window) * - * @returns null if this key ies not known + * @param conv: conversation info */ -static MatrixRoomEvent *matrix_room_get_state_event( - MatrixRoomStateEventTable *state_table, const gchar *event_type, - const gchar *state_key) +static void _update_room_alias(PurpleConversation *conv) { - GHashTable *tmp; + gchar *room_name; + MatrixConnectionData *conn = _get_connection_data_from_conversation(conv); + PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name); - tmp = (GHashTable *) g_hash_table_lookup(state_table, event_type); - if(tmp == NULL) - return NULL; + /* we know there should be a buddy list entry for this room */ + g_assert(chat != NULL); - return (MatrixRoomEvent *)g_hash_table_lookup(tmp, state_key); + room_name = _get_room_name(conn, conv); + purple_blist_alias_chat(chat, room_name); + g_free(room_name); } /** - * Called when there is a change to the member list + * Called when there is a change to the member list. Tells the MemberTable + * about it. */ static void _on_member_change(PurpleConversation *conv, const gchar *member_user_id, MatrixRoomEvent *new_state) @@ -181,10 +133,11 @@ static void _on_member_change(PurpleConversation *conv, * old_state may be NULL to indicate addition of a state * key. */ -static void _on_state_update(PurpleConversation *conv, - const gchar *event_type, const gchar *state_key, - MatrixRoomEvent *old_state, MatrixRoomEvent *new_state) +static void _on_state_update(const gchar *event_type, + const gchar *state_key, MatrixRoomEvent *old_state, + MatrixRoomEvent *new_state, gpointer user_data) { + PurpleConversation *conv = user_data; g_assert(new_state != NULL); if(strcmp(event_type, "m.room.member") == 0) { @@ -196,55 +149,19 @@ static void _on_state_update(PurpleConversation *conv, } } -/** - * Update the state table on a room - */ -void matrix_room_handle_state_event(PurpleConversation *conv, +void matrix_room_handle_state_event(struct _PurpleConversation *conv, const gchar *event_id, JsonObject *json_event_obj) { - const gchar *event_type, *state_key; - JsonObject *json_content_obj; - MatrixRoomEvent *event, *old_event; - MatrixRoomStateEventTable *state_table; - GHashTable *state_table_entry; - - event_type = matrix_json_object_get_string_member( - json_event_obj, "type"); - state_key = matrix_json_object_get_string_member( - json_event_obj, "state_key"); - json_content_obj = matrix_json_object_get_object_member( - json_event_obj, "content"); - - if(event_type == NULL || state_key == NULL || json_content_obj == NULL) { - purple_debug_warning("matrixprpl", "event missing fields"); - return; - } - - event = _alloc_room_event(event_type, json_content_obj); - - state_table = matrix_room_get_state_table(conv); - state_table_entry = g_hash_table_lookup(state_table, event_type); - if(state_table_entry == NULL) { - state_table_entry = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, (GDestroyNotify)_free_room_event); - g_hash_table_insert(state_table, g_strdup(event_type), - state_table_entry); - old_event = NULL; - } else { - old_event = g_hash_table_lookup(state_table_entry, - state_key); - } - - _on_state_update(conv, event_type, state_key, old_event, event); - - g_hash_table_insert(state_table_entry, g_strdup(state_key), event); + MatrixRoomStateEventTable *state_table = matrix_room_get_state_table(conv); + matrix_statetable_update(state_table, event_id, json_event_obj, + _on_state_update, conv); } /** * figure out the best name for a room based on its members list * - * @returns a string which should be freedd + * @returns a string which should be freed */ static gchar *_get_room_name_from_members(MatrixConnectionData *conn, PurpleConversation *conv) @@ -264,9 +181,8 @@ static gchar *_get_room_name_from_members(MatrixConnectionData *conn, } if(members == NULL) { - /* nobody else here. Self-chat or an invitation. TODO: improve this - */ - return g_strdup("invitation"); + /* nobody else here! */ + return NULL; } member1 = matrix_roommembers_get_displayname_for_member( @@ -289,79 +205,33 @@ static gchar *_get_room_name_from_members(MatrixConnectionData *conn, return res; } + /** * figure out the best name for a room * * @returns a string which should be freed */ -static char *_get_room_name(MatrixConnectionData *conn, +static gchar *_get_room_name(MatrixConnectionData *conn, PurpleConversation *conv) { - GHashTable *tmp; - MatrixRoomEvent *event; - const gchar *tmpname = NULL; - MatrixRoomStateEventTable *state_table; - - state_table = matrix_room_get_state_table(conv); - - /* start by looking for the official room name */ - event = matrix_room_get_state_event(state_table, "m.room.name", ""); - if(event != NULL) { - tmpname = matrix_json_object_get_string_member( - event->content, "name"); - if(tmpname != NULL) { - return g_strdup(tmpname); - } - } - + MatrixRoomStateEventTable *state_table = matrix_room_get_state_table(conv); + gchar *res; - /* look for an alias */ - tmp = (GHashTable *) g_hash_table_lookup(state_table, "m.room.aliases"); - if(tmp != NULL) { - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init(&iter, tmp); - while(g_hash_table_iter_next(&iter, &key, &value)) { - MatrixRoomEvent *event = value; - JsonArray *array = matrix_json_object_get_array_member( - event->content, "aliases"); - if(array != NULL && json_array_get_length(array) > 0) { - tmpname = matrix_json_array_get_string_element(array, 0); - if(tmpname != NULL) { - return g_strdup(tmpname); - } - } - } - } + /* first try to pick a name based on the official name / alias */ + res = matrix_statetable_get_room_alias(state_table); + if (res) + return res; /* look for room members, and pick a name based on that */ - return _get_room_name_from_members(conn, conv); -} + res = _get_room_name_from_members(conn, conv); + if (res) + return res; + /* failing all else, just use the room id */ + return g_strdup(conv -> name); -/** - * 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 @@ -393,7 +263,7 @@ static void _event_send_complete(MatrixConnectionData *account, gpointer user_da event_queue = _get_event_queue(conv); event = event_queue -> data; - _free_room_event(event); + matrix_event_free(event); event_queue = g_list_remove(event_queue, event); purple_conversation_set_data(conv, PURPLE_CONV_DATA_EVENT_QUEUE, @@ -474,7 +344,7 @@ static void _enqueue_event(PurpleConversation *conv, const gchar *event_type, GList *event_queue; MatrixApiRequestData *active_send; - event = _alloc_room_event(event_type, event_content); + event = matrix_event_new(event_type, event_content); event->txn_id = g_strdup_printf("%"G_GINT64_FORMAT"%"G_GUINT32_FORMAT, g_get_monotonic_time(), g_random_int()); @@ -602,7 +472,7 @@ PurpleConversation *matrix_room_create_conversation( conv = serv_got_joined_chat(pc, g_str_hash(room_id), room_id); /* set our data on it */ - state_table = _create_state_table(); + state_table = matrix_statetable_new(); 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); @@ -651,7 +521,7 @@ void matrix_room_leave_chat(PurpleConversation *conv) event_queue = _get_event_queue(conv); if(event_queue != NULL) { - g_list_free_full(event_queue, (GDestroyNotify)_free_room_event); + g_list_free_full(event_queue, (GDestroyNotify)matrix_event_free); purple_conversation_set_data(conv, PURPLE_CONV_DATA_EVENT_QUEUE, NULL); } } |