diff --git a/configure.ac b/configure.ac index a65e3ab..367f277 100644 --- a/configure.ac +++ b/configure.ac @@ -55,6 +55,7 @@ AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums]) PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.38]) PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 >= 2.38]) PKG_CHECK_MODULES([SOUP], [libsoup-2.4]) +PKG_CHECK_MODULES([JSON], [json-glib-1.0]) LIBMATRIX_GLIB_LIBS='$(top_builddir)/src/libmatrix-glib-$(MATRIX_GLIB_API_VERSION).la' AC_SUBST(LIBMATRIX_GLIB_LIBS) diff --git a/docs/reference/matrix-glib/matrix-glib-docs.xml b/docs/reference/matrix-glib/matrix-glib-docs.xml index 792f07e..86add7e 100644 --- a/docs/reference/matrix-glib/matrix-glib-docs.xml +++ b/docs/reference/matrix-glib/matrix-glib-docs.xml @@ -19,9 +19,9 @@ Matrix Client - + - + Object Hierarchy diff --git a/docs/reference/matrix-glib/matrix-glib-sections.txt b/docs/reference/matrix-glib/matrix-glib-sections.txt index def1caa..243b1dc 100644 --- a/docs/reference/matrix-glib/matrix-glib-sections.txt +++ b/docs/reference/matrix-glib/matrix-glib-sections.txt @@ -18,19 +18,55 @@ matrix_client_get_type
matrix-api MatrixAPI +MatrixAPICallback +matrix_api_ban_user +matrix_api_create_room +matrix_api_event_stream +matrix_api_get_emote_body +matrix_api_get_html_body +matrix_api_get_text_body +matrix_api_get_room_name +matrix_api_get_room_state +matrix_api_get_room_topic +matrix_api_initial_sync +matrix_api_invite_user +matrix_api_join_room +matrix_api_kick_user +matrix_api_leave_room +matrix_api_login +matrix_api_register_account +matrix_api_send_emote +matrix_api_send_message +matrix_api_send_message_event +matrix_api_send_state_event +matrix_api_set_membership MatrixAPI -MatrixAPIClass -MATRIX_IS_API -MATRIX_IS_API_CLASS -MATRIX_API -MATRIX_API_CLASS -MATRIX_API_GET_CLASS +MatrixAPIInterface MATRIX_TYPE_API +MATRIX_API +MATRIX_IS_API +MATRIX_API_GET_IFACE MatrixApiPrivate matrix_api_get_type
+
+matrix-http-api +matrix_http_api_get_validate_certificate +matrix_http_api_set_validate_certificate + +MatrixHTTPAPI +MatrixHTTPAPIClass +MATRIX_TYPE_HTTP_API +MATRIX_HTTP_API +MATRIX_HTTP_API_CLASS +MATRIX_IS_HTTP_API +MATRIX_IS_HTTP_API_CLASS +MATRIX_HTTP_API_GET_CLASS +matrix_http_api_get_type +
+
matrix-version MATRIX_GLIB_MAJOR_VERSION diff --git a/src/Makefile.am b/src/Makefile.am index 0d645e2..2cd5539 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,7 @@ lib_LTLIBRARIES = libmatrix-glib-0.0.la INST_H_SRC_FILES = \ matrix-client.h \ matrix-api.h \ + matrix-http-api.h \ $(NULL) INST_H_BUILT_FILES = matrix-version.h @@ -13,12 +14,13 @@ libmatrix_glib_0_0_la_SOURCES = \ matrix-client.c \ matrix-version.c \ matrix-api.c \ + matrix-http-api.c \ $(INST_H_SRC_FILES) \ $(INST_H_BUILT_FILES) \ $(NULL) -libmatrix_glib_0_0_la_CFLAGS = $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(SOUP_CFLAGS) -libmatrix_glib_0_0_la_LIBADD = $(GLIB_LIBS) $(GOBJECT_LIBS) $(SOUP_LIBS) +libmatrix_glib_0_0_la_CFLAGS = $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) +libmatrix_glib_0_0_la_LIBADD = $(GLIB_LIBS) $(GOBJECT_LIBS) $(SOUP_LIBS) $(JSON_LIBS) libmatrix_glib_0_0_la_DEPENDENCIES = CLEANFILES = @@ -29,7 +31,7 @@ MatrixGlib-$(MATRIX_GLIB_API_VERSION).gir: libmatrix-glib-0.0.la Matrix_@MATRIX_GLIB_API_VERSION_U@_gir_FILES = $(INST_H_SRC_FILES) $(INST_H_BUILT_FILES) $(filter %.c,$(libmatrix_glib_0_0_la_SOURCES)) Matrix_@MATRIX_GLIB_API_VERSION_U@_gir_LIBS = libmatrix-glib-0.0.la Matrix_@MATRIX_GLIB_API_VERSION_U@_gir_SCANNERFLAGS = --identifier-prefix=Matrix --symbol-prefix=matrix --warn-all -Matrix_@MATRIX_GLIB_API_VERSION_U@_gir_INCLUDES = GLib-2.0 GObject-2.0 Soup-2.4 +Matrix_@MATRIX_GLIB_API_VERSION_U@_gir_INCLUDES = GLib-2.0 GObject-2.0 Soup-2.4 Json-1.0 Matrix_@MATRIX_GLIB_API_VERSION_U@_gir_CFLAGS = -D__MATRIX_GLIB_BUILDING__ -I$(top_srcdir) -I$(srcdir) -I$(builddir) Matrix_@MATRIX_GLIB_API_VERSION_U@_gir_EXPORT_PACKAGES = matrix-glib INTROSPECTION_GIRS = Matrix-$(MATRIX_GLIB_API_VERSION).gir diff --git a/src/matrix-api.c b/src/matrix-api.c index d01085c..63e9f05 100644 --- a/src/matrix-api.c +++ b/src/matrix-api.c @@ -18,168 +18,529 @@ #include "matrix-api.h" -#include -#include - /** * SECTION:matrix-api - * @short_description: Low level API calls to communicate with a - * Matrix.org server * @title: MatrixAPI - * @stability: Unstable - * @include: matrix-glib/matrix.h + * @short_description: An interface for actual API implementations, + * like #MatrixHTTPAPI * - * This is a class for low level communication with a Matrix.org - * server. - */ + * This interface provides a skeleton for all API functionality for + * client communication with a Matrix.org homeserver. + **/ /** * MatrixAPI: * - * The MatrixAPI object’s instance definition. + * An opaque pointer type. + **/ + +/** + * MatrixAPIInterface: + * @login: virtual function for matrix_api_login() + * @register_account: virtual_function for + * matrix_api_register_account() + * @initial_sync: virtual function for matrix_api_initial_sync() + * @event_stream: virtual function for matrix_api_event_stream() + * @create_room: virtual function for matrix_api_create_room() + * @join_room: virtual function for matrix_api_join_room() + * @send_state_event: virtual function for + * matrix_api_send_state_event() + * @send_message_event: virtual function for + * matrix_api_send_message_event() + * @send_message: virtual function for matrix_api_send_message() + * @send_emote: virtual function for matrix_api_send_emote() + * @get_room_name: virtual function for matrix_api_get_room_name() + * @get_room_topic: virtual function for matrix_api_get_room_topic() + * @leave_room: virtual function for matrix_api_leave_room() + * @invite_user: virtual function for matrix_api_invite_user() + * @kick_user: virtual function for matrix_api_kick_user() + * @set_membership: virtual function for matrix_api_set_membership() + * @ban_user: virtual function for matrix_api_ban_user() + * @get_room_state: virtual function for matrix_api_get_room_state() + * @get_text_body: virtual function for matrix_api_get_text_body() + * @get_html_body: virtual function for matrix_api_get_html_body() + * @get_emote_body: virtual function for matrix_api_get_emote_body() + * @_send: virtual function for matrix_api_send() + * + * The interface vtable for #MatrixAPI */ /** - * MatrixAPIClass: - * @parent_class: the parent class structure (#GObjectClass) + * MatrixAPICallback: + * @api: A #MatrixAPI implementation + * @content: the JSON content of the response, as a #JsonNode + * @data: User data specified when calling original request function * - * The MatrixAPI object’s class definition. + * A callback function to use with API calls. */ -#define API_ENDPOINT "/_matrix/client/api/v1" - -typedef struct _MatrixAPIPrivate { - SoupSession *soup_session; - guint txn_id; - gchar *url; - gchar *token; - gboolean validate_cert; -} MatrixAPIPrivate; - -enum { - PROP_URL = 1, - N_PROPERTIES -}; - -GParamSpec *obj_properties[N_PROPERTIES] = {NULL,}; - -G_DEFINE_TYPE_WITH_PRIVATE(MatrixAPI, matrix_api, G_TYPE_OBJECT); +G_DEFINE_INTERFACE(MatrixAPI, matrix_api, G_TYPE_OBJECT); static void -matrix_api_finalize(GObject *gobject) +matrix_api_default_init(MatrixAPIInterface *iface) { - g_signal_handlers_destroy(gobject); - G_OBJECT_CLASS(matrix_api_parent_class)->finalize(gobject); } -static void -matrix_api_set_property(GObject *gobject, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +/** + * matrix_api_ban_user: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room ID where the user should be banned + * @user_id: the user ID to ban + * @reason: (allow-none): the reason of the ban + * + * Ban the specified user from the specified room. An optional reason + * can be specified. + */ +void +matrix_api_ban_user(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id, + gchar *reason) { - MatrixAPI *api = MATRIX_API(gobject); - MatrixAPIPrivate *priv = matrix_api_get_instance_private(api); + g_return_if_fail(MATRIX_IS_API(api)); - switch (prop_id) { - case PROP_URL: - { - const gchar *base_url; - gchar *last_occurence; - - base_url = g_value_get_string(value); - - if (!g_str_is_ascii(base_url)) { - g_warning("URL specified (%s) is not ASCII", base_url); - - return; - } - - last_occurence = g_strrstr(base_url, API_ENDPOINT); - - if ((g_strcmp0(last_occurence, API_ENDPOINT) == 0) || - (g_strcmp0(last_occurence, API_ENDPOINT"/") == 0)) { - priv->url = g_strdup(base_url); - } else { - priv->url = g_strdup_printf( - "%s%s%s", - base_url, - (base_url[strlen(base_url) - 1] == '/') ? "" : "/", - API_ENDPOINT); - } - - break; - } - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); - } + MATRIX_API_GET_IFACE(api) + ->ban_user(api, callback, user_data, room_id, user_id, reason); } -static void -matrix_api_get_property(GObject *gobject, - guint prop_id, - GValue *value, - GParamSpec *pspec) +/** + * matrix_api_create_room: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @alias: the alias (name) of the room + * @is_public: if %TRUE, the room will be accessible for anyone + * @invitees: (allow-none): list of user IDs to invite to the new room + * + * Create a new room with the given name and invite the users in + * @invitees. + */ +void +matrix_api_create_room(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *alias, + gboolean is_public, + GStrv invitees) { - MatrixAPI *api = MATRIX_API(gobject); - MatrixAPIPrivate *priv = matrix_api_get_instance_private(api); + g_return_if_fail(MATRIX_IS_API(api)); - switch (prop_id) { - case PROP_URL: - g_value_set_string(value, priv->url); - - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); - } + MATRIX_API_GET_IFACE(api) + ->create_room(api, callback, user_data, alias, is_public, invitees); } -static void -matrix_api_class_init(MatrixAPIClass *klass) +/** + * matrix_api_event_stream: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @from_token: (allow-none): events will be listed from this token + * @timeout: timeout of the request + * + * Get the event stream, optionally beginning from @from_token. + */ +void +matrix_api_event_stream(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *from_token, + gulong timeout) { - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + g_return_if_fail(MATRIX_IS_API(api)); - gobject_class->set_property = matrix_api_set_property; - gobject_class->get_property = matrix_api_get_property; - gobject_class->finalize = matrix_api_finalize; - - /** - * MatrixAPI:url: - * - * The base URL to use for communication with the Matrix.org - * server. - */ - obj_properties[PROP_URL] = g_param_spec_string( - "url", "Server URL", - "Matrix.org home server to connect to.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(gobject_class, - N_PROPERTIES, - obj_properties); + MATRIX_API_GET_IFACE(api) + ->event_stream(api, callback, user_data, from_token, timeout); } -static void -matrix_api_init(MatrixAPI *api) +/** + * matrix_api_get_room_name: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room ID to get a name for + * + * Get the name (alias) of a room. + */ +void +matrix_api_get_room_name(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id) { - MatrixAPIPrivate *priv = matrix_api_get_instance_private(api); + g_return_if_fail(MATRIX_IS_API(api)); - priv->txn_id = 0; - priv->url = NULL; - priv->token = NULL; - priv->validate_cert = TRUE; - priv->soup_session = soup_session_new_with_options( - SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_SNIFFER, - NULL); + MATRIX_API_GET_IFACE(api) + ->get_room_name(api, callback, user_data, room_id); } -MatrixAPI * -matrix_api_new(const gchar *base_url, const gchar *token) +/** + * matrix_api_get_room_state: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room ID to get a state for + * + * Get the state of a room. + */ +void +matrix_api_get_room_state(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id) { - return g_object_new(MATRIX_TYPE_API, - "base-url", base_url, - "token", token, - NULL); + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->get_room_state(api, callback, user_data, room_id); +} + +/** + * matrix_api_get_room_topic: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room ID to get a topic for + * + * Get the topic of a room. + */ +void +matrix_api_get_room_topic(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->get_room_topic(api, callback, user_data, room_id); +} + +/** + * matrix_api_initial_sync: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @limit: the maximum number of events to get + * + * perform an initial sync of events + */ +void +matrix_api_initial_sync(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + guint limit) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->initial_sync(api, callback, user_data, limit); +} + +/** + * matrix_api_invite_user: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room ID to invite the user to + * @user_id: the user ID to invite + * + * Invite a user to a room. + */ +void +matrix_api_invite_user(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->invite_user(api, callback, user_data, room_id, user_id); +} + +/** + * matrix_api_join_room: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id_or_alias: the room ID or room alias to join to + * + * Join a room. + */ +void +matrix_api_join_room(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id_or_alias) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->join_room(api, callback, user_data, room_id_or_alias); +} + +/** + * matrix_api_kick_user: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room ID to kick the user from + * @user_id: the user to kick + * @reason: (allow-none): the reason of kicking + * + * Kick a user from a room, with an optional reason. + */ +void +matrix_api_kick_user(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id, + gchar *reason) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->kick_user(api, callback, user_data, room_id, user_id, reason); +} + +/** + * matrix_api_leave_room: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room ID to kick the user from + * + * Leave a room + */ +void +matrix_api_leave_room(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->leave_room(api, callback, user_data, room_id); +} + +/** + * matrix_api_login: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @login_type: the login type to use + * @parameters: (allow-none): parameters to pass for the login request + * + * Attempt to login with type @login_type. Implementations of this + * method must set the token property on a successful login. + */ +void +matrix_api_login(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *login_type, + GHashTable *parameters) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->login(api, callback, user_data, login_type, parameters); +} + +/** + * matrix_api_register_account: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @login_type: the login type to use + * @parameters: (allow-none): parameters to pass for the registration + * request + * + * Attempt to register with type @login_type. Implementations of this + * method must set the token property on a successful login. + */ +void +matrix_api_register_account(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *login_type, + GHashTable *parameters) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->register_account(api, callback, user_data, login_type, parameters); +} + +/** + * matrix_api_send_emote: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room to send the emote to + * @text_content: the emote text to send + * + * Send an emote to the room. + */ +void +matrix_api_send_emote(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *text_content) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->send_emote(api, callback, user_data, room_id, text_content); +} + +/** + * matrix_api_send_message: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room to send the emote to + * @text_content: the emote text to send + * @msg_type: the type of the message to be sent + * + * Send a custom message to the room. + */ +void +matrix_api_send_message(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *text_content, + gchar *msg_type) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->send_message(api, + callback, user_data, + room_id, + text_content, + msg_type); +} + +/** + * matrix_api_send_message_event: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room to send the emote to + * @event_type: the type of the event to send + * @content: the content of the event as a #JsonNode + * @txn_id: the transaction ID to use + * + * Send a message event to the room. + */ +void +matrix_api_send_message_event(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *event_type, + JsonNode *content, + guint txn_id) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->send_message_event(api, + callback, user_data, + room_id, + event_type, + content, + txn_id); +} + +/** + * matrix_api_send_state_event: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room to send the emote to + * @event_type: the type of the event to send + * @content: the content of the event as a #JsonNode + * @state_key: the state key to send + * + * Send a state event to the room + */ +void +matrix_api_send_state_event(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *event_type, + JsonNode *content, + gchar *state_key) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->send_state_event(api, + callback, user_data, + room_id, + event_type, + content, + state_key); +} + +/** + * matrix_api_set_membership: + * @api: a #MatrixAPI implementation + * @callback: (scope async): the function to call when the request is + * finished + * @user_data: user data to pass to the callback function + * @room_id: the room to send the emote to + * @user_id: the user of whom membership will be set + * @membership: the new membership of the user + * @reason: (allow-none): the reason of the change + * + * Set the membership of the user for the given room. + */ +void +matrix_api_set_membership(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id, + gchar *membership, + gchar *reason) +{ + g_return_if_fail(MATRIX_IS_API(api)); + + MATRIX_API_GET_IFACE(api) + ->set_membership(api, + callback, user_data, + room_id, + user_id, + membership, + reason); } diff --git a/src/matrix-api.h b/src/matrix-api.h index 00ab55e..190f9b1 100644 --- a/src/matrix-api.h +++ b/src/matrix-api.h @@ -16,80 +16,245 @@ * . */ -#ifndef __MATRIX_API_H__ -#define __MATRIX_API_H__ +#ifndef __MATRIX_API_IFACE_H__ +#define __MATRIX_API_IFACE_H__ #include +#include G_BEGIN_DECLS #define MATRIX_TYPE_API (matrix_api_get_type()) #define MATRIX_API(o) (G_TYPE_CHECK_INSTANCE_CAST((o), MATRIX_TYPE_API, MatrixAPI)) -#define MATRIX_API_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MATRIX_TYPE_API, MatrixAPIClass)) #define MATRIX_IS_API(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), MATRIX_TYPE_API)) -#define MATRIX_IS_API_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), MATRIX_TYPE_API)) -#define MATRIX_API_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), MATRIX_TYPE_API, MatrixAPIClass)) +#define MATRIX_API_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), MATRIX_TYPE_API, MatrixAPIInterface)) -typedef struct _MatrixAPI MatrixAPI; -typedef struct _MatrixAPIClass MatrixAPIClass; +typedef struct _MatrixAPIInterface MatrixAPIInterface; +typedef struct _MatrixAPI MatrixAPI; -struct _MatrixAPI { - /* Parent instance structure */ - GObject parent_instance; +typedef void (*MatrixAPICallback)(MatrixAPI *api, JsonNode *content, gpointer data); - /* Instance members */ +struct _MatrixAPIInterface { + /*< private >*/ + GTypeInterface g_iface; + + /*< public >*/ + + void (*register_account)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *login_type, + GHashTable *parameters); + void (*login)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *login_type, + GHashTable *parameters); + void (*initial_sync)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + guint limit); + void (*event_stream)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *from_token, + gulong timeout); + void (*create_room)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_alias, + gboolean is_public, + GStrv invitees); + void (*join_room)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id_or_alias); + void (*send_state_event)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *event_type, + JsonNode *content, + gchar *state_key); + void (*send_message_event)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *event_type, + JsonNode *content, + guint txn_id); + void (*send_message)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *text_content, + gchar *msg_type); + void (*send_emote)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *text_content); + void (*get_room_name)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); + void (*get_room_topic)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); + void (*leave_room)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); + void (*invite_user)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id); + void (*kick_user)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id, + gchar *reason); + void (*set_membership)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id, + gchar *membership, + gchar *reason); + void (*ban_user)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id, + gchar *reason); + void (*get_room_state)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); + void (*get_text_body)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *text, + gchar *msgtype); + void (*get_html_body)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *html, + gchar *msgtype); + void (*get_emote_body)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *text); + void (*_send)(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *method, + gchar *path, + gchar *content, + gchar *query_params, + gchar *headers); + + /*< private >*/ + void *padding[20]; }; -struct _MatrixAPIClass { - GObjectClass parent_class; -}; - -GType matrix_api_get_type(void) G_GNUC_CONST; - -void matrix_api_initial_sync(MatrixAPI *api, guint limit); -void matrix_api_set_validate_certificate(MatrixAPI *api, gboolean valid); -gboolean matrix_api_get_validate_certificate(MatrixAPI *api); -void matrix_api_register(MatrixAPI *api, gchar *login_type, ...); -void matrix_api_login(MatrixAPI *api, gchar *login_type, ...); +void matrix_api_initial_sync(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + guint limit); +void matrix_api_register_account(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *login_type, + GHashTable *parameters); +void matrix_api_login(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *login_type, + GHashTable *parameters); void matrix_api_create_room(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, gchar *alias, gboolean is_public, - GList *invitees); -void matrix_api_join_room(MatrixAPI *api, gchar *room_id_or_alias); -void matrix_api_event_stream(MatrixAPI *api, gchar *from_token, gulong timeout); + GStrv invitees); +void matrix_api_join_room(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id_or_alias); +void matrix_api_event_stream(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *from_token, + gulong timeout); void matrix_api_send_state_event(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, gchar *room_id, gchar *event_type, JsonNode *content, gchar *state_key); void matrix_api_send_message_event(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, gchar *room_id, gchar *event_type, JsonNode *content, guint txn_id); void matrix_api_send_message(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, gchar *room_id, gchar *text_content, gchar *msg_type); -void matrix_api_send_emote(MatrixAPI *api, gchar *room_id, gchar *text_content); -void matrix_api_get_room_name(MatrixAPI *api, gchar *room_id); -void matrix_api_get_room_topic(MatrixAPI *api, gchar *room_id); -void matrix_api_leave_room(MatrixAPI *api, gchar *room_id); -void matrix_api_invite_user(MatrixAPI *api, gchar *room_id, gchar *user_id); +void matrix_api_send_emote(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *text_content); +void matrix_api_get_room_name(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); +void matrix_api_get_room_topic(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); +void matrix_api_leave_room(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); +void matrix_api_invite_user(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id, + gchar *user_id); void matrix_api_kick_user(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, gchar *room_id, gchar *user_id, gchar *reason); void matrix_api_set_membership(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, gchar *room_id, gchar *user_id, gchar *membership, gchar *reason); void matrix_api_ban_user(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, gchar *room_id, gchar *user_id, gchar *reason); -void matrix_api_get_room_state(MatrixAPI *api, gchar *room_id); +void matrix_api_get_room_state(MatrixAPI *api, + MatrixAPICallback callback, + gpointer user_data, + gchar *room_id); void matrix_api_get_text_body(MatrixAPI *api, gchar *text, gchar *msgtype); void matrix_api_get_html_body(MatrixAPI *api, gchar *html, gchar *msgtype); void matrix_api_get_emote_body(MatrixAPI *api, gchar *text); @@ -102,4 +267,4 @@ void _send(MatrixAPI *api, G_END_DECLS -#endif /* __MATRIX_API_H__ */ +#endif /* __MATRIX_API_IFACE_H__ */ diff --git a/src/matrix-http-api.c b/src/matrix-http-api.c new file mode 100644 index 0000000..6b58885 --- /dev/null +++ b/src/matrix-http-api.c @@ -0,0 +1,251 @@ +/* + * This file is part of matrix-glib-sdk + * + * matrix-glib-sdk is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * matrix-glib-sdk is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with matrix-glib-sdk. If not, see + * . + */ + +#include "matrix-http-api.h" +#include "matrix-api.h" + +#include +#include + +/** + * SECTION:matrix-http-api + * @short_description: Low level API calls to communicate with a + * Matrix.org server via HTTP + * @title: MatrixHTTPAPI + * @stability: Unstable + * @include: matrix-glib/matrix.h + * + * This is a class for low level communication with a Matrix.org + * server via HTTP. + */ + +/** + * MatrixHTTPAPI: + * + * The MatrixHTTPAPI object’s instance definition. + */ + +/** + * MatrixHTTPAPIClass: + * @parent_class: the parent class structure (#GObjectClass) + * + * The MatrixHTTPAPI object’s class definition. + */ + +#define API_ENDPOINT "/_matrix/client/api/v1" + +typedef struct _MatrixHTTPAPIPrivate { + SoupSession *soup_session; + guint txn_id; + gchar *url; + gchar *token; + gboolean validate_certificate; +} MatrixHTTPAPIPrivate; + +enum { + PROP_VALIDATE_CERTIFICATE = 1, + PROP_URL, + N_PROPERTIES +}; + +GParamSpec *obj_properties[N_PROPERTIES] = {NULL,}; + +static void matrix_http_api_matrix_api_init(MatrixAPIInterface *iface); + +G_DEFINE_TYPE_WITH_CODE(MatrixHTTPAPI, matrix_http_api, G_TYPE_OBJECT, + G_ADD_PRIVATE(MatrixHTTPAPI) + G_IMPLEMENT_INTERFACE(MATRIX_TYPE_API, matrix_http_api_matrix_api_init)); + +static void +matrix_http_api_matrix_api_init(MatrixAPIInterface *iface) +{} + +static void +matrix_http_api_finalize(GObject *gobject) +{ + g_signal_handlers_destroy(gobject); + G_OBJECT_CLASS(matrix_http_api_parent_class)->finalize(gobject); +} + +static void +matrix_http_api_set_property(GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MatrixHTTPAPI *api = MATRIX_HTTP_API(gobject); + MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(api); + + switch (prop_id) { + case PROP_VALIDATE_CERTIFICATE: + priv->validate_certificate = g_value_get_boolean(value); + + break; + + case PROP_URL: + { + const gchar *base_url; + gchar *last_occurence; + + base_url = g_value_get_string(value); + + if (!g_str_is_ascii(base_url)) { + g_warning("URL specified (%s) is not ASCII", base_url); + + return; + } + + last_occurence = g_strrstr(base_url, API_ENDPOINT); + + if ((g_strcmp0(last_occurence, API_ENDPOINT) == 0) || + (g_strcmp0(last_occurence, API_ENDPOINT"/") == 0)) { + priv->url = g_strdup(base_url); + } else { + priv->url = g_strdup_printf( + "%s%s%s", + base_url, + (base_url[strlen(base_url) - 1] == '/') ? "" : "/", + API_ENDPOINT); + } + + break; + } + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); + } +} + +static void +matrix_http_api_get_property(GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MatrixHTTPAPI *api = MATRIX_HTTP_API(gobject); + MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(api); + + switch (prop_id) { + case PROP_VALIDATE_CERTIFICATE: + g_value_set_boolean(value, priv->validate_certificate); + + break; + + case PROP_URL: + g_value_set_string(value, priv->url); + + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); + } +} + +static void +matrix_http_api_class_init(MatrixHTTPAPIClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->set_property = matrix_http_api_set_property; + gobject_class->get_property = matrix_http_api_get_property; + gobject_class->finalize = matrix_http_api_finalize; + + /** + * MatrixHTTPAPI:validate-certificate: + * + * Set to %FALSE if you don’t want the SSL/TLS certificates to be + * validated. + */ + obj_properties[PROP_VALIDATE_CERTIFICATE] = g_param_spec_boolean( + "validate-certificate", + "Validate certificate", + "TRUE if server certificates should be validated", + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * MatrixHTTPAPI:url: + * + * The base URL to use for communication with the Matrix.org + * server. + */ + obj_properties[PROP_URL] = g_param_spec_string( + "url", "Server URL", + "Matrix.org home server to connect to.", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(gobject_class, + N_PROPERTIES, + obj_properties); +} + +static void +matrix_http_api_init(MatrixHTTPAPI *api) +{ + MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(api); + + priv->txn_id = 0; + priv->url = NULL; + priv->token = NULL; + priv->validate_certificate = TRUE; + priv->soup_session = soup_session_new_with_options( + SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_SNIFFER, + NULL); +} + +MatrixHTTPAPI * +matrix_http_api_new(const gchar *base_url, const gchar *token) +{ + return g_object_new(MATRIX_TYPE_HTTP_API, + "base-url", base_url, + "token", token, + NULL); +} + +/** + * matrix_http_api_set_validate_certificate: + * @api: a #MatrixHTTPAPI implementation + * @validate_certificate: %TRUE if server certificates should be + * validated + * + * Sets if server certificates should be validated. + */ +void +matrix_http_api_set_validate_certificate(MatrixHTTPAPI *api, + gboolean validate_certificate) +{ + MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(api); + + priv->validate_certificate = validate_certificate; +} + +/** + * matrix_http_api_get_validate_certificate: + * @api: a #MatrixHTTPAPI implementation + * + * Gets the value set by matrix_http_api_set_validate_certificate() + * + * Returns: %TRUE if the server certificates should be validated + */ +gboolean +matrix_http_api_get_validate_certificate(MatrixHTTPAPI *api) +{ + MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(api); + + return priv->validate_certificate; +} diff --git a/src/matrix-http-api.h b/src/matrix-http-api.h new file mode 100644 index 0000000..3b45672 --- /dev/null +++ b/src/matrix-http-api.h @@ -0,0 +1,54 @@ +/* + * 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_HTTP_API_H__ +#define __MATRIX_HTTP_API_H__ + +#include + +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(k) (G_TYPE_CHECK_CLASS_CAST((k), 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(k) (G_TYPE_CHECK_CLASS_TYPE((k), 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; + +struct _MatrixHTTPAPI { + /* Parent instance structure */ + GObject parent_instance; + + /* Instance members */ +}; + +struct _MatrixHTTPAPIClass { + GObjectClass parent_class; +}; + +GType matrix_http_api_get_type(void) G_GNUC_CONST; +void matrix_http_api_set_validate_certificate(MatrixHTTPAPI *api, + gboolean validate_certificate); +gboolean matrix_http_api_get_validate_certificate(MatrixHTTPAPI *api); + +G_END_DECLS + +#endif /* __MATRIX_HTTP_API_H__ */