Port MatrixHTTPClient to C
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -47,7 +47,6 @@ Makefile.in
 | 
			
		||||
/src/vala-temp
 | 
			
		||||
/src/vala-stamp
 | 
			
		||||
/src/matrix-glib.h
 | 
			
		||||
/src/matrix-http-client.c
 | 
			
		||||
/src/namespace-info.vala
 | 
			
		||||
/src/namespace-info.c
 | 
			
		||||
/src/matrix-glib-0.0.pc
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ lib_LTLIBRARIES = libmatrix-glib-0.0.la
 | 
			
		||||
# Vala source files
 | 
			
		||||
libmatrix_glib_0_0_la_VALA_SOURCES = \
 | 
			
		||||
	namespace-info.vala \
 | 
			
		||||
	matrix-http-client.vala \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
AM_CPPFLAGS += \
 | 
			
		||||
@@ -76,6 +75,7 @@ INST_H_SRC_FILES = \
 | 
			
		||||
	matrix-api.h \
 | 
			
		||||
	matrix-http-api.h \
 | 
			
		||||
	matrix-client.h \
 | 
			
		||||
	matrix-http-client.h \
 | 
			
		||||
	matrix-event-base.h \
 | 
			
		||||
	matrix-event-call-base.h \
 | 
			
		||||
	matrix-event-call-answer.h \
 | 
			
		||||
@@ -136,6 +136,7 @@ libmatrix_glib_0_0_la_SOURCES = \
 | 
			
		||||
	matrix-api.c \
 | 
			
		||||
	matrix-http-api.c \
 | 
			
		||||
	matrix-client.c \
 | 
			
		||||
	matrix-http-client.c \
 | 
			
		||||
	matrix-types.c \
 | 
			
		||||
	matrix-compacts.c \
 | 
			
		||||
	matrix-event-base.c \
 | 
			
		||||
 
 | 
			
		||||
@@ -314,7 +314,7 @@ _matrix_http_api_response_callback(SoupSession *session, SoupMessage *msg, gpoin
 | 
			
		||||
                                          "Malformed response (invalid JSON)");
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
                g_debug("Malformed response (%s): %s", request_url, data);
 | 
			
		||||
                g_debug("Malformed response (%s): %s", request_url, buffer->data);
 | 
			
		||||
#endif
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										911
									
								
								src/matrix-http-client.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										911
									
								
								src/matrix-http-client.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,911 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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
 | 
			
		||||
 * <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "matrix-http-client.h"
 | 
			
		||||
#include "matrix-client.h"
 | 
			
		||||
#include "matrix-event-room-base.h"
 | 
			
		||||
#include "matrix-event-presence.h"
 | 
			
		||||
#include "matrix-event-room-member.h"
 | 
			
		||||
#include "matrix-event-room-aliases.h"
 | 
			
		||||
#include "matrix-event-room-avatar.h"
 | 
			
		||||
#include "matrix-event-room-canonical-alias.h"
 | 
			
		||||
#include "matrix-event-room-create.h"
 | 
			
		||||
#include "matrix-event-room-guest-access.h"
 | 
			
		||||
#include "matrix-event-room-history-visibility.h"
 | 
			
		||||
#include "matrix-event-room-join-rules.h"
 | 
			
		||||
#include "matrix-event-room-name.h"
 | 
			
		||||
#include "matrix-event-room-power-levels.h"
 | 
			
		||||
#include "matrix-event-room-topic.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:matrix-http-client
 | 
			
		||||
 * @short_description: event-driven communication with Matrix.org homeserver via HTTP.
 | 
			
		||||
 *
 | 
			
		||||
 * An event-driven client class to communicate with HTTP based Matrix.org servers.
 | 
			
		||||
 */
 | 
			
		||||
static void matrix_http_client_matrix_client_interface_init (MatrixClientInterface * iface);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    gboolean _polling;
 | 
			
		||||
    gulong _event_timeout;
 | 
			
		||||
    gchar* _last_sync_token;
 | 
			
		||||
    GHashTable* _user_global_profiles;
 | 
			
		||||
    GHashTable* _user_global_presence;
 | 
			
		||||
    GHashTable* _rooms;
 | 
			
		||||
    gulong _last_txn_id;
 | 
			
		||||
} MatrixHTTPClientPrivate;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_EXTENDED(MatrixHTTPClient, matrix_http_client, MATRIX_TYPE_HTTP_API, 0, G_ADD_PRIVATE(MatrixHTTPClient) G_IMPLEMENT_INTERFACE(MATRIX_TYPE_CLIENT, matrix_http_client_matrix_client_interface_init));
 | 
			
		||||
 | 
			
		||||
MatrixHTTPClient *
 | 
			
		||||
matrix_http_client_new(const gchar* base_url)
 | 
			
		||||
{
 | 
			
		||||
    g_return_val_if_fail(base_url != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    return (MatrixHTTPClient *)g_object_new(MATRIX_TYPE_HTTP_CLIENT,
 | 
			
		||||
                                            "base-url", base_url,
 | 
			
		||||
                                            NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
login_callback(MatrixAPI *matrix_api, const gchar *content_type, JsonNode *json_content, GByteArray *raw_content, GError *err, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    g_signal_emit_by_name((MatrixClient *)matrix_api,
 | 
			
		||||
                          "login-finished",
 | 
			
		||||
                          g_error_matches(err, MATRIX_ERROR, MATRIX_ERROR_NONE));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_login_with_password(MatrixClient *matrix_client, const gchar *username, const gchar *password, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    JsonBuilder *builder;
 | 
			
		||||
    JsonNode *root_node;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (username != NULL);
 | 
			
		||||
    g_return_if_fail (password != NULL);
 | 
			
		||||
 | 
			
		||||
    builder = json_builder_new();
 | 
			
		||||
 | 
			
		||||
    json_builder_begin_object(builder);
 | 
			
		||||
 | 
			
		||||
    json_builder_set_member_name(builder, "user");
 | 
			
		||||
    json_builder_add_string_value(builder, username);
 | 
			
		||||
 | 
			
		||||
    json_builder_set_member_name(builder, "password");
 | 
			
		||||
    json_builder_add_string_value(builder, password);
 | 
			
		||||
 | 
			
		||||
    json_builder_end_object(builder);
 | 
			
		||||
    root_node = json_builder_get_root(builder);
 | 
			
		||||
 | 
			
		||||
    matrix_api_login(MATRIX_API(matrix_client), "m.login.password", root_node, login_callback, NULL, error);
 | 
			
		||||
 | 
			
		||||
    json_node_unref(root_node);
 | 
			
		||||
    g_object_unref(builder);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_register_with_password(MatrixClient *matrix_client, const gchar *username, const gchar *password, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    matrix_api_register_account(MATRIX_API(matrix_client),
 | 
			
		||||
                                MATRIX_ACCOUNT_KIND_USER, FALSE, username, password,
 | 
			
		||||
                                login_callback, NULL,
 | 
			
		||||
                                error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
logout_callback(MatrixAPI *matrix_api, const gchar *content_type, JsonNode *json_content, GByteArray *raw_content, GError *err, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    matrix_api_abort_pending(matrix_api);
 | 
			
		||||
    matrix_api_set_token(matrix_api, NULL);
 | 
			
		||||
    matrix_api_set_refresh_token(matrix_api, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_logout(MatrixClient *matrix_client, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    matrix_api_logout(MATRIX_API(matrix_client), logout_callback, NULL, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MatrixRoom *
 | 
			
		||||
_get_or_create_room(MatrixHTTPClient *matrix_http_client, const gchar *room_id)
 | 
			
		||||
{
 | 
			
		||||
    MatrixRoom *room = NULL;
 | 
			
		||||
    MatrixHTTPClientPrivate *priv;
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail(matrix_http_client != NULL, NULL);
 | 
			
		||||
    g_return_val_if_fail(room_id != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    priv = matrix_http_client_get_instance_private(matrix_http_client);
 | 
			
		||||
 | 
			
		||||
    if ((room = g_hash_table_lookup(priv->_rooms, room_id)) == NULL) {
 | 
			
		||||
        room = matrix_room_new(room_id);
 | 
			
		||||
        g_hash_table_insert(priv->_rooms, g_strdup(room_id), room);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return room;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
_process_event(MatrixHTTPClient *matrix_http_client, JsonNode *event_node, const gchar *room_id)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv;
 | 
			
		||||
    JsonObject *root;
 | 
			
		||||
    JsonNode *node;
 | 
			
		||||
    const gchar *event_type;
 | 
			
		||||
    MatrixEventBase *evt = NULL;
 | 
			
		||||
    GError *inner_error = NULL;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail(matrix_http_client != NULL);
 | 
			
		||||
    g_return_if_fail(event_node != NULL);
 | 
			
		||||
 | 
			
		||||
    if (json_node_get_node_type(event_node) != JSON_NODE_OBJECT) {
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_warning("Received event that is not an object.");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    root = json_node_get_object(event_node);
 | 
			
		||||
 | 
			
		||||
    if ((node = json_object_get_member(root, "type")) == NULL) {
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_warning("Received event without type.");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    priv = matrix_http_client_get_instance_private(matrix_http_client);
 | 
			
		||||
    event_type = json_node_get_string(node);
 | 
			
		||||
    evt = matrix_event_base_new_from_json(event_type, event_node, &inner_error);
 | 
			
		||||
 | 
			
		||||
    if (inner_error != NULL) {
 | 
			
		||||
        evt = NULL;
 | 
			
		||||
        g_clear_error(&inner_error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (evt != NULL) {
 | 
			
		||||
        if (MATRIX_EVENT_IS_ROOM(evt)) {
 | 
			
		||||
            MatrixEventRoom *revt = MATRIX_EVENT_ROOM(evt);
 | 
			
		||||
 | 
			
		||||
            // Make sure Room events have room_id set, even if it was stripped by the HS
 | 
			
		||||
            if (matrix_event_room_get_room_id(revt) == NULL) {
 | 
			
		||||
                matrix_event_room_set_room_id(revt, room_id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        else if (MATRIX_EVENT_IS_PRESENCE(evt)) {
 | 
			
		||||
            MatrixEventPresence *pevt = MATRIX_EVENT_PRESENCE(evt);
 | 
			
		||||
            const gchar *user_id = matrix_event_presence_get_user_id(pevt);
 | 
			
		||||
            MatrixProfile *profile;
 | 
			
		||||
 | 
			
		||||
            g_hash_table_replace(priv->_user_global_presence, g_strdup(user_id), GINT_TO_POINTER(matrix_event_presence_get_presence(pevt)));
 | 
			
		||||
 | 
			
		||||
            profile = g_hash_table_lookup(priv->_user_global_profiles, user_id);
 | 
			
		||||
 | 
			
		||||
            if (profile == NULL) {
 | 
			
		||||
                profile = matrix_profile_new();
 | 
			
		||||
                g_hash_table_insert(priv->_user_global_profiles, g_strdup(user_id), profile);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            matrix_profile_set_avatar_url(profile, matrix_event_presence_get_avatar_url(pevt));
 | 
			
		||||
            matrix_profile_set_display_name(profile, matrix_event_presence_get_display_name(pevt));
 | 
			
		||||
        } else if (MATRIX_EVENT_IS_ROOM(evt)) {
 | 
			
		||||
            MatrixEventRoom *revt = MATRIX_EVENT_ROOM(evt);
 | 
			
		||||
            MatrixRoom *room = _get_or_create_room(matrix_http_client, matrix_event_room_get_room_id(revt));
 | 
			
		||||
 | 
			
		||||
            if (MATRIX_EVENT_IS_ROOM_MEMBER(evt)) {
 | 
			
		||||
                MatrixEventRoomMember *mevt = MATRIX_EVENT_ROOM_MEMBER(evt);
 | 
			
		||||
                const gchar *user_id = matrix_event_room_member_get_user_id(mevt);
 | 
			
		||||
                MatrixProfile *profile = matrix_room_get_or_add_member(room, user_id, matrix_event_room_member_get_tpi_display_name(mevt) != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
                matrix_profile_set_avatar_url(profile, matrix_event_room_member_get_avatar_url(mevt));
 | 
			
		||||
                matrix_profile_set_display_name(profile, matrix_event_room_member_get_display_name(mevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_ALIASES(evt)) {
 | 
			
		||||
                gint n_aliases;
 | 
			
		||||
                const gchar **aliases;
 | 
			
		||||
                MatrixEventRoomAliases *aevt = MATRIX_EVENT_ROOM_ALIASES(evt);
 | 
			
		||||
 | 
			
		||||
                aliases = matrix_event_room_aliases_get_aliases(aevt, &n_aliases);
 | 
			
		||||
                matrix_room_set_aliases(room, aliases, n_aliases);
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_AVATAR(evt)) {
 | 
			
		||||
                MatrixEventRoomAvatar *aevt = MATRIX_EVENT_ROOM_AVATAR(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_avatar_url(room, matrix_event_room_avatar_get_url(aevt));
 | 
			
		||||
                matrix_room_set_avatar_info(room, matrix_event_room_avatar_get_info(aevt));
 | 
			
		||||
                matrix_room_set_avatar_thumbnail_url(room, matrix_event_room_avatar_get_thumbnail_url(aevt));
 | 
			
		||||
                matrix_room_set_avatar_thumbnail_info(room, matrix_event_room_avatar_get_thumbnail_info(aevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_CANONICAL_ALIAS(evt)) {
 | 
			
		||||
                MatrixEventRoomCanonicalAlias *cevt = MATRIX_EVENT_ROOM_CANONICAL_ALIAS(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_canonical_alias(room, matrix_event_room_canonical_alias_get_canonical_alias(cevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_CREATE(evt)) {
 | 
			
		||||
                MatrixEventRoomCreate *cevt = MATRIX_EVENT_ROOM_CREATE(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_creator(room, matrix_event_room_create_get_creator(cevt));
 | 
			
		||||
                matrix_room_set_federate(room, matrix_event_room_create_get_federate(cevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_GUEST_ACCESS(evt)) {
 | 
			
		||||
                MatrixEventRoomGuestAccess *gevt = MATRIX_EVENT_ROOM_GUEST_ACCESS(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_guest_access(room, matrix_event_room_guest_access_get_guest_access(gevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_HISTORY_VISIBILITY(evt)) {
 | 
			
		||||
                MatrixEventRoomHistoryVisibility *hevt = MATRIX_EVENT_ROOM_HISTORY_VISIBILITY(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_history_visibility(room, matrix_event_room_history_visibility_get_visibility(hevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_JOIN_RULES(evt)) {
 | 
			
		||||
                MatrixEventRoomJoinRules *jevt = MATRIX_EVENT_ROOM_JOIN_RULES(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_join_rules(room, matrix_event_room_join_rules_get_join_rules(jevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_ROOM_NAME(evt)) {
 | 
			
		||||
                MatrixEventRoomName *nevt = MATRIX_EVENT_ROOM_NAME(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_name(room, matrix_event_room_name_get_name(nevt));
 | 
			
		||||
            } else if (MATRIX_EVENT_ROOM_POWER_LEVELS(evt)) {
 | 
			
		||||
                MatrixEventRoomPowerLevels *levt = MATRIX_EVENT_ROOM_POWER_LEVELS(evt);
 | 
			
		||||
                GHashTable *user_levels;
 | 
			
		||||
                GHashTable *event_levels;
 | 
			
		||||
                GHashTableIter iter;
 | 
			
		||||
                gchar *key;
 | 
			
		||||
                gpointer level;
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_default_power_level(room, matrix_event_room_power_levels_get_users_default(levt));
 | 
			
		||||
                matrix_room_set_default_event_level(room, matrix_event_room_power_levels_get_events_default(levt));
 | 
			
		||||
                matrix_room_set_default_state_level(room, matrix_event_room_power_levels_get_state_default(levt));
 | 
			
		||||
                matrix_room_set_ban_level(room, matrix_event_room_power_levels_get_ban(levt));
 | 
			
		||||
                matrix_room_set_kick_level(room, matrix_event_room_power_levels_get_kick(levt));
 | 
			
		||||
                matrix_room_set_redact_level(room, matrix_event_room_power_levels_get_redact(levt));
 | 
			
		||||
                matrix_room_set_invite_level(room, matrix_event_room_power_levels_get_invite(levt));
 | 
			
		||||
                matrix_room_clear_user_levels(room);
 | 
			
		||||
                matrix_room_clear_event_levels(room);
 | 
			
		||||
 | 
			
		||||
                user_levels = matrix_event_room_power_levels_get_user_levels(levt);
 | 
			
		||||
                g_hash_table_iter_init(&iter, user_levels);
 | 
			
		||||
 | 
			
		||||
                while (g_hash_table_iter_next(&iter, (gpointer *)&key, &level)) {
 | 
			
		||||
                    matrix_room_set_user_level(room, key, GPOINTER_TO_INT(level));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                event_levels = matrix_event_room_power_levels_get_event_levels(levt);
 | 
			
		||||
                g_hash_table_iter_init(&iter, event_levels);
 | 
			
		||||
 | 
			
		||||
                while (g_hash_table_iter_next(&iter, (gpointer *)&key, &level)) {
 | 
			
		||||
                    matrix_room_set_event_level(room, key, GPOINTER_TO_INT(level));
 | 
			
		||||
                }
 | 
			
		||||
            } else if (MATRIX_EVENT_IS_ROOM_TOPIC(evt)) {
 | 
			
		||||
                MatrixEventRoomTopic *tevt = MATRIX_EVENT_ROOM_TOPIC(evt);
 | 
			
		||||
 | 
			
		||||
                matrix_room_set_topic(room, matrix_event_room_topic_get_topic(tevt));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    matrix_client_incoming_event(MATRIX_CLIENT(matrix_http_client), room_id, event_node, evt);
 | 
			
		||||
    g_object_unref(evt);
 | 
			
		||||
    json_node_unref(node);
 | 
			
		||||
    json_object_unref(root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
_process_event_list_obj(MatrixHTTPClient *matrix_http_client, JsonNode* node, const gchar* room_id)
 | 
			
		||||
{
 | 
			
		||||
    JsonObject *root;
 | 
			
		||||
    JsonNode *events_node;
 | 
			
		||||
 | 
			
		||||
    root = json_node_get_object(node);
 | 
			
		||||
 | 
			
		||||
    if ((events_node = json_object_get_member(root, "events")) != NULL) {
 | 
			
		||||
        if (json_node_get_node_type(events_node) == JSON_NODE_ARRAY) {
 | 
			
		||||
            JsonArray *events_array = json_node_get_array(events_node);
 | 
			
		||||
            gint len = json_array_get_length(events_array);
 | 
			
		||||
 | 
			
		||||
            for (gint idx = 0; idx < len; idx++) {
 | 
			
		||||
                JsonNode *event_node = json_array_get_element(events_array, idx);
 | 
			
		||||
 | 
			
		||||
                _process_event(matrix_http_client, event_node, room_id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
refresh_callback(MatrixAPI *matrix_api, const gchar *content_type, JsonNode *json_content, GByteArray *raw_content, GError *err, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    g_signal_emit_by_name(MATRIX_CLIENT(matrix_api), "login-finished", g_error_matches(err, MATRIX_ERROR, MATRIX_ERROR_NONE));
 | 
			
		||||
 | 
			
		||||
    if (matrix_api_get_token(matrix_api) == NULL) {
 | 
			
		||||
        matrix_api_set_refresh_token(matrix_api, NULL);
 | 
			
		||||
        g_signal_emit_by_name(MATRIX_CLIENT(matrix_api), "polling-stopped", err);
 | 
			
		||||
 | 
			
		||||
        matrix_client_stop_polling(MATRIX_CLIENT(matrix_api), FALSE, NULL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
cb_sync(MatrixAPI *matrix_api, const gchar *content_type, JsonNode *json_content, GByteArray *raw_content, GError *error, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(matrix_api));
 | 
			
		||||
 | 
			
		||||
    if (error == NULL) {
 | 
			
		||||
        JsonObject *root = json_node_get_object(json_content);
 | 
			
		||||
        JsonNode *node;
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_debug("Processing account data");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        _process_event_list_obj(MATRIX_HTTP_CLIENT(matrix_api), json_object_get_member(root, "account_data"), NULL);
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_debug("Processing presence");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        _process_event_list_obj(MATRIX_HTTP_CLIENT(matrix_api), json_object_get_member(root, "presence"), NULL);
 | 
			
		||||
 | 
			
		||||
        if ((node = json_object_get_member(root, "rooms")) != NULL) {
 | 
			
		||||
            if (json_node_get_node_type(node) == JSON_NODE_OBJECT) {
 | 
			
		||||
                JsonObject *rooms_root = json_node_get_object(node);
 | 
			
		||||
                JsonNode *rooms_node;
 | 
			
		||||
                        MatrixHTTPClient *matrix_http_client = MATRIX_HTTP_CLIENT(matrix_api);
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
                g_debug("Processing rooms");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
                if ((rooms_node = json_object_get_member(rooms_root, "invite")) != NULL) {
 | 
			
		||||
                    JsonObjectIter iter;
 | 
			
		||||
                    const gchar *room_id;
 | 
			
		||||
                    JsonNode *room_node;
 | 
			
		||||
 | 
			
		||||
                    json_object_iter_init(&iter, json_node_get_object(rooms_node));
 | 
			
		||||
 | 
			
		||||
                    while (json_object_iter_next(&iter, &room_id, &room_node)) {
 | 
			
		||||
                        JsonObject *room_root;
 | 
			
		||||
 | 
			
		||||
                        if (json_node_get_node_type(room_node) != JSON_NODE_OBJECT) {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        room_root = json_node_get_object(room_node);
 | 
			
		||||
 | 
			
		||||
                        _process_event_list_obj(MATRIX_HTTP_CLIENT(matrix_api), json_object_get_member(room_root, "invite_state"), room_id);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ((rooms_node = json_object_get_member(rooms_root, "join")) != NULL) {
 | 
			
		||||
                    JsonObjectIter iter;
 | 
			
		||||
                    const gchar *room_id;
 | 
			
		||||
                    JsonNode *room_node;
 | 
			
		||||
 | 
			
		||||
                    json_object_iter_init(&iter, json_node_get_object(rooms_node));
 | 
			
		||||
 | 
			
		||||
                    while (json_object_iter_next(&iter, &room_id, &room_node)) {
 | 
			
		||||
                        JsonObject *room_root;
 | 
			
		||||
 | 
			
		||||
                        if (json_node_get_node_type(room_node) != JSON_NODE_OBJECT) {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        room_root = json_node_get_object(room_node);
 | 
			
		||||
 | 
			
		||||
                        _process_event_list_obj(matrix_http_client, json_object_get_member(room_root, "timeline"), room_id);
 | 
			
		||||
                        _process_event_list_obj(matrix_http_client, json_object_get_member(room_root, "state"), room_id);
 | 
			
		||||
                        _process_event_list_obj(matrix_http_client, json_object_get_member(room_root, "account_data"), room_id);
 | 
			
		||||
                        _process_event_list_obj(matrix_http_client, json_object_get_member(room_root, "ephemeral"), room_id);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ((rooms_node = json_object_get_member(rooms_root, "leave")) != NULL) {
 | 
			
		||||
                    JsonObjectIter iter;
 | 
			
		||||
                    const gchar *room_id;
 | 
			
		||||
                    JsonNode *room_node;
 | 
			
		||||
 | 
			
		||||
                    json_object_iter_init(&iter, json_node_get_object(rooms_node));
 | 
			
		||||
 | 
			
		||||
                    while (json_object_iter_next(&iter, &room_id, &room_node)) {
 | 
			
		||||
                        JsonObject *room_root;
 | 
			
		||||
 | 
			
		||||
                        if (json_node_get_node_type(room_node) != JSON_NODE_OBJECT) {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        room_root = json_node_get_object(room_node);
 | 
			
		||||
 | 
			
		||||
                        _process_event_list_obj(matrix_http_client, json_object_get_member(room_root, "timeline"), room_id);
 | 
			
		||||
                        _process_event_list_obj(matrix_http_client, json_object_get_member(room_root, "state"), room_id);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((node = json_object_get_member(root, "next_batch")) != NULL) {
 | 
			
		||||
            g_free(priv->_last_sync_token);
 | 
			
		||||
            priv->_last_sync_token = g_strdup(json_node_get_string(node));
 | 
			
		||||
        }
 | 
			
		||||
    } else if ((error->domain == MATRIX_ERROR) &&
 | 
			
		||||
               ((error->code == MATRIX_ERROR_M_FORBIDDEN) ||
 | 
			
		||||
                (error->code == MATRIX_ERROR_M_UNKNOWN_TOKEN) ||
 | 
			
		||||
                (error->code == MATRIX_ERROR_M_UNAUTHORIZED))) {
 | 
			
		||||
        matrix_api_set_token(matrix_api, NULL);
 | 
			
		||||
        matrix_api_token_refresh(matrix_api,
 | 
			
		||||
                                 NULL,
 | 
			
		||||
                                 refresh_callback, NULL,
 | 
			
		||||
                                 NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // It is possible that polling has been disabled while we were processing events. Don’t
 | 
			
		||||
    // continue polling if that is the case.
 | 
			
		||||
    if (priv->_polling) {
 | 
			
		||||
        if ((error == NULL) || (error->code < MATRIX_ERROR_M_MISSING_TOKEN)) {
 | 
			
		||||
            matrix_client_begin_polling(MATRIX_CLIENT(matrix_api), NULL);
 | 
			
		||||
        } else if ((error != NULL) && (error->code >= MATRIX_ERROR_M_MISSING_TOKEN)) {
 | 
			
		||||
            g_signal_emit_by_name(MATRIX_CLIENT(matrix_api), "polling-stopped", error);
 | 
			
		||||
            matrix_client_stop_polling(MATRIX_CLIENT(matrix_api), FALSE, NULL);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_begin_polling(MatrixClient *matrix_client, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(matrix_client));
 | 
			
		||||
    GError *inner_error = NULL;
 | 
			
		||||
 | 
			
		||||
    matrix_api_sync(MATRIX_API(matrix_client),
 | 
			
		||||
                    NULL, NULL,
 | 
			
		||||
                    priv->_last_sync_token, FALSE, FALSE,
 | 
			
		||||
                    priv->_event_timeout,
 | 
			
		||||
                    cb_sync, NULL,
 | 
			
		||||
                    &inner_error);
 | 
			
		||||
 | 
			
		||||
    if (inner_error != NULL) {
 | 
			
		||||
        g_propagate_error(error, inner_error);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (priv->_polling == FALSE) {
 | 
			
		||||
        g_signal_emit_by_name (matrix_client, "polling-started");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    priv->_polling = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_stop_polling (MatrixClient *matrix_client, gboolean cancel_ongoing, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(matrix_client));
 | 
			
		||||
 | 
			
		||||
    priv->_polling = FALSE;
 | 
			
		||||
 | 
			
		||||
    if (cancel_ongoing) {
 | 
			
		||||
        matrix_api_abort_pending(MATRIX_API(matrix_client));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MatrixProfile *
 | 
			
		||||
matrix_http_client_real_get_user_profile(MatrixClient *matrix_client, const gchar *user_id, const gchar *room_id, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(matrix_client));
 | 
			
		||||
    MatrixRoom *room;
 | 
			
		||||
 | 
			
		||||
    if (room_id == NULL) {
 | 
			
		||||
        MatrixProfile *profile = g_hash_table_lookup(priv->_user_global_profiles, user_id);
 | 
			
		||||
 | 
			
		||||
        if (profile == NULL) {
 | 
			
		||||
            g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_UNAVAILABLE,
 | 
			
		||||
                        "Global profile for %s is not cached yet.",
 | 
			
		||||
                        user_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return profile;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((room = g_hash_table_lookup(priv->_rooms, room_id)) == NULL) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_UNAVAILABLE,
 | 
			
		||||
                    "Room data for %s is not cached yet.", room_id);
 | 
			
		||||
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return matrix_room_get_member(room, user_id, NULL, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MatrixPresence
 | 
			
		||||
matrix_http_client_real_get_user_presence(MatrixClient *matrix_client, const gchar *user_id, const gchar *room_id, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(matrix_client));
 | 
			
		||||
    gpointer value;
 | 
			
		||||
 | 
			
		||||
    if (room_id != NULL) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_UNSUPPORTED,
 | 
			
		||||
                    "Per-room presences are not supported yet.");
 | 
			
		||||
 | 
			
		||||
        return MATRIX_PRESENCE_UNKNOWN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!g_hash_table_lookup_extended(priv->_user_global_presence, user_id, NULL, &value)) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_UNAVAILABLE,
 | 
			
		||||
                    "Global presence for %s is not cached yet.",
 | 
			
		||||
                    user_id);
 | 
			
		||||
 | 
			
		||||
        return MATRIX_PRESENCE_UNKNOWN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GPOINTER_TO_INT(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MatrixRoom *
 | 
			
		||||
matrix_http_client_real_get_room_by_id(MatrixClient *matrix_client, const gchar *room_id, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv;
 | 
			
		||||
    MatrixRoom *room;
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail(room_id != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(matrix_client));
 | 
			
		||||
 | 
			
		||||
    if ((room = g_hash_table_lookup(priv->_rooms, room_id)) == NULL) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_UNAVAILABLE,
 | 
			
		||||
                    "Room data for %s is not cached yet.", room_id);
 | 
			
		||||
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return room;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MatrixRoom *
 | 
			
		||||
matrix_http_client_real_get_room_by_alias(MatrixClient *matrix_client, const gchar *room_alias, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv;
 | 
			
		||||
    MatrixRoom *room_found = NULL;
 | 
			
		||||
    GHashTableIter iter;
 | 
			
		||||
    gpointer key;
 | 
			
		||||
    gpointer value;
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (room_alias != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(matrix_client));
 | 
			
		||||
 | 
			
		||||
    g_hash_table_iter_init(&iter, priv->_rooms);
 | 
			
		||||
 | 
			
		||||
    while (g_hash_table_iter_next(&iter, &key, &value)) {
 | 
			
		||||
        MatrixRoom *room = value;
 | 
			
		||||
        gchar **aliases;
 | 
			
		||||
        gint n_aliases;
 | 
			
		||||
 | 
			
		||||
        if (g_strcmp0(room_alias, matrix_room_get_canonical_alias(room)) == 0) {
 | 
			
		||||
            room_found = room;
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        aliases = matrix_room_get_aliases(room, &n_aliases);
 | 
			
		||||
 | 
			
		||||
        for (gint i = 0; i < n_aliases; i++) {
 | 
			
		||||
            if (g_strcmp0(room_alias, aliases[i]) == 0) {
 | 
			
		||||
                room_found = room;
 | 
			
		||||
 | 
			
		||||
                // Whee!
 | 
			
		||||
                goto found_room;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  found_room:
 | 
			
		||||
 | 
			
		||||
    if (room_found == NULL) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_UNAVAILABLE,
 | 
			
		||||
                    "No room data found for alias %s", room_alias);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return room_found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * matrix_http_client_next_txn_id:
 | 
			
		||||
 * @client: a #MatrixHTTPClient
 | 
			
		||||
 *
 | 
			
		||||
 * Get the next transaction ID to use.  It increments the internally stored value and returns
 | 
			
		||||
 * that, so it is guaranteed to be unique until we run out of #ulong boundaries.
 | 
			
		||||
 *
 | 
			
		||||
 * It is called internally by send().
 | 
			
		||||
 */
 | 
			
		||||
gulong
 | 
			
		||||
matrix_http_client_next_txn_id(MatrixHTTPClient *matrix_http_client)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv;
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail(matrix_http_client != NULL, 0UL);
 | 
			
		||||
 | 
			
		||||
    priv = matrix_http_client_get_instance_private(matrix_http_client);
 | 
			
		||||
 | 
			
		||||
    return ++(priv->_last_txn_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    MatrixClientSendCallback cb;
 | 
			
		||||
    gpointer callback_target;
 | 
			
		||||
} SendCallbackData;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
send_callback(MatrixAPI *matrix_api, const gchar *content_type, JsonNode *json_content, GByteArray *raw_content, GError *err, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    const gchar *event_id = NULL;
 | 
			
		||||
    GError *new_err = err;
 | 
			
		||||
    SendCallbackData *cb_data = user_data;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail(matrix_api != NULL);
 | 
			
		||||
 | 
			
		||||
    // If there is no callback, there is no point to continue
 | 
			
		||||
    if (cb_data->cb == NULL) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (err == NULL) {
 | 
			
		||||
        JsonObject *root = json_node_get_object(json_content);
 | 
			
		||||
 | 
			
		||||
        if (json_object_has_member(root, "event_id")) {
 | 
			
		||||
            event_id = json_object_get_string_member(root, "event_id");
 | 
			
		||||
        } else {
 | 
			
		||||
            new_err = g_error_new_literal(MATRIX_ERROR, MATRIX_ERROR_BAD_RESPONSE,
 | 
			
		||||
                                          "event_id is missing from an event response");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cb_data->cb(MATRIX_CLIENT(matrix_api), event_id, new_err, cb_data->callback_target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_send(MatrixClient *matrix_client, const gchar *room_id, MatrixEventBase *evt, MatrixClientSendCallback cb, void *cb_target, gulong txn_id, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    JsonNode *evt_node;
 | 
			
		||||
    JsonObject *evt_root;
 | 
			
		||||
    const gchar *state_key = NULL;
 | 
			
		||||
    SendCallbackData cb_data;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (room_id != NULL);
 | 
			
		||||
    g_return_if_fail (evt != NULL);
 | 
			
		||||
 | 
			
		||||
    evt_node = matrix_event_base_get_json(evt);
 | 
			
		||||
    evt_root = json_node_get_object(evt_node);
 | 
			
		||||
 | 
			
		||||
    if (json_object_has_member(evt_root, "state_key")) {
 | 
			
		||||
        state_key = json_object_get_string_member(evt_root, "state_key");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cb_data.cb = cb;
 | 
			
		||||
    cb_data.callback_target = cb_target;
 | 
			
		||||
 | 
			
		||||
    if (state_key != NULL) {
 | 
			
		||||
        matrix_api_send_state_event(MATRIX_API(matrix_client),
 | 
			
		||||
                                    room_id,
 | 
			
		||||
                                    matrix_event_base_get_event_type(evt),
 | 
			
		||||
                                    state_key,
 | 
			
		||||
                                    json_object_get_member(evt_root, "content"),
 | 
			
		||||
                                    send_callback, &cb_data,
 | 
			
		||||
                                    error);
 | 
			
		||||
    } else {
 | 
			
		||||
        txn_id = matrix_http_client_next_txn_id(MATRIX_HTTP_CLIENT(matrix_client));
 | 
			
		||||
        gchar *txn_id_str = g_strdup_printf("%lu", txn_id);
 | 
			
		||||
 | 
			
		||||
        matrix_api_send_event(MATRIX_API(matrix_client),
 | 
			
		||||
                              room_id,
 | 
			
		||||
                              matrix_event_base_get_event_type(evt),
 | 
			
		||||
                              txn_id_str,
 | 
			
		||||
                              json_object_get_member(evt_root, "content"),
 | 
			
		||||
                              send_callback, &cb_data,
 | 
			
		||||
                              error);
 | 
			
		||||
        g_free(txn_id_str);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_save_state(MatrixClient *matrix_client, const gchar *filename, GError * *error)
 | 
			
		||||
{
 | 
			
		||||
    JsonObject *root;
 | 
			
		||||
    const gchar *user_id;
 | 
			
		||||
    const gchar *homeserver;
 | 
			
		||||
    const gchar *token;
 | 
			
		||||
    const gchar *refresh_token;
 | 
			
		||||
    JsonNode *node;
 | 
			
		||||
    JsonGenerator *generator;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail(filename != NULL);
 | 
			
		||||
 | 
			
		||||
    root = json_object_new();
 | 
			
		||||
 | 
			
		||||
    json_object_set_string_member(root, "base_url", matrix_http_api_get_base_url(MATRIX_HTTP_API(matrix_client)));
 | 
			
		||||
 | 
			
		||||
    json_object_set_boolean_member(root, "validate_certificate", matrix_http_api_get_validate_certificate(MATRIX_HTTP_API(matrix_client)));
 | 
			
		||||
 | 
			
		||||
    if ((user_id = matrix_api_get_user_id(MATRIX_API(matrix_client))) != NULL) {
 | 
			
		||||
        json_object_set_string_member(root, "user_id", user_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((homeserver = matrix_api_get_homeserver(MATRIX_API(matrix_client))) != NULL) {
 | 
			
		||||
        json_object_set_string_member(root, "homeserver_name", homeserver);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((token = matrix_api_get_token(MATRIX_API(matrix_client))) != NULL) {
 | 
			
		||||
        json_object_set_string_member(root, "access_token", token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((refresh_token = matrix_api_get_refresh_token(MATRIX_API(matrix_client))) != NULL) {
 | 
			
		||||
        json_object_set_string_member(root, "refresh_token", refresh_token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    node = json_node_new(JSON_NODE_OBJECT);
 | 
			
		||||
    json_node_set_object(node, root);
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
    g_debug("Saving state to %s\n", filename);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    generator = json_generator_new();
 | 
			
		||||
    json_generator_set_root(generator, node);
 | 
			
		||||
    json_generator_to_file(generator, filename, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_real_load_state(MatrixClient *matrix_client, const gchar *filename, GError **error)
 | 
			
		||||
{
 | 
			
		||||
    JsonParser *parser;
 | 
			
		||||
    JsonNode *node;
 | 
			
		||||
    JsonNode *root_node;
 | 
			
		||||
    JsonObject *root;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail(filename != NULL);
 | 
			
		||||
 | 
			
		||||
    parser = json_parser_new();
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
    g_debug("Loading state from %s\n", filename);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (!json_parser_load_from_file(parser, filename, error)) {
 | 
			
		||||
        g_object_unref(parser);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    root_node = json_node_ref(json_parser_get_root(parser));
 | 
			
		||||
    g_object_unref(parser);
 | 
			
		||||
 | 
			
		||||
    if (json_node_get_node_type(root_node) != JSON_NODE_OBJECT) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_INVALID_FORMAT,
 | 
			
		||||
                    "Save data must be a JSON object.");
 | 
			
		||||
 | 
			
		||||
        json_node_unref(root_node);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    root = json_node_get_object(root_node);
 | 
			
		||||
 | 
			
		||||
    if ((node = json_object_get_member(root, "base_url")) == NULL) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_INVALID_FORMAT,
 | 
			
		||||
                    "Save data has no base_url key");
 | 
			
		||||
 | 
			
		||||
        json_node_unref(root_node);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    matrix_http_api_set_base_url(MATRIX_HTTP_API(matrix_client), json_node_get_string(node));
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
    g_debug("Loaded base URL %s", json_node_get_string(node));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if ((node = json_object_get_member(root, "validate_certificate")) == NULL) {
 | 
			
		||||
        g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_INVALID_FORMAT,
 | 
			
		||||
                    "Save data has no validate_certificate key");
 | 
			
		||||
 | 
			
		||||
        json_node_unref(root_node);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    matrix_http_api_set_validate_certificate(MATRIX_HTTP_API(matrix_client), json_node_get_boolean(node));
 | 
			
		||||
 | 
			
		||||
    if ((node = json_object_get_member(root, "user_id")) != NULL) {
 | 
			
		||||
        g_free(MATRIX_HTTP_API(matrix_client)->_user_id);
 | 
			
		||||
        MATRIX_HTTP_API(matrix_client)->_user_id = g_strdup(json_node_get_string(node));
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_debug("Loaded user ID %s", MATRIX_HTTP_API(matrix_client)->_user_id);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((node = json_object_get_member(root, "homeserver_name")) != NULL) {
 | 
			
		||||
        g_free(MATRIX_HTTP_API(matrix_client)->_homeserver);
 | 
			
		||||
        MATRIX_HTTP_API(matrix_client)->_homeserver = g_strdup(json_node_get_string(node));
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_debug("Loaded homeserver name %s", MATRIX_HTTP_API(matrix_client)->_homeserver);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((node = json_object_get_member(root, "access_token")) != NULL) {
 | 
			
		||||
        matrix_api_set_token(MATRIX_API(matrix_client), json_node_get_string(node));
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_debug("Loaded access token %s", matrix_api_get_token(MATRIX_API(matrix_client)));
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((node = json_object_get_member(root, "refresh_token")) != NULL) {
 | 
			
		||||
        matrix_api_set_refresh_token(MATRIX_API(matrix_client), json_node_get_string(node));
 | 
			
		||||
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        g_debug("Loaded refresh token %s", matrix_api_get_refresh_token(MATRIX_API(matrix_client)));
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    json_node_unref(root_node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_finalize(GObject *gobject)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv = matrix_http_client_get_instance_private(MATRIX_HTTP_CLIENT(gobject));
 | 
			
		||||
 | 
			
		||||
    g_free(priv->_last_sync_token);
 | 
			
		||||
    g_hash_table_unref(priv->_user_global_profiles);
 | 
			
		||||
    g_hash_table_unref(priv->_user_global_presence);
 | 
			
		||||
    g_hash_table_unref(priv->_rooms);
 | 
			
		||||
 | 
			
		||||
    G_OBJECT_CLASS(matrix_http_client_parent_class)->finalize(gobject);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_class_init(MatrixHTTPClientClass *klass)
 | 
			
		||||
{
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = matrix_http_client_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_matrix_client_interface_init(MatrixClientInterface * iface)
 | 
			
		||||
{
 | 
			
		||||
    iface->login_with_password = matrix_http_client_real_login_with_password;
 | 
			
		||||
    iface->register_with_password = matrix_http_client_real_register_with_password;
 | 
			
		||||
    iface->logout = matrix_http_client_real_logout;
 | 
			
		||||
    iface->begin_polling = matrix_http_client_real_begin_polling;
 | 
			
		||||
    iface->stop_polling = matrix_http_client_real_stop_polling;
 | 
			
		||||
    iface->get_user_profile = matrix_http_client_real_get_user_profile;
 | 
			
		||||
    iface->get_user_presence = matrix_http_client_real_get_user_presence;
 | 
			
		||||
    iface->get_room_by_id = matrix_http_client_real_get_room_by_id;
 | 
			
		||||
    iface->get_room_by_alias = matrix_http_client_real_get_room_by_alias;
 | 
			
		||||
    iface->send = matrix_http_client_real_send;
 | 
			
		||||
    iface->save_state = matrix_http_client_real_save_state;
 | 
			
		||||
    iface->load_state = matrix_http_client_real_load_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
matrix_http_client_init(MatrixHTTPClient *matrix_http_client)
 | 
			
		||||
{
 | 
			
		||||
    MatrixHTTPClientPrivate *priv = matrix_http_client_get_instance_private(matrix_http_client);
 | 
			
		||||
 | 
			
		||||
    priv->_polling = FALSE;
 | 
			
		||||
    priv->_event_timeout = (gulong)30000;
 | 
			
		||||
    priv->_user_global_profiles = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
 | 
			
		||||
    priv->_user_global_presence = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 | 
			
		||||
    priv->_rooms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
 | 
			
		||||
    priv->_last_txn_id = (gulong)0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								src/matrix-http-client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/matrix-http-client.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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
 | 
			
		||||
 * <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MATRIX_GLIB_SDK_HTTP_CLIENT_H__
 | 
			
		||||
# define __MATRIX_GLIB_SDK_HTTP_CLIENT_H__
 | 
			
		||||
 | 
			
		||||
# include <glib-object.h>
 | 
			
		||||
# include "matrix-http-api.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
# define MATRIX_TYPE_HTTP_CLIENT matrix_http_client_get_type()
 | 
			
		||||
G_DECLARE_DERIVABLE_TYPE(MatrixHTTPClient, matrix_http_client, MATRIX, HTTP_CLIENT, MatrixHTTPAPI)
 | 
			
		||||
 | 
			
		||||
struct _MatrixHTTPClientClass {
 | 
			
		||||
    MatrixHTTPAPIClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MatrixHTTPClient* matrix_http_client_new(const gchar* base_url);
 | 
			
		||||
gulong matrix_http_client_next_txn_id(MatrixHTTPClient *client);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __MATRIX_GLIB_SDK_HTTP_CLIENT_H__ */
 | 
			
		||||
@@ -1,711 +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
 | 
			
		||||
 * <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An event-driven client class to communicate with HTTP based
 | 
			
		||||
 * Matrix.org servers.
 | 
			
		||||
 */
 | 
			
		||||
public class Matrix.HTTPClient : Matrix.HTTPAPI, Matrix.Client {
 | 
			
		||||
    private bool _polling = false;
 | 
			
		||||
    private ulong _event_timeout = 30000;
 | 
			
		||||
    private string? _last_sync_token;
 | 
			
		||||
    private HashTable<string, Profile> _user_global_profiles =
 | 
			
		||||
        new HashTable<string, Profile>(str_hash, str_equal);
 | 
			
		||||
    private HashTable<string, Presence> _user_global_presence =
 | 
			
		||||
        new HashTable<string, Presence>(str_hash, str_equal);
 | 
			
		||||
    private HashTable<string, Room> _rooms =
 | 
			
		||||
        new HashTable<string, Room>(str_hash, str_equal);
 | 
			
		||||
    private ulong _last_txn_id = 0;
 | 
			
		||||
 | 
			
		||||
    public
 | 
			
		||||
    HTTPClient(string base_url)
 | 
			
		||||
    {
 | 
			
		||||
        Object(base_url : base_url);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void
 | 
			
		||||
    login_with_password(string username, string password)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        var builder = new Json.Builder();
 | 
			
		||||
 | 
			
		||||
        builder.begin_object();
 | 
			
		||||
 | 
			
		||||
        builder.set_member_name("user");
 | 
			
		||||
        builder.add_string_value(username);
 | 
			
		||||
 | 
			
		||||
        builder.set_member_name("password");
 | 
			
		||||
        builder.add_string_value(password);
 | 
			
		||||
 | 
			
		||||
        builder.end_object();
 | 
			
		||||
 | 
			
		||||
        login((i, content_type, json_content, raw_content, error) => {
 | 
			
		||||
                login_finished((error == null) || (error is Matrix.Error.NONE));
 | 
			
		||||
            },
 | 
			
		||||
            "m.login.password",
 | 
			
		||||
            builder.get_root());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void
 | 
			
		||||
    register_with_password(string? username, string password)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        register_account(
 | 
			
		||||
                (i, content_type, json_content, raw_content, error) => {
 | 
			
		||||
                    login_finished((error is Matrix.Error.NONE));
 | 
			
		||||
                },
 | 
			
		||||
                Matrix.AccountKind.USER,
 | 
			
		||||
                false, username, password);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public new void
 | 
			
		||||
    logout()
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        ((Matrix.API)this).logout(
 | 
			
		||||
            () => {
 | 
			
		||||
                token = null;
 | 
			
		||||
                refresh_token = null;
 | 
			
		||||
                abort_pending();
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void
 | 
			
		||||
    process_event(Json.Node event_node, string? room_id)
 | 
			
		||||
    {
 | 
			
		||||
        Json.Object root_obj;
 | 
			
		||||
        Json.Node node;
 | 
			
		||||
        string event_type;
 | 
			
		||||
        Matrix.Event.Base? evt = null;
 | 
			
		||||
 | 
			
		||||
        if (event_node.get_node_type() != Json.NodeType.OBJECT) {
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                warning("Received event that is not an object.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        root_obj = event_node.get_object();
 | 
			
		||||
 | 
			
		||||
        if ((node = root_obj.get_member("type")) == null) {
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                warning("Received event without type.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        event_type = node.get_string();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            evt = Matrix.Event.Base.new_from_json(event_type, event_node);
 | 
			
		||||
        } catch (GLib.Error e) {
 | 
			
		||||
            evt = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (evt != null) {
 | 
			
		||||
            // Make sure Room events have room_id set, even if it was
 | 
			
		||||
            // stripped by the HS
 | 
			
		||||
            if (evt is Matrix.Event.Room) {
 | 
			
		||||
                Matrix.Event.Room revt = (Matrix.Event.Room)evt;
 | 
			
		||||
 | 
			
		||||
                if (revt.room_id == null) {
 | 
			
		||||
                    revt.room_id = room_id;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (evt is Matrix.Event.Presence) {
 | 
			
		||||
                var pevt = (Matrix.Event.Presence)evt;
 | 
			
		||||
                var user_id = pevt.user_id;
 | 
			
		||||
 | 
			
		||||
                _user_global_presence[user_id] = pevt.presence;
 | 
			
		||||
 | 
			
		||||
                Profile? profile = _user_global_profiles[user_id];
 | 
			
		||||
 | 
			
		||||
                if (profile == null) {
 | 
			
		||||
                    profile = new Profile();
 | 
			
		||||
                    _user_global_profiles[user_id] = profile;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                profile.avatar_url = pevt.avatar_url;
 | 
			
		||||
                profile.display_name = pevt.display_name;
 | 
			
		||||
            } else if (evt is Matrix.Event.Room) {
 | 
			
		||||
                var revt = (Matrix.Event.Room)evt;
 | 
			
		||||
                var room = _get_or_create_room(revt.room_id);
 | 
			
		||||
 | 
			
		||||
                if (evt is Matrix.Event.RoomMember) {
 | 
			
		||||
                    var mevt = (Matrix.Event.RoomMember)evt;
 | 
			
		||||
                    var user_id = mevt.user_id;
 | 
			
		||||
                    Profile? profile = null;
 | 
			
		||||
 | 
			
		||||
                    try {
 | 
			
		||||
                        profile = room.get_or_add_member(
 | 
			
		||||
                                user_id,
 | 
			
		||||
                                (mevt.tpi_display_name != null));
 | 
			
		||||
                    } catch (Matrix.Error e) {}
 | 
			
		||||
 | 
			
		||||
                    profile.avatar_url = mevt.avatar_url;
 | 
			
		||||
                    profile.display_name = mevt.display_name;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomAliases) {
 | 
			
		||||
                    var aevt = (Matrix.Event.RoomAliases)evt;
 | 
			
		||||
 | 
			
		||||
                    room.aliases = aevt.aliases;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomAvatar) {
 | 
			
		||||
                    var aevt = (Matrix.Event.RoomAvatar)evt;
 | 
			
		||||
 | 
			
		||||
                    room.avatar_url = aevt.url;
 | 
			
		||||
                    room.avatar_info = aevt.info;
 | 
			
		||||
                    room.avatar_thumbnail_url = aevt.thumbnail_url;
 | 
			
		||||
                    room.avatar_thumbnail_info = aevt.thumbnail_info;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomCanonicalAlias) {
 | 
			
		||||
                    var cevt = (Matrix.Event.RoomCanonicalAlias)evt;
 | 
			
		||||
 | 
			
		||||
                    room.canonical_alias = cevt.canonical_alias;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomCreate) {
 | 
			
		||||
                    var cevt = (Matrix.Event.RoomCreate)evt;
 | 
			
		||||
 | 
			
		||||
                    room.creator = cevt.creator;
 | 
			
		||||
                    room.federate = cevt.federate;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomGuestAccess) {
 | 
			
		||||
                    var gevt = (Matrix.Event.RoomGuestAccess)evt;
 | 
			
		||||
 | 
			
		||||
                    room.guest_access = gevt.guest_access;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomHistoryVisibility) {
 | 
			
		||||
                    var hevt = (Matrix.Event.RoomHistoryVisibility)evt;
 | 
			
		||||
 | 
			
		||||
                    room.history_visibility = hevt.visibility;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomJoinRules) {
 | 
			
		||||
                    var jevt = (Matrix.Event.RoomJoinRules)evt;
 | 
			
		||||
 | 
			
		||||
                    room.join_rules = jevt.join_rules;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomName) {
 | 
			
		||||
                    var nevt = (Matrix.Event.RoomName)evt;
 | 
			
		||||
 | 
			
		||||
                    room.name = nevt.name;
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomPowerLevels) {
 | 
			
		||||
                    var levt = (Matrix.Event.RoomPowerLevels)evt;
 | 
			
		||||
 | 
			
		||||
                    room.default_power_level = levt.users_default;
 | 
			
		||||
                    room.default_event_level = levt.events_default;
 | 
			
		||||
                    room.default_state_level = levt.state_default;
 | 
			
		||||
                    room.ban_level = levt.ban;
 | 
			
		||||
                    room.kick_level = levt.kick;
 | 
			
		||||
                    room.redact_level = levt.redact;
 | 
			
		||||
                    room.invite_level = levt.invite;
 | 
			
		||||
                    room.clear_user_levels();
 | 
			
		||||
                    room.clear_event_levels();
 | 
			
		||||
 | 
			
		||||
                    levt.user_levels.foreach(
 | 
			
		||||
                        (key, value) => {
 | 
			
		||||
                            room.set_user_level(key, value);
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                    levt.event_levels.foreach(
 | 
			
		||||
                        (key, value) => {
 | 
			
		||||
                            room.set_event_level(key, value);
 | 
			
		||||
                        });
 | 
			
		||||
                } else if (evt is Matrix.Event.RoomTopic) {
 | 
			
		||||
                    var tevt = (Matrix.Event.RoomTopic)evt;
 | 
			
		||||
 | 
			
		||||
                    room.topic = tevt.topic;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        incoming_event(room_id, event_node, evt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Room
 | 
			
		||||
    _get_or_create_room(string room_id)
 | 
			
		||||
    {
 | 
			
		||||
        Room? room = null;
 | 
			
		||||
 | 
			
		||||
        if ((room = _rooms[room_id]) == null) {
 | 
			
		||||
            room = new Room(room_id);
 | 
			
		||||
            _rooms[room_id] = room;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return room;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void
 | 
			
		||||
    _process_event_list_obj(Json.Node node, string? room_id)
 | 
			
		||||
        requires(node.get_node_type() == Json.NodeType.OBJECT)
 | 
			
		||||
    {
 | 
			
		||||
        Json.Object node_obj;
 | 
			
		||||
        Json.Node events_node;
 | 
			
		||||
 | 
			
		||||
        node_obj = node.get_object();
 | 
			
		||||
 | 
			
		||||
        if ((events_node = node_obj.get_member("events")) != null) {
 | 
			
		||||
            if (events_node.get_node_type() == Json.NodeType.ARRAY) {
 | 
			
		||||
                events_node.get_array().foreach_element(
 | 
			
		||||
                        (array, idx, event_node) => {
 | 
			
		||||
                            process_event(event_node, room_id);
 | 
			
		||||
                        });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void
 | 
			
		||||
    cb_sync(string content_type,
 | 
			
		||||
            Json.Node? json_content,
 | 
			
		||||
            ByteArray? raw_content,
 | 
			
		||||
            Matrix.Error? error)
 | 
			
		||||
    {
 | 
			
		||||
        if (error == null) {
 | 
			
		||||
            var root_obj = json_content.get_object();
 | 
			
		||||
            Json.Node? node;
 | 
			
		||||
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                debug("Processing account data");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _process_event_list_obj(root_obj.get_member("account_data"),
 | 
			
		||||
                                    null);
 | 
			
		||||
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                debug("Processing presence");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _process_event_list_obj(root_obj.get_member("presence"),
 | 
			
		||||
                                    null);
 | 
			
		||||
 | 
			
		||||
            if ((node = root_obj.get_member("rooms")) != null) {
 | 
			
		||||
                if (node.get_node_type() == Json.NodeType.OBJECT) {
 | 
			
		||||
                    Json.Object rooms_object = node.get_object();
 | 
			
		||||
                    Json.Node rooms_node;
 | 
			
		||||
 | 
			
		||||
                    if (Config.DEBUG) {
 | 
			
		||||
                        debug("Processing rooms");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if ((rooms_node = rooms_object.get_member(
 | 
			
		||||
                                 "invite")) != null) {
 | 
			
		||||
                        rooms_node.get_object().foreach_member(
 | 
			
		||||
                                (obj, room_id, room_node) => {
 | 
			
		||||
                                    if (room_node.get_node_type() != Json.NodeType.OBJECT) {
 | 
			
		||||
                                        return;
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    _process_event_list_obj(
 | 
			
		||||
                                            room_node
 | 
			
		||||
                                                .get_object()
 | 
			
		||||
                                                .get_member("invite_state"),
 | 
			
		||||
                                            room_id);
 | 
			
		||||
                                });
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if ((rooms_node = rooms_object.get_member(
 | 
			
		||||
                                 "join")) != null) {
 | 
			
		||||
                        rooms_node.get_object().foreach_member(
 | 
			
		||||
                                (obj, room_id, room_node) => {
 | 
			
		||||
                                    if (room_node.get_node_type() != Json.NodeType.OBJECT) {
 | 
			
		||||
                                        return;
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    _process_event_list_obj(
 | 
			
		||||
                                            room_node
 | 
			
		||||
                                                .get_object()
 | 
			
		||||
                                                .get_member("timeline"),
 | 
			
		||||
                                            room_id);
 | 
			
		||||
                                    _process_event_list_obj(
 | 
			
		||||
                                            room_node
 | 
			
		||||
                                                .get_object()
 | 
			
		||||
                                                .get_member("state"),
 | 
			
		||||
                                            room_id);
 | 
			
		||||
                                    _process_event_list_obj(
 | 
			
		||||
                                            room_node
 | 
			
		||||
                                                .get_object()
 | 
			
		||||
                                                .get_member("account_data"),
 | 
			
		||||
                                            room_id);
 | 
			
		||||
                                    _process_event_list_obj(
 | 
			
		||||
                                            room_node
 | 
			
		||||
                                                .get_object()
 | 
			
		||||
                                                .get_member("ephemeral"),
 | 
			
		||||
                                            room_id);
 | 
			
		||||
                                });
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if ((rooms_node = rooms_object.get_member(
 | 
			
		||||
                                 "leave")) != null) {
 | 
			
		||||
                        rooms_node.get_object().foreach_member(
 | 
			
		||||
                                (obj, room_id, room_node) => {
 | 
			
		||||
                                    if (room_node.get_node_type() != Json.NodeType.OBJECT) {
 | 
			
		||||
                                        return;
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    _process_event_list_obj(
 | 
			
		||||
                                            room_node
 | 
			
		||||
                                                .get_object()
 | 
			
		||||
                                                .get_member("timeline"),
 | 
			
		||||
                                            room_id);
 | 
			
		||||
                                    _process_event_list_obj(
 | 
			
		||||
                                            room_node
 | 
			
		||||
                                                .get_object()
 | 
			
		||||
                                                .get_member("state"),
 | 
			
		||||
                                            room_id);
 | 
			
		||||
                                });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((node = root_obj.get_member("next_batch")) != null) {
 | 
			
		||||
                _last_sync_token = node.get_string();
 | 
			
		||||
            }
 | 
			
		||||
        } else if ((error is Matrix.Error.M_FORBIDDEN)
 | 
			
		||||
                   || (error is Matrix.Error.M_UNKNOWN_TOKEN)
 | 
			
		||||
                   || (error is Matrix.Error.M_UNAUTHORIZED)) {
 | 
			
		||||
            try {
 | 
			
		||||
                token = null;
 | 
			
		||||
 | 
			
		||||
                token_refresh((i, ct, jc, rc, err) => {
 | 
			
		||||
                        login_finished((error == null)
 | 
			
		||||
                                       || (error is Matrix.Error.NONE));
 | 
			
		||||
 | 
			
		||||
                        if (token == null) {
 | 
			
		||||
                            refresh_token = null;
 | 
			
		||||
                            polling_stopped(err);
 | 
			
		||||
 | 
			
		||||
                            try {
 | 
			
		||||
                                stop_polling(false);
 | 
			
		||||
                            } catch (GLib.Error e) {}
 | 
			
		||||
                        }
 | 
			
		||||
                    } , null);
 | 
			
		||||
            } catch (Matrix.Error e) {}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // It is possible that polling has been disabled while we were
 | 
			
		||||
        // processing events. Don’t continue polling if that is the
 | 
			
		||||
        // case.
 | 
			
		||||
        if (_polling) {
 | 
			
		||||
            // This `500` should be changed to M_MISSING_TOKEN somehow
 | 
			
		||||
            try {
 | 
			
		||||
                if ((error == null) || (error.code < 500)) {
 | 
			
		||||
                    begin_polling();
 | 
			
		||||
                } else if ((error != null) && error.code >= 500) {
 | 
			
		||||
                    polling_stopped(error);
 | 
			
		||||
                    stop_polling(false);
 | 
			
		||||
                }
 | 
			
		||||
            } catch (Matrix.Error e) {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void
 | 
			
		||||
    begin_polling()
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            sync((API.Callback)cb_sync,
 | 
			
		||||
                 null, null, _last_sync_token,
 | 
			
		||||
                 false, false, _event_timeout);
 | 
			
		||||
 | 
			
		||||
            _polling = true;
 | 
			
		||||
        } catch (Matrix.Error e) {
 | 
			
		||||
            throw e;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (_polling == false) {
 | 
			
		||||
            polling_started();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _polling = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void
 | 
			
		||||
    stop_polling(bool cancel_ongoing)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        _polling = false;
 | 
			
		||||
 | 
			
		||||
        if (cancel_ongoing) {
 | 
			
		||||
            abort_pending();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Profile?
 | 
			
		||||
    get_user_profile(string user_id, string? room_id = null)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        if (room_id == null) {
 | 
			
		||||
            var profile = _user_global_profiles[user_id];
 | 
			
		||||
 | 
			
		||||
            if (profile == null) {
 | 
			
		||||
                throw new Matrix.Error.UNAVAILABLE(
 | 
			
		||||
                        "Global profile for %s is not cached yet.",
 | 
			
		||||
                        user_id);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return profile;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var room = _rooms[room_id];
 | 
			
		||||
 | 
			
		||||
        if (room == null) {
 | 
			
		||||
            throw new Matrix.Error.UNAVAILABLE(
 | 
			
		||||
                    "Room data for %s is not cached yet.", room_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return room.get_member(user_id, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Presence
 | 
			
		||||
    get_user_presence(string user_id, string? room_id = null)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        if (room_id == null) {
 | 
			
		||||
            Presence? presence = _user_global_presence[user_id];
 | 
			
		||||
 | 
			
		||||
            if (presence == null) {
 | 
			
		||||
                throw new Matrix.Error.UNAVAILABLE(
 | 
			
		||||
                        "Global presence for %s is not cached yet.",
 | 
			
		||||
                        user_id);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return presence;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new Matrix.Error.UNSUPPORTED(
 | 
			
		||||
                "Per-room presences are not supported yet.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Room
 | 
			
		||||
    get_room_by_id(string room_id)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        Room? room;
 | 
			
		||||
 | 
			
		||||
        if ((room = _rooms[room_id]) == null) {
 | 
			
		||||
            throw new Matrix.Error.UNAVAILABLE(
 | 
			
		||||
                    "Room data for %s is not cached yet.", room_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return room;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Room
 | 
			
		||||
    get_room_by_alias(string room_alias)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        Room? room_found = _rooms.find(
 | 
			
		||||
            (key, room) => {
 | 
			
		||||
                if (room.canonical_alias == room_alias) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (room_alias in room.aliases) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (room_found != null) {
 | 
			
		||||
            return room_found;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new Matrix.Error.UNAVAILABLE(
 | 
			
		||||
                "Noo room data found for alias %s", room_alias);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the next transaction ID to use. It increments the
 | 
			
		||||
     * internally stored value and returns that, so it is guaranteed
 | 
			
		||||
     * to be unique until we run out of ulong boundaries.
 | 
			
		||||
     *
 | 
			
		||||
     * It is called internally by send().
 | 
			
		||||
     */
 | 
			
		||||
    public ulong
 | 
			
		||||
    next_txn_id()
 | 
			
		||||
    {
 | 
			
		||||
        return ++_last_txn_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void
 | 
			
		||||
    send_callback(Json.Node? json_content,
 | 
			
		||||
                  GLib.Error? err,
 | 
			
		||||
                  Matrix.Client.SendCallback? cb)
 | 
			
		||||
    {
 | 
			
		||||
        string? event_id = null;
 | 
			
		||||
        GLib.Error? new_err = err;
 | 
			
		||||
 | 
			
		||||
        // If there is no callback, there is no point to continue
 | 
			
		||||
        if (cb == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (err == null) {
 | 
			
		||||
            var root = json_content.get_object();
 | 
			
		||||
 | 
			
		||||
            if (root.has_member("event_id")) {
 | 
			
		||||
                event_id = root.get_string_member("event_id");
 | 
			
		||||
            } else {
 | 
			
		||||
                new_err = new Matrix.Error.BAD_RESPONSE(
 | 
			
		||||
                        "event_id is missing from an event response");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        cb(event_id, new_err);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void
 | 
			
		||||
    send(string room_id,
 | 
			
		||||
         Matrix.Event.Base evt,
 | 
			
		||||
         Matrix.Client.SendCallback? cb,
 | 
			
		||||
         out ulong txn_id)
 | 
			
		||||
        throws Matrix.Error
 | 
			
		||||
    {
 | 
			
		||||
        var evt_node = evt.json;
 | 
			
		||||
        var evt_root = evt_node.get_object();
 | 
			
		||||
        string? state_key = null;
 | 
			
		||||
 | 
			
		||||
        if (evt_root.has_member("state_key")) {
 | 
			
		||||
            state_key = evt_root.get_string_member("state_key");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state_key != null) {
 | 
			
		||||
            txn_id = 0;
 | 
			
		||||
            send_state_event(
 | 
			
		||||
                    (i, ct, json_node, rc, err) =>
 | 
			
		||||
                        send_callback(json_node, err, cb),
 | 
			
		||||
                    room_id,
 | 
			
		||||
                    evt.event_type,
 | 
			
		||||
                    (state_key == "") ? null : state_key,
 | 
			
		||||
                    evt_root.get_member("content"));
 | 
			
		||||
        } else {
 | 
			
		||||
            txn_id = next_txn_id();
 | 
			
		||||
            send_event(
 | 
			
		||||
                    (i, ct, json_node, rc, err) =>
 | 
			
		||||
                        send_callback(json_node, err, cb),
 | 
			
		||||
                    room_id,
 | 
			
		||||
                    evt.event_type,
 | 
			
		||||
                    "%lu".printf(txn_id),
 | 
			
		||||
                    evt_root.get_member("content"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void
 | 
			
		||||
    save_state(string filename)
 | 
			
		||||
        throws Matrix.Error, GLib.Error
 | 
			
		||||
    {
 | 
			
		||||
        var root = new Json.Object();
 | 
			
		||||
 | 
			
		||||
        root.set_string_member("base_url", base_url);
 | 
			
		||||
 | 
			
		||||
        root.set_boolean_member("validate_certificate", validate_certificate);
 | 
			
		||||
 | 
			
		||||
        if (user_id != null) {
 | 
			
		||||
            root.set_string_member("user_id", user_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (homeserver != null) {
 | 
			
		||||
            root.set_string_member("homeserver_name", homeserver);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (token != null) {
 | 
			
		||||
            root.set_string_member("access_token", token);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (refresh_token != null) {
 | 
			
		||||
            root.set_string_member("refresh_token", refresh_token);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var node = new Json.Node(Json.NodeType.OBJECT);
 | 
			
		||||
        node.set_object(root);
 | 
			
		||||
 | 
			
		||||
        if (Config.DEBUG) {
 | 
			
		||||
            debug("Saving state to %s\n", filename);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var generator = new Json.Generator();
 | 
			
		||||
        generator.set_root(node);
 | 
			
		||||
        generator.to_file(filename);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void
 | 
			
		||||
    load_state(string filename)
 | 
			
		||||
        throws Matrix.Error, GLib.Error
 | 
			
		||||
    {
 | 
			
		||||
        var parser = new Json.Parser();
 | 
			
		||||
 | 
			
		||||
        if (Config.DEBUG) {
 | 
			
		||||
            debug("Loading state from %s\n", filename);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        parser.load_from_file(filename);
 | 
			
		||||
        Json.Node? node = parser.get_root();
 | 
			
		||||
 | 
			
		||||
        if (node.get_node_type() != Json.NodeType.OBJECT) {
 | 
			
		||||
            throw new Matrix.Error.INVALID_FORMAT(
 | 
			
		||||
                    "Save data must be a JSON object.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var root = node.get_object();
 | 
			
		||||
 | 
			
		||||
        if ((node = root.get_member("base_url")) == null) {
 | 
			
		||||
            throw new Matrix.Error.INVALID_FORMAT(
 | 
			
		||||
                    "Save data has no base_url key");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        base_url = node.get_string();
 | 
			
		||||
 | 
			
		||||
        if (Config.DEBUG) {
 | 
			
		||||
            debug("Loaded base URL %s", base_url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((node = root.get_member("validate_certificate")) == null) {
 | 
			
		||||
            throw new Matrix.Error.INVALID_FORMAT(
 | 
			
		||||
                    "Save data has no validate_certificate key");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        validate_certificate = node.get_boolean();
 | 
			
		||||
 | 
			
		||||
        if ((node = root.get_member("user_id")) != null) {
 | 
			
		||||
            _user_id = node.get_string();
 | 
			
		||||
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                debug("Loaded user ID %s", user_id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((node = root.get_member("homeserver_name")) != null) {
 | 
			
		||||
            _homeserver = node.get_string();
 | 
			
		||||
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                debug("Loaded homeserver name %s", homeserver);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((node = root.get_member("access_token")) != null) {
 | 
			
		||||
            token = node.get_string();
 | 
			
		||||
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                debug("Loaded access token %s", token);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((node = root.get_member("refresh_token")) != null) {
 | 
			
		||||
            refresh_token = node.get_string();
 | 
			
		||||
 | 
			
		||||
            if (Config.DEBUG) {
 | 
			
		||||
                debug("Loaded refresh token %s", refresh_token);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -19,7 +19,8 @@
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <glib/gprintf.h>
 | 
			
		||||
 | 
			
		||||
#include "matrix-glib.h"
 | 
			
		||||
#include "matrix-client.h"
 | 
			
		||||
#include "matrix-http-client.h"
 | 
			
		||||
#include "matrix-event-presence.h"
 | 
			
		||||
#include "matrix-event-room-member.h"
 | 
			
		||||
#include "matrix-event-room-message.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -1018,6 +1018,48 @@ namespace Matrix {
 | 
			
		||||
        throws Matrix.Error, GLib.Error;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [CCode (cheader_filename = "matrix-http-client.h")]
 | 
			
		||||
    public class HTTPClient : HTTPAPI, Client {
 | 
			
		||||
        public HTTPClient(string base_url);
 | 
			
		||||
 | 
			
		||||
        public void login_with_password(string username, string password)
 | 
			
		||||
            throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public void register_with_password(string? username, string password)
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public new void logout()
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public void begin_polling()
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public void stop_polling(bool cancel_ongoing)
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public Profile? get_user_profile(string user_id, string? room_id = null)
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public Presence get_user_presence(string user_id, string? room_id = null)
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public Room get_room_by_id(string room_id)
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public Room get_room_by_alias(string room_alias)
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public ulong next_txn_id();
 | 
			
		||||
 | 
			
		||||
        public void send(string room_id, Matrix.Event.Base evt, Matrix.Client.SendCallback? cb, out ulong txn_id)
 | 
			
		||||
        throws Matrix.Error;
 | 
			
		||||
 | 
			
		||||
        public void save_state(string filename)
 | 
			
		||||
        throws Matrix.Error, GLib.Error;
 | 
			
		||||
 | 
			
		||||
        public void load_state(string filename)
 | 
			
		||||
        throws Matrix.Error, GLib.Error;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * The major version number of the Matrix.org GLib SDK.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user