diff --git a/.gitignore b/.gitignore index 77dc04d..c3a6f24 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,3 @@ Makefile.in /src/matrix-event-call-hangup.c /src/matrix-glib-0.0.pc /src/matrix-message-notice.c -/src/matrix-room.c diff --git a/src/Makefile.am b/src/Makefile.am index 716828d..03ed382 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,7 +36,6 @@ libmatrix_glib_0_0_la_VALA_SOURCES = \ matrix-event-call-answer.vala \ matrix-event-call-hangup.vala \ matrix-message-notice.vala \ - matrix-room.vala \ $(NULL) AM_CPPFLAGS += \ @@ -115,6 +114,7 @@ INST_H_SRC_FILES = \ matrix-event-receipt.h \ utils.h \ matrix-profile.h \ + matrix-room.h \ $(NULL) INST_H_BUILT_FILES = \ @@ -157,6 +157,7 @@ libmatrix_glib_0_0_la_SOURCES = \ matrix-event-room-avatar.c \ matrix-event-room-name.c \ matrix-profile.c \ + matrix-room.c \ utils.c \ matrix-enumtypes.c \ $(INST_H_SRC_FILES) \ diff --git a/src/matrix-room.c b/src/matrix-room.c new file mode 100644 index 0000000..10162c0 --- /dev/null +++ b/src/matrix-room.c @@ -0,0 +1,1629 @@ +/* + * This file is part of matrix-glib-sdk + * + * matrix-glib-sdk is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * matrix-glib-sdk 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with matrix-glib-sdk. If not, see + * . + */ + +#include "matrix-room.h" +#include "matrix-enumtypes.h" + +/** + * SECTION:matrix-room + * @short_description: class to hold room data + * + */ + +#define MATRIX_ROOM_TYPE_MEMBER_DATA (matrix_room_member_data_get_type ()) + +enum { + PROP_0, + PROP_ROOM_ID, + PROP_ALIASES, + PROP_AVATAR_URL, + PROP_AVATAR_THUMBNAIL_URL, + PROP_CANONICAL_ALIAS, + PROP_CREATOR, + PROP_FEDERATE, + PROP_GUEST_ACCESS, + PROP_HISTORY_VISIBILITY, + PROP_JOIN_RULES, + PROP_NAME, + PROP_DEFAULT_POWER_LEVEL, + PROP_DEFAULT_EVENT_LEVEL, + PROP_DEFAULT_STATE_LEVEL, + PROP_BAN_LEVEL, + PROP_KICK_LEVEL, + PROP_REDACT_LEVEL, + PROP_INVITE_LEVEL, + PROP_TOPIC, + PROP_TYPING_USERS, + PROP_AVATAR_INFO, + PROP_AVATAR_THUMBNAIL_INFO, + NUM_PROPERTIES +}; + +static GParamSpec *matrix_room_properties[NUM_PROPERTIES]; + +typedef struct { + MatrixProfile* profile; + gboolean thirdparty; +} MatrixRoomMemberData; + +MatrixRoomMemberData * +matrix_room_member_data_new(void) +{ + return g_new0(MatrixRoomMemberData, 1); +} + +void +matrix_room_member_data_free(MatrixRoomMemberData *member_data) +{ + g_return_if_fail(member_data != NULL); + + g_object_unref(member_data->profile); + g_free(member_data); +} + +typedef struct { + gchar *room_id; + gchar **aliases; + gint aliases_len; + gchar *avatar_url; + MatrixImageInfo *avatar_info; + gchar *avatar_thumbnail_url; + MatrixImageInfo *avatar_thumbnail_info; + gchar *canonical_alias; + gchar *creator; + gboolean federate; + MatrixGuestAccess guest_access; + MatrixHistoryVisibility history_visibility; + MatrixJoinRules join_rules; + gchar *name; + gint default_power_level; + gint default_event_level; + gint default_state_level; + gint ban_level; + gint kick_level; + gint redact_level; + gint invite_level; + gchar *topic; + gchar **typing_users; + gint typing_users_len; + GHashTable* event_levels; + GHashTable* user_levels; + GHashTable* members; +} MatrixRoomPrivate; + +/** + * MatrixRoom: + * + * The #MatrixRoom class is there to hold different parameters of a room like its known aliases, + * its members, etc. + */ +G_DEFINE_TYPE_WITH_PRIVATE(MatrixRoom, matrix_room, G_TYPE_OBJECT); + +/** + * matrix_room_new: + * @room_id: a room ID + * + * Create a new #MatrixRoom object. + * + * Returns: (transfer full): a new #MatrixRoom object + */ +MatrixRoom * +matrix_room_new(const gchar *room_id) +{ + g_return_val_if_fail(room_id != NULL, NULL); + + return (MatrixRoom *)g_object_new(MATRIX_TYPE_ROOM, + "room-id", room_id, + NULL); +} + +/** + * matrix_room_add_member: + * @room: a #MatrixRoom + * @user_id: the Matrix ID of the user to add + * @profile: a #MatrixProfile + * @third_party: if true, the member is marked as a pending 3rd party invitation + * @error: a #GError, or %NULL to ignore errors + * + * Add a member to the room member list. If a member with the same @user_id exists, @error is + * set to #MATRIX_ERROR_ALREADY_EXISTS. + */ +void +matrix_room_add_member(MatrixRoom *matrix_room, const gchar *user_id, MatrixProfile *profile, gboolean third_party, GError **error) +{ + MatrixRoomPrivate *priv; + MatrixRoomMemberData *data = NULL; + + g_return_if_fail(matrix_room != NULL); + g_return_if_fail(user_id != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if ((data = g_hash_table_lookup(priv->members, user_id)) != NULL) { + g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_ALREADY_EXISTS, + "User already exists in that room"); + + return; + } + + data = matrix_room_member_data_new(); + + if (profile == NULL) { + data->profile = matrix_profile_new(); + } else { + data->profile = profile; + } + + data->thirdparty = third_party; + + g_hash_table_insert(priv->members, g_strdup(user_id), data); +} + +/** + * matrix_room_get_or_add_member: + * @room: a #MatrixRoom + * @user_id: the Matrix ID of the user to add + * @third_party: if %TRUE, the member is marked as a pending 3rd party invitation + * @error: a #GError, or %NULL to ignore errors + * + * Gets the profile of the room member specified in @user_id. If that user is not added to the + * room yet, it gets added with an empty profile and that profile is returned. + * + * Returns: (transfer none): the #MatrixProfile of the user + */ +MatrixProfile * +matrix_room_get_or_add_member(MatrixRoom *matrix_room, const gchar *user_id, gboolean third_party, GError **error) +{ + MatrixProfile *profile; + GError *inner_error = NULL; + + g_return_val_if_fail(matrix_room != NULL, NULL); + g_return_val_if_fail(user_id != NULL, NULL); + + profile = matrix_room_get_member(matrix_room, user_id, NULL, &inner_error); + + if (inner_error == NULL) { + return profile; + } + + if ((inner_error->domain != MATRIX_ERROR) || (inner_error->code == MATRIX_ERROR_NOT_FOUND)) { + g_propagate_error(error, inner_error); + + return NULL; + } + + g_clear_error(&inner_error); + + matrix_room_add_member(matrix_room, user_id, NULL, third_party, &inner_error); + + if (inner_error != NULL) { + g_propagate_error(error, inner_error); + + return NULL; + } + + profile = matrix_room_get_member(matrix_room, user_id, &third_party, &inner_error); + + if (inner_error != NULL) { + g_propagate_error(error, inner_error); + + return NULL; + } + + return profile; +} + +/** + * matrix_room_get_member: + * @room: a #MatrixRoom + * @user_id: the Matrix ID of the user to find + * @third_party: gets a true value if the member is actually a pending 3rd party invitation + * @error: (nullable): a #GError, or %NULL to ignore errors + * + * Gets the profile of the room member specified in @user_id. If that user is not added to + * the room yet, @error is set to #MATRIX_ERROR_NOT_FOUND. + * + * Returns: (transfer none): the profile of the user + */ +MatrixProfile * +matrix_room_get_member(MatrixRoom *matrix_room, const gchar *user_id, gboolean *third_party, GError **error) +{ + MatrixRoomMemberData *data; + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + g_return_val_if_fail(user_id != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if ((data = g_hash_table_lookup(priv->members, user_id)) == NULL) { + g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_NOT_FOUND, + "No such room member"); + + return NULL; + } + + if (third_party != NULL) { + *third_party = data->thirdparty; + } + + return data->profile; +} + +/** + * matrix_room_remove_member: + * @room: a #MatrixRoom + * @user_id: a Matrix ID + * @error: (nullable): a #GError, or %NULL to ignore errors + * + * Removes @user_id from the member list. + */ +void +matrix_room_remove_member(MatrixRoom *matrix_room, const gchar *user_id, GError **error) +{ + MatrixRoomMemberData *data; + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + g_return_if_fail(user_id != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if ((data = g_hash_table_lookup(priv->members, user_id)) == NULL) { + g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_NOT_FOUND, + "No such room member"); + + return; + } + + g_hash_table_remove(priv->members, user_id); +} + +/** + * matrix_room_clear_user_levels: + * @room: a #MatrixRoom + * + * Clear the stored individual user levels. This should be called eg. when receiving a new + * `m.room.power_levels` event. + */ +void +matrix_room_clear_user_levels(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + g_hash_table_remove_all(priv->user_levels); +} + +/** + * matrix_room_set_user_level: + * @room: a #MatrixRoom + * @user_id: a fully qualified Matrix ID + * @level: the new power level + * + * Set an individual power level for a user. + */ +void +matrix_room_set_user_level(MatrixRoom *matrix_room, const gchar *user_id, gint level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + g_return_if_fail(user_id != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + g_hash_table_insert (priv->user_levels, g_strdup(user_id), GINT_TO_POINTER(level)); +} + +/** + * matrix_room_get_user_level: + * @room: a #MatrixRoom + * @user_id: a fully qualified Matrix ID + * + * Get the power level of a user. If the user doesn’t have an individually set power level, + * the default value is returned. + * + * Returns: the level of the user. + */ +gint +matrix_room_get_user_level(MatrixRoom *matrix_room, const gchar *user_id) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + g_return_val_if_fail(user_id != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + gpointer level = NULL; + + if (!g_hash_table_lookup_extended(priv->user_levels, user_id, NULL, &level)) { + return priv->default_power_level; + } + + return GPOINTER_TO_INT(level); +} + +/** + * matrix_room_clear_event_levels: + * @room: a #MatrixRoom + * + * Clear the stored event level requirements. This should be called eg. when receiving a new + * `m.room.power_levels` event. + */ +void +matrix_room_clear_event_levels(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + g_hash_table_remove_all(priv->event_levels); +} + +/** + * matrix_room_set_event_level: + * @room: a #MatrixRoom + * @event_type: the event type to restrict + * @level: the desired level for the event type + * + * Set the required level to send an event of type @event_type. + */ +void +matrix_room_set_event_level(MatrixRoom *matrix_room, const gchar *event_type, gint level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + g_return_if_fail (event_type != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + g_hash_table_insert(priv->event_levels, g_strdup(event_type), GINT_TO_POINTER(level)); +} + +/** + * matrix_room_get_event_level: + * @room: a #MatrixRoom + * @event_type: the event type to query + * @error: (nullable): a #GError, or %NULL to ignore errors + * + * Get the required level to send an event of type @event_type. If there is no level + * requirement set for this event type, this function returns %NULL as there is no way to + * decide if #MatrixRoom:default-state-level or #MatrixRoom:default-event-level should be used. + * + * Returns: the level required to send a specific event + */ +gint +matrix_room_get_event_level(MatrixRoom *matrix_room, const gchar *event_type, GError **error) +{ + MatrixRoomPrivate *priv; + gpointer level; + + g_return_val_if_fail(matrix_room != NULL, 0); + g_return_val_if_fail(event_type != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + if (!g_hash_table_lookup_extended(priv->event_levels, event_type, NULL, &level)) { + g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_NOT_FOUND, "No level set for this event type"); + + return 0; + } + + return GPOINTER_TO_INT(level); +} + +const gchar * +matrix_room_get_room_id(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->room_id; +} + +static void +matrix_room_set_room_id(MatrixRoom *matrix_room, const gchar *room_id) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (g_strcmp0(room_id, priv->room_id) != 0) { + g_free(priv->room_id); + priv->room_id = g_strdup(room_id); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_ROOM_ID]); + } +} + +/** + * matrix_room_get_aliases: + * @room: a #MatrixRoom + * @n_aliases: (nullable): a placeholder for the length of the list + * + * Returns: (transfer none): the list of room aliases + */ +gchar ** +matrix_room_get_aliases(MatrixRoom *matrix_room, int *n_aliases) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (n_aliases != NULL) { + *n_aliases = priv->aliases_len; + } + + return priv->aliases; +} + +/** + * matrix_room_set_aliases: + * @room: a #MatrixRoom + * @aliases: a list of aliases to assign to @room + * @n_aliases: the length of @aliases + */ +void +matrix_room_set_aliases(MatrixRoom *matrix_room, const gchar **aliases, int n_aliases) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + for (gint i = 0; i < priv->aliases_len; i++) { + g_free(priv->aliases[i]); + } + + g_free(priv->aliases); + + priv->aliases = g_new(gchar *, n_aliases); + + for (gint i = 0; i < n_aliases; i++) { + priv->aliases[i] = g_strdup(aliases[i]); + } + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_ALIASES]); +} + +const gchar * +matrix_room_get_avatar_url(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->avatar_url; +} + +void +matrix_room_set_avatar_url(MatrixRoom *matrix_room, const gchar *avatar_url) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (g_strcmp0(avatar_url, priv->avatar_url) != 0) { + g_free(priv->avatar_url); + priv->avatar_url = g_strdup(avatar_url); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_AVATAR_URL]); + } +} + +MatrixImageInfo * +matrix_room_get_avatar_info(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->avatar_info; +} + +void +matrix_room_set_avatar_info(MatrixRoom *matrix_room, MatrixImageInfo *avatar_info) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->avatar_info != avatar_info) { + matrix_image_info_unref(priv->avatar_info); + priv->avatar_info = matrix_image_info_ref(avatar_info); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_AVATAR_INFO]); + } +} + +const gchar * +matrix_room_get_avatar_thumbnail_url(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->avatar_thumbnail_url; +} + +void +matrix_room_set_avatar_thumbnail_url(MatrixRoom *matrix_room, const gchar *avatar_thumbnail_url) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (g_strcmp0(avatar_thumbnail_url, priv->avatar_thumbnail_url) != 0) { + g_free(priv->avatar_thumbnail_url); + priv->avatar_thumbnail_url = g_strdup(avatar_thumbnail_url); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_AVATAR_THUMBNAIL_URL]); + } +} + +MatrixImageInfo * +matrix_room_get_avatar_thumbnail_info(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->avatar_thumbnail_info; +} + +void +matrix_room_set_avatar_thumbnail_info(MatrixRoom *matrix_room, MatrixImageInfo *avatar_thumbnail_info) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->avatar_thumbnail_info != avatar_thumbnail_info) { + matrix_image_info_unref(priv->avatar_thumbnail_info); + priv->avatar_thumbnail_info = matrix_image_info_ref(avatar_thumbnail_info); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_AVATAR_THUMBNAIL_INFO]); + } +} + +const gchar * +matrix_room_get_canonical_alias(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->canonical_alias; +} + +void +matrix_room_set_canonical_alias(MatrixRoom *matrix_room, const gchar *canonical_alias) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (g_strcmp0(canonical_alias, priv->canonical_alias) != 0) { + g_free(priv->canonical_alias); + priv->canonical_alias = g_strdup(canonical_alias); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_CANONICAL_ALIAS]); + } +} + +const gchar * +matrix_room_get_creator(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->creator; +} + +void +matrix_room_set_creator(MatrixRoom *matrix_room, const gchar *creator) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (g_strcmp0(creator, priv->creator) != 0) { + g_free(priv->creator); + priv->creator = g_strdup(creator); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_CREATOR]); + } +} + +gboolean +matrix_room_get_federate(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, FALSE); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->federate; +} + +void +matrix_room_set_federate(MatrixRoom *matrix_room, gboolean federate) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->federate != federate) { + priv->federate = federate; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_FEDERATE]); + } +} + +MatrixGuestAccess +matrix_room_get_guest_access(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->guest_access; +} + +void +matrix_room_set_guest_access(MatrixRoom *matrix_room, MatrixGuestAccess guest_access) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->guest_access != guest_access) { + priv->guest_access = guest_access; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_GUEST_ACCESS]); + } +} + +MatrixHistoryVisibility +matrix_room_get_history_visibility(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->history_visibility; +} + +void +matrix_room_set_history_visibility(MatrixRoom *matrix_room, MatrixHistoryVisibility history_visibility) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->history_visibility != history_visibility) { + priv->history_visibility = history_visibility; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_HISTORY_VISIBILITY]); + } +} + +MatrixJoinRules +matrix_room_get_join_rules(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->join_rules; +} + +void +matrix_room_set_join_rules(MatrixRoom *matrix_room, MatrixJoinRules join_rules) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->join_rules != join_rules) { + priv->join_rules = join_rules; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_JOIN_RULES]); + } +} + +const gchar * +matrix_room_get_name(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->name; +} + +void +matrix_room_set_name(MatrixRoom *matrix_room, const gchar *name) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (g_strcmp0(name, priv->name) != 0) { + g_free(priv->name); + priv->name = g_strdup(name); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_NAME]); + } +} + +gint +matrix_room_get_default_power_level(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->default_power_level; +} + +void +matrix_room_set_default_power_level(MatrixRoom *matrix_room, gint default_power_level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->default_power_level != default_power_level) { + priv->default_power_level = default_power_level; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_DEFAULT_POWER_LEVEL]); + } +} + +gint +matrix_room_get_default_event_level(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->default_event_level; +} + +void +matrix_room_set_default_event_level(MatrixRoom *matrix_room, gint default_event_level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->default_event_level != default_event_level) { + priv->default_event_level = default_event_level; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_DEFAULT_EVENT_LEVEL]); + } +} + +gint +matrix_room_get_default_state_level(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->default_state_level; +} + +void +matrix_room_set_default_state_level(MatrixRoom *matrix_room, gint defaul_state_level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->default_state_level != defaul_state_level) { + priv->default_state_level = defaul_state_level; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_DEFAULT_STATE_LEVEL]); + } +} + +gint +matrix_room_get_ban_level(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->ban_level; +} + +void +matrix_room_set_ban_level(MatrixRoom *matrix_room, gint ban_level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->ban_level != ban_level) { + priv->ban_level = ban_level; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_BAN_LEVEL]); + } +} + +gint +matrix_room_get_kick_level(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->kick_level; +} + +void +matrix_room_set_kick_level(MatrixRoom *matrix_room, gint kick_level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->kick_level != kick_level) { + priv->kick_level = kick_level; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_KICK_LEVEL]); + } +} + +gint +matrix_room_get_redact_level(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->redact_level; +} + +void +matrix_room_set_redact_level(MatrixRoom *matrix_room, gint redact_level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->redact_level != redact_level) { + priv->redact_level = redact_level; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_REDACT_LEVEL]); + } +} + +gint +matrix_room_get_invite_level(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, 0); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->invite_level; +} + +void +matrix_room_set_invite_level(MatrixRoom *matrix_room, gint invite_level) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (priv->invite_level != invite_level) { + priv->invite_level = invite_level; + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_INVITE_LEVEL]); + } +} + +const gchar * +matrix_room_get_topic(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + return priv->topic; +} + +void +matrix_room_set_topic(MatrixRoom *matrix_room, const gchar *topic) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (g_strcmp0(topic, priv->topic) != 0) { + g_free(priv->topic); + priv->topic = g_strdup(topic); + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_TOPIC]); + } +} + +/** + * matrix_room_get_typing_users: + * @room: a #MatrixRoom + * @n_typing_users: (nullable): placeholder for the length of the returned list + * + * Returns: (transfer none): the list of typing users in @room + */ +gchar ** +matrix_room_get_typing_users(MatrixRoom *matrix_room, int *n_typing_users) +{ + MatrixRoomPrivate *priv; + + g_return_val_if_fail(matrix_room != NULL, NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + if (n_typing_users != NULL) { + *n_typing_users = priv->typing_users_len; + } + + return priv->typing_users; +} + +void +matrix_room_set_typing_users(MatrixRoom *matrix_room, gchar **typing_users, int n_typing_users) +{ + MatrixRoomPrivate *priv; + + g_return_if_fail(matrix_room != NULL); + + priv = matrix_room_get_instance_private(matrix_room); + + for (gint i = 0; i < priv->typing_users_len; i++) { + g_free(priv->typing_users[i]); + } + + g_free(priv->typing_users); + + priv->typing_users = g_new(gchar *, n_typing_users); + + for (gint i = 0; i < n_typing_users; i++) { + priv->typing_users[i] = g_strdup(typing_users[i]); + } + + g_object_notify_by_pspec((GObject *)matrix_room, matrix_room_properties[PROP_TYPING_USERS]); +} + +static void +matrix_room_finalize(GObject *gobject) +{ + MatrixRoomPrivate *priv = matrix_room_get_instance_private(MATRIX_ROOM(gobject)); + + g_free(priv->room_id); + + for (gint i = 0; i < priv->aliases_len; i++) { + g_free(priv->aliases[i]); + } + + g_free(priv->aliases); + g_free(priv->avatar_url); + matrix_image_info_unref(priv->avatar_info); + g_free(priv->avatar_thumbnail_url); + matrix_image_info_unref(priv->avatar_thumbnail_info); + g_free(priv->canonical_alias); + g_free(priv->creator); + g_free(priv->name); + g_free(priv->topic); + + for (gint i = 0; i < priv->typing_users_len; i++) { + g_free(priv->typing_users[i]); + } + + g_free(priv->typing_users); + g_hash_table_unref(priv->event_levels); + g_hash_table_unref(priv->user_levels); + g_hash_table_unref(priv->members); + + G_OBJECT_CLASS(matrix_room_parent_class)->finalize(gobject); +} + +static void +matrix_room_get_property(GObject *gobject, guint property_id, GValue *value, GParamSpec *pspec) +{ + MatrixRoom *matrix_room = MATRIX_ROOM(gobject); + + switch (property_id) { + case PROP_ROOM_ID: + g_value_set_string(value, matrix_room_get_room_id(matrix_room)); + + break; + case PROP_ALIASES: + g_value_set_boxed(value, matrix_room_get_aliases(matrix_room, NULL)); + + break; + case PROP_AVATAR_URL: + g_value_set_string(value, matrix_room_get_avatar_url(matrix_room)); + + break; + case PROP_AVATAR_THUMBNAIL_URL: + g_value_set_string(value, matrix_room_get_avatar_thumbnail_url(matrix_room)); + + break; + case PROP_CANONICAL_ALIAS: + g_value_set_string(value, matrix_room_get_canonical_alias(matrix_room)); + + break; + case PROP_CREATOR: + g_value_set_string(value, matrix_room_get_creator(matrix_room)); + + break; + case PROP_FEDERATE: + g_value_set_boolean(value, matrix_room_get_federate(matrix_room)); + + break; + case PROP_GUEST_ACCESS: + g_value_set_enum(value, matrix_room_get_guest_access(matrix_room)); + + break; + case PROP_HISTORY_VISIBILITY: + g_value_set_enum(value, matrix_room_get_history_visibility(matrix_room)); + + break; + case PROP_JOIN_RULES: + g_value_set_enum(value, matrix_room_get_join_rules(matrix_room)); + + break; + case PROP_NAME: + g_value_set_string(value, matrix_room_get_name(matrix_room)); + + break; + case PROP_DEFAULT_POWER_LEVEL: + g_value_set_int(value, matrix_room_get_default_power_level(matrix_room)); + + break; + case PROP_DEFAULT_EVENT_LEVEL: + g_value_set_int(value, matrix_room_get_default_event_level(matrix_room)); + + break; + case PROP_DEFAULT_STATE_LEVEL: + g_value_set_int(value, matrix_room_get_default_state_level(matrix_room)); + + break; + case PROP_BAN_LEVEL: + g_value_set_int(value, matrix_room_get_ban_level(matrix_room)); + + break; + case PROP_KICK_LEVEL: + g_value_set_int(value, matrix_room_get_kick_level(matrix_room)); + + break; + case PROP_REDACT_LEVEL: + g_value_set_int(value, matrix_room_get_redact_level(matrix_room)); + + break; + case PROP_INVITE_LEVEL: + g_value_set_int(value, matrix_room_get_invite_level(matrix_room)); + + break; + case PROP_TOPIC: + g_value_set_string(value, matrix_room_get_topic(matrix_room)); + + break; + case PROP_TYPING_USERS: + g_value_set_boxed(value, matrix_room_get_typing_users(matrix_room, NULL)); + + break; + case PROP_AVATAR_INFO: + g_value_set_boxed(value, matrix_room_get_avatar_info(matrix_room)); + + break; + case PROP_AVATAR_THUMBNAIL_INFO: + g_value_set_boxed(value, matrix_room_get_avatar_thumbnail_info(matrix_room)); + + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec); + + break; + } +} + +static void +matrix_room_set_property(GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec) +{ + MatrixRoom * matrix_room = MATRIX_ROOM(gobject); + + switch (property_id) { + case PROP_ROOM_ID: + matrix_room_set_room_id(matrix_room, g_value_get_string(value)); + + break; + case PROP_ALIASES: + { + gpointer boxed = g_value_get_boxed(value); + + matrix_room_set_aliases(matrix_room, boxed, (boxed == NULL) ? 0 : g_strv_length(boxed)); + + break; + } + case PROP_AVATAR_URL: + matrix_room_set_avatar_url(matrix_room, g_value_get_string(value)); + + break; + case PROP_AVATAR_THUMBNAIL_URL: + matrix_room_set_avatar_thumbnail_url(matrix_room, g_value_get_string(value)); + + break; + case PROP_CANONICAL_ALIAS: + matrix_room_set_canonical_alias(matrix_room, g_value_get_string(value)); + + break; + case PROP_CREATOR: + matrix_room_set_creator(matrix_room, g_value_get_string(value)); + + break; + case PROP_FEDERATE: + matrix_room_set_federate(matrix_room, g_value_get_boolean(value)); + + break; + case PROP_GUEST_ACCESS: + matrix_room_set_guest_access(matrix_room, g_value_get_enum(value)); + + break; + case PROP_HISTORY_VISIBILITY: + matrix_room_set_history_visibility(matrix_room, g_value_get_enum(value)); + + break; + case PROP_JOIN_RULES: + matrix_room_set_join_rules(matrix_room, g_value_get_enum (value)); + + break; + case PROP_NAME: + matrix_room_set_name(matrix_room, g_value_get_string(value)); + + break; + case PROP_DEFAULT_POWER_LEVEL: + matrix_room_set_default_power_level(matrix_room, g_value_get_int(value)); + + break; + case PROP_DEFAULT_EVENT_LEVEL: + matrix_room_set_default_event_level(matrix_room, g_value_get_int(value)); + + break; + case PROP_DEFAULT_STATE_LEVEL: + matrix_room_set_default_state_level(matrix_room, g_value_get_int(value)); + + break; + case PROP_BAN_LEVEL: + matrix_room_set_ban_level(matrix_room, g_value_get_int(value)); + + break; + case PROP_KICK_LEVEL: + matrix_room_set_kick_level(matrix_room, g_value_get_int(value)); + + break; + case PROP_REDACT_LEVEL: + matrix_room_set_redact_level(matrix_room, g_value_get_int(value)); + + break; + case PROP_INVITE_LEVEL: + matrix_room_set_invite_level(matrix_room, g_value_get_int(value)); + + break; + case PROP_TOPIC: + matrix_room_set_topic(matrix_room, g_value_get_string(value)); + + break; + case PROP_TYPING_USERS: + { + gpointer boxed = g_value_get_boxed(value); + + matrix_room_set_typing_users(matrix_room, boxed, (boxed == NULL) ? 0 : g_strv_length(boxed)); + + break; + } + case PROP_AVATAR_INFO: + matrix_room_set_avatar_info(matrix_room, g_value_get_boxed(value)); + + break; + case PROP_AVATAR_THUMBNAIL_INFO: + matrix_room_set_avatar_thumbnail_info(matrix_room, g_value_get_boxed(value)); + + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec); + + break; + } +} + +static void +matrix_room_class_init(MatrixRoomClass *klass) +{ + G_OBJECT_CLASS(klass)->get_property = matrix_room_get_property; + G_OBJECT_CLASS(klass)->set_property = matrix_room_set_property; + G_OBJECT_CLASS(klass)->finalize = matrix_room_finalize; + + /** + * MatrixRoom:room-id: + * + * The ID of the room this object belongs to. + */ + matrix_room_properties[PROP_ROOM_ID] = g_param_spec_string( + "room-id", "room-id", "room-id", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_ROOM_ID, matrix_room_properties[PROP_ROOM_ID]); + + /** + * MatrixRoom:aliases: + * + * All the known room aliases. + */ + matrix_room_properties[PROP_ALIASES] = g_param_spec_boxed( + "aliases", "aliases", "aliases", + G_TYPE_STRV, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_ALIASES, matrix_room_properties[PROP_ALIASES]); + + /** + * MatrixRoom:avatar-url: + * + * The URL of the room’s avatar. + */ + matrix_room_properties[PROP_AVATAR_URL] = g_param_spec_string( + "avatar-url", "avatar-url", "avatar-url", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_AVATAR_URL, matrix_room_properties[PROP_AVATAR_URL]); + + /** + * MatrixRoom:avatar-thumbnail-url: + * + * The URL of the room avatar’s thumbnail. + */ + matrix_room_properties[PROP_AVATAR_THUMBNAIL_URL] = g_param_spec_string( + "avatar-thumbnail-url", "avatar-thumbnail-url", "avatar-thumbnail-url", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_AVATAR_THUMBNAIL_URL, matrix_room_properties[PROP_AVATAR_THUMBNAIL_URL]); + + /** + * MatrixRoom:canonical-alias: + * + * The canonical alias of the room. + */ + matrix_room_properties[PROP_CANONICAL_ALIAS] = g_param_spec_string( + "canonical-alias", "canonical-alias", "canonical-alias", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_CANONICAL_ALIAS, matrix_room_properties[PROP_CANONICAL_ALIAS]); + + /** + * MatrixRoom:creator: + * + * The Matrix ID of the room’s creator. + */ + matrix_room_properties[PROP_CREATOR] = g_param_spec_string( + "creator", "creator", "creator", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_CREATOR, matrix_room_properties[PROP_CREATOR]); + + /** + * MatrixRoom:federate: + * + * If %FALSE, the room is not federated. + */ + matrix_room_properties[PROP_FEDERATE] = g_param_spec_boolean( + "federate", "federate", "federate", + FALSE, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_FEDERATE, matrix_room_properties[PROP_FEDERATE]); + + /** + * MatrixRoom:guest-access: + * + * Wether guests are allowed to join the room. + */ + matrix_room_properties[PROP_GUEST_ACCESS] = g_param_spec_enum( + "guest-access", "guest-access", "guest-access", + MATRIX_TYPE_GUEST_ACCESS, MATRIX_GUEST_ACCESS_UNKNOWN, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_GUEST_ACCESS, matrix_room_properties[PROP_GUEST_ACCESS]); + + /** + * MatrixRoom:history-visibility: + * This value controls the visibility of the room’s history. + */ + matrix_room_properties[PROP_HISTORY_VISIBILITY] = g_param_spec_enum( + "history-visibility", "history-visibility", "history-visibility", + MATRIX_TYPE_HISTORY_VISIBILITY, MATRIX_HISTORY_VISIBILITY_UNKNOWN, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_HISTORY_VISIBILITY, matrix_room_properties[PROP_HISTORY_VISIBILITY]); + /** + * MatrixRoom:join-rules: + * + * Controls who can join the room. + */ + matrix_room_properties[PROP_JOIN_RULES] = g_param_spec_enum( + "join-rules", "join-rules", "join-rules", + MATRIX_TYPE_JOIN_RULES, MATRIX_JOIN_RULES_UNKNOWN, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_JOIN_RULES, matrix_room_properties[PROP_JOIN_RULES]); + + /** + * MatrixRoom:name: + * + * The room’s name. + */ + matrix_room_properties[PROP_NAME] = g_param_spec_string( + "name", "name", "name", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_NAME, matrix_room_properties[PROP_NAME]); + + /** + * MatrixRoom:default-power-level: + * + * The default power level users get upon joining the room. + */ + matrix_room_properties[PROP_DEFAULT_POWER_LEVEL] = g_param_spec_int( + "default-power-level", "default-power-level", "default-power-level", + G_MININT, G_MAXINT, 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_DEFAULT_POWER_LEVEL, matrix_room_properties[PROP_DEFAULT_POWER_LEVEL]); + + /** + * MatrixRoom:default-event-level: + * + * The power level required to send non-state events to the room. This gets applied if + * the event type doesn’t have an explicit level requirement (see + * matrix_room_set_event_level() and matrix_room_get_event_level() for more information). + */ + matrix_room_properties[PROP_DEFAULT_EVENT_LEVEL] = g_param_spec_int( + "default-event-level", "default-event-level", "default-event-level", + G_MININT, G_MAXINT, 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_DEFAULT_EVENT_LEVEL, matrix_room_properties[PROP_DEFAULT_EVENT_LEVEL]); + + /** + * MatrixRoom:default-state-level: + * + * The power level required to send state events to the room. This get applied if the + * event type doesn’t have an explicit level requirement (see matrix_room_set_event_level() + * and matrix_room_get_event_level() for more information). + */ + matrix_room_properties[PROP_DEFAULT_STATE_LEVEL] = g_param_spec_int( + "default-state-level", "default-state-level", "default-state-level", + G_MININT, G_MAXINT, 10, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_DEFAULT_STATE_LEVEL, matrix_room_properties[PROP_DEFAULT_STATE_LEVEL]); + + /** + * MatrixRoom:ban-level: + * + * The power level required to ban other users from the room. + */ + matrix_room_properties[PROP_BAN_LEVEL] = g_param_spec_int( + "ban-level", "ban-level", "ban-level", + G_MININT, G_MAXINT, 5, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_BAN_LEVEL, matrix_room_properties[PROP_BAN_LEVEL]); + + /** + * MatrixRoom:kick-level: + * + * The power level required to kick other users from the room. + */ + matrix_room_properties[PROP_KICK_LEVEL] = g_param_spec_int( + "kick-level", "kick-level", "kick-level", + G_MININT, G_MAXINT, 5, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_KICK_LEVEL, matrix_room_properties[PROP_KICK_LEVEL]); + + /** + * MatrixRoom:redact-level: + * + * The power level required to redact events in the room. + */ + matrix_room_properties[PROP_REDACT_LEVEL] = g_param_spec_int( + "redact-level", "redact-level", "redact-level", + G_MININT, G_MAXINT, 20, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_REDACT_LEVEL, matrix_room_properties[PROP_REDACT_LEVEL]); + + /** + * MatrixRoom:invite-level: + * + * The power level required to invite users to the room. + */ + matrix_room_properties[PROP_INVITE_LEVEL] = g_param_spec_int( + "invite-level", "invite-level", "invite-level", + G_MININT, G_MAXINT, 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_INVITE_LEVEL, matrix_room_properties[PROP_INVITE_LEVEL]); + + /** + * MatrixRoom:topic: + * + * The room’s topic. + */ + matrix_room_properties[PROP_TOPIC] = g_param_spec_string( + "topic", "topic", "topic", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TOPIC, matrix_room_properties[PROP_TOPIC]); + + /** + * MatrixRoom:typing-users: + * + * The users currently typing in the room. + */ + matrix_room_properties[PROP_TYPING_USERS] = g_param_spec_boxed( + "typing-users", "typing-users", "typing-users", + G_TYPE_STRV, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TYPING_USERS, matrix_room_properties[PROP_TYPING_USERS]); + + /** + * MatrixRoom:avatar-info: + * + * A #MatrixImageInfo describing #MatrixRoom:avatar-url. + */ + matrix_room_properties[PROP_AVATAR_INFO] = g_param_spec_boxed( + "avatar-info", "avatar-info", "avatar-info", + MATRIX_TYPE_IMAGE_INFO, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_AVATAR_INFO, matrix_room_properties[PROP_AVATAR_INFO]); + + /** + * MatrixRoom:avatar-thumbnail-info: + * + * A #MatrixImageInfo describing #MatrixRoom:avatar-thumbnail-url: + */ + matrix_room_properties[PROP_AVATAR_THUMBNAIL_INFO] = g_param_spec_boxed( + "avatar-thumbnail-info", "avatar-thumbnail-info", "avatar-thumbnail-info", + MATRIX_TYPE_IMAGE_INFO, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_AVATAR_THUMBNAIL_INFO, matrix_room_properties[PROP_AVATAR_THUMBNAIL_INFO]); +} + +static void +matrix_room_init(MatrixRoom *matrix_room) +{ + MatrixRoomPrivate *priv = matrix_room_get_instance_private(matrix_room); + + priv->avatar_url = NULL; + priv->avatar_info = NULL; + priv->avatar_thumbnail_url = NULL; + priv->avatar_thumbnail_info = NULL; + priv->canonical_alias = NULL; + priv->creator = NULL; + priv->federate = FALSE; + priv->guest_access = MATRIX_GUEST_ACCESS_UNKNOWN; + priv->history_visibility = MATRIX_HISTORY_VISIBILITY_UNKNOWN; + priv->join_rules = MATRIX_JOIN_RULES_UNKNOWN; + priv->name = NULL; + priv->default_power_level = 0; + priv->default_event_level = 0; + priv->default_state_level = 10; + priv->ban_level = 5; + priv->kick_level = 5; + priv->redact_level = 20; + priv->invite_level = 0; + priv->topic = NULL; + priv->event_levels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + priv->user_levels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + priv->members = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)matrix_room_member_data_free); +} diff --git a/src/matrix-room.h b/src/matrix-room.h new file mode 100644 index 0000000..bcc2b8e --- /dev/null +++ b/src/matrix-room.h @@ -0,0 +1,92 @@ +/* + * This file is part of matrix-glib-sdk + * + * matrix-glib-sdk is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * matrix-glib-sdk 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with matrix-glib-sdk. If not, see + * . + */ + +#ifndef __MATRIX_GLIB_SDK_ROOM_H__ +# define __MATRIX_GLIB_SDK_ROOM_H__ + +# include +# include "matrix-profile.h" +# include "matrix-types.h" + +G_BEGIN_DECLS + +# define MATRIX_TYPE_ROOM matrix_room_get_type() +G_DECLARE_DERIVABLE_TYPE(MatrixRoom, matrix_room, MATRIX, ROOM, GObject) + +struct _MatrixRoomClass { + GObjectClass parent_class; +}; + +MatrixRoom *matrix_room_new(const gchar *room_id); +void matrix_room_add_member(MatrixRoom *room, const gchar *user_id, MatrixProfile *profile, gboolean third_party, GError **error); +MatrixProfile *matrix_room_get_or_add_member(MatrixRoom *room, const gchar *user_id, gboolean third_party, GError **error); +MatrixProfile *matrix_room_get_member(MatrixRoom *room, const gchar *user_id, gboolean *third_party, GError **error); +void matrix_room_remove_member(MatrixRoom *room, const gchar *user_id, GError **error); +void matrix_room_clear_user_levels(MatrixRoom *room); +void matrix_room_set_user_level(MatrixRoom *room, const gchar *user_id, gint level); +gint matrix_room_get_user_level(MatrixRoom *room, const gchar *user_id); +void matrix_room_clear_event_levels(MatrixRoom *room); +void matrix_room_set_event_level(MatrixRoom *room, const gchar *event_type, gint level); +gint matrix_room_get_event_level(MatrixRoom *room, const gchar *event_type, GError **error); +const gchar *matrix_room_get_room_id(MatrixRoom *room); +gchar **matrix_room_get_aliases(MatrixRoom *room, int *n_aliases); +void matrix_room_set_aliases(MatrixRoom *room, const gchar **aliases, int n_aliases); +const gchar *matrix_room_get_avatar_url(MatrixRoom *room); +void matrix_room_set_avatar_url(MatrixRoom *room, const gchar *avatar_url); +MatrixImageInfo *matrix_room_get_avatar_info(MatrixRoom *room); +void matrix_room_set_avatar_info(MatrixRoom *room, MatrixImageInfo *avatar_info); +const gchar *matrix_room_get_avatar_thumbnail_url(MatrixRoom *room); +void matrix_room_set_avatar_thumbnail_url(MatrixRoom *room, const gchar *avatar_thumbnail_url); +MatrixImageInfo *matrix_room_get_avatar_thumbnail_info(MatrixRoom *room); +void matrix_room_set_avatar_thumbnail_info(MatrixRoom *room, MatrixImageInfo *avatar_thumbnail_info); +const gchar *matrix_room_get_canonical_alias(MatrixRoom *room); +void matrix_room_set_canonical_alias(MatrixRoom *room, const gchar *canonical_alias); +const gchar *matrix_room_get_creator(MatrixRoom *room); +void matrix_room_set_creator(MatrixRoom *room, const gchar *creator); +gboolean matrix_room_get_federate(MatrixRoom *room); +void matrix_room_set_federate(MatrixRoom *room, gboolean federate); +MatrixGuestAccess matrix_room_get_guest_access(MatrixRoom *room); +void matrix_room_set_guest_access(MatrixRoom *room, MatrixGuestAccess guest_access); +MatrixHistoryVisibility matrix_room_get_history_visibility(MatrixRoom *room); +void matrix_room_set_history_visibility(MatrixRoom *room, MatrixHistoryVisibility history_visibility); +MatrixJoinRules matrix_room_get_join_rules(MatrixRoom *room); +void matrix_room_set_join_rules(MatrixRoom *room, MatrixJoinRules join_rules); +const gchar *matrix_room_get_name(MatrixRoom *room); +void matrix_room_set_name(MatrixRoom *room, const gchar *name); +gint matrix_room_get_default_power_level(MatrixRoom *room); +void matrix_room_set_default_power_level(MatrixRoom *room, gint default_power_level); +gint matrix_room_get_default_event_level(MatrixRoom *room); +void matrix_room_set_default_event_level(MatrixRoom *room, gint default_event_level); +gint matrix_room_get_default_state_level(MatrixRoom *room); +void matrix_room_set_default_state_level(MatrixRoom *room, gint default_state_level); +gint matrix_room_get_ban_level(MatrixRoom *room); +void matrix_room_set_ban_level(MatrixRoom *room, gint ban_level); +gint matrix_room_get_kick_level(MatrixRoom *room); +void matrix_room_set_kick_level(MatrixRoom *room, gint kick_level); +gint matrix_room_get_redact_level(MatrixRoom *room); +void matrix_room_set_redact_level(MatrixRoom *room, gint redact_level); +gint matrix_room_get_invite_level(MatrixRoom *room); +void matrix_room_set_invite_level(MatrixRoom *room, gint invite_level); +const gchar *matrix_room_get_topic(MatrixRoom *room); +void matrix_room_set_topic(MatrixRoom *room, const gchar *topic); +gchar **matrix_room_get_typing_users(MatrixRoom *room, int *n_typing_users); +void matrix_room_set_typing_users(MatrixRoom *room, gchar **typing_users, int n_typing_users); + +G_END_DECLS + +#endif /* __MATRIX_GLIB_SDK_ROOM_H__ */ diff --git a/src/matrix-room.vala b/src/matrix-room.vala deleted file mode 100644 index 25279ac..0000000 --- a/src/matrix-room.vala +++ /dev/null @@ -1,347 +0,0 @@ -/* - * This file is part of matrix-glib-sdk - * - * matrix-glib-sdk is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * matrix-glib-sdk 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with matrix-glib-sdk. If not, see - * . - */ - -/** - * Class to hold data about rooms - * - * The Room class is there to hold different parameters of a room like - * its known aliases, its members, etc. - */ -public class Matrix.Room : GLib.Object { - /** - * The ID of the room this object belongs to. - */ - public string room_id { get; construct; } - - /** - * All the known room aliases. - */ - public string[] aliases { get; set; } - - /** - * The URL of the room’s avatar. - */ - public string? avatar_url { get; set; default = null; } - - /** - * ImageInfo relevant to the room avatar. - */ - public ImageInfo? avatar_info { get; set; default = null; } - - /** - * The URL of the room avatar’s thumbnail. - */ - public string? avatar_thumbnail_url { get; set; default = null; } - - /** - * ImageInfo relevant to the room avatar’s thumbnail. - */ - public ImageInfo? avatar_thumbnail_info { get; set; default = null; } - - /** - * The canonical alias of the room. - */ - public string? canonical_alias { get; set; default = null; } - - /** - * The Matrix ID of the room’s creator. - */ - public string? creator { get; set; default = null; } - - /** - * If false, the room is not federated. - */ - public bool federate { get; set; default = false; } - - /** - * Wether guests are allowed to join the room. - */ - public GuestAccess guest_access { get; set; default = GuestAccess.UNKNOWN; } - - /** - * This value controls the visibility of the room’s history. - */ - public HistoryVisibility history_visibility { - get; set; - default = HistoryVisibility.UNKNOWN; - } - - /** - * Controls who can join the room. - */ - public JoinRules join_rules { get; set; default = JoinRules.UNKNOWN; } - - /** - * The room’s name. - */ - public string? name { get; set; default = null; } - - /** - * The default power level users get upon joining the room. - */ - public int default_power_level { get; set; default = 0; } - - /** - * The power level required to send non-state events to the - * room. This gets applied if the event type doesn’t have an - * explicit level requirement (see set_event_level() and - * get_event_level()). - */ - public int default_event_level { get; set; default = 0; } - - /** - * The power level required to send state events to the room. This - * get applied if the event type doesn’t have an explicit level - * requirement (see set_event_level() and get_event_level()). - */ - public int default_state_level { get; set; default = 10; } - - /** - * The power level required to ban other users from the room. - */ - public int ban_level { get; set; default = 5; } - - /** - * The power level required to kick other users from the room. - */ - public int kick_level { get; set; default = 5; } - - /** - * The power level required to redact events in the room. - */ - public int redact_level { get; set; default = 20; } - - /** - * The power level required to invite users to the room. - */ - public int invite_level { get; set; default = 0; } - - /** - * The room’s topic. - */ - public string? topic { get; set; default = null; } - - /** - * The users currently typing in the room. - */ - public string[] typing_users { get; set; } - - private HashTable _event_levels = - new HashTable(str_hash, str_equal); - - private HashTable _user_levels = - new HashTable(str_hash, str_equal); - - private struct MemberData { - Profile profile; - bool thirdparty; - } - - private HashTable _members = - new HashTable(str_hash, str_equal); - - /** - * Create a new Room object. - */ - public - Room(string room_id) - { - Object(room_id : room_id); - } - - /** - * Add a member to the room member list. If a member with the - * same @user_id exists, {@link Matrix.Error.ALREADY_EXISTS} is - * thrown. - * - * @param user_id the Matrix ID of the user to add - * @param third_party if true, the member is marked as a pending - * 3rd party invitation - */ - public void - add_member(string user_id, Profile? profile, bool third_party) - throws Matrix.Error - { - MemberData? data = null; - - if ((data = _members[user_id]) != null) { - throw new Matrix.Error.ALREADY_EXISTS( - "User already exists in that room"); - } - - data = MemberData(); - - if (profile == null) { - data.profile = new Profile(); - } else { - data.profile = profile; - } - - data.thirdparty = third_party; - - _members[user_id] = data; - } - - /** - * Gets the profile of the room member specified in @user_id. If - * that user is not added to the room yet, it gets added with an - * empty profile and that profile is returned. - * - * @param user_id the Matrix ID of the user to add - * @param third_party if true, the member is marked as a pending - * 3rd party invitation - * @return the {@link Matrix.Profile} of the user - */ - public Profile - get_or_add_member(string user_id, bool third_party = false) - throws Matrix.Error - { - try { - return get_member(user_id, null); - } catch (Matrix.Error e) { - add_member(user_id, null, third_party); - - return get_member(user_id, null); - } - } - - /** - * Gets the profile of the room member specified in @user_id. If - * that user is not added to the room yet, - * {@link Matrix.Error.NOT_FOUND} is thrown. - * - * @param user_id the Matrix ID of the user to find - * @param third_party gets a true value if the member is actually - * a pending 3rd party invitation - * @return the profile of the user - */ - public Profile - get_member(string user_id, out bool third_party) - throws Matrix.Error - { - MemberData? data = null; - - if ((data = _members[user_id]) == null) { - throw new Matrix.Error.NOT_FOUND( - "No such room member"); - } - - third_party = data.thirdparty; - - return data.profile; - } - - /** - * Removes a member from the member list. - */ - public void - remove_member(string user_id) - throws Matrix.Error - { - MemberData? data = null; - - if ((data = _members[user_id]) == null) { - throw new Matrix.Error.NOT_FOUND( - "No such room member"); - } - - _members.remove(user_id); - } - - /** - * Clear the stored individual user levels. This should be called - * e.g. when receiving a new m.room.power_levels event. - */ - public void - clear_user_levels() - { - _user_levels.remove_all(); - } - - /** - * Set an individual power level for a user. - * - * @param user_id a fully qualified Matrix ID - * @param level the new power level - */ - public void - set_user_level(string user_id, int level) - { - _user_levels[user_id] = level; - } - - /** - * Get the power level of a user. - * - * @param user_id a fully qualified Matrix ID - * @return the level of the user. If the user doesn’t have an - * individually set power level, the default value is - * returned - */ - public int - get_user_level(string user_id) - { - int? level = _user_levels[user_id]; - - if (level == null) { - level = _default_power_level; - } - - return level; - } - - /** - * Clear the stored event level requirements. This should be - * called e.g. when receiving a new m.room.power_levels event. - */ - public void - clear_event_levels() - { - _event_levels.remove_all(); - } - - /** - * Set the required level to send an event of - * type @param event_type. - * - * @param event_type the event type to restrict - * @param level the desired level for the event type - */ - public void - set_event_level(string event_type, int level) - { - _event_levels[event_type] = level; - } - - /** - * Get the required level to send an event of - * type @param event_type. - * - * @param event_type the event type to query - * @return the level required to send a specific event. If there - * is no level requirement is set for this event type, - * this function returns null as there is no way to decide - * if {@link Matrix.Room.default_state_level} or - * {@link Matrix.Room.default_event_level} should be used - */ - public int? - get_event_level(string event_type) - { - return _event_levels[event_type]; - } -} diff --git a/vapi/c-api.vapi b/vapi/c-api.vapi index e83cca5..31a392d 100644 --- a/vapi/c-api.vapi +++ b/vapi/c-api.vapi @@ -405,6 +405,61 @@ namespace Matrix { throws Matrix.Error; } + [CCode (cheader_filename = "matrix-room.h")] + public class Room : GLib.Object { + public string room_id { get; construct; } + public string[] aliases { get; set; } + public string? avatar_url { get; set; default = null; } + public Matrix.ImageInfo? avatar_info { get; set; default = null; } + public string? avatar_thumbnail_url { get; set; default = null; } + public Matrix.ImageInfo? avatar_thumbnail_info { get; set; default = null; } + public string? canonical_alias { get; set; default = null; } + public string? creator { get; set; default = null; } + public bool federate { get; set; default = false; } + public Matrix.GuestAccess guest_access { get; set; default = Matrix.GuestAccess.UNKNOWN; } + public Matrix.HistoryVisibility history_visibility { get; set; default = Matrix.HistoryVisibility.UNKNOWN; } + public Matrix.JoinRules join_rules { get; set; default = Matrix.JoinRules.UNKNOWN; } + public string? name { get; set; default = null; } + public int default_power_level { get; set; default = 0; } + public int default_event_level { get; set; default = 0; } + public int default_state_level { get; set; default = 10; } + public int ban_level { get; set; default = 5; } + public int kick_level { get; set; default = 5; } + public int redact_level { get; set; default = 20; } + public int invite_level { get; set; default = 0; } + public string? topic { get; set; default = null; } + public string[] typing_users { get; set; } + + public Room(string room_id); + + public void add_member(string user_id, Profile? profile, bool third_party) + throws Matrix.Error; + + public Profile + get_or_add_member(string user_id, bool third_party = false) + throws Matrix.Error; + + public Profile + get_member(string user_id, out bool third_party) + throws Matrix.Error; + + public void + remove_member(string user_id) + throws Matrix.Error; + + public void clear_user_levels(); + + public void set_user_level(string user_id, int level); + + public int get_user_level(string user_id) + throws Matrix.Error; + + public void clear_event_levels(); + + public void set_event_level(string event_type, int level); + + public int? get_event_level(string event_type); + } /* Utilities */ [CCode (cheader_filename = "utils.h", cname = "_matrix_g_enum_to_string")] public string? _g_enum_value_to_nick(GLib.Type enum_type, int value, char convert_dashes = '_');