diff --git a/.gitignore b/.gitignore
index 5d26349..bbada99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,7 +48,6 @@ Makefile.in
/src/vala-stamp
/src/matrix-glib.h
/src/matrix-client.c
-/src/matrix-http-api.c
/src/matrix-http-client.c
/src/namespace-info.vala
/src/namespace-info.c
diff --git a/src/Makefile.am b/src/Makefile.am
index da6331d..8f59e26 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,6 @@ lib_LTLIBRARIES = libmatrix-glib-0.0.la
libmatrix_glib_0_0_la_VALA_SOURCES = \
namespace-info.vala \
matrix-client.vala \
- matrix-http-api.vala \
matrix-http-client.vala \
$(NULL)
@@ -76,6 +75,7 @@ INST_H_SRC_FILES = \
matrix-types.h \
matrix-compacts.h \
matrix-api.h \
+ matrix-http-api.h \
matrix-event-base.h \
matrix-event-call-base.h \
matrix-event-call-answer.h \
@@ -134,6 +134,7 @@ libmatrix_glib_0_0_la_SOURCES = \
matrix-event-types.c \
matrix-version.c \
matrix-api.c \
+ matrix-http-api.c \
matrix-types.c \
matrix-compacts.c \
matrix-event-base.c \
diff --git a/src/matrix-http-api.c b/src/matrix-http-api.c
new file mode 100644
index 0000000..ce2de33
--- /dev/null
+++ b/src/matrix-http-api.c
@@ -0,0 +1,2627 @@
+/*
+ * 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
+#include
+#include
+#include "matrix-http-api.h"
+#include "matrix-enumtypes.h"
+#include "config.h"
+#include "utils.h"
+#include "matrix-compacts.h"
+#include "matrix-event-state-base.h"
+#include "matrix-event-base.h"
+
+/**
+ * SECTION:matrix-http-api
+ * @short_description: low-level API to communicate with homeservers via HTTP
+ *
+ * This is a class for low level communication with a Matrix.org server via HTTP.
+ */
+enum {
+ PROP_0,
+ PROP_BASE_URL,
+ PROP_VALIDATE_CERTIFICATE,
+ PROP_USER_ID,
+ PROP_TOKEN,
+ PROP_REFRESH_TOKEN,
+ PROP_HOMESERVER,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *matrix_http_api_properties[NUM_PROPERTIES];
+
+typedef struct {
+ SoupSession *soup_session;
+ gchar *base_url;
+ SoupURI *api_uri;
+ SoupURI *media_uri;
+ gchar *token;
+ gchar *refresh_token;
+} MatrixHTTPAPIPrivate;
+
+static void matrix_http_api_matrix_api_interface_init(MatrixAPIInterface * iface);
+
+G_DEFINE_TYPE_EXTENDED(MatrixHTTPAPI, matrix_http_api, G_TYPE_OBJECT, 0, G_ADD_PRIVATE(MatrixHTTPAPI) G_IMPLEMENT_INTERFACE(MATRIX_TYPE_API, matrix_http_api_matrix_api_interface_init));
+
+typedef enum {
+ CALL_TYPE_API,
+ CALL_TYPE_MEDIA
+} CallType;
+
+#define API_ENDPOINT "/_matrix/client/r0/"
+#define MEDIA_ENDPOINT "/_matrix/media/r0/"
+
+#define string_get(s, i) (((s) == NULL) ? 0 : s[i])
+#define string_offset(s, o) (((s) == NULL) ? NULL : (s) + o)
+#define uri_encode(s) gchar *enc_ ## s = soup_uri_encode(s, NULL)
+
+static void
+_matrix_http_api_set_url(MatrixHTTPAPI *matrix_http_api, SoupURI **uri, const gchar *base_url, const gchar *endpoint)
+{
+ gchar *url;
+ SoupURI *new_uri;
+
+ g_return_if_fail(matrix_http_api != NULL);
+ g_return_if_fail(base_url != NULL);
+ g_return_if_fail(endpoint != NULL);
+ g_return_if_fail(uri != NULL);
+
+ if (string_get(base_url, strlen(base_url) - 1) == '/') {
+ url = g_strdup_printf("%s%s", base_url, string_offset(endpoint, 1));
+ } else {
+ url = g_strdup_printf("%s%s", base_url, endpoint);
+ }
+
+ new_uri = soup_uri_new(url);
+
+ if (SOUP_URI_VALID_FOR_HTTP(new_uri)) {
+ *uri = new_uri;
+ } else {
+ *uri = NULL;
+ }
+ g_free(url);
+}
+
+/**
+ * matrix_http_api_new:
+ * @base_url: the base URL of the homeserver to use
+ * @token: an access token to use
+ * @refresh_token: a refresh token to use
+ *
+ * Create a new #MatrixHTTPAPI object.
+ *
+ * Returns: (transfer full): a new #MatrixHTTPAPI object
+ */
+MatrixHTTPAPI *
+matrix_http_api_new(const gchar *base_url, const gchar *token, const gchar *refresh_token)
+{
+ MatrixHTTPAPI *ret;
+ MatrixHTTPAPIPrivate *priv;
+
+ g_return_val_if_fail(base_url != NULL, NULL);
+
+ ret = (MatrixHTTPAPI*) g_object_new(MATRIX_TYPE_HTTP_API,
+ "base-url", base_url,
+ "token", token,
+ "refresh-token", refresh_token,
+ NULL);
+ priv = matrix_http_api_get_instance_private(ret);
+
+ g_object_set(priv->soup_session, "ssl-strict", TRUE, NULL);
+
+ return ret;
+}
+
+static GHashTable *
+_matrix_http_api_create_query_params(void)
+{
+ return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+}
+
+typedef struct {
+ MatrixHTTPAPI *matrix_http_api;
+ MatrixAPICallback cb;
+ CallType call_type;
+ gboolean accept_non_json;
+ gpointer cb_target;
+ guint refcount;
+} SendCallbackData;
+
+static void
+_matrix_http_api_response_callback(SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+ SendCallbackData *callback_data = user_data;
+ MatrixHTTPAPI *matrix_http_api = callback_data->matrix_http_api;
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(matrix_http_api);
+ CallType call_type = callback_data->call_type;
+ gboolean accept_non_json = callback_data->accept_non_json;
+ MatrixAPICallback cb = callback_data->cb;
+ void *cb_target = callback_data->cb;
+ SoupURI *request_uri = soup_message_get_uri(msg);
+ const gchar *request_url = soup_uri_get_path(request_uri);
+ GError *err = NULL;
+ GByteArray *raw_content = NULL;
+ JsonNode *content = NULL;
+
+ switch (call_type) {
+ case CALL_TYPE_API:
+ request_url = g_strdup(request_url + strlen(API_ENDPOINT));
+
+ break;
+ case CALL_TYPE_MEDIA:
+ request_url = g_strdup(request_url + strlen(MEDIA_ENDPOINT));
+
+ break;
+ }
+
+ if ((msg->status_code < 100) || (msg->status_code >= 400)) {
+ err = g_error_new(MATRIX_ERROR, MATRIX_ERROR_COMMUNICATION_ERROR,
+ "%s %u: %s",
+ (msg->status_code < 100) ? "Network error" : "HTTP",
+ msg->status_code,
+ msg->reason_phrase);
+ } else {
+ SoupBuffer *buffer = soup_message_body_flatten(msg->response_body);
+ gsize datalen = buffer->length;
+ JsonParser *parser = json_parser_new();
+ gboolean is_json;
+
+ is_json = json_parser_load_from_data(parser, buffer->data, (gssize)buffer->length, NULL);
+
+ if (is_json) {
+#if DEBUG
+ g_debug("Response (%s): %s", request_url, buffer->data);
+#endif
+
+ content = json_parser_get_root(parser);
+
+ if (json_node_get_node_type(content) == JSON_NODE_OBJECT) {
+ JsonObject *root = json_node_get_object(content);
+ JsonNode *node;
+ JsonNode *errcode_node;
+ JsonNode *error_node;
+
+ /* Check if the response holds an access token; if it
+ * does, set it as our new token */
+ if ((node = json_object_get_member(root, "access_token")) != NULL) {
+ const gchar *access_token;
+
+ if ((access_token = json_node_get_string(node)) != NULL) {
+#if DEBUG
+ g_debug("Got new access token: %s", access_token);
+#endif
+
+ g_free(priv->token);
+ priv->token = g_strdup(access_token);
+ }
+ }
+
+ /* Check if the response holds a refresh token; if it
+ * does, set it as our new refresh token */
+ if ((node = json_object_get_member(root, "refresh_token")) != NULL) {
+ const gchar *refresh_token;
+
+ if ((refresh_token = json_node_get_string(node)) != NULL) {
+#if DEBUG
+ g_debug("Got new refresh token: %s", refresh_token);
+#endif
+
+ g_free(priv->refresh_token);
+ priv->refresh_token = g_strdup(refresh_token);
+ }
+ }
+
+ /* Check if the response holds a homeserver name */
+ if ((node = json_object_get_member(root, "home_server")) != NULL) {
+ const gchar *homeserver = json_node_get_string(node);
+
+#if DEBUG
+ g_debug("Our home server calls itself %s", homeserver);
+#endif
+
+ g_free(matrix_http_api->_homeserver);
+ matrix_http_api->_homeserver = g_strdup(homeserver);
+ }
+
+ /* Check if the response holds a user ID; if it does,
+ * set this as our user ID */
+ if ((node = json_object_get_member(root, "user_id")) != NULL) {
+ const gchar *user_id = json_node_get_string(node);
+
+#if DEBUG
+ g_debug("We are reported to be logged in as %s", user_id);
+#endif
+
+ g_free(matrix_http_api->_user_id);
+ matrix_http_api->_user_id = g_strdup(user_id);
+ }
+
+ /* Check if the response holds an error */
+ errcode_node = json_object_get_member(root, "errcode");
+ error_node = json_object_get_member(root, "error");
+ const gchar *error = NULL;
+ const gchar *errcode = NULL;
+
+ if ((errcode_node != NULL) || (error_node != NULL)) {
+ err = g_error_new_literal(MATRIX_ERROR, MATRIX_ERROR_UNKNOWN_ERROR,
+ "The error is not known to this library");
+
+ if (error_node != NULL) {
+ error = json_node_get_string(error_node);
+ }
+
+ if (errcode_node != NULL) {
+ errcode = json_node_get_string(errcode_node);
+
+ if (g_ascii_strncasecmp(errcode, "M_", 2) == 0) {
+ gchar *errcode_enum_name = g_strdup_printf("MATRIX_ERROR_%s", errcode);
+ GEnumClass *error_class = g_type_class_ref(MATRIX_TYPE_ERROR);
+ GEnumValue *enum_value = g_enum_get_value_by_name(error_class, errcode_enum_name);
+ g_type_class_unref(error_class);
+ g_free(errcode_enum_name);
+
+ if (enum_value != NULL) {
+ err->code = enum_value->value;
+ } else {
+ g_warning("An unknown error code '%s' was sent by the homeserver. You may want to report it to the Matrix GLib developers", errcode);
+ }
+ }
+ } else {
+ g_warning("An error was sent by the homeserver, but no error code was specified. You may want to report this to the homeserver admins.");
+ g_clear_error(&err);
+
+ err = g_error_new_literal(MATRIX_ERROR, MATRIX_ERROR_UNSPECIFIED, "No error code was sent by the server");
+ }
+
+ if ((errcode_node != NULL) && (error_node != NULL)) {
+ err->message = g_strdup_printf("%s: %s", errcode, error);
+ } else if (errcode_node != NULL) {
+ err->message = g_strdup(errcode);
+ } else {
+ err->message = g_strdup_printf("(No errcode given) %s", error);
+ }
+ }
+ } else if (json_node_get_node_type(content) != JSON_NODE_ARRAY) {
+ err = g_error_new_literal(MATRIX_ERROR, MATRIX_ERROR_BAD_RESPONSE,
+ "Bad response: not a JSON object, nor an array.");
+ }
+ } else {
+ if (accept_non_json) {
+ raw_content = g_byte_array_sized_new((uint)datalen);
+ g_byte_array_append(raw_content, (guint8 *)buffer->data, buffer->length);
+
+#if DEBUG
+ g_debug("Binary data (%s): %u bytes", request_url, (uint)datalen);
+#endif
+ } else {
+ err = g_error_new_literal(MATRIX_ERROR, MATRIX_ERROR_BAD_RESPONSE,
+ "Malformed response (invalid JSON)");
+
+#if DEBUG
+ g_debug("Malformed response (%s): %s", request_url, data);
+#endif
+ }
+ }
+ }
+
+ /* Call the assigned function, if any */
+ if (cb != NULL) {
+ cb(MATRIX_API(matrix_http_api),
+ soup_message_headers_get_content_type(msg->response_headers, NULL),
+ content, raw_content,
+ err,
+ cb_target);
+ }
+
+ g_free(callback_data);
+}
+
+static void
+_matrix_http_api_send(MatrixHTTPAPI *matrix_http_api,
+ MatrixAPICallback cb,
+ void *cb_target,
+ CallType call_type,
+ const gchar *method,
+ const gchar *path,
+ GHashTable *parms,
+ const gchar *content_type,
+ JsonNode *json_content,
+ GByteArray *raw_content,
+ gboolean accept_non_json,
+ GError **error)
+{
+ MatrixHTTPAPIPrivate *priv;
+ SoupMessage *message;
+ SoupURI *request_path = NULL;
+ gpointer request_data;
+ gsize request_len;
+ SendCallbackData *callback_data;
+
+ g_return_if_fail(matrix_http_api != NULL);
+ g_return_if_fail(method != NULL);
+ g_return_if_fail(path != NULL);
+
+ priv = matrix_http_api_get_instance_private(matrix_http_api);
+
+ if ((priv->api_uri == NULL) || (priv->media_uri == NULL)) {
+ g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_COMMUNICATION_ERROR, "No valid base URL");
+
+ return;
+ }
+
+ if ((json_content != NULL) && (raw_content != NULL)) {
+ g_critical("json_content and raw_content cannot be used together. This is a bug.");
+ }
+
+ if (!g_str_is_ascii(method)) {
+ g_critical("Method must be ASCII. This is a bug.");
+ }
+
+ if ((g_ascii_strcasecmp(method, "GET") != 0) &&
+ (g_ascii_strcasecmp(method, "POST") != 0) &&
+ (g_ascii_strcasecmp(method, "PUT") != 0) &&
+ (g_ascii_strcasecmp(method, "DELETE") != 0)) {
+ g_critical("Method %s is invalid. This is a bug.", method);
+ }
+
+ if (call_type == CALL_TYPE_MEDIA) {
+ request_path = soup_uri_new_with_base(priv->media_uri, path);
+ } else {
+ request_path = soup_uri_new_with_base(priv->api_uri, path);
+ }
+
+ if (parms == NULL) {
+ parms = _matrix_http_api_create_query_params();
+ }
+
+ if (priv->token != NULL) {
+#if DEBUG
+ g_debug("Adding access token '%s'", priv->token);
+#endif
+
+ g_hash_table_replace(parms, g_strdup("access_token"), priv->token);
+ }
+
+ soup_uri_set_query_from_form(request_path, parms);
+
+ message = soup_message_new_from_uri(method, request_path);
+
+ if (json_content != NULL) {
+ JsonGenerator *generator = json_generator_new();
+
+ json_generator_set_root(generator, json_content);
+ request_data = json_generator_to_data(generator, &request_len);
+ } else if (raw_content != NULL) {
+ request_len = raw_content->len;
+ request_data = raw_content->data;
+ } else {
+ request_len = 2;
+ request_data = g_strdup("{}");
+ }
+
+#if DEBUG
+ g_debug("Sending %lu bytes (%s %s): %s",
+ request_len,
+ method,
+ soup_uri_to_string(request_path, FALSE), // TODO: Free this!
+ (raw_content != NULL) ? "" : (gchar *)request_data);
+#endif
+
+ soup_message_set_flags(message, SOUP_MESSAGE_NO_REDIRECT);
+ soup_message_set_request(message,
+ (content_type == NULL) ? "application/json" : content_type,
+ SOUP_MEMORY_COPY,
+ request_data,
+ request_len);
+
+ callback_data = g_new0(SendCallbackData, 1);
+
+ callback_data->matrix_http_api = matrix_http_api;
+ callback_data->refcount = 1;
+ callback_data->cb = cb;
+ callback_data->cb_target = cb_target;
+ callback_data->call_type = call_type;
+ callback_data->accept_non_json = accept_non_json;
+
+ soup_session_queue_message(priv->soup_session, message, _matrix_http_api_response_callback, callback_data);
+}
+
+static void
+matrix_http_api_media_download(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *server_name, const gchar *media_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(server_name != NULL);
+ g_return_if_fail(media_id != NULL);
+
+ uri_encode(server_name);
+ uri_encode(media_id);
+ path = g_strconcat("download/", enc_server_name, "/", enc_media_id, NULL);
+ g_free(enc_server_name);
+ g_free(enc_media_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_MEDIA, "GET", path, NULL, NULL, NULL, NULL, TRUE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_media_thumbnail(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *server_name, const gchar *media_id, guint width, guint height, MatrixResizeMethod method, GError **error)
+{
+ gchar *path;
+ GHashTable *parms;
+
+ g_return_if_fail(server_name != NULL);
+ g_return_if_fail(media_id != NULL);
+
+ uri_encode(server_name);
+ uri_encode(media_id);
+ path = g_strconcat("download/", enc_server_name, "/", enc_media_id, NULL);
+ g_free(enc_server_name);
+ g_free(enc_media_id);
+
+ parms = _matrix_http_api_create_query_params();
+
+ if (width > 0) {
+ g_hash_table_replace(parms, g_strdup("width"), g_strdup_printf("%u", width));
+ }
+
+ if (height > 0) {
+ g_hash_table_replace(parms, g_strdup("height"), g_strdup_printf("%u", height));
+ }
+
+ if (method != MATRIX_RESIZE_METHOD_DEFAULT) {
+ switch (method) {
+ case MATRIX_RESIZE_METHOD_CROP:
+ g_hash_table_replace(parms, g_strdup("method"), g_strdup("crop"));
+
+ break;
+ case MATRIX_RESIZE_METHOD_SCALE:
+ g_hash_table_replace(parms, g_strdup("method"), g_strdup("scale"));
+
+ break;
+ // This is here only to prevent compiler warnings
+ case MATRIX_RESIZE_METHOD_DEFAULT: break;
+ }
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_MEDIA, "GET", path, parms, NULL, NULL, NULL, TRUE, error);
+
+ g_free(path);
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_media_upload(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *content_type, GByteArray *content, GError **error)
+{
+ g_return_if_fail(content != NULL);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_MEDIA, "POST", "upload", NULL, content_type, NULL, content, FALSE, error);
+}
+
+static void
+matrix_http_api_get_presence_list(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("presence/list/", enc_user_id, NULL);
+ g_free(enc_user_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_update_presence_list(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, gchar **drop_ids, int n_drop_ids, gchar **invite_ids, int n_invite_ids, GError **error)
+{
+ gchar *path;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("presence/", enc_user_id, "/status", NULL);
+ g_free(enc_user_id);
+
+ builder = json_builder_new();
+ json_builder_begin_object(builder);
+
+ if (n_drop_ids > 0) {
+ json_builder_set_member_name(builder, "drop");
+ json_builder_begin_array(builder);
+
+ for (gint i = 0; i < n_drop_ids; i++) {
+ json_builder_add_string_value(builder, drop_ids[i]);
+ }
+
+ json_builder_end_array(builder);
+ }
+
+ if (n_invite_ids > 0) {
+ json_builder_set_member_name(builder, "invite");
+ json_builder_begin_array(builder);
+
+ for (gint i = 0; i < n_invite_ids; i++) {
+ json_builder_add_string_value(builder, invite_ids[i]);
+ }
+
+ json_builder_end_array(builder);
+ }
+
+ json_builder_end_object(builder);
+
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_get_presence(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("presence/", enc_user_id, "/status", NULL);
+ g_free(enc_user_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_set_presence(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, MatrixPresence presence, const gchar *status_message, GError **error)
+{
+ gchar *path;
+ gchar *presence_str;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("presence/", enc_user_id, "/status", NULL);
+ g_free(enc_user_id);
+
+ builder = json_builder_new();
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "presence");
+ presence_str = _matrix_g_enum_to_string(MATRIX_TYPE_PRESENCE, presence, '_');
+ json_builder_add_string_value(builder, presence_str);
+ g_free(presence_str);
+
+ if (status_message != NULL) {
+ json_builder_set_member_name(builder, "status_msg");
+ json_builder_add_string_value(builder, status_message);
+ }
+
+ json_builder_end_object(builder);
+
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+ g_free(path);
+}
+
+static void
+matrix_http_api_update_pusher(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, MatrixPusher *pusher, GError **error)
+{
+ JsonNode *pusher_node;
+ GError *inner_error = NULL;
+
+ g_return_if_fail(pusher != NULL);
+
+ pusher_node = matrix_json_compact_get_json_node(MATRIX_JSON_COMPACT(pusher), &inner_error);
+
+ if (inner_error != NULL) {
+ g_propagate_error(error, inner_error);
+ return;
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", "pushers/set", NULL, NULL, pusher_node, NULL, FALSE, error);
+
+ json_node_unref(pusher_node);
+}
+
+static void
+matrix_http_api_get_pushers(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, GError **error)
+{
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", "pushrules", NULL, NULL, NULL, NULL, FALSE, error);
+}
+
+static gchar *
+_matrix_http_api_pusher_url(const gchar *scope, MatrixPusherKind kind, const gchar *rule_id)
+{
+ gchar *kind_str;
+ gchar *url;
+
+ g_return_val_if_fail(scope != NULL, NULL);
+ g_return_val_if_fail(rule_id != NULL, NULL);
+
+ uri_encode(scope);
+ kind_str = _matrix_g_enum_to_string(MATRIX_TYPE_PUSHER_KIND, kind, '_');
+ uri_encode(kind_str);
+ g_free(kind_str);
+ uri_encode(rule_id);
+ url = g_strconcat("pushrules/", enc_scope, "/", enc_kind_str, "/", enc_rule_id, NULL);
+ g_free(enc_scope);
+ g_free(enc_kind_str);
+ g_free(enc_rule_id);
+
+ return url;
+}
+
+static void
+_matrix_http_api_pusher_modif(MatrixHTTPAPI *matrix_http_api, MatrixAPICallback cb, void *cb_target, const gchar *method, const gchar *scope, MatrixPusherKind kind, const gchar *rule_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(matrix_http_api != NULL);
+ g_return_if_fail(method != NULL);
+ g_return_if_fail(scope != NULL);
+ g_return_if_fail(rule_id != NULL);
+
+ path = _matrix_http_api_pusher_url(scope, kind, rule_id);
+
+ _matrix_http_api_send(matrix_http_api, cb, cb_target, CALL_TYPE_API, method, path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_delete_pushrule(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *scope, MatrixPusherKind kind, const gchar *rule_id, GError **error)
+{
+ g_return_if_fail(scope != NULL);
+ g_return_if_fail(rule_id != NULL);
+
+ _matrix_http_api_pusher_modif(MATRIX_HTTP_API(matrix_api), cb, cb_target, "DELETE", scope, kind, rule_id, error);
+}
+
+static void
+matrix_http_api_get_pushrule(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *scope, MatrixPusherKind kind, const gchar *rule_id, GError **error)
+{
+ g_return_if_fail(scope != NULL);
+ g_return_if_fail(rule_id != NULL);
+
+ _matrix_http_api_pusher_modif(MATRIX_HTTP_API(matrix_api), cb, cb_target, "GET", scope, kind, rule_id, error);
+}
+
+static void
+matrix_http_api_add_pushrule(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *scope, MatrixPusherKind kind, const gchar *rule_id, const gchar *before, const gchar *after, gchar **actions, int n_actions, MatrixPusherConditionKind *conditions, int n_conditions, GError **error)
+{
+ JsonBuilder *builder;
+ GHashTable *parms;
+ gchar *path;
+ JsonNode *root_node;
+
+ g_return_if_fail(scope != NULL);
+ g_return_if_fail(rule_id != NULL);
+
+ parms = _matrix_http_api_create_query_params();
+
+ if (before != NULL) {
+ g_hash_table_replace(parms, g_strdup("before"), g_strdup(before));
+ }
+
+ if (after != NULL) {
+ g_hash_table_replace(parms, g_strdup("after"), g_strdup(after));
+ }
+
+ builder = json_builder_new();
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "actions");
+ json_builder_begin_array(builder);
+
+ for (gint i = 0; i < n_actions; i++) {
+ json_builder_add_string_value(builder, actions[i]);
+ }
+
+ json_builder_end_array(builder);
+
+ if (n_conditions > 0) {
+ json_builder_set_member_name(builder, "conditions");
+ json_builder_begin_array(builder);
+
+ for (gint i = 0; i < n_conditions; i++) {
+ gchar *kind_str = _matrix_g_enum_to_string(MATRIX_TYPE_PUSHER_CONDITION_KIND, conditions[i], '_');
+
+ if (kind_str == NULL) {
+ g_warning("Skipping invalid condition kind %d", conditions[i]);
+
+ continue;
+ }
+
+ json_builder_begin_object(builder);
+ json_builder_set_member_name(builder, "kind");
+ json_builder_add_string_value(builder, kind_str);
+ json_builder_end_object(builder);
+ }
+
+ json_builder_end_array(builder);
+ }
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ path = _matrix_http_api_pusher_url(scope, kind, rule_id);
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", path, parms, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+
+static void
+matrix_http_api_toggle_pushrule(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *scope, MatrixPusherKind kind, const gchar *rule_id, gboolean enabled, GError **error)
+{
+ JsonBuilder *builder;
+ JsonNode *root_node;
+ gchar *path;
+
+ g_return_if_fail(scope != NULL);
+ g_return_if_fail(rule_id != NULL);
+
+ builder = json_builder_new();
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "enabled");
+ json_builder_add_boolean_value(builder, enabled);
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ path = _matrix_http_api_pusher_url(scope, kind, rule_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_get_pushrules(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, GError **error)
+{
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", "pushrules", NULL, NULL, NULL, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_create_room(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, MatrixRoomPreset preset, const gchar *room_name, const gchar *room_alias, const gchar *topic, MatrixRoomVisibility visibility, JsonNode *creation_content, MatrixEventState **initial_state, int n_initial_state, gchar **invitees, int n_invitees, Matrix3PidCredential **invite_3pids, int n_invite_3pids, GError **error)
+{
+ JsonBuilder *builder = json_builder_new();
+ JsonNode *root_node;
+
+ json_builder_begin_object(builder);
+
+ if (creation_content != NULL) {
+ json_builder_set_member_name(builder, "creation_content");
+ json_builder_add_value(builder, creation_content);
+ }
+
+ if (n_initial_state > 0) {
+ json_builder_set_member_name(builder, "initial_state");
+ json_builder_begin_array(builder);
+
+ for (gint i = 0; i < n_initial_state; i++) {
+ JsonNode *event_node = matrix_event_base_get_json(MATRIX_EVENT_BASE(initial_state[i]));
+
+ json_builder_add_value(builder, event_node);
+ }
+
+ json_builder_end_array(builder);
+ }
+
+ if (n_invitees > 0) {
+ json_builder_set_member_name(builder, "invite");
+ json_builder_begin_array(builder);
+
+ for (gint i = 0; i < n_invitees; i++) {
+ json_builder_add_string_value(builder, invitees[i]);
+ }
+
+ json_builder_end_array(builder);
+ }
+
+ if (n_invite_3pids > 0) {
+ json_builder_set_member_name(builder, "invite_3pid");
+ json_builder_begin_array(builder);
+
+ for (gint i = 0; i < n_invite_3pids; i++) {
+ GError *inner_error = NULL;
+ JsonNode *node = matrix_json_compact_get_json_node(MATRIX_JSON_COMPACT(invite_3pids[i]), &inner_error);
+
+ if (inner_error == NULL) {
+ json_builder_add_value(builder, node);
+ }
+ // TODO exceptions should be handled here somehow
+ }
+
+ json_builder_end_array(builder);
+ }
+
+ if (room_name != NULL) {
+ json_builder_set_member_name(builder, "name");
+ json_builder_add_string_value(builder, room_name);
+ }
+
+ if (preset != MATRIX_ROOM_PRESET_NONE) {
+ gchar *preset_str = _matrix_g_enum_to_string(MATRIX_TYPE_ROOM_PRESET, preset, '_');
+
+ if (preset_str != NULL) {
+ json_builder_set_member_name(builder, "preset");
+ json_builder_add_string_value(builder, preset_str);
+ g_free(preset_str);
+ } else {
+ g_warning("Invalid room preset type");
+ }
+ }
+
+ if (room_alias != NULL) {
+ json_builder_set_member_name(builder, "room_alias_name");
+ json_builder_add_string_value(builder, room_alias);
+ }
+
+ if (topic != NULL) {
+ json_builder_set_member_name(builder, "topic");
+ json_builder_add_string_value(builder, topic);
+ }
+
+ if (visibility != MATRIX_ROOM_VISIBILITY_DEFAULT) {
+ gchar *visibility_str = _matrix_g_enum_to_string(MATRIX_TYPE_ROOM_VISIBILITY, visibility, '_');
+
+ if (visibility_str != NULL) {
+ json_builder_set_member_name(builder, "visibility");
+ json_builder_add_string_value(builder, visibility_str);
+ g_free(visibility_str);
+ } else {
+ g_warning("Invalid room visibility type");
+ }
+ }
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", "createRoom", NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_delete_room_alias(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_alias, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_alias != NULL);
+
+ uri_encode(room_alias);
+ path = g_strconcat("directory/room/", enc_room_alias, NULL);
+ g_free(enc_room_alias);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "DELETE", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_get_room_id(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_alias, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_alias != NULL);
+
+ uri_encode(room_alias);
+ path = g_strconcat("directory/room/", enc_room_alias, NULL);
+ g_free(enc_room_alias);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_create_room_alias(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *room_alias, GError **error)
+{
+ JsonBuilder *builder;
+ JsonNode *root_node;
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(room_alias != NULL);
+
+ uri_encode(room_alias);
+ path = g_strconcat("directory/room/", enc_room_alias, NULL);
+ g_free(enc_room_alias);
+
+ builder = json_builder_new();
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "room_id");
+ json_builder_add_string_value(builder, room_id);
+
+ json_builder_end_object(builder);
+
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "PUT", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_list_public_rooms(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, GError **error)
+{
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", "publicRooms", NULL, NULL, NULL, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_ban_user(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *user_id, const gchar *reason, GError **error)
+{
+ gchar *path;
+ JsonNode *root_node;
+ JsonBuilder *builder;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/ban", NULL);
+ g_free(enc_room_id);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "user_id");
+ json_builder_add_string_value(builder, user_id);
+
+ if (reason != NULL) {
+ json_builder_set_member_name(builder, "reason");
+ json_builder_add_string_value(builder, reason);
+ }
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_unban_user(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *user_id, GError **error)
+{
+ gchar *path;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/unban", NULL);
+ g_free(enc_room_id);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "user_id");
+ json_builder_add_string_value(builder, user_id);
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_forget_room(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/forget", NULL);
+ g_free(enc_room_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_invite_user_3rdparty(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, Matrix3PidCredential *credential, GError **error)
+{
+ gchar *path;
+ JsonNode *body;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(credential != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/invite", NULL);
+ g_free(enc_room_id);
+
+ if ((body = matrix_json_compact_get_json_node(MATRIX_JSON_COMPACT(credential), error)) == NULL) {
+ return;
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, body, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(body);
+}
+
+static void
+matrix_http_api_invite_user(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *user_id, GError **error)
+{
+ gchar *path;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/invite", NULL);
+ g_free(enc_room_id);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "user_id");
+ json_builder_add_string_value(builder, user_id);
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_join_room(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/join", NULL);
+ g_free(enc_room_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_leave_room(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/leave", NULL);
+ g_free(enc_room_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_join_room_id_or_alias(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id_or_alias, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id_or_alias != NULL);
+
+ uri_encode(room_id_or_alias);
+ path = g_strconcat("join/", enc_room_id_or_alias, NULL);
+ g_free(enc_room_id_or_alias);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_kick_user(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *user_id, const gchar *reason, GError **error)
+{
+ gchar *path;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/kick", NULL);
+ g_free(enc_room_id);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "user_id");
+ json_builder_add_string_value(builder, user_id);
+
+ if (reason != NULL) {
+ json_builder_set_member_name(builder, "reason");
+ json_builder_add_string_value(builder, reason);
+ }
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "POST", path, NULL, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_event_stream(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *from_token, gulong timeout, GError **error)
+{
+ GHashTable *parms = _matrix_http_api_create_query_params();
+
+ if (from_token != NULL) {
+ g_hash_table_replace(parms, g_strdup("from"), g_strdup(from_token));
+ }
+
+ if (timeout > 0) {
+ g_hash_table_replace(parms, g_strdup("timeout"), g_strdup_printf("%lu", timeout));
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", "events", parms, NULL, NULL, NULL, FALSE, error);
+
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_get_event(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *event_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(event_id != NULL);
+
+ uri_encode(event_id);
+ path = g_strconcat("events/", enc_event_id, NULL);
+ g_free(enc_event_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api), cb, cb_target, CALL_TYPE_API, "GET", path, NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_initial_sync(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, guint limit, gboolean archived, GError **error)
+{
+ GHashTable *parms = _matrix_http_api_create_query_params();
+
+ if (limit != 0) {
+ g_hash_table_replace(parms, g_strdup("limit"), g_strdup_printf("%u", limit));
+ }
+
+ if (archived) {
+ g_hash_table_replace(parms, g_strdup("archived"), g_strdup("true"));
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", "initialSync",
+ parms, NULL, NULL, NULL, FALSE, error);
+
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_get_event_context(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *event_id, guint limit, GError **error)
+{
+ gchar *path;
+ GHashTable *parms = NULL;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(event_id != NULL);
+
+ uri_encode(room_id);
+ uri_encode(event_id);
+ path = g_strconcat("rooms/", enc_room_id, "/context", enc_event_id, NULL);
+ g_free(enc_room_id);
+ g_free(enc_event_id);
+
+ if (limit > 0) {
+ parms = _matrix_http_api_create_query_params();
+
+ g_hash_table_replace(parms, g_strdup("limit"), g_strdup_printf("%u", limit));
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ parms, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_initial_sync_room(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/initialSync", NULL);
+ g_free(enc_room_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_list_room_members(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/members", NULL);
+ g_free(enc_room_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_list_room_messages(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *from_token, MatrixEventDirection direction, guint limit, GError **error)
+{
+ gchar *path;
+ GHashTable *parms;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(from_token != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/messages", NULL);
+ g_free(enc_room_id);
+
+ parms = _matrix_http_api_create_query_params();
+
+ g_hash_table_replace(parms, g_strdup("from"), g_strdup(from_token));
+
+ switch (direction) {
+ case MATRIX_EVENT_DIRECTION_BACKWARD:
+ g_hash_table_replace(parms, g_strdup("dir"), g_strdup("b"));
+
+ break;
+ case MATRIX_EVENT_DIRECTION_FORWARD:
+ g_hash_table_replace(parms, g_strdup("dir"), g_strdup("f"));
+
+ break;
+ }
+
+ if (limit > 0) {
+ g_hash_table_replace(parms, g_strdup("limit"), g_strdup_printf("%u", limit));
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ parms, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_send_event_receipt(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, MatrixReceiptType receipt_type, const gchar *event_id, JsonNode *receipt, GError **error)
+{
+ gchar *path;
+ gchar *type_str;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(event_id != NULL);
+ g_return_if_fail(receipt != NULL);
+
+ uri_encode(room_id);
+ type_str = _matrix_g_enum_to_string(MATRIX_TYPE_RECEIPT_TYPE, receipt_type, '_');
+ uri_encode(type_str);
+ g_free(type_str);
+ uri_encode(event_id);
+ path = g_strconcat("rooms/", enc_room_id, "/receipt/", enc_type_str, "/", enc_event_id, NULL);
+ g_free(enc_room_id);
+ g_free(enc_type_str);
+ g_free(enc_event_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", path,
+ NULL, NULL, receipt, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_redact_event(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *event_id, const gchar *txn_id, const gchar *reason, GError **error)
+{
+ gchar *path;
+ JsonNode *body = NULL;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(event_id != NULL);
+ g_return_if_fail(txn_id != NULL);
+
+ uri_encode(room_id);
+ uri_encode(event_id);
+ uri_encode(txn_id);
+ path = g_strconcat("rooms/", enc_room_id, "/redact/", enc_event_id, "/", enc_txn_id, NULL);
+ g_free(enc_room_id);
+ g_free(enc_event_id);
+ g_free(enc_txn_id);
+
+ if (reason != NULL) {
+ JsonBuilder *builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "reason");
+ json_builder_add_string_value(builder, reason);
+
+ json_builder_end_object(builder);
+ body = json_builder_get_root(builder);
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, body, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(body);
+}
+
+static void
+matrix_http_api_send_event(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *event_type, const gchar *txn_id, JsonNode *content, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(event_type != NULL);
+ g_return_if_fail(txn_id != NULL);
+ g_return_if_fail(content != NULL);
+
+ uri_encode(room_id);
+ uri_encode(event_type);
+ uri_encode(txn_id);
+ path = g_strconcat("rooms/", enc_room_id, "/send/", enc_event_type, "/", enc_txn_id, NULL);
+ g_free(enc_room_id);
+ g_free(enc_event_type);
+ g_free(enc_txn_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, content, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_get_room_state(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *event_type, const gchar *state_key, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(room_id);
+ path = g_strconcat("rooms/", enc_room_id, "/state", NULL);
+ g_free(enc_room_id);
+
+ if (event_type != NULL) {
+ gchar *tmp = path;
+
+ uri_encode(event_type);
+ path = g_strconcat(tmp, "/", enc_event_type, NULL);
+ g_free(enc_event_type);
+ g_free(tmp);
+ }
+
+ if (state_key != NULL) {
+ gchar *tmp = path;
+
+ uri_encode(state_key);
+ path = g_strconcat(tmp, "/", enc_state_key, NULL);
+ g_free(enc_state_key);
+ g_free(tmp);
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_send_state_event(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *room_id, const gchar *event_type, const gchar *state_key, JsonNode *content, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(event_type != NULL);
+ g_return_if_fail(content != NULL);
+
+ uri_encode(room_id);
+ uri_encode(event_type);
+ path = g_strconcat("rooms/", enc_room_id, "/state/", enc_event_type, NULL);
+ g_free(enc_room_id);
+ g_free(enc_event_type);
+
+ if (state_key != NULL) {
+ gchar *tmp = path;
+
+ uri_encode(state_key);
+ path = g_strconcat(tmp, "/", enc_state_key, NULL);
+ g_free(enc_state_key);
+ g_free(tmp);
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, content, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_notify_room_typing(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, const gchar *room_id, guint timeout, gboolean typing, GError **error)
+{
+ gchar *path;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(room_id);
+ uri_encode(user_id);
+
+ path = g_strconcat("rooms/", enc_room_id, "/typing/", enc_user_id, NULL);
+
+ g_free(enc_room_id);
+ g_free(enc_user_id);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ if (timeout > 0) {
+ json_builder_set_member_name(builder, "timeout");
+ json_builder_add_int_value(builder, timeout);
+ }
+
+ json_builder_set_member_name(builder, "typing");
+ json_builder_add_boolean_value(builder, typing);
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, root_node, NULL, FALSE, error);
+
+ g_free(path);
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_sync(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *filter_id, MatrixFilter *filter, const gchar *since, gboolean full_state, gboolean set_presence, gulong timeout, GError **error)
+{
+ GHashTable *parms;
+
+ if ((filter_id != NULL) && (filter != NULL)) {
+ g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_BAD_REQUEST,
+ "Cannot set both filter_id and filter");
+
+ return;
+ }
+
+ parms = _matrix_http_api_create_query_params();
+
+ if (filter_id != NULL) {
+ g_hash_table_replace(parms, g_strdup("filter"), g_strdup(filter_id));
+ }
+
+ if (filter != NULL) {
+ GError *inner_error = NULL;
+ gchar *filter_data = matrix_json_compact_get_json_data(MATRIX_JSON_COMPACT(filter), NULL, &inner_error);
+
+ if (inner_error != NULL) {
+ g_propagate_error(error, inner_error);
+ g_hash_table_unref(parms);
+
+ return;
+ }
+
+ g_hash_table_replace(parms, g_strdup("filter"), filter_data);
+ }
+
+ if (since != NULL) {
+ g_hash_table_replace(parms, g_strdup("since"), g_strdup(since));
+ }
+
+ g_hash_table_replace(parms, g_strdup("full_state"), g_strdup((full_state) ? "true" : "false"));
+
+ if (!set_presence) {
+ g_hash_table_replace(parms, g_strdup("set_presence"), g_strdup("offline"));
+ }
+
+ if (timeout != 0) {
+ g_hash_table_replace(parms, g_strdup("timeout"), g_strdup_printf("%lu", timeout));
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", "sync",
+ parms, NULL, NULL, NULL, FALSE, error);
+
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_create_filter(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, MatrixFilter *filter, GError **error)
+{
+ gchar *path;
+ JsonNode *filter_node;
+ GError *inner_error = NULL;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(filter != NULL);
+
+ filter_node = matrix_json_compact_get_json_node(MATRIX_JSON_COMPACT(filter), &inner_error);
+
+ if (inner_error != NULL) {
+ g_propagate_error(error, inner_error);
+
+ return;
+ }
+
+ uri_encode(user_id);
+ path = g_strconcat("user/", enc_user_id, "/filter", NULL);
+ g_free(enc_user_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", path,
+ NULL, NULL, filter_node, NULL, FALSE, error);
+
+ json_node_unref(filter_node);
+ g_free(path);
+}
+
+static void
+matrix_http_api_download_filter(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, const gchar *filter_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(filter_id != NULL);
+
+ uri_encode(user_id);
+ uri_encode(filter_id);
+ path = g_strconcat("user/", enc_user_id, "/filter/", enc_filter_id, NULL);
+ g_free(enc_user_id);
+ g_free(enc_filter_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_search(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *next_batch, MatrixSearchCategories *search_categories, GError **error)
+{
+ GHashTable *parms = NULL;
+ JsonNode *search_node;
+ GError *inner_error = NULL;
+
+ g_return_if_fail(search_categories != NULL);
+
+ search_node = matrix_json_compact_get_json_node(MATRIX_JSON_COMPACT(search_categories), &inner_error);
+
+ if (inner_error != NULL) {
+ g_propagate_error(error, inner_error);
+
+ return;
+ }
+
+ if (next_batch != NULL) {
+ parms = _matrix_http_api_create_query_params();
+
+ g_hash_table_replace(parms, g_strdup("next_batch"), g_strdup(next_batch));
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "search",
+ parms, NULL, search_node, NULL, FALSE, error);
+
+ json_node_unref(search_node);
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_whois(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("admin/whois/", enc_user_id, NULL);
+ g_free(enc_user_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_versions(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, GError **error)
+{
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", "versions",
+ NULL, NULL, NULL, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_login(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *login_type, JsonNode *content, GError **error)
+{
+ JsonNode *body;
+ JsonObject *root;
+
+ g_return_if_fail(login_type != NULL);
+
+ body = _matrix_json_node_deep_copy(content);
+ root = json_node_get_object(body);
+
+ json_object_set_string_member(root, "type", login_type);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "login",
+ NULL, NULL, body, NULL, FALSE, error);
+
+ json_node_unref(body);
+}
+
+static void
+matrix_http_api_token_refresh(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *refresh_token, GError **error)
+{
+ JsonBuilder *builder;
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(MATRIX_HTTP_API(matrix_api));
+ JsonNode *root_node;
+
+ if ((refresh_token == NULL) && (priv->refresh_token == NULL)) {
+ g_set_error(error, MATRIX_ERROR, MATRIX_ERROR_M_MISSING_TOKEN, "No token available");
+
+ return;
+ }
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "refresh_token");
+ json_builder_add_string_value(builder, (refresh_token != NULL) ? refresh_token : priv->refresh_token);
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "tokenrefresh",
+ NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_logout(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, GError **error)
+{
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "logout",
+ NULL, NULL, NULL, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_get_3pids(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, GError **error)
+{
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", "account/3pid",
+ NULL, NULL, NULL, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_add_3pid(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, gboolean bind_creds, Matrix3PidCredential *creds, GError **error)
+{
+ JsonNode *creds_node;
+ JsonNode *root_node;
+ JsonBuilder *builder;
+ GError *inner_error = NULL;
+
+ g_return_if_fail(creds != NULL);
+
+ creds_node = matrix_json_compact_get_json_node(MATRIX_JSON_COMPACT(creds), &inner_error);
+
+ if (inner_error != NULL) {
+ g_propagate_error(error, inner_error);
+
+ return;
+ }
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "bind");
+ json_builder_add_boolean_value(builder, bind_creds);
+
+ json_builder_set_member_name(builder, "threePidCreds");
+ json_builder_add_value(builder, creds_node);
+
+ json_builder_end_object(builder);
+
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "account/3pid",
+ NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_change_password(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *new_password, GError **error)
+{
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(new_password != NULL);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "new_password");
+ json_builder_add_string_value(builder, new_password);
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "account/password",
+ NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+}
+
+static void
+matrix_http_api_get_profile(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("profile/", enc_user_id, NULL);
+ g_free(enc_user_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_get_avatar_url(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("profile/", enc_user_id, "/avatar_url", NULL);
+ g_free(enc_user_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_set_avatar_url(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, const gchar *avatar_url, GError **error)
+{
+ gchar *path;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(avatar_url != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("profile/", enc_user_id, "/avatar_url", NULL);
+ g_free(enc_user_id);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "avatar_url");
+ json_builder_add_string_value(builder, avatar_url);
+
+ json_builder_end_object(builder);
+
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+ g_free(path);
+}
+
+static void
+matrix_http_api_get_display_name(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+
+ uri_encode(user_id);
+ path = g_strconcat("profile/", enc_user_id, "/displayname", NULL);
+ g_free(enc_user_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_set_display_name(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_name, const gchar *display_name, GError **error)
+{
+ gchar *path;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(user_name != NULL);
+ g_return_if_fail(display_name != NULL);
+
+ uri_encode(user_name);
+ path = g_strconcat("profile/", enc_user_name, "/displayname", NULL);
+ g_free(enc_user_name);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "displayname");
+ json_builder_add_string_value(builder, display_name);
+
+ json_builder_end_object(builder);
+ root_node = json_builder_get_root(builder);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+ g_free(path);
+}
+
+static void
+matrix_http_api_register_account(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, MatrixAccountKind account_kind, gboolean bind_email, const gchar *username, const gchar *password, GError **error)
+{
+ GHashTable *parms = NULL;
+ JsonBuilder *builder;
+ JsonNode *root_node;
+
+ g_return_if_fail(password != NULL);
+
+ builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "bind_email");
+ json_builder_add_boolean_value(builder, bind_email);
+
+ if (username != NULL) {
+ json_builder_set_member_name(builder, "username");
+ 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);
+
+ if (account_kind != MATRIX_ACCOUNT_KIND_DEFAULT) {
+ gchar *account_kind_str = _matrix_g_enum_to_string(MATRIX_TYPE_ACCOUNT_KIND, account_kind, '_');
+
+ if (account_kind_str != NULL) {
+ parms = _matrix_http_api_create_query_params();
+
+ g_hash_table_replace(parms, g_strdup("kind"), account_kind_str);
+ }
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "register",
+ parms, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+ g_object_unref(builder);
+ g_hash_table_unref(parms);
+}
+
+static void
+matrix_http_api_set_account_data(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, const gchar *room_id, const gchar *event_type, JsonNode *content, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(event_type != NULL);
+ g_return_if_fail(content != NULL);
+
+ uri_encode(user_id);
+ uri_encode(event_type);
+
+ if (room_id != NULL) {
+ uri_encode(room_id);
+ path = g_strconcat("user/", enc_user_id, "/rooms/", enc_room_id, "/account_data/", enc_event_type, NULL);
+ g_free(enc_room_id);
+ } else {
+ path = g_strconcat("user/", enc_user_id, "/account_data/", enc_event_type, NULL);
+ }
+
+ g_free(enc_user_id);
+ g_free(enc_event_type);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, content, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_get_room_tags(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, const gchar *room_id, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(room_id != NULL);
+
+ uri_encode(user_id);
+ uri_encode(room_id);
+ path = g_strconcat("user/", enc_user_id, "/rooms/", enc_room_id, "/tags", NULL);
+ g_free(enc_user_id);
+ g_free(enc_room_id);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_delete_room_tag(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, const gchar *room_id, const gchar *tag, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(tag != NULL);
+
+ uri_encode(user_id);
+ uri_encode(room_id);
+ uri_encode(tag);
+ path = g_strconcat("user/", enc_user_id, "/rooms/", enc_room_id, "/tags/", enc_tag, NULL);
+ g_free(enc_user_id);
+ g_free(enc_room_id);
+ g_free(enc_tag);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "DELETE", path,
+ NULL, NULL, NULL, NULL, FALSE, error);
+
+ g_free(path);
+}
+
+static void
+matrix_http_api_add_room_tag(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *user_id, const gchar *room_id, const gchar *tag, JsonNode *content, GError **error)
+{
+ gchar *path;
+
+ g_return_if_fail(user_id != NULL);
+ g_return_if_fail(room_id != NULL);
+ g_return_if_fail(tag != NULL);
+
+ uri_encode(user_id);
+ uri_encode(room_id);
+ uri_encode(tag);
+
+ path = g_strconcat("user/", enc_user_id, "/rooms/", enc_room_id, "/tags/", enc_tag, NULL);
+
+ g_free(enc_user_id);
+ g_free(enc_room_id);
+ g_free(enc_tag);
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "PUT", path,
+ NULL, NULL, content, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_deactivate_account(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, const gchar *session, const gchar *login_type, GError **error)
+{
+ JsonNode *root_node = NULL;
+
+ if (login_type != NULL) {
+ JsonBuilder *builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "auth");
+ json_builder_begin_object(builder);
+
+ if (session != NULL) {
+ json_builder_set_member_name(builder, "session");
+ json_builder_add_string_value(builder, session);
+ }
+
+ json_builder_set_member_name(builder, "type");
+ json_builder_add_string_value(builder, login_type);
+
+ json_builder_end_object(builder);
+ json_builder_end_object(builder);
+
+ root_node = json_builder_get_root(builder);
+
+ g_object_unref(builder);
+ }
+
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "POST", "account/deactivate",
+ NULL, NULL, root_node, NULL, FALSE, error);
+
+ json_node_unref(root_node);
+}
+
+static void
+matrix_http_api_get_turn_server(MatrixAPI *matrix_api, MatrixAPICallback cb, void *cb_target, GError **error)
+{
+ _matrix_http_api_send(MATRIX_HTTP_API(matrix_api),
+ cb, cb_target,
+ CALL_TYPE_API, "GET", "voip/turnServer",
+ NULL, NULL, NULL, NULL, FALSE, error);
+}
+
+static void
+matrix_http_api_abort_pending (MatrixAPI *matrix_api)
+{
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(MATRIX_HTTP_API(matrix_api));
+
+ soup_session_abort(priv->soup_session);
+}
+
+const gchar *
+matrix_http_api_get_base_url (MatrixHTTPAPI *matrix_http_api)
+{
+ MatrixHTTPAPIPrivate *priv;
+
+ g_return_val_if_fail(matrix_http_api != NULL, NULL);
+
+ priv = matrix_http_api_get_instance_private(matrix_http_api);
+
+ return priv->base_url;
+}
+
+static gint
+string_last_index_of(const gchar *str, const gchar *needle, gint start_index)
+{
+ gchar *occurence = NULL;
+
+ g_return_val_if_fail(str != NULL, -1);
+ g_return_val_if_fail(needle != NULL, -1);
+
+ if ((occurence = g_strrstr (str + start_index, needle)) != NULL){
+ return (gint)(occurence - ((gchar*)str));
+ }
+
+ return -1;
+}
+
+void
+matrix_http_api_set_base_url(MatrixHTTPAPI *matrix_http_api, const gchar *base_url)
+{
+ MatrixHTTPAPIPrivate *priv;
+ SoupURI *api_uri;
+ SoupURI *media_uri;
+
+ g_return_if_fail(matrix_http_api != NULL);
+
+ priv = matrix_http_api_get_instance_private(matrix_http_api);
+
+ if (!g_str_is_ascii(base_url)) {
+ g_warning("URL specified(%s) is not ASCII", base_url);
+
+ return;
+ }
+
+ if (string_last_index_of(base_url, API_ENDPOINT, 0) != -1) {
+ g_warning("Provided URL (%s) already contains the API endpoint. Please use an URL without it!",
+ base_url);
+
+ return;
+ }
+
+ _matrix_http_api_set_url(matrix_http_api, &api_uri, base_url, API_ENDPOINT);
+ _matrix_http_api_set_url(matrix_http_api, &media_uri, base_url, MEDIA_ENDPOINT);
+
+ if ((api_uri != NULL) && (media_uri != NULL)) {
+ if (priv->api_uri != NULL) {
+ soup_uri_free(priv->api_uri);
+ }
+
+ if (priv->media_uri != NULL) {
+ soup_uri_free(priv->media_uri);
+ }
+
+ g_free(priv->base_url);
+
+ priv->api_uri = api_uri;
+ priv->media_uri = media_uri;
+ priv->base_url = g_strdup(base_url);
+
+ g_free(priv->token);
+ g_free(priv->refresh_token);
+ g_free(matrix_http_api->_homeserver);
+ g_free(matrix_http_api->_user_id);
+ priv->token = NULL;
+ priv->refresh_token = NULL;
+ matrix_http_api->_homeserver = NULL;
+ matrix_http_api->_user_id = NULL;
+
+#if DEBUG
+ gchar *uri;
+
+ uri = soup_uri_to_string(api_uri, FALSE);
+ g_debug("API URL: %s", uri);
+ g_free(uri);
+
+ uri = soup_uri_to_string(media_uri, FALSE);
+ g_debug("Media URL: %s", uri);
+ g_free(uri);
+#endif
+ } else {
+ g_warning("Invalid base URL: %s", base_url);
+ }
+
+ g_object_notify_by_pspec((GObject *)matrix_http_api, matrix_http_api_properties[PROP_BASE_URL]);
+}
+
+gboolean
+matrix_http_api_get_validate_certificate(MatrixHTTPAPI *matrix_http_api)
+{
+ MatrixHTTPAPIPrivate *priv;
+ gboolean result;
+
+ g_return_val_if_fail(matrix_http_api != NULL, FALSE);
+
+ priv = matrix_http_api_get_instance_private(matrix_http_api);
+
+ g_object_get(priv->soup_session, "ssl-strict", &result, NULL);
+
+ return result;
+}
+
+void
+matrix_http_api_set_validate_certificate(MatrixHTTPAPI *matrix_http_api, gboolean validate_certificate)
+{
+ MatrixHTTPAPIPrivate *priv;
+
+ g_return_if_fail(matrix_http_api != NULL);
+
+ priv = matrix_http_api_get_instance_private(matrix_http_api);
+
+ g_object_set(priv->soup_session, "ssl-strict", validate_certificate, NULL);
+
+ g_object_notify_by_pspec ((GObject *) matrix_http_api, matrix_http_api_properties[PROP_VALIDATE_CERTIFICATE]);
+}
+
+static const gchar *
+matrix_http_api_get_user_id (MatrixAPI *api)
+{
+ return MATRIX_HTTP_API(matrix_api)->_user_id;
+}
+
+static const gchar *
+matrix_http_api_get_token(MatrixAPI *matrix_api)
+{
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(MATRIX_HTTP_API(matrix_api));
+
+ return priv->token;
+}
+
+static void
+matrix_http_api_set_token(MatrixAPI *matrix_api, const gchar *token)
+{
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(MATRIX_HTTP_API(matrix_api));
+
+ if (g_strcmp0(token, priv->token) != 0) {
+ g_free(priv->token);
+ priv->token = g_strdup(token);
+
+ g_object_notify_by_pspec((GObject *)matrix_api, matrix_http_api_properties[PROP_TOKEN]);
+ }
+}
+
+static const gchar *
+matrix_http_api_get_refresh_token (MatrixAPI *matrix_api)
+{
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(MATRIX_HTTP_API(matrix_api));
+
+ return priv->refresh_token;
+}
+
+static void
+matrix_http_api_set_refresh_token(MatrixAPI *matrix_api, const gchar *refresh_token)
+{
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(MATRIX_HTTP_API(matrix_api));
+
+ if (g_strcmp0(refresh_token, priv->refresh_token) != 0) {
+ g_free(priv->refresh_token);
+ priv->refresh_token = g_strdup(refresh_token);
+
+ g_object_notify_by_pspec((GObject *)matrix_api, matrix_http_api_properties[PROP_REFRESH_TOKEN]);
+ }
+}
+
+static const gchar *
+matrix_http_api_get_homeserver(MatrixAPI *api) {
+ return MATRIX_HTTP_API(api)->_homeserver;
+}
+
+static void
+matrix_http_api_finalize(GObject *gobject)
+{
+ MatrixHTTPAPI *matrix_http_api = MATRIX_HTTP_API(gobject);
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(MATRIX_HTTP_API(gobject));
+
+ g_object_unref(priv->soup_session);
+ g_free(priv->base_url);
+
+ if (priv->api_uri != NULL) {
+ soup_uri_free(priv->api_uri);
+ }
+
+ if (priv->media_uri != NULL) {
+ soup_uri_free(priv->media_uri);
+ }
+
+ g_free(matrix_http_api->_user_id);
+ g_free(priv->token);
+ g_free(priv->refresh_token);
+ g_free(matrix_http_api->_homeserver);
+
+ G_OBJECT_CLASS(matrix_http_api_parent_class)->finalize(gobject);
+}
+
+static void
+matrix_http_api_get_property(GObject *gobject, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ MatrixHTTPAPI *matrix_http_api = MATRIX_HTTP_API(gobject);
+
+ switch (property_id) {
+ case PROP_BASE_URL:
+ g_value_set_string(value, matrix_http_api_get_base_url(matrix_http_api));
+
+ break;
+ case PROP_VALIDATE_CERTIFICATE:
+ g_value_set_boolean(value, matrix_http_api_get_validate_certificate(matrix_http_api));
+
+ break;
+ case PROP_USER_ID:
+ g_value_set_string(value, matrix_api_get_user_id((MatrixAPI*) matrix_http_api));
+
+ break;
+ case PROP_TOKEN:
+ g_value_set_string(value, matrix_api_get_token((MatrixAPI*) matrix_http_api));
+
+ break;
+ case PROP_REFRESH_TOKEN:
+ g_value_set_string(value, matrix_api_get_refresh_token((MatrixAPI*) matrix_http_api));
+
+ break;
+ case PROP_HOMESERVER:
+ g_value_set_string(value, matrix_api_get_homeserver((MatrixAPI*) matrix_http_api));
+
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec);
+
+ break;
+ }
+}
+
+static void
+matrix_http_api_set_property(GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ MatrixHTTPAPI * matrix_http_api = MATRIX_HTTP_API(gobject);
+
+ switch(property_id) {
+ case PROP_BASE_URL:
+ matrix_http_api_set_base_url(matrix_http_api, g_value_get_string(value));
+
+ break;
+ case PROP_VALIDATE_CERTIFICATE:
+ matrix_http_api_set_validate_certificate(matrix_http_api, g_value_get_boolean(value));
+
+ break;
+ case PROP_TOKEN:
+ matrix_api_set_token((MatrixAPI*) matrix_http_api, g_value_get_string(value));
+
+ break;
+ case PROP_REFRESH_TOKEN:
+ matrix_api_set_refresh_token((MatrixAPI*) matrix_http_api, g_value_get_string(value));
+
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec);
+
+ break;
+ }
+}
+
+static void
+matrix_http_api_class_init(MatrixHTTPAPIClass *klass)
+{
+ G_OBJECT_CLASS(klass)->get_property = matrix_http_api_get_property;
+ G_OBJECT_CLASS(klass)->set_property = matrix_http_api_set_property;
+ G_OBJECT_CLASS(klass)->finalize = matrix_http_api_finalize;
+
+ /**
+ * MatrixHTTPAPI:base-url:
+ *
+ * The base URL of the API.
+ */
+ matrix_http_api_properties[PROP_BASE_URL] = g_param_spec_string(
+ "base-url", "base-url", "base-url",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_BASE_URL, matrix_http_api_properties[PROP_BASE_URL]);
+
+ /**
+ * MatrixHTTPAPI:validate-certificate:
+ *
+ * If %TRUE (the default), the certificate will be checked; otherwise the library accepts
+ * invalid (eg. self-signed) certificates.
+ */
+ matrix_http_api_properties[PROP_VALIDATE_CERTIFICATE] = g_param_spec_boolean(
+ "validate-certificate", "validate-certificate", "validate-certificate",
+ FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_VALIDATE_CERTIFICATE, matrix_http_api_properties[PROP_VALIDATE_CERTIFICATE]);
+
+ matrix_http_api_properties[PROP_USER_ID] = g_param_spec_string(
+ "user-id", "user-id", "user-id",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_USER_ID, matrix_http_api_properties[PROP_USER_ID]);
+
+ matrix_http_api_properties[PROP_TOKEN] = g_param_spec_string(
+ "token", "token", "token",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TOKEN, matrix_http_api_properties[PROP_TOKEN]);
+
+ matrix_http_api_properties[PROP_REFRESH_TOKEN] = g_param_spec_string(
+ "refresh-token", "refresh-token", "refresh-token",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_REFRESH_TOKEN, matrix_http_api_properties[PROP_REFRESH_TOKEN]);
+
+ matrix_http_api_properties[PROP_HOMESERVER] = g_param_spec_string(
+ "homeserver", "homeserver", "homeserver",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_HOMESERVER, matrix_http_api_properties[PROP_HOMESERVER]);
+}
+
+static void
+matrix_http_api_matrix_api_interface_init(MatrixAPIInterface * iface)
+{
+ iface->media_download = matrix_http_api_media_download;
+ iface->media_thumbnail = matrix_http_api_media_thumbnail;
+ iface->media_upload = matrix_http_api_media_upload;
+ iface->get_presence_list = matrix_http_api_get_presence_list;
+ iface->update_presence_list = matrix_http_api_update_presence_list;
+ iface->get_presence = matrix_http_api_get_presence;
+ iface->set_presence = matrix_http_api_set_presence;
+ iface->update_pusher = matrix_http_api_update_pusher;
+ iface->get_pushers = matrix_http_api_get_pushers;
+ iface->delete_pushrule = matrix_http_api_delete_pushrule;
+ iface->get_pushrule = matrix_http_api_get_pushrule;
+ iface->add_pushrule = matrix_http_api_add_pushrule;
+ iface->toggle_pushrule = matrix_http_api_toggle_pushrule;
+ iface->get_pushrules = matrix_http_api_get_pushrules;
+ iface->create_room = matrix_http_api_create_room;
+ iface->delete_room_alias = matrix_http_api_delete_room_alias;
+ iface->get_room_id = matrix_http_api_get_room_id;
+ iface->create_room_alias = matrix_http_api_create_room_alias;
+ iface->list_public_rooms = matrix_http_api_list_public_rooms;
+ iface->ban_user = matrix_http_api_ban_user;
+ iface->unban_user = matrix_http_api_unban_user;
+ iface->forget_room = matrix_http_api_forget_room;
+ iface->invite_user_3rdparty = matrix_http_api_invite_user_3rdparty;
+ iface->invite_user = matrix_http_api_invite_user;
+ iface->join_room = matrix_http_api_join_room;
+ iface->leave_room = matrix_http_api_leave_room;
+ iface->join_room_id_or_alias = matrix_http_api_join_room_id_or_alias;
+ iface->kick_user = matrix_http_api_kick_user;
+ iface->event_stream = matrix_http_api_event_stream;
+ iface->get_event = matrix_http_api_get_event;
+ iface->initial_sync = matrix_http_api_initial_sync;
+ iface->get_event_context = matrix_http_api_get_event_context;
+ iface->initial_sync_room = matrix_http_api_initial_sync_room;
+ iface->list_room_members = matrix_http_api_list_room_members;
+ iface->list_room_messages = matrix_http_api_list_room_messages;
+ iface->send_event_receipt = matrix_http_api_send_event_receipt;
+ iface->redact_event = matrix_http_api_redact_event;
+ iface->send_event = matrix_http_api_send_event;
+ iface->get_room_state = matrix_http_api_get_room_state;
+ iface->send_state_event = matrix_http_api_send_state_event;
+ iface->notify_room_typing = matrix_http_api_notify_room_typing;
+ iface->sync = matrix_http_api_sync;
+ iface->create_filter = matrix_http_api_create_filter;
+ iface->download_filter = matrix_http_api_download_filter;
+ iface->search = matrix_http_api_search;
+ iface->whois = matrix_http_api_whois;
+ iface->versions = matrix_http_api_versions;
+ iface->login = matrix_http_api_login;
+ iface->token_refresh = matrix_http_api_token_refresh;
+ iface->logout = matrix_http_api_logout;
+ iface->get_3pids = matrix_http_api_get_3pids;
+ iface->add_3pid = matrix_http_api_add_3pid;
+ iface->change_password = matrix_http_api_change_password;
+ iface->get_profile = matrix_http_api_get_profile;
+ iface->get_avatar_url = matrix_http_api_get_avatar_url;
+ iface->set_avatar_url = matrix_http_api_set_avatar_url;
+ iface->get_display_name = matrix_http_api_get_display_name;
+ iface->set_display_name = matrix_http_api_set_display_name;
+ iface->register_account = matrix_http_api_register_account;
+ iface->set_account_data = matrix_http_api_set_account_data;
+ iface->get_room_tags = matrix_http_api_get_room_tags;
+ iface->delete_room_tag = matrix_http_api_delete_room_tag;
+ iface->add_room_tag = matrix_http_api_add_room_tag;
+ iface->deactivate_account = matrix_http_api_deactivate_account;
+ iface->get_turn_server = matrix_http_api_get_turn_server;
+ iface->abort_pending = matrix_http_api_abort_pending;
+ iface->get_user_id = matrix_http_api_get_user_id;
+ iface->get_token = matrix_http_api_get_token;
+ iface->set_token = matrix_http_api_set_token;
+ iface->get_refresh_token = matrix_http_api_get_refresh_token;
+ iface->set_refresh_token = matrix_http_api_set_refresh_token;
+ iface->get_homeserver = matrix_http_api_get_homeserver;
+}
+
+static void
+matrix_http_api_init(MatrixHTTPAPI *matrix_http_api)
+{
+ MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(matrix_http_api);
+
+ priv->soup_session = soup_session_new();
+ priv->base_url = NULL;
+ priv->api_uri = NULL;
+ priv->media_uri = NULL;
+ priv->token = NULL;
+ priv->refresh_token = NULL;
+}
diff --git a/src/matrix-http-api.h b/src/matrix-http-api.h
new file mode 100644
index 0000000..9d1698e
--- /dev/null
+++ b/src/matrix-http-api.h
@@ -0,0 +1,58 @@
+/*
+ * 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_HTTP_API_H__
+# define __MATRIX_GLIB_SDK_HTTP_API_H__
+
+# include
+# include "matrix-api.h"
+
+G_BEGIN_DECLS
+
+# define MATRIX_TYPE_HTTP_API (matrix_http_api_get_type ())
+# define MATRIX_HTTP_API(o) (G_TYPE_CHECK_INSTANCE_CAST((o), MATRIX_TYPE_HTTP_API, MatrixHTTPAPI))
+# define MATRIX_HTTP_API_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), MATRIX_TYPE_HTTP_API, MatrixHTTPAPIClass))
+# define MATRIX_IS_HTTP_API(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), MATRIX_TYPE_HTTP_API))
+# define MATRIX_IS_HTTP_API_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), MATRIX_TYPE_HTTP_API))
+# define MATRIX_HTTP_API_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), MATRIX_TYPE_HTTP_API, MatrixHTTPAPIClass))
+
+typedef struct _MatrixHTTPAPI MatrixHTTPAPI;
+typedef struct _MatrixHTTPAPIClass MatrixHTTPAPIClass;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(MatrixHTTPAPI, g_object_unref)
+
+struct _MatrixHTTPAPI {
+ GObject parent_instance;
+
+ gchar *_homeserver;
+ gchar *_user_id;
+};
+
+struct _MatrixHTTPAPIClass {
+ GObjectClass parent_class;
+};
+
+GType matrix_http_api_get_type(void) G_GNUC_CONST;
+MatrixHTTPAPI *matrix_http_api_new(const gchar *base_url, const gchar *token, const gchar *refresh_token);
+const gchar *matrix_http_api_get_base_url(MatrixHTTPAPI *http_api);
+void matrix_http_api_set_base_url(MatrixHTTPAPI *http_api, const gchar *base_url);
+gboolean matrix_http_api_get_validate_certificate(MatrixHTTPAPI *http_api);
+void matrix_http_api_set_validate_certificate(MatrixHTTPAPI *http_api, gboolean validate_certificate);
+
+G_END_DECLS
+
+#endif /* __MATRIX_GLIB_SDK_HTTP_API_H__ */
diff --git a/src/matrix-http-api.vala b/src/matrix-http-api.vala
deleted file mode 100644
index dd89011..0000000
--- a/src/matrix-http-api.vala
+++ /dev/null
@@ -1,1913 +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
- * .
- */
-
-/**
- * This is a class for low level communication with a Matrix.org
- * server via HTTP.
- */
-[CCode (lower_case_csuffix = "http_api")]
-public class Matrix.HTTPAPI : GLib.Object, Matrix.API {
- private enum CallType {
- API,
- MEDIA;
- }
-
- private const string API_ENDPOINT = "/_matrix/client/r0/";
- private const string MEDIA_ENDPOINT = "/_matrix/media/r0/";
-
- private Soup.Session _soup_session = new Soup.Session();
- private string? _base_url = null;
- private Soup.URI? _api_uri = null;
- private Soup.URI? _media_uri = null;
-
- public string base_url {
- get {
- return _base_url;
- }
-
- set {
- Soup.URI? api_uri;
- Soup.URI? media_uri;
-
- if (!value.is_ascii()) {
- warning("URL specified(%s) is not ASCII", value);
-
- return;
- }
-
- if (value.last_index_of(API_ENDPOINT) != -1) {
- warning("Provided URL (%s) already contains the API endpoint. Please use an URL without it!",
- base_url);
-
- return;
- }
-
- _set_url(out api_uri, value, API_ENDPOINT);
- _set_url(out media_uri, value, MEDIA_ENDPOINT);
-
- if ((api_uri != null) && (media_uri != null)) {
- _api_uri = api_uri;
- _media_uri = media_uri;
- _base_url = value;
-
- _token = null;
- _refresh_token = null;
- _homeserver = null;
- _user_id = null;
-
- if (Config.DEBUG) {
- debug("API URL: %s", api_uri.to_string(false));
- debug("Media URL: %s", media_uri.to_string(false));
- }
- } else {
- warning("Invalid base URL: %s", value);
- }
- }
- }
- public bool validate_certificate {
- get {
- return _soup_session.ssl_strict;
- }
-
- set {
- _soup_session.ssl_strict = value;
- }
- }
- protected string? _user_id;
- public string? user_id {
- get {
- return _user_id;
- }
-
- default = null;
- }
- public string? token { get; set; default = null; }
- public string? refresh_token { get; set; default = null; }
- protected string? _homeserver;
- public string? homeserver {
- get {
- return _homeserver;
- }
-
- default = null;
- }
-
- private void
- _set_url(out Soup.URI? uri, string base_url, string endpoint)
- {
- string url;
-
- if (base_url[base_url.length - 1] == '/') {
- url = "%s%s".printf(base_url, endpoint.offset(1));
- } else {
- url = "%s%s".printf(base_url, endpoint);
- }
-
- var new_uri = new Soup.URI(url);
-
- if (SOUP_URI_VALID_FOR_HTTP(new_uri)) {
- uri = new_uri;
- } else {
- uri = null;
- }
- }
-
- /**
- * Create a new MatrixHTTPAPI object.
- *
- * @param base_url the base URL of the homeserver to use
- * @param token an access token to use
- * @param refresh_token a refresh token to use
- * @return a new MatrixHTTPAPI object
- */
- protected
- HTTPAPI(string base_url, string? token = null, string? refresh_token = null)
- {
- Object(base_url : base_url,
- token : token,
- refresh_token : refresh_token);
- _soup_session.ssl_strict = true;
- }
-
- // This macro is not available in Vala
- private static bool
- SOUP_URI_VALID_FOR_HTTP(Soup.URI? uri)
- {
- return ((uri != null)
- && ((uri.scheme == "http")
- || (uri.scheme == "https"))
- && (uri.host != null)
- && (uri.path != null));
- }
-
- private void
- _send(API.Callback? cb,
- CallType call_type,
- string method,
- string path,
- owned GLib.HashTable? parms,
- string? content_type,
- Json.Node? json_content,
- ByteArray? raw_content,
- bool accept_non_json)
- throws Matrix.Error
- {
- if ((_api_uri == null) || (_media_uri == null)) {
- throw new Matrix.Error.COMMUNICATION_ERROR("No valid base URL");
- }
-
- if ((json_content != null) && (raw_content != null)) {
- critical("json_content and raw_content cannot be used together. This is a bug.");
- }
-
- if (!method.is_ascii()) {
- critical("Method must be ASCII. This is a bug.");
- }
-
- if ((method.ascii_casecmp("GET") != 0)
- && (method.ascii_casecmp("POST") != 0)
- && (method.ascii_casecmp("PUT") != 0)
- && (method.ascii_casecmp("DELETE") != 0)) {
- critical("Method %s is invalid. This is a bug.", method);
- }
-
- Soup.URI? request_path = null;
-
- if (call_type == CallType.MEDIA) {
- request_path = new Soup.URI.with_base(_media_uri, path);
- } else {
- request_path = new Soup.URI.with_base(_api_uri, path);
- }
-
- if (parms == null) {
- parms = _create_query_params();
- }
-
- if (token != null) {
- if (Config.DEBUG) {
- debug("Adding access token '%s'", token);
- }
-
- parms.replace("access_token", token);
- }
-
- request_path.set_query_from_form(parms);
-
- var message = new Soup.Message.from_uri(method, request_path);
-
- uint8[] request_data;
-
- if (json_content != null) {
- var generator = new Json.Generator();
- generator.set_root(json_content);
- var json_str = generator.to_data(null);
- request_data = json_str.data;
- request_data[request_data.length] = 0;
- } else if (raw_content != null) {
- request_data = raw_content.data;
- } else {
- request_data = "{}".data;
- request_data[2] = 0;
- }
-
- if (Config.DEBUG) {
- debug("Sending %d bytes (%s %s): %s",
- request_data.length,
- method,
- request_path.to_string(false),
- (raw_content != null)
- ? ""
- : (string)request_data);
- }
-
- message.set_flags(Soup.MessageFlags.NO_REDIRECT);
- message.set_request(
- (content_type == null)
- ? "application/json"
- : content_type,
- Soup.MemoryUse.COPY,
- request_data);
-
- _soup_session.queue_message(
- message,
- (session, msg) => _response_callback(msg,
- call_type,
- accept_non_json,
- cb));
- }
-
- private void
- _response_callback(Soup.Message msg,
- CallType call_type,
- bool accept_non_json,
- API.Callback? cb)
- {
- string request_url = msg.get_uri().get_path();
- Matrix.Error? err = null;
- ByteArray? raw_content = null;
- Json.Node? content = null;
-
- switch (call_type) {
- case CallType.API:
- request_url = request_url .substring(API_ENDPOINT.length);
-
- break;
-
- case CallType.MEDIA:
- request_url = request_url.substring(MEDIA_ENDPOINT.length);
-
- break;
- }
-
- if ((msg.status_code < 100)
- || (msg.status_code >= 400)) {
- err = new Matrix.Error.COMMUNICATION_ERROR(
- "%s %u: %s",
- (msg.status_code < 100) ? "Network error" : "HTTP",
- msg.status_code,
- msg.reason_phrase);
- } else {
- var buffer = msg.response_body.flatten();
- string data = (string)buffer.data;
- var datalen = buffer.length;
- var parser = new Json.Parser();
- bool is_json;
-
- try {
- is_json = parser.load_from_data(data, (ssize_t)datalen);
- } catch (GLib.Error e) {
- is_json = false;
- }
-
- if (is_json) {
- if (Config.DEBUG) {
- debug("Response (%s): %s", request_url, data);
- }
-
- content = parser.get_root();
-
- if (content.get_node_type() == Json.NodeType.OBJECT) {
- var root = content.get_object();
- Json.Node node;
-
- /* Check if the response holds an access token; if it
- * does, set it as our new token */
- if ((node = root.get_member("access_token")) != null) {
- string? access_token;
-
- if ((access_token = node.get_string()) != null) {
- if (Config.DEBUG) {
- debug("Got new access token: %s", access_token);
- }
-
- token = access_token;
- }
- }
-
- /* Check if the response holds a refresh token; if it
- * does, set it as our new refresh token */
- if ((node = root.get_member("refresh_token")) != null) {
- string? refresh_token;
-
- if ((refresh_token = node.get_string()) != null) {
- if (Config.DEBUG) {
- debug("Got new refresh token: %s",
- refresh_token);
- }
-
- this.refresh_token = refresh_token;
- }
- }
-
- /* Check if the response holds a homeserver name */
- if ((node = root.get_member("home_server")) != null) {
- string homeserver = node.get_string();
-
- if (Config.DEBUG) {
- debug("Our home server calls itself %s",
- homeserver);
- }
-
- this._homeserver = homeserver;
- }
-
- /* Check if the response holds a user ID; if it does,
- * set this as our user ID */
- if ((node = root.get_member("user_id")) != null) {
- string user_id = node.get_string();
-
- if (Config.DEBUG) {
- debug("We are reported to be logged in as %s",
- user_id);
- }
-
- this._user_id = user_id;
- }
-
- /* Check if the response holds an error */
- var errcode_node = root.get_member("errcode");
- var error_node = root.get_member("error");
- string? error = null;
- string? errcode = null;
-
- if ((errcode_node != null) || (error_node != null)) {
- err = new Matrix.Error.UNKNOWN_ERROR(
- "The error is not known to this library");
-
- if (error_node != null) {
- error = error_node.get_string();
- }
-
- if (errcode_node != null) {
- errcode = errcode_node.get_string();
-
- if (errcode.ascii_ncasecmp("M_", 2) == 0) {
- // This is an ugly hack until Vala
- // registers errordomains as an
- // EnumClass
- switch (errcode) {
- case "M_MISSING_TOKEN":
- err = new Matrix.Error.M_MISSING_TOKEN("");
-
- break;
-
- case "M_FORBIDDEN":
- err = new Matrix.Error.M_FORBIDDEN("");
-
- break;
-
- case "M_UNKNOWN":
- err = new Matrix.Error.M_UNKNOWN("");
-
- break;
-
- case "M_UNKNOWN_TOKEN":
- err = new Matrix.Error.M_UNKNOWN_TOKEN("");
-
- break;
-
- case "M_NOT_JSON":
- err = new Matrix.Error.M_NOT_JSON("");
-
- break;
-
- case "M_UNRECOGNIZED":
- err = new Matrix.Error.M_UNRECOGNIZED("");
-
- break;
-
- default:
- warning("An unknown error code '%s' was sent by the homeserver. You may want to report it to the Matrix GLib developers", errcode);
-
- break;
- }
- }
- } else {
- warning("An error was sent by the homeserver, but no error code was specified. You may want to report this to the homeserver admins.");
- err = new Matrix.Error.UNSPECIFIED("No error code was sent by the server");
- }
-
- if ((errcode_node != null) && (error_node != null)) {
- err.message = "%s: %s".printf(errcode, error);
- } else if (errcode_node != null) {
- err.message = errcode;
- } else {
- err.message = "(No errcode given) %s".printf(error);
- }
- }
- } else if (content.get_node_type() != Json.NodeType.ARRAY) {
- err = new Matrix.Error.BAD_RESPONSE(
- "Bad response: not a JSON object, nor an array.");
- }
- } else {
- if (accept_non_json) {
- raw_content = new ByteArray.sized((uint)datalen);
- raw_content.append(buffer.data);
-
- if (Config.DEBUG) {
- debug("Binary data (%s): %u bytes",
- request_url, (uint)datalen);
- }
- } else {
- err = new Matrix.Error.BAD_RESPONSE(
- "Malformed response (invalid JSON)");
-
- if (Config.DEBUG) {
- debug("Malformed response (%s): %s", request_url, data);
- }
- }
- }
- }
-
- /* Call the assigned function, if any */
- if (cb != null) {
- cb(this,
- msg.response_headers.get_content_type(null),
- content,
- raw_content,
- err);
- }
- }
-
- private static HashTable
- _create_query_params()
- {
- return new HashTable(str_hash, str_equal);
- }
-
- /* Media */
-
- public void
- media_download(API.Callback? cb,
- string server_name,
- string media_id)
- throws Matrix.Error
- {
- string path = "download/"
- + Soup.URI.encode(server_name, null)
- + "/"
- + Soup.URI.encode(media_id, null);
-
- _send(cb,
- CallType.MEDIA, "GET", path,
- null, null, null, null, true);
- }
-
- public void
- media_thumbnail(API.Callback? cb,
- string server_name,
- string media_id,
- uint width,
- uint height,
- ResizeMethod method)
- throws Matrix.Error
- {
- string path = "download/"
- + Soup.URI.encode(server_name, null)
- + "/"
- + Soup.URI.encode(media_id, null);
- HashTable parms;
-
- parms = _create_query_params();
-
- if (width > 0) {
- parms.replace("width", "%u".printf(width));
- }
-
- if (height > 0) {
- parms.replace("height", "%u".printf(height));
- }
-
- if (method != ResizeMethod.DEFAULT) {
- switch (method) {
- case ResizeMethod.CROP:
- parms.replace("method", "crop");
-
- break;
-
- case ResizeMethod.SCALE:
- parms.replace("method", "scale");
-
- break;
-
- // This is here to prevent compiler warnings
- case ResizeMethod.DEFAULT: break;
- }
- }
-
- _send(cb,
- CallType.MEDIA, "GET", path,
- parms, null, null, null, true);
- }
-
- public void
- media_upload(API.Callback? cb,
- string? content_type,
- owned ByteArray content)
- throws Matrix.Error
- {
- _send(cb,
- CallType.MEDIA, "POST", "upload",
- null, content_type, null, content, false);
- }
-
- /* Presence */
-
- public void
- get_presence_list(API.Callback? cb, string user_id)
- throws Matrix.Error
- {
- string path = "presence/list/" + Soup.URI.encode(user_id, null);
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- update_presence_list(API.Callback? cb,
- string user_id,
- string[] drop_ids,
- string[] invite_ids)
- throws Matrix.Error
- {
- Json.Builder builder;
- string path = "presence/"
- + Soup.URI.encode(user_id, null)
- + "/status";
-
- builder = new Json.Builder();
- builder.begin_object();
-
- if (drop_ids.length > 0) {
- builder.set_member_name("drop");
- builder.begin_array();
-
- foreach (var entry in drop_ids) {
- builder.add_string_value(entry);
- }
-
- builder.end_array();
- }
-
- if (invite_ids.length > 0) {
- builder.set_member_name("invite");
- builder.begin_array();
-
- foreach (var entry in invite_ids) {
- builder.add_string_value(entry);
- }
-
- builder.end_array();
- }
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, builder.get_root(), null, false);
- }
-
- public void
- get_presence(API.Callback? cb,
- string user_id)
- throws Matrix.Error
- {
- string path = "presence/"
- + Soup.URI.encode(user_id, null)
- + "/status";
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- set_presence(API.Callback? cb,
- string user_id,
- Presence presence,
- string? status_message)
- throws Matrix.Error
- {
- Json.Builder builder;
- string path = "presence/"
- + Soup.URI.encode(user_id, null)
- + "/status";
-
- builder = new Json.Builder();
- builder.begin_object();
-
- builder.set_member_name("presence");
- builder.add_string_value(
- _g_enum_value_to_nick(typeof(Matrix.Presence),
- presence));
-
- if (status_message != null) {
- builder.set_member_name("status_msg");
- builder.add_string_value(status_message);
- }
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, builder.get_root(), null, false);
- }
-
- /* Push notifications */
-
- public void
- update_pusher(API.Callback? cb,
- Matrix.Pusher pusher)
- throws Matrix.Error
- {
- Json.Node? pusher_node;
-
- if ((pusher_node = pusher.get_json_node()) != null) {
- return;
- }
-
- _send(cb,
- CallType.API, "POST", "pushers/set",
- null, null, pusher_node, null, false);
- }
-
- public void
- get_pushers(API.Callback? cb)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, "GET", "pushrules",
- null, null, null, null, false);
- }
-
- private static string
- _pusher_url(string scope,
- PusherKind kind,
- string rule_id)
- {
- return "pushrules/"
- + Soup.URI.encode(scope, null)
- + "/"
- + Soup.URI.encode(_g_enum_value_to_nick(
- typeof(Matrix.PusherKind),
- kind),
- null)
- + "/"
- + Soup.URI.encode(rule_id, null);
- }
-
- private void
- _pusher_modif(API.Callback? cb,
- string method,
- string scope,
- PusherKind kind,
- string rule_id)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, method,
- _pusher_url(scope, kind, rule_id),
- null, null, null, null, false);
- }
-
- public void
- delete_pushrule(API.Callback? cb,
- string scope,
- PusherKind kind,
- string rule_id)
- throws Matrix.Error
- {
- _pusher_modif(cb, "DELETE", scope, kind, rule_id);
- }
-
- public void
- get_pushrule(API.Callback? cb,
- string scope,
- PusherKind kind,
- string rule_id)
- throws Matrix.Error
- {
- _pusher_modif(cb, "GET", scope, kind, rule_id);
- }
-
- public void
- add_pushrule(API.Callback? cb,
- string scope,
- PusherKind kind,
- string rule_id,
- string? before,
- string? after,
- string[] actions,
- PusherConditionKind[] conditions)
- throws Matrix.Error
- {
- Json.Builder builder;
- HashTable parms = _create_query_params();
-
- if (before != null) {
- parms.replace("before", before);
- }
-
- if (after != null) {
- parms.replace("after", after);
- }
-
- builder = new Json.Builder();
- builder.begin_object();
-
- builder.set_member_name("actions");
- builder.begin_array();
- foreach (var entry in actions) {
- builder.add_string_value(entry);
- }
- builder.end_array();
-
- if (conditions.length > 0) {
- builder.set_member_name("conditions");
- builder.begin_array();
-
- foreach (var entry in conditions) {
- string? kind_string = _g_enum_value_to_nick(
- typeof(Matrix.PusherConditionKind),
- entry);
-
- if (kind_string == null) {
- warning("Invalid condition kind");
-
- return;
- }
-
- builder.begin_object();
- builder.set_member_name("kind");
- builder.add_string_value(kind_string);
- builder.end_object();
- }
-
- builder.end_array();
- }
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "GET",
- _pusher_url(scope, kind, rule_id),
- parms, null, builder.get_root(), null, false);
- }
-
- public void
- toggle_pushrule(API.Callback? cb,
- string scope,
- PusherKind kind,
- string rule_id,
- bool enabled)
- throws Matrix.Error
- {
- Json.Builder builder;
-
- builder = new Json.Builder();
- builder.begin_object();
-
- builder.set_member_name("enabled");
- builder.add_boolean_value(enabled);
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "GET",
- _pusher_url(scope, kind, rule_id),
- null, null, builder.get_root(), null, false);
- }
-
- public void
- get_pushrules(API.Callback? cb)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, "GET", "pushrules",
- null, null, null, null, false);
- }
-
- /* Room creation */
-
- public void
- create_room(API.Callback? cb,
- RoomPreset preset,
- string? room_name,
- string? room_alias,
- string? topic,
- RoomVisibility visibility,
- Json.Node? creation_content,
- Matrix.Event.State[] initial_state,
- string[] invitees,
- 3PidCredential[] invite_3pids)
- throws Matrix.Error
- {
- Json.Builder builder = new Json.Builder();
-
- builder.begin_object();
-
- if (creation_content != null) {
- builder.set_member_name("creation_content");
- builder.add_value(creation_content);
- }
-
- if (initial_state.length > 0) {
- builder.set_member_name("initial_state");
- builder.begin_array();
-
- foreach (var entry in initial_state) {
- builder.add_value(entry.json);
- }
-
- builder.end_array();
- }
-
- if (invitees.length > 0) {
- builder.set_member_name("invite");
- builder.begin_array();
-
- foreach (var entry in invitees) {
- builder.add_string_value(entry);
- }
-
- builder.end_array();
- }
-
- if (invite_3pids.length > 0) {
- builder.set_member_name("invite_3pid");
- builder.begin_array();
-
- foreach (var entry in invite_3pids) {
- try {
- builder.add_value(entry.get_json_node());
- // TODO exceptions should be handled here somehow
- } catch (Matrix.Error e) {}
- }
-
- builder.end_array();
- }
-
- if (room_name != null) {
- builder.set_member_name("name");
- builder.add_string_value(room_name);
- }
-
- if (preset != RoomPreset.NONE) {
- string? preset_string = _g_enum_value_to_nick(
- typeof(RoomPreset),
- preset);
-
- if (preset_string != null) {
- builder.set_member_name("preset");
- builder.add_string_value(preset_string);
- } else {
- warning("Invalid room preset type");
- }
- }
-
- if (room_alias != null) {
- builder.set_member_name("room_alias_name");
- builder.add_string_value(room_alias);
- }
-
- if (topic != null) {
- builder.set_member_name("topic");
- builder.add_string_value(topic);
- }
-
- if (visibility != RoomVisibility.DEFAULT) {
- string? visibility_string = _g_enum_value_to_nick(
- typeof(RoomVisibility), visibility);
-
- if (visibility_string != null) {
- builder.set_member_name("visibility");
- builder.add_string_value(visibility_string);
- } else {
- warning("Invalid room visibility type");
- }
- }
-
- _send(cb,
- CallType.API, "POST", "createRoom",
- null, null, builder.get_root(), null, false);
- }
-
- /* Room directory */
-
- public void
- delete_room_alias(API.Callback? cb,
- string room_alias)
- throws Matrix.Error
- {
- string path = "room/" + Soup.URI.encode(room_alias, null);
-
- _send(cb,
- CallType.API, "DELETE", path,
- null, null, null, null, false);
- }
-
- public void
- get_room_id(API.Callback? cb,
- string room_alias)
- throws Matrix.Error
- {
- string path = "room/" + Soup.URI.encode(room_alias, null);
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- create_room_alias(API.Callback? cb,
- string room_id,
- string room_alias)
- throws Matrix.Error
- {
- Json.Builder builder;
- string path = "room/" + Soup.URI.encode(room_alias, null);
-
- builder = new Json.Builder();
- builder.begin_object();
-
- builder.set_member_name("room_id");
- builder.add_string_value(room_id);
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, builder.get_root(), null, false);
- }
-
- /* Room discovery */
-
- public void
- list_public_rooms(API.Callback? cb)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, "GET", "publicRooms",
- null, null, null, null, false);
- }
-
- /* Room membership */
-
- public void
- ban_user(API.Callback? cb,
- string room_id,
- string user_id,
- string? reason)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/ban";
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("user_id");
- builder.add_string_value(user_id);
-
- if (reason != null) {
- builder.set_member_name("reason");
- builder.add_string_value(reason);
- }
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, builder.get_root(), null, false);
- }
-
- public void
- unban_user(API.Callback? cb,
- string room_id,
- string user_id)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/unban";
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("user_id");
- builder.add_string_value(user_id);
-
- builder.end_object();
-
- _send(cb, CallType.API, "POST", path, null, null, builder.get_root(), null, false);
- }
-
- public void
- forget_room(API.Callback? cb,
- string room_id)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/forget";
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, null, null, false);
- }
-
- public void
- invite_user_3rdparty(API.Callback? cb,
- string room_id,
- Matrix.3PidCredential credential)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/invite";
- Json.Node? body;
-
- if ((body = credential.get_json_node()) == null) {
- return;
- }
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, body, null, false);
- }
-
- public void
- invite_user(API.Callback? cb,
- string room_id,
- string user_id)
- throws Matrix.Error
- {
- var builder = new Json.Builder();
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/invite";
-
- builder.begin_object();
-
- builder.set_member_name("user_id");
- builder.add_string_value(user_id);
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, builder.get_root(), null, false);
- }
-
- public void
- join_room(API.Callback? cb,
- string room_id)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/join";
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, null, null, false);
- }
-
- public void
- leave_room(API.Callback? cb,
- string room_id)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/leave";
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, null, null, false);
- }
-
- public void
- join_room_id_or_alias(API.Callback? cb, string room_id_or_alias)
- throws Matrix.Error
- {
- var path = "join/" + Soup.URI.encode(room_id_or_alias, null);
-
- _send(cb, CallType.API, "POST", path,
- null, null, null, null, false);
- }
-
- public void
- kick_user(API.Callback? cb,
- string room_id, string user_id, string? reason)
- throws Matrix.Error
- {
- var path = "rooms/" + Soup.URI.encode(room_id, null) + "/kick";
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("user_id");
- builder.add_string_value(user_id);
-
- if (reason != null) {
- builder.set_member_name("reason");
- builder.add_string_value(reason);
- }
-
- builder.end_object();
-
- _send(cb, CallType.API, "POST", path,
- null, null, builder.get_root(), null, false);
- }
-
- /* Room participation */
-
- public void
- event_stream(API.Callback? cb,
- string? from_token,
- ulong timeout)
- throws Matrix.Error
- {
- HashTable parms = _create_query_params();
-
- if (from_token != null) {
- parms.replace("from", from_token);
- }
-
- if (timeout > 0) {
- parms.replace("timeout", "%lu".printf(timeout));
- }
-
- _send(cb,
- CallType.API, "GET", "events",
- parms, null, null, null, false);
- }
-
- public void
- get_event(API.Callback? cb,
- string event_id)
- throws Matrix.Error
- {
- string path = "events/" + Soup.URI.encode(event_id, null);
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- initial_sync(API.Callback? cb,
- uint limit,
- bool archived)
- throws Matrix.Error
- {
- HashTable parms = _create_query_params();
-
- if (limit != 0) {
- parms.replace("limit", "%u".printf(limit));
- }
-
- if (archived) {
- parms.replace("archived", "true");
- }
-
- _send(cb,
- CallType.API, "GET", "initialSync",
- parms, null, null, null, false);
- }
-
- public void
- get_event_context(API.Callback? cb,
- string room_id,
- string event_id,
- uint limit)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/"
- + Soup.URI.encode(event_id, null);
- HashTable? parms = null;
-
- if (limit > 0) {
- parms = _create_query_params();
-
- parms.replace("limit", "%u".printf(limit));
- }
-
- _send(cb,
- CallType.API, "GET", path,
- parms, null, null, null, false);
- }
-
- public void
- initial_sync_room(API.Callback? cb,
- string room_id)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/initialSync";
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- list_room_members(API.Callback? cb,
- string room_id)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/members";
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- list_room_messages(API.Callback? cb,
- string room_id,
- string from_token,
- EventDirection direction,
- uint limit)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/messages";
- HashTable parms = _create_query_params();
-
- parms.replace("from", from_token);
-
- switch (direction) {
- case EventDirection.BACKWARD:
- parms.replace("dir", "b");
-
- break;
-
- case EventDirection.FORWARD:
- parms.replace("dir", "f");
-
- break;
- }
-
- if (limit > 0) {
- parms.replace("limit", "%u".printf(limit));
- }
-
- _send(cb,
- CallType.API, "GET", path,
- parms, null, null, null, false);
- }
-
- public void
- send_event_receipt(API.Callback? cb,
- string room_id,
- ReceiptType receipt_type,
- string event_id,
- Json.Node receipt)
- throws Matrix.Error
- {
- string path = "rooms/"
- + Soup.URI.encode(room_id, null)
- + "/receipt/"
- + Soup.URI.encode(_g_enum_value_to_nick(
- typeof(ReceiptType),
- receipt_type),
- null)
- + "/"
- + Soup.URI.encode(event_id, null);
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, receipt, null, false);
- }
-
- public void
- redact_event(API.Callback? cb,
- string room_id,
- string event_id,
- string txn_id,
- string? reason)
- throws Matrix.Error
- {
- Json.Node? body = null;
- string path = "rooms/%s/redact/%s/%s".printf(
- Soup.URI.encode(room_id, null),
- Soup.URI.encode(event_id, null),
- Soup.URI.encode(txn_id, null));
-
- if (reason != null) {
- var builder = new Json.Builder();
- builder.begin_object();
-
- builder.set_member_name("reason");
- builder.add_string_value(reason);
-
- builder.end_object();
- body = builder.get_root();
- }
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, body, null, false);
- }
-
- public void
- send_event(API.Callback? cb,
- string room_id,
- string event_type,
- string txn_id,
- owned Json.Node content)
- throws Matrix.Error
- {
- string path = "rooms/%s/send/%s/%s".printf(
- Soup.URI.encode(room_id, null),
- Soup.URI.encode(event_type, null),
- Soup.URI.encode(txn_id, null));
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, content, null, false);
- }
-
- public void
- get_room_state(API.Callback? cb,
- string room_id,
- string? event_type,
- string? state_key)
- throws Matrix.Error
- {
- string path = "rooms/%s/state".printf(
- Soup.URI.encode(room_id, null));
-
- if (event_type != null) {
- path += "/%s".printf(Soup.URI.encode(event_type, null));
- }
-
- if (state_key != null) {
- path += "/%s".printf(Soup.URI.encode(state_key, null));
- }
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- send_state_event(API.Callback? cb,
- string room_id,
- string event_type,
- string? state_key,
- owned Json.Node content)
- throws Matrix.Error
- {
- string path = "rooms/%s/state/%s".printf(
- Soup.URI.encode(room_id, null),
- Soup.URI.encode(event_type, null));
-
- if (state_key != null) {
- path += "/%s".printf(Soup.URI.encode(state_key, null));
- }
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, content, null, false);
- }
-
- public void
- notify_room_typing(API.Callback? cb,
- string user_id,
- string room_id,
- uint timeout,
- bool typing)
- throws Matrix.Error
- {
- string path = "rooms/%s/typing/%s".printf(
- Soup.URI.encode(room_id, null),
- Soup.URI.encode(user_id, null));
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- if (timeout > 0) {
- builder.set_member_name("timeout");
- builder.add_int_value(timeout);
- }
-
- builder.set_member_name("typing");
- builder.add_boolean_value(typing);
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, builder.get_root(), null, false);
- }
-
- public void
- sync(API.Callback? cb,
- string? filter_id,
- Filter? filter,
- string? since,
- bool full_state,
- bool set_presence,
- ulong timeout)
- throws Matrix.Error
- {
- HashTable parms = _create_query_params();
-
- if ((filter_id != null) && (filter != null)) {
- throw new Matrix.Error.BAD_REQUEST(
- "Cannot set both filter_id and filter");
- }
-
- if (filter_id != null) {
- parms.replace("filter", filter_id);
- }
-
- if (filter != null) {
- parms.replace("filter", filter.get_json_data(null));
- }
-
- if (since != null) {
- parms.replace("since", since);
- }
-
- parms.replace("full_state", (full_state) ? "true" : "false");
-
- if (!set_presence) {
- parms.replace("set_presence", "offline");
- }
-
- if (timeout != 0) {
- parms.replace("timeout", "%lu".printf(timeout));
- }
-
- _send(cb,
- CallType.API, "GET", "sync",
- parms, null, null, null, false);
- }
-
- public void
- create_filter(API.Callback? cb,
- string user_id,
- Filter filter)
- throws Matrix.Error
- {
- string path = "user/%s/filter".printf(
- Soup.URI.encode(user_id, null));
-
- _send(cb,
- CallType.API, "POST", path,
- null, null, filter.get_json_node(), null, false);
- }
-
- public void
- download_filter(API.Callback? cb,
- string user_id,
- string filter_id)
- throws Matrix.Error
- {
- string path = "user/%s/filter/%s".printf(
- Soup.URI.encode(user_id, null),
- Soup.URI.encode(filter_id, null));
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- /* Search */
-
- public void
- search(Matrix.API.Callback? cb,
- string? next_batch,
- SearchCategories search_categories)
- throws Matrix.Error
- {
- HashTable? parms = null;
-
- if (next_batch == null) {
- parms = _create_query_params();
-
- parms.replace("next_batch", next_batch);
- }
-
- _send(cb,
- CallType.API, "POST", "search",
- parms, null, search_categories.get_json_node(), null, false);
- }
-
- /* Server administration */
-
- public void
- whois(API.Callback? cb, string user_id)
- throws Matrix.Error
- {
- string path = "admin/whois/" + Soup.URI.encode(user_id, null);
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- versions(API.Callback? cb)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, "GET", "versions",
- null, null, null, null, false);
- }
-
- /* Session management */
-
- public void
- login(API.Callback? cb,
- string login_type,
- Json.Node? content)
- throws Matrix.Error
- {
- Json.Node body = _json_node_deep_copy(content);
-
- body.get_object().set_string_member("type", login_type);
-
- _send(cb,
- CallType.API, "POST", "login",
- null, null, body, null, false);
- }
-
- public void
- token_refresh(API.Callback? cb,
- string? refresh_token)
- throws Matrix.Error
- {
- if ((refresh_token == null) && (this.refresh_token == null)) {
- throw new Matrix.Error.M_MISSING_TOKEN("No token available");
- }
-
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("refresh_token");
- builder.add_string_value((refresh_token != null)
- ? refresh_token
- : this.refresh_token);
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "POST", "tokenrefresh",
- null, null, builder.get_root(), null, false);
- }
-
- public void
- logout(API.Callback? cb)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, "POST", "logout",
- null, null, null, null, false);
- }
-
- /* User data */
-
- public void
- get_3pids(API.Callback? cb)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, "GET", "account/3pid",
- null, null, null, null, false);
- }
-
- public void
- add_3pid(API.Callback? cb,
- bool bind_creds,
- Matrix.3PidCredential creds)
- throws Matrix.Error
- {
- var id_node = creds.get_json_node();
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("bind");
- builder.add_boolean_value(bind_creds);
-
- builder.set_member_name("threePidCreds");
- builder.add_value(id_node);
-
- _send(cb,
- CallType.API, "POST", "account/3pid",
- null, null, builder.get_root(), null, false);
- }
-
- public void
- change_password(API.Callback? cb,
- string new_password)
- throws Matrix.Error
- {
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("new_password");
- builder.add_string_value(new_password);
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "POST", "account/password",
- null, null, builder.get_root(), null, false);
- }
-
- public void
- get_profile(API.Callback? cb,
- string user_id)
- throws Matrix.Error
- {
- string path = "profile/%s".printf(Soup.URI.encode(user_id, null));
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- get_avatar_url(API.Callback? cb,
- string user_id)
- throws Matrix.Error
- {
- string path = "profile/%s/avatar_url".printf(
- Soup.URI.encode(user_id, null));
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- set_avatar_url(API.Callback? cb,
- string user_id,
- string avatar_url)
- throws Matrix.Error
- {
- string path = "profile/%s/avatar_url".printf(
- Soup.URI.encode(user_id, null));
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("avatar_url");
- builder.add_string_value(avatar_url);
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, builder.get_root(), null, false);
- }
-
- public void
- get_display_name(API.Callback? cb,
- string user_id)
- throws Matrix.Error
- {
- string path = "profile/%s/displayname".printf(
- Soup.URI.encode(user_id, null));
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- set_display_name(API.Callback? cb,
- string user_name,
- string display_name)
- throws Matrix.Error
- {
- string path = "profile/%s/displayname".printf(
- Soup.URI.encode(user_id, null));
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("displayname");
- builder.add_string_value(display_name);
-
- builder.end_object();
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, builder.get_root(), null, false);
- }
-
- public void
- register_account(API.Callback? cb,
- AccountKind account_kind,
- bool bind_email,
- string? username,
- string password)
- throws Matrix.Error
- {
- HashTable? parms = null;
- var builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("bind_email");
- builder.add_boolean_value(bind_email);
-
- if (username != null) {
- builder.set_member_name("username");
- builder.add_string_value(username);
- }
-
- builder.set_member_name("password");
- builder.add_string_value(password);
-
- builder.end_object();
-
- if (account_kind != AccountKind.DEFAULT) {
- string? kind_string = _g_enum_value_to_nick(
- typeof(Matrix.AccountKind), account_kind);
-
- if (kind_string != null) {
- parms = _create_query_params();
-
- parms.replace("kind", kind_string);
- }
- }
-
- _send(cb,
- CallType.API, "POST", "register",
- parms, null, builder.get_root(), null, false);
- }
-
- public void
- set_account_data(API.Callback? cb,
- string user_id,
- string? room_id,
- string event_type,
- owned Json.Node content)
- throws Matrix.Error
- {
- string path;
-
- if (room_id != null) {
- path = "user/%s/rooms/%s/account_data/%s".printf(
- Soup.URI.encode(user_id, null),
- Soup.URI.encode(room_id, null),
- Soup.URI.encode(event_type, null));
- } else {
- path = "user/%s/account_data/%s".printf(
- Soup.URI.encode(user_id, null),
- Soup.URI.encode(event_type, null));
- }
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, content, null, false);
- }
-
- public void
- get_room_tags(API.Callback? cb,
- string user_id,
- string room_id)
- throws Matrix.Error
- {
- string path = "user/%s/rooms/%s/tags".printf(
- Soup.URI.encode(user_id, null),
- Soup.URI.encode(room_id, null));
-
- _send(cb,
- CallType.API, "GET", path,
- null, null, null, null, false);
- }
-
- public void
- delete_room_tag(API.Callback? cb,
- string user_id,
- string room_id,
- string tag)
- throws Matrix.Error
- {
- string path = "user/%s/rooms/%s/tags/%s".printf(
- Soup.URI.encode(user_id, null),
- Soup.URI.encode(room_id, null),
- Soup.URI.encode(tag, null));
-
- _send(cb,
- CallType.API, "DELETE", path,
- null, null, null, null, false);
- }
-
- public void
- add_room_tag(API.Callback? cb,
- string user_id,
- string room_id,
- string tag,
- owned Json.Node? content)
- throws Matrix.Error
- {
- string path = "user/%s/rooms/%s/tags/%s".printf(
- Soup.URI.encode(user_id, null),
- Soup.URI.encode(room_id, null),
- Soup.URI.encode(tag, null));
-
- _send(cb,
- CallType.API, "PUT", path,
- null, null, content, null, false);
- }
-
- public void
- deactivate_account(API.Callback? cb, string? session, string? login_type)
- throws Matrix.Error
- {
- Json.Builder? builder = null;
-
- if (login_type != null) {
- builder = new Json.Builder();
-
- builder.begin_object();
-
- builder.set_member_name("auth");
- builder.begin_object();
-
- if (session != null) {
- builder.set_member_name("session");
- builder.add_string_value(session);
- }
-
- builder.set_member_name("type");
- builder.add_string_value(login_type);
-
- builder.end_object();
- builder.end_object();
- }
-
- _send(cb, CallType.API, "POST", "account/deactivate",
- null, null, (builder != null) ? builder.get_root() : null, null, false);
- }
-
- /* VoIP */
-
- public void
- get_turn_server(API.Callback? cb)
- throws Matrix.Error
- {
- _send(cb,
- CallType.API, "GET", "voip/turnServer",
- null, null, null, null, false);
- }
-
- /* Non-spec methods */
-
- public void
- abort_pending()
- {
- _soup_session.abort();
- }
-}
diff --git a/src/test-api-client.c b/src/test-api-client.c
index fb108f1..001547a 100644
--- a/src/test-api-client.c
+++ b/src/test-api-client.c
@@ -20,7 +20,7 @@
#include
#include
-#include "matrix-glib.h"
+#include "matrix-http-api.h"
#define LOG_DOMAIN "Matrix-Test-Client"
diff --git a/vapi/c-api.vapi b/vapi/c-api.vapi
index 5d83efa..7fc386e 100644
--- a/vapi/c-api.vapi
+++ b/vapi/c-api.vapi
@@ -704,6 +704,250 @@ namespace Matrix {
throws Matrix.Error;
}
+ [CCode (lower_case_csuffix = "http_api", cheader_filename = "matrix-http-api.h")]
+ public class HTTPAPI : GLib.Object, API {
+ public string base_url { get; set; }
+ public bool validate_certificate { get; set; }
+ protected string? _user_id;
+ public string? user_id { get; default = null; }
+ public string? token { get; set; default = null; }
+ public string? refresh_token { get; set; default = null; }
+ protected string? _homeserver;
+ public string? homeserver { get; default = null; }
+
+ protected HTTPAPI(string base_url, string? token = null, string? refresh_token = null);
+
+ /* Media */
+
+ public void media_download(API.Callback? cb, string server_name, string media_id)
+ throws Matrix.Error;
+
+ public void media_thumbnail(API.Callback? cb, string server_name, string media_id, uint width, uint height, ResizeMethod method)
+ throws Matrix.Error;
+
+ public void media_upload(API.Callback? cb, string? content_type, owned GLib.ByteArray content)
+ throws Matrix.Error;
+
+ /* Presence */
+
+ public void get_presence_list(API.Callback? cb, string user_id)
+ throws Matrix.Error;
+
+ public void
+ update_presence_list(API.Callback? cb, string user_id, string[] drop_ids, string[] invite_ids)
+ throws Matrix.Error;
+
+ public void get_presence(API.Callback? cb, string user_id)
+ throws Matrix.Error;
+
+ public void set_presence(API.Callback? cb, string user_id, Presence presence, string? status_message)
+ throws Matrix.Error;
+
+ /* Push notifications */
+
+ public void update_pusher(API.Callback? cb, Matrix.Pusher pusher)
+ throws Matrix.Error;
+
+ public void get_pushers(API.Callback? cb)
+ throws Matrix.Error;
+
+
+ private void _pusher_modif(API.Callback? cb, string method, string scope, PusherKind kind, string rule_id)
+ throws Matrix.Error;
+
+ public void delete_pushrule(API.Callback? cb, string scope, PusherKind kind, string rule_id)
+ throws Matrix.Error;
+
+ public void get_pushrule(API.Callback? cb, string scope, PusherKind kind, string rule_id)
+ throws Matrix.Error;
+
+ public void add_pushrule(API.Callback? cb, string scope, PusherKind kind, string rule_id, string? before, string? after, string[] actions, PusherConditionKind[] conditions)
+ throws Matrix.Error;
+
+ public void toggle_pushrule(API.Callback? cb, string scope, PusherKind kind, string rule_id, bool enabled)
+ throws Matrix.Error;
+
+ public void get_pushrules(API.Callback? cb)
+ throws Matrix.Error;
+
+ /* Room creation */
+
+ public void create_room(API.Callback? cb, RoomPreset preset, string? room_name, string? room_alias, string? topic, RoomVisibility visibility, Json.Node? creation_content, Matrix.Event.State[] initial_state, string[] invitees, 3PidCredential[] invite_3pids)
+ throws Matrix.Error;
+
+ /* Room directory */
+
+ public void delete_room_alias(API.Callback? cb, string room_alias)
+ throws Matrix.Error;
+
+ public void get_room_id(API.Callback? cb, string room_alias)
+ throws Matrix.Error;
+
+ public void create_room_alias(API.Callback? cb, string room_id, string room_alias)
+ throws Matrix.Error;
+
+ /* Room discovery */
+
+ public void list_public_rooms(API.Callback? cb)
+ throws Matrix.Error;
+
+ /* Room membership */
+
+ public void ban_user(API.Callback? cb, string room_id, string user_id, string? reason)
+ throws Matrix.Error;
+
+ public void unban_user(API.Callback? cb, string room_id, string user_id)
+ throws Matrix.Error;
+
+ public void forget_room(API.Callback? cb, string room_id)
+ throws Matrix.Error;
+
+ public void invite_user_3rdparty(API.Callback? cb, string room_id, Matrix.3PidCredential credential)
+ throws Matrix.Error;
+
+ public void invite_user(API.Callback? cb, string room_id, string user_id)
+ throws Matrix.Error;
+
+ public void join_room(API.Callback? cb, string room_id)
+ throws Matrix.Error;
+
+ public void leave_room(API.Callback? cb, string room_id)
+ throws Matrix.Error;
+
+ public void join_room_id_or_alias(API.Callback? cb, string room_id_or_alias)
+ throws Matrix.Error;
+
+ public void kick_user(API.Callback? cb, string room_id, string user_id, string? reason)
+ throws Matrix.Error;
+
+ /* Room participation */
+
+ public void event_stream(API.Callback? cb, string? from_token, ulong timeout)
+ throws Matrix.Error;
+
+ public void get_event(API.Callback? cb, string event_id)
+ throws Matrix.Error;
+
+ public void initial_sync(API.Callback? cb, uint limit, bool archived)
+ throws Matrix.Error;
+
+ public void get_event_context(API.Callback? cb, string room_id, string event_id, uint limit)
+ throws Matrix.Error;
+
+ public void initial_sync_room(API.Callback? cb, string room_id)
+ throws Matrix.Error;
+
+ public void list_room_members(API.Callback? cb, string room_id)
+ throws Matrix.Error;
+
+ public void list_room_messages(API.Callback? cb, string room_id, string from_token, EventDirection direction, uint limit)
+ throws Matrix.Error;
+
+ public void send_event_receipt(API.Callback? cb, string room_id, ReceiptType receipt_type, string event_id, Json.Node receipt)
+ throws Matrix.Error;
+
+ public void redact_event(API.Callback? cb, string room_id, string event_id, string txn_id, string? reason)
+ throws Matrix.Error;
+
+ public void send_event(API.Callback? cb, string room_id, string event_type, string txn_id, owned Json.Node content)
+ throws Matrix.Error;
+
+ public void get_room_state(API.Callback? cb, string room_id, string? event_type, string? state_key)
+ throws Matrix.Error;
+
+ public void send_state_event(API.Callback? cb, string room_id, string event_type, string? state_key, owned Json.Node content)
+ throws Matrix.Error;
+
+ public void notify_room_typing(API.Callback? cb, string user_id, string room_id, uint timeout, bool typing)
+ throws Matrix.Error;
+
+ public void sync(API.Callback? cb, string? filter_id, Filter? filter, string? since, bool full_state, bool set_presence, ulong timeout)
+ throws Matrix.Error;
+
+ public void create_filter(API.Callback? cb, string user_id, Filter filter)
+ throws Matrix.Error;
+
+ public void download_filter(API.Callback? cb, string user_id, string filter_id)
+ throws Matrix.Error;
+
+ /* Search */
+
+ public void search(Matrix.API.Callback? cb, string? next_batch, SearchCategories search_categories)
+ throws Matrix.Error;
+
+ /* Server administration */
+
+ public void whois(API.Callback? cb, string user_id)
+ throws Matrix.Error;
+
+ public void versions(API.Callback? cb)
+ throws Matrix.Error;
+
+ /* Session management */
+
+ public void login(API.Callback? cb, string login_type, Json.Node? content)
+ throws Matrix.Error;
+
+ public void token_refresh(API.Callback? cb, string? refresh_token)
+ throws Matrix.Error;
+
+ public void logout(API.Callback? cb)
+ throws Matrix.Error;
+
+ /* User data */
+
+ public void get_3pids(API.Callback? cb)
+ throws Matrix.Error;
+
+ public void add_3pid(API.Callback? cb, bool bind_creds, Matrix.3PidCredential creds)
+ throws Matrix.Error;
+
+ public void change_password(API.Callback? cb, string new_password)
+ throws Matrix.Error;
+
+ public void get_profile(API.Callback? cb, string user_id)
+ throws Matrix.Error;
+
+ public void get_avatar_url(API.Callback? cb, string user_id)
+ throws Matrix.Error;
+
+ public void set_avatar_url(API.Callback? cb, string user_id, string avatar_url)
+ throws Matrix.Error;
+
+ public void get_display_name(API.Callback? cb, string user_id)
+ throws Matrix.Error;
+
+ public void set_display_name(API.Callback? cb, string user_name, string display_name)
+ throws Matrix.Error;
+
+ public void register_account(API.Callback? cb, AccountKind account_kind, bool bind_email, string? username, string password)
+ throws Matrix.Error;
+
+ public void set_account_data(API.Callback? cb, string user_id, string? room_id, string event_type, owned Json.Node content)
+ throws Matrix.Error;
+
+ public void get_room_tags(API.Callback? cb, string user_id, string room_id)
+ throws Matrix.Error;
+
+ public void delete_room_tag(API.Callback? cb, string user_id, string room_id, string tag)
+ throws Matrix.Error;
+
+ public void add_room_tag(API.Callback? cb, string user_id, string room_id, string tag, owned Json.Node? content)
+ throws Matrix.Error;
+
+ public void deactivate_account(API.Callback? cb, string? session, string? login_type)
+ throws Matrix.Error;
+
+ /* VoIP */
+
+ public void get_turn_server(API.Callback? cb)
+ throws Matrix.Error;
+
+ /* Non-spec methods */
+
+ public void abort_pending();
+ }
+
/**
* The major version number of the Matrix.org GLib SDK.
*/