diff --git a/.gitignore b/.gitignore
index 7d721f2..0647576 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,10 @@ src/telepathy-matrix.8
core
cscope.out
tags
+GPATH
+GRTAGS
+GSYMS
+GTAGS
tests/test-ctcp-kill-blingbling
tests/test-ctcp-tokenize
diff --git a/src/Makefile.am b/src/Makefile.am
index d1196ce..379b756 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,6 +10,10 @@ libmatrix_convenience_la_SOURCES = \
matrix-protocol.h \
matrix-debug.c \
matrix-debug.h \
+ matrix-handles.c \
+ matrix-handles.h \
+ matrix-connection.c \
+ matrix-connection.h \
$(NULL)
nodist_libmatrix_convenience_la_SOURCES = \
diff --git a/src/matrix-connection.c b/src/matrix-connection.c
new file mode 100644
index 0000000..495fd0e
--- /dev/null
+++ b/src/matrix-connection.c
@@ -0,0 +1,415 @@
+/*
+ * This file is part of telepathy-matrix.
+ *
+ * telepathy-matrix is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * telepathy-matrix is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with telepathy-matrix. If not, see
+ * .
+ */
+
+#include "matrix-connection.h"
+
+static void _aliasing_iface_init(gpointer, gpointer);
+
+struct _MatrixConnectionPrivate {
+ gchar *matrix_id;
+ gchar *homeserver;
+ gchar *password;
+ GHashTable *aliases;
+ gboolean dispose_has_run;
+ TpSimplePasswordManager *password_manager;
+};
+
+enum {
+ PROP_0,
+ PROP_MATRIX_ID,
+ PROP_HOMESERVER,
+ PROP_PASSWORD,
+ PROP_COUNT
+};
+
+G_DEFINE_TYPE_WITH_CODE(
+ MatrixConnection, matrix_connection, TP_TYPE_BASE_CONNECTION,
+ G_IMPLEMENT_INTERFACE(
+ TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
+ _aliasing_iface_init);
+/*
+ G_IMPLEMENT_INTERFACE(
+ TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
+ matrix_contact_info_iface_init);
+ G_IMPLEMENT_INTERFACE(
+ MATRIX_TYPE_SVC_CONNECTION_INTERFACE_RENAMING,
+ _renaming_interface_init);
+*/
+ G_IMPLEMENT_INTERFACE(
+ TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
+ tp_contacts_mixin_iface_init);
+ );
+
+static void
+matrix_connection_set_property(GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MatrixConnection *connection = MATRIX_CONNECTION(obj);
+ MatrixConnectionPrivate *priv = connection->priv;
+
+ switch (prop_id) {
+ case PROP_MATRIX_ID:
+ g_free(priv->matrix_id);
+ priv->matrix_id = g_value_dup_string(value);
+
+ break;
+
+ case PROP_HOMESERVER:
+ g_free(priv->homeserver);
+ priv->homeserver = g_value_dup_string(value);
+
+ break;
+
+ case PROP_PASSWORD:
+ g_free(priv->password);
+ priv->password = g_value_dup_string(value);
+
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+
+ break;
+ }
+}
+
+static void
+matrix_connection_get_property(GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MatrixConnection *connection = MATRIX_CONNECTION(obj);
+ MatrixConnectionPrivate *priv = connection->priv;
+
+ switch (prop_id) {
+ case PROP_MATRIX_ID:
+ g_value_set_string(value, priv->matrix_id);
+
+ break;
+
+ case PROP_HOMESERVER:
+ g_value_set_string(value, priv->homeserver);
+
+ break;
+
+ case PROP_PASSWORD:
+ g_value_set_string(value, priv->password);
+
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+
+ break;
+ }
+}
+
+static void
+matrix_connection_get_alias_flags(TpSvcConnectionInterfaceAliasing *iface,
+ DBusGMethodInvocation *context)
+{
+ tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context, 0);
+}
+
+static const gchar *
+gimme_an_alias(MatrixConnection *connection,
+ TpHandleRepoIface *repo,
+ TpHandle handle)
+{
+ const gchar *alias = g_hash_table_lookup(connection->priv->aliases,
+ GUINT_TO_POINTER(handle));
+
+ if (alias != NULL) {
+ return alias;
+ } else {
+ return tp_handle_inspect(repo, handle);
+ }
+}
+
+static void
+matrix_connection_get_aliases(TpSvcConnectionInterfaceAliasing *iface,
+ const GArray *handles,
+ DBusGMethodInvocation *context)
+{
+ MatrixConnection *self = MATRIX_CONNECTION(iface);
+ TpHandleRepoIface *repo = tp_base_connection_get_handles(
+ TP_BASE_CONNECTION(iface),
+ TP_HANDLE_TYPE_CONTACT);
+ GError *err = NULL;
+ GHashTable *aliases;
+
+ if (!tp_handles_are_valid(repo, handles, FALSE, &err)) {
+ dbus_g_method_return_error(context, err);
+ g_error_free(err);
+
+ return;
+ }
+
+ aliases = g_hash_table_new(NULL, NULL);
+
+ for (guint i = 0; i < handles->len; i++) {
+ TpHandle handle = g_array_index(handles, TpHandle, i);
+
+ g_hash_table_insert(aliases,
+ GUINT_TO_POINTER(handle),
+ (gpointer)gimme_an_alias(self, repo, handle));
+ }
+
+ tp_svc_connection_interface_aliasing_return_from_get_aliases(context, aliases);
+ g_hash_table_unref(aliases);
+}
+
+static void
+matrix_connection_request_aliases(TpSvcConnectionInterfaceAliasing *iface,
+ const GArray *handles,
+ DBusGMethodInvocation *context)
+{
+ MatrixConnection *connection = MATRIX_CONNECTION(iface);
+ TpHandleRepoIface *repo = tp_base_connection_get_handles(
+ TP_BASE_CONNECTION(iface), TP_HANDLE_TYPE_CONTACT);
+ GError *err = NULL;
+ const gchar **aliases;
+
+ if (!tp_handles_are_valid(repo, handles, FALSE, &err)) {
+ dbus_g_method_return_error(context, err);
+ g_error_free(err);
+
+ return;
+ }
+
+ aliases = g_new0(const gchar *, handles->len + 1);
+
+ for (guint i = 0; i < handles->len; i++) {
+ TpHandle handle = g_array_index(handles, TpHandle, i);
+
+ aliases[i] = gimme_an_alias(connection, repo, handle);
+ }
+
+ tp_svc_connection_interface_aliasing_return_from_request_aliases(context, aliases);
+ g_free(aliases);
+}
+
+static void
+_aliasing_iface_init(gpointer g_iface, gpointer iface_data)
+{
+ TpSvcConnectionInterfaceAliasingClass *klass = (TpSvcConnectionInterfaceAliasingClass *)g_iface;
+
+#define IMPLEMENT(x) tp_svc_connection_interface_aliasing_implement_##x(klass, matrix_connection_##x)
+ IMPLEMENT(get_alias_flags);
+ IMPLEMENT(get_aliases);
+ IMPLEMENT(request_aliases);
+#undef IMPLEMENT
+}
+
+static void
+matrix_connection_finalize(GObject *gobject)
+{
+ g_signal_handlers_destroy(gobject);
+ G_OBJECT_CLASS(matrix_connection_parent_class)->finalize(gobject);
+}
+
+static void
+_aliasing_fill_contact_attributes(GObject *obj,
+ const GArray *contacts,
+ GHashTable *attributes_hash)
+{
+ MatrixConnection *connection = MATRIX_CONNECTION(obj);
+ TpHandleRepoIface *repo = tp_base_connection_get_handles(
+ TP_BASE_CONNECTION(connection),
+ TP_HANDLE_TYPE_CONTACT);
+
+ for (guint i = 0; i < contacts->len; i++) {
+ TpHandle handle = g_array_index(contacts, TpHandle, i);
+ const gchar *alias = gimme_an_alias(connection, repo, handle);
+
+ g_assert(alias != NULL);
+
+ tp_contacts_mixin_set_contact_attribute(
+ attributes_hash,
+ handle,
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING"/alias",
+ tp_g_value_slice_new_string(alias));
+ }
+}
+
+static void
+matrix_connection_constructed(GObject *obj)
+{
+ //MatrixConnection *connection = MATRIX_CONNECTION(obj);
+
+ //matrix_contact_info_init(connection);
+ tp_contacts_mixin_add_contact_attributes_iface(obj, TP_IFACE_CONNECTION_INTERFACE_ALIASING, _aliasing_fill_contact_attributes);
+}
+
+static void
+matrix_connection_dispose(GObject *obj)
+{
+ MatrixConnection *connection = MATRIX_CONNECTION(obj);
+ MatrixConnectionPrivate *priv = connection->priv;
+
+ if (priv->dispose_has_run) {
+ return;
+ }
+
+ priv->dispose_has_run = TRUE;
+
+ tp_clear_pointer(&priv->aliases, g_hash_table_unref);
+
+ if (G_OBJECT_CLASS(matrix_connection_parent_class)->dispose) {
+ G_OBJECT_CLASS(matrix_connection_parent_class)->dispose(obj);
+ }
+}
+
+static void
+_iface_create_handle_repos(TpBaseConnection *connection,
+ TpHandleRepoIface **repos)
+{
+ for (int i = 0; i < NUM_TP_HANDLE_TYPES; i++) {
+ repos[i] = NULL;
+ }
+
+// TODO matrix_handle_repos_init(repos);
+}
+
+static gchar *
+_iface_get_unique_connection_name(TpBaseConnection *base)
+{
+ MatrixConnection *connection = MATRIX_CONNECTION(base);
+ MatrixConnectionPrivate *priv = connection->priv;
+
+ return g_strdup_printf(
+ "@%s:%s%p",
+ priv->matrix_id, priv->homeserver, connection);
+}
+
+static GPtrArray *
+_iface_create_channel_managers(TpBaseConnection *base)
+{
+ MatrixConnection *connection = MATRIX_CONNECTION(base);
+ MatrixConnectionPrivate *priv = connection->priv;
+ GPtrArray *managers = g_ptr_array_sized_new(1);
+ //GObject *manager;
+
+ /*
+ manager = g_object_new(MATRIX_TYPE_IM_MANAGER,
+ "connection", connection,
+ NULL);
+ g_ptr_array_add(managers, manager);
+
+ manager = g_object_new(MATRIX_TYPE_IM_MUC_MANAGER,
+ "connection", connection,
+ NULL);
+ */
+
+ priv->password_manager = tp_simple_password_manager_new(base);
+ g_ptr_array_add(managers, priv->password_manager);
+
+ /*
+ manager = g_object_new(MATRIX_TYPE_ROOMLIST_MANAGER,
+ "connection", connection,
+ NULL);
+ g_ptr_array_add(managers, manager);
+
+ priv->tls_manager = g_object_new(IDLE_TYPE_SERVER_TLS_MANAGER,
+ "connection", connection,
+ NULL);
+ g_ptr_array_add(managers, manager);
+ */
+
+ return managers;
+}
+
+static void
+_iface_disconnected(TpBaseConnection *base)
+{}
+
+static void
+matrix_connection_class_init(MatrixConnectionClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ TpBaseConnectionClass *parent_class = TP_BASE_CONNECTION_CLASS(klass);
+ GParamSpec *param_spec;
+
+ g_type_class_add_private(klass, sizeof(MatrixConnectionPrivate));
+
+ gobject_class->constructed = matrix_connection_constructed;
+ gobject_class->set_property = matrix_connection_set_property;
+ gobject_class->get_property = matrix_connection_get_property;
+ gobject_class->dispose = matrix_connection_dispose;
+ gobject_class->finalize = matrix_connection_finalize;
+
+ parent_class->create_handle_repos = _iface_create_handle_repos;
+ parent_class->get_unique_connection_name = _iface_get_unique_connection_name;
+ parent_class->create_channel_factories = NULL;
+ parent_class->create_channel_managers = _iface_create_channel_managers;
+ parent_class->connecting = NULL;
+ parent_class->connected = NULL;
+ parent_class->disconnected = _iface_disconnected;
+ /*
+ parent_class->shut_down = _iface_shut_down;
+ parent_class->start_connecting = _iface_start_connecting;
+ parent_class->get_interfaces_always_present = get_interfaces_always_present;
+ */
+
+ param_spec = g_param_spec_string(
+ "matrix-id",
+ "Matrix ID",
+ "Your registered Matrix ID",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property(gobject_class, PROP_MATRIX_ID, param_spec);
+
+ param_spec = g_param_spec_string(
+ "homeserver",
+ "Homeserver",
+ "The home server to connect to",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property(gobject_class, PROP_HOMESERVER, param_spec);
+
+ param_spec = g_param_spec_string(
+ "password",
+ "Password",
+ "Password to authenticate to the server with",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property(gobject_class, PROP_PASSWORD, param_spec);
+
+ tp_contacts_mixin_class_init(gobject_class, G_STRUCT_OFFSET(MatrixConnectionClass, contacts));
+ //matrix_contact_info_class_init(klass);
+}
+
+static void
+matrix_connection_init(MatrixConnection *connection)
+{
+ MatrixConnectionPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(
+ connection,
+ MATRIX_TYPE_CONNECTION, MatrixConnectionPrivate);
+
+ connection->priv = priv;
+ priv->aliases = g_hash_table_new_full(NULL, NULL, NULL, g_free);
+
+ tp_contacts_mixin_init(
+ G_OBJECT(connection),
+ G_STRUCT_OFFSET(MatrixConnection, contacts));
+ tp_base_connection_register_with_contacts_mixin(
+ (TpBaseConnection *)connection);
+}
diff --git a/src/matrix-connection.h b/src/matrix-connection.h
new file mode 100644
index 0000000..4338c01
--- /dev/null
+++ b/src/matrix-connection.h
@@ -0,0 +1,38 @@
+#ifndef __MATRIX_CONNECTION_H__
+#define __MATRIX_CONNECTION_H__
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define MATRIX_TYPE_CONNECTION (matrix_connection_get_type())
+#define MATRIX_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_CAST((o), MATRIX_TYPE_CONNECTION, MatrixConnection))
+#define MATRIX_CONNECTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MATRIX_TYPE_CONNECTION, MatrixConnectionClass))
+#define MATRIX_IS_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), MATRIX_TYPE_CONNECTION))
+#define MATRIX_IS_CONNECTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), MATRIX_TYPE_CONNECTION))
+#define MATRIX_CONNECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), MATRIX_TYPE_CONNECTION, MatrixConnectionClass))
+
+typedef struct _MatrixConnection MatrixConnection;
+typedef struct _MatrixConnectionClass MatrixConnectionClass;
+typedef struct _MatrixConnectionPrivate MatrixConnectionPrivate;
+
+struct _MatrixConnection {
+ /* Parent instance structure */
+ TpBaseConnection parent_instance;
+ TpContactsMixin contacts;
+
+ /* Instance members */
+ MatrixConnectionPrivate *priv;
+};
+
+struct _MatrixConnectionClass {
+ TpBaseConnectionClass parent_class;
+ TpContactsMixinClass contacts;
+};
+
+GType matrix_connection_get_type(void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __MATRIX_CONNECTION_H__ */
diff --git a/src/matrix-debug.h b/src/matrix-debug.h
index c94abab..594140f 100644
--- a/src/matrix-debug.h
+++ b/src/matrix-debug.h
@@ -16,8 +16,8 @@
* .
*/
-#ifndef __MATRIX_DEBUG_H_
-#define __MATRIX_DEBUG_H_
+#ifndef __MATRIX_DEBUG_H__
+#define __MATRIX_DEBUG_H__
#include
@@ -38,12 +38,10 @@ void matrix_debug(MatrixDebugFlags flag, const gchar *format, ...) G_GNUC_PRINTF
void matrix_debug_free (void);
-#endif
+#endif /* __MATRIX_DEBUG_H__ */
#ifdef MATRIX_DEBUG_FLAG
-
-#undef MATRIX_DEBUG
-#define MATRIX_DEBUG(format, ...) \
+# undef MATRIX_DEBUG
+# define MATRIX_DEBUG(format, ...) \
matrix_debug(MATRIX_DEBUG_FLAG, "%s: " format, G_STRFUNC, ##__VA_ARGS__)
-
-#endif
+#endif /* MATRIX_DEBUG_FLAG */
diff --git a/src/matrix-handles.c b/src/matrix-handles.c
new file mode 100644
index 0000000..f0b688c
--- /dev/null
+++ b/src/matrix-handles.c
@@ -0,0 +1,42 @@
+/*
+ * This file is part of telepathy-matrix.
+ *
+ * telepathy-matrix is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * telepathy-matrix is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with telepathy-matrix. If not, see
+ * .
+ */
+
+#include "matrix-handles.h"
+
+#define MATRIX_DEBUG_FLAG MATRIX_DEBUG_PARSER
+#include "matrix-debug.h"
+
+gboolean
+matrix_id_is_valid(const gchar *matrix_id, gboolean strict_mode)
+{
+ MATRIX_DEBUG(
+ "Validating Matrix ID '%s' with strict mode %d",
+ matrix_id, strict_mode);
+
+ if (!matrix_id || *matrix_id == '\0') {
+ return FALSE;
+ }
+
+ if (!g_utf8_validate(matrix_id, -1, NULL)) {
+ return FALSE;
+ }
+
+ /* TODO: Do the actual validation */
+
+ return TRUE;
+}
diff --git a/src/matrix-handles.h b/src/matrix-handles.h
new file mode 100644
index 0000000..9f94b34
--- /dev/null
+++ b/src/matrix-handles.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of telepathy-matrix.
+ *
+ * telepathy-matrix is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * telepathy-matrix is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with telepathy-matrix. If not, see
+ * .
+ */
+
+#ifndef __MATRIX_HANDLES_H__
+#define __MATRIX_HANDLES_H__
+
+#include
+
+gboolean matrix_id_is_valid(const gchar *matrix_id, gboolean strict_mode);
+
+#endif /* __MATRIX_HANDLES_H__ */
diff --git a/src/matrix-protocol.c b/src/matrix-protocol.c
index 533c5f1..7337c0e 100644
--- a/src/matrix-protocol.c
+++ b/src/matrix-protocol.c
@@ -17,24 +17,86 @@
*/
#include "matrix-protocol.h"
+#include "matrix-handles.h"
+#include "matrix-connection.h"
+
+#include
#define PROTOCOL_NAME "matrix"
+static gboolean
+filter_account(const TpCMParamSpec *paramspec, GValue *value, GError **err)
+{
+ const gchar *matrixid = g_value_get_string(value);
+
+ g_assert(matrixid);
+ g_assert(G_VALUE_HOLDS_STRING(value));
+
+ if (!matrix_id_is_valid(matrixid, TRUE)) {
+ g_set_error(err,
+ TP_ERROR, TP_ERROR_INVALID_HANDLE,
+ "Invalid account name '%s'", matrixid);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static const TpCMParamSpec matrix_params[] = {
+ {
+ "account",
+ DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING,
+ TP_CONN_MGR_PARAM_FLAG_REQUIRED,
+ NULL, 0, filter_account
+ },
+ {
+ "homeserver",
+ DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING,
+ TP_CONN_MGR_PARAM_FLAG_REQUIRED
+ },
+ {
+ "password",
+ DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING,
+ TP_CONN_MGR_PARAM_FLAG_SECRET
+ },
+ {NULL, NULL, 0, 0, NULL, 0}
+};
+
G_DEFINE_TYPE(MatrixProtocol, matrix_protocol, TP_TYPE_BASE_PROTOCOL);
-static void
-matrix_protocol_finalize(GObject *gobject)
+static const TpCMParamSpec *
+get_parameters(TpBaseProtocol *self G_GNUC_UNUSED)
{
- g_signal_handlers_destroy(gobject);
- G_OBJECT_CLASS(matrix_protocol_parent_class)->finalize(gobject);
+ return matrix_params;
+}
+
+static TpBaseConnection *
+new_connection(TpBaseProtocol *protocol G_GNUC_UNUSED,
+ GHashTable *params,
+ GError **err G_GNUC_UNUSED)
+{
+ return g_object_new(MATRIX_TYPE_CONNECTION,
+ "homeserver", tp_asv_get_string(params, "homeserver"),
+ "matrix_id", tp_asv_get_string(params, "account"),
+ "password", tp_asv_get_string(params, "password"),
+ NULL);
}
static void
matrix_protocol_class_init(MatrixProtocolClass *klass)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ TpBaseProtocolClass *base_class = (TpBaseProtocolClass *)klass;
- gobject_class->finalize = matrix_protocol_finalize;
+ base_class->get_parameters = get_parameters;
+ base_class->new_connection = new_connection;
+ /*
+ base_class->normalize_contact = normalize_contact;
+ base_class->identify_account = identify_account;
+ base_class->get_interfaces_array = get_interfaces_array;
+ base_class->get_connection_details = get_connection_details;
+ base_class->dup_authentication_types = dup_authentication_types;
+ */
}
static void