aboutsummaryrefslogtreecommitdiffstats
path: root/matrix-room.c
diff options
context:
space:
mode:
authorRichard van der Hoff <richard@matrix.org>2015-10-30 17:10:15 +0000
committerRichard van der Hoff <richard@matrix.org>2015-10-30 17:10:15 +0000
commit2ed95f49507a2fa528df6eeacdf8954df473a75e (patch)
tree87a44f0a7ab85ebce37735d891b975b1f7272ffe /matrix-room.c
parente354189a87d01942a0abe782583f0b30eb7f8839 (diff)
downloadpurple-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.c260
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);
}
}