/*
* matrix-roommember.c
*
*
* Copyright (c) Openmarket UK Ltd 2015
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "matrix-roommembers.h"
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "matrix-json.h"
/******************************************************************************
*
* Individual members
*/
typedef struct _MatrixRoomMember {
gchar *userid;
/* 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;
/**
* 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);
}
}
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(const gchar *userid)
{
MatrixRoomMember *mem = g_new0(MatrixRoomMember, 1);
mem->userid = 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;
g_free(member);
}
/******************************************************************************
*
* member table
*/
struct _MatrixRoomMemberTable {
GHashTable *hash_table;
GSList *new_members;
GSList *left_members;
GSList *renamed_members;
};
MatrixRoomMemberTable *matrix_roommembers_new_table()
{
MatrixRoomMemberTable *table;
table = g_new0(MatrixRoomMemberTable, 1);
table -> hash_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify) _free_member);
return table;
}
void matrix_roommembers_free_table(MatrixRoomMemberTable *table)
{
g_hash_table_destroy(table->hash_table);
table->hash_table = NULL;
g_free(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)
{
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;
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);
member->current_displayname = displayname;
*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);
}
}
void matrix_roommembers_update_member(MatrixRoomMemberTable *table,
const gchar *member_user_id, JsonObject *new_state)
{
const gchar *old_displayname = NULL;
MatrixRoomMember *member;
int old_membership_val = MATRIX_ROOM_MEMBERSHIP_NONE,
new_membership_val;
const gchar *new_displayname, *new_membership;
new_displayname = matrix_json_object_get_string_member(
new_state, "displayname");
new_membership = matrix_json_object_get_string_member(
new_state, "membership");
new_membership_val = _parse_membership(new_membership);
member = _lookup_member(table, member_user_id);
if(member != NULL) {
old_displayname = member -> state_displayname;
old_membership_val = member -> membership;
}
if(!member) {
member = _new_member(member_user_id);
g_hash_table_insert(table->hash_table, g_strdup(member_user_id),
member);
}
member->membership = new_membership_val;
member->state_displayname = new_displayname;
purple_debug_info("matrixprpl", "member %s change %i->%i, "
"%s->%s\n", 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) {
table->new_members = g_slist_append(
table->new_members, member);
} else if(g_strcmp0(old_displayname, new_displayname) != 0) {
table->renamed_members = g_slist_append(
table->renamed_members, member);
}
} else {
if(old_membership_val == MATRIX_ROOM_MEMBERSHIP_JOIN) {
table->left_members = g_slist_append(
table->left_members, member);
}
}
}
/**
* Returns a list of user ids. Free the list, but not the string pointers.
*/
GList *matrix_roommembers_get_active_members(
MatrixRoomMemberTable *member_table)
{
GHashTableIter iter;
gpointer key, value;
GList *members = NULL;
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)
members = g_list_prepend(members, (gpointer)user_id);
}
return members;
}