diff options
author | Richard van der Hoff <richard@matrix.org> | 2015-10-26 11:53:52 +0000 |
---|---|---|
committer | Richard van der Hoff <richard@matrix.org> | 2015-10-26 11:53:52 +0000 |
commit | e2500a76ee35cb3be863342573495a28f47c5eb8 (patch) | |
tree | 0a5ca502cfe97e6669468ebedbccc29f0576fe78 | |
parent | e6880c64f78a505e07c2ba9feb6397d304b5ed27 (diff) | |
download | purple-matrix-e2500a76ee35cb3be863342573495a28f47c5eb8.tar.gz |
Better room names for one-to-one chats
Give rooms a name according to who's in it, if there is no proper name.
-rw-r--r-- | matrix-connection.c | 5 | ||||
-rw-r--r-- | matrix-connection.h | 1 | ||||
-rw-r--r-- | matrix-room.c | 150 | ||||
-rw-r--r-- | matrix-room.h | 5 | ||||
-rw-r--r-- | matrix-sync.c | 3 |
5 files changed, 149 insertions, 15 deletions
diff --git a/matrix-connection.c b/matrix-connection.c index 3481287..e891818 100644 --- a/matrix-connection.c +++ b/matrix-connection.c @@ -61,6 +61,9 @@ void matrix_connection_free(PurpleConnection *pc) g_free(conn->access_token); conn->access_token = NULL; + g_free(conn->user_id); + conn->user_id = NULL; + conn->pc = NULL; g_free(conn); @@ -150,6 +153,8 @@ static void _login_completed(MatrixConnectionData *conn, return; } conn->access_token = g_strdup(access_token); + conn->user_id = g_strdup(matrix_json_object_get_string_member(root_obj, + "user_id")); /* TODO: there may be rooms which came through on a previous connection, * but for which we never got the state table. We should update them here diff --git a/matrix-connection.h b/matrix-connection.h index bdf1148..9e9c166 100644 --- a/matrix-connection.h +++ b/matrix-connection.h @@ -33,6 +33,7 @@ struct _PurpleConnection; typedef struct _MatrixConnectionData { struct _PurpleConnection *pc; gchar *homeserver; /* hostname (:port) of the homeserver */ + gchar *user_id; /* our full user id ("@user:server") */ gchar *access_token; /* access token corresponding to our user */ /* the active sync request */ diff --git a/matrix-room.c b/matrix-room.c index 067ac0a..632bf29 100644 --- a/matrix-room.c +++ b/matrix-room.c @@ -185,7 +185,7 @@ static void _state_update_complete(MatrixConnectionData *conn, response_array = matrix_json_node_get_array(json_root); if(response_array != NULL) json_array_foreach_element(response_array, _parse_state_event, conv); - matrix_room_update_buddy_list(conv); + matrix_room_update_buddy_list(conn, conv); } @@ -218,46 +218,167 @@ static MatrixRoomEvent *matrix_room_get_state_event( return (MatrixRoomEvent *)g_hash_table_lookup(tmp, state_key); } + +/** + * given the userid of a room member, return their display name + * + * @returns a string, which should be freed + */ +static gchar *_get_display_name_for_member( + MatrixRoomStateEventTable *state_table, const gchar *member_id) +{ + MatrixRoomEvent *event; + const gchar *displayname = NULL; + + /* find this user's m.room.member event */ + event = matrix_room_get_state_event(state_table, "m.room.member", + member_id); + + if (event != NULL) + displayname = matrix_json_object_get_string_member( + event->content, "displayname"); + + if (displayname == NULL) + return g_strdup(member_id); + + /* TODO: if there is more than one user with this displayname in this room, + * we need to disambiguate. But we need to do it without introducing an + * O(N^2) algorithm. + */ + + return g_strdup(displayname); +} + + +/** + * Get a list of the members in a room + * + * @returns a GList of the user ids. Don't free the pointers, but do free + * the list. + */ +static GList *_get_room_members(MatrixRoomStateEventTable *state_table) +{ + GHashTable *tmp; + GHashTableIter iter; + gpointer key, value; + GList *members = NULL; /* a list of user ids */ + + tmp = (GHashTable *) g_hash_table_lookup(state_table, "m.room.member"); + if(tmp == NULL) { + // no member table yet + return NULL; + } + + g_hash_table_iter_init(&iter, tmp); + + while(g_hash_table_iter_next(&iter, &key, &value)) { + MatrixRoomEvent *event = value; + const gchar *membership; + + membership = matrix_json_object_get_string_member( + event->content, "membership"); + if(membership != NULL && strcmp(membership, "leave") == 0) { + /* not actually a member here */ + continue; + } + members = g_list_append(members, key); + } + + return members; +} + +/** + * figure out the best name for a room based on its members list + * + * @returns a string which should be freedd + */ +static gchar *_get_room_name_from_members(MatrixConnectionData *conn, + MatrixRoomStateEventTable *state_table) +{ + GList *members, *tmp; + gchar *member1, *res; + + members = _get_room_members(state_table); + + /* remove ourselves from the list */ + tmp = g_list_find_custom(members, conn->user_id, (GCompareFunc)strcmp); + if(tmp != NULL) { + members = g_list_delete_link(members, tmp); + } + + if(members == NULL) { + /* nobody else here. Self-chat or an invitation. TODO: improve this + */ + return g_strdup("invitation"); + } + + member1 = _get_display_name_for_member(state_table, members->data); + + if(members->next == NULL) { + /* one other person */ + res = member1; + } else if(members->next->next == NULL) { + /* two other people */ + gchar *member2 = _get_display_name_for_member(state_table, + members->next->data); + res = g_strdup_printf(_("%s and %s"), member1, member2); + g_free(member1); + g_free(member2); + } else { + int nmembers = g_list_length(members); + res = g_strdup_printf(_("%s and %i others"), member1, nmembers); + g_free(member1); + } + + g_list_free(members); + return res; +} + /** * figure out the best name for a room + * + * @returns a string which should be freed */ -static const char *matrix_room_get_name(MatrixRoomStateEventTable *state_table) +static char *matrix_room_get_name(MatrixConnectionData *conn, + MatrixRoomStateEventTable *state_table) { GHashTable *tmp; MatrixRoomEvent *event; + const gchar *tmpname = NULL; /* start by looking for the official room name */ event = matrix_room_get_state_event(state_table, "m.room.name", ""); if(event != NULL) { - const gchar *tmpname = matrix_json_object_get_string_member( + tmpname = matrix_json_object_get_string_member( event->content, "name"); if(tmpname != NULL) { - return tmpname; + return g_strdup(tmpname); } } + /* look for an alias */ tmp = (GHashTable *) g_hash_table_lookup(state_table, "m.room.aliases"); if(tmp != NULL) { GHashTableIter iter; - g_hash_table_iter_init(&iter, tmp); 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) { - const gchar *tmpname = matrix_json_array_get_string_element(array, 0); + tmpname = matrix_json_array_get_string_element(array, 0); if(tmpname != NULL) { - return tmpname; + return g_strdup(tmpname); } } } } - /* TODO: look for room members, and pick a name based on that */ - - return "unknown"; + /* look for room members, and pick a name based on that */ + return _get_room_name_from_members(conn, state_table); } @@ -522,9 +643,11 @@ void matrix_room_leave_chat(PurpleConversation *conv) * * @param conv: conversation info */ -void matrix_room_update_buddy_list(PurpleConversation *conv) +void matrix_room_update_buddy_list(MatrixConnectionData *conn, + PurpleConversation *conv) { - const gchar *room_id, *room_name; + const gchar *room_id; + gchar *room_name; PurpleChat *chat; room_id = conv->name; @@ -551,8 +674,9 @@ void matrix_room_update_buddy_list(PurpleConversation *conv) purple_blist_add_chat(chat, group, NULL); } - room_name = matrix_room_get_name(matrix_room_get_state_table(conv)); + room_name = matrix_room_get_name(conn, matrix_room_get_state_table(conv)); purple_blist_alias_chat(chat, room_name); + g_free(room_name); } diff --git a/matrix-room.h b/matrix-room.h index b454653..dd1da06 100644 --- a/matrix-room.h +++ b/matrix-room.h @@ -34,14 +34,17 @@ struct _PurpleConversation; struct _PurpleConnection; +struct _MatrixConnectionData; /** * Ensure the room is up to date in the buddy list (ie, it is present, * and the alias is correct) * + * @param conn connection data for the account * @param conv conversation info */ -void matrix_room_update_buddy_list(struct _PurpleConversation *conv); +void matrix_room_update_buddy_list(struct _MatrixConnectionData *conn, + struct _PurpleConversation *conv); /** * If this is an active conversation, return it; otherwise, create it anew. diff --git a/matrix-sync.c b/matrix-sync.c index 5386917..8cb8acd 100644 --- a/matrix-sync.c +++ b/matrix-sync.c @@ -115,7 +115,8 @@ static void matrix_sync_room(const gchar *room_id, _parse_room_event_array(conv, timeline_array, event_map, FALSE); /* ensure the buddy list is up to date*/ - matrix_room_update_buddy_list(conv); + matrix_room_update_buddy_list(purple_connection_get_protocol_data(pc), + conv); } |