/* * This file is part of telepathy-cauchy * * telepathy-cauchy 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. * * telepathy-cauchy 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 telepathy-cauchy. If not, see * . */ #include "cauchy-connection.h" #include "cauchy-contact-info.h" static void _aliasing_iface_init(gpointer, gpointer); struct _CauchyConnectionPrivate { gchar *cauchy_id; gchar *homeserver; gchar *password; GHashTable *aliases; gboolean dispose_has_run; TpSimplePasswordManager *password_manager; }; enum { PROP_0, PROP_CAUCHY_ID, PROP_HOMESERVER, PROP_PASSWORD, PROP_COUNT }; static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO, /* TODO: CAUCHY_IFACE_CONNECTION_INTERFACE_RENAMING, */ TP_IFACE_CONNECTION_INTERFACE_REQUESTS, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, NULL }; G_DEFINE_TYPE_WITH_CODE( CauchyConnection, cauchy_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, cauchy_contact_info_iface_init); /* TODO: G_IMPLEMENT_INTERFACE( CAUCHY_TYPE_SVC_CONNECTION_INTERFACE_RENAMING, _renaming_interface_init); */ G_IMPLEMENT_INTERFACE( TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, tp_contacts_mixin_iface_init); ); static void cauchy_connection_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { CauchyConnection *connection = CAUCHY_CONNECTION(obj); CauchyConnectionPrivate *priv = connection->priv; switch (prop_id) { case PROP_CAUCHY_ID: g_free(priv->cauchy_id); priv->cauchy_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 cauchy_connection_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { CauchyConnection *connection = CAUCHY_CONNECTION(obj); CauchyConnectionPrivate *priv = connection->priv; switch (prop_id) { case PROP_CAUCHY_ID: g_value_set_string(value, priv->cauchy_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 cauchy_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(CauchyConnection *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 cauchy_connection_get_aliases(TpSvcConnectionInterfaceAliasing *iface, const GArray *handles, DBusGMethodInvocation *context) { CauchyConnection *self = CAUCHY_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 cauchy_connection_request_aliases(TpSvcConnectionInterfaceAliasing *iface, const GArray *handles, DBusGMethodInvocation *context) { CauchyConnection *connection = CAUCHY_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, cauchy_connection_##x) IMPLEMENT(get_alias_flags); IMPLEMENT(get_aliases); IMPLEMENT(request_aliases); #undef IMPLEMENT } static void cauchy_connection_finalize(GObject *gobject) { g_signal_handlers_destroy(gobject); G_OBJECT_CLASS(cauchy_connection_parent_class)->finalize(gobject); } static void _aliasing_fill_contact_attributes(GObject *obj, const GArray *contacts, GHashTable *attributes_hash) { CauchyConnection *connection = CAUCHY_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 cauchy_connection_constructed(GObject *obj) { CauchyConnection *connection = CAUCHY_CONNECTION(obj); cauchy_contact_info_init(connection); tp_contacts_mixin_add_contact_attributes_iface( obj, TP_IFACE_CONNECTION_INTERFACE_ALIASING, _aliasing_fill_contact_attributes); } static void cauchy_connection_dispose(GObject *obj) { CauchyConnection *connection = CAUCHY_CONNECTION(obj); CauchyConnectionPrivate *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(cauchy_connection_parent_class)->dispose) { G_OBJECT_CLASS(cauchy_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 cauchy_handle_repos_init(repos); } static gchar * _iface_get_unique_connection_name(TpBaseConnection *base) { CauchyConnection *connection = CAUCHY_CONNECTION(base); CauchyConnectionPrivate *priv = connection->priv; return g_strdup_printf( "@%s:%s%p", priv->cauchy_id, priv->homeserver, connection); } static GPtrArray * _iface_create_channel_managers(TpBaseConnection *base) { CauchyConnection *connection = CAUCHY_CONNECTION(base); CauchyConnectionPrivate *priv = connection->priv; GPtrArray *managers = g_ptr_array_sized_new(1); //GObject *manager; /* TODO: manager = g_object_new(CAUCHY_TYPE_IM_MANAGER, "connection", connection, NULL); g_ptr_array_add(managers, manager); manager = g_object_new(CAUCHY_TYPE_IM_MUC_MANAGER, "connection", connection, NULL); */ priv->password_manager = tp_simple_password_manager_new(base); g_ptr_array_add(managers, priv->password_manager); /* TODO: manager = g_object_new(CAUCHY_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 cauchy_connection_class_init(CauchyConnectionClass *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(CauchyConnectionPrivate)); gobject_class->constructed = cauchy_connection_constructed; gobject_class->set_property = cauchy_connection_set_property; gobject_class->get_property = cauchy_connection_get_property; gobject_class->dispose = cauchy_connection_dispose; gobject_class->finalize = cauchy_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; /* TODO: 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( "cauchy-id", "Cauchy ID", "Your registered Cauchy ID", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property(gobject_class, PROP_CAUCHY_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(CauchyConnectionClass, contacts)); cauchy_contact_info_class_init(klass); } static void cauchy_connection_init(CauchyConnection *connection) { CauchyConnectionPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE( connection, CAUCHY_TYPE_CONNECTION, CauchyConnectionPrivate); 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(CauchyConnection, contacts)); tp_base_connection_register_with_contacts_mixin( (TpBaseConnection *)connection); } const gchar * const * cauchy_connection_get_implemented_interfaces(void) { /* We don’t have any conditionally implemented interfaces */ return interfaces_always_present; }