From d9197f01fa5e751701349ca1849f0b21277d9980 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 6 Nov 2013 18:35:37 +0000 Subject: [PATCH 05/11] TpBaseConnection: absorb the functionality of the TpContactsMixin It's a somewhat different "shape" - using a fill_contacts_attribute() virtual method - so that it's (hopefully) introspectable. This is a step towards folding Contacts into Connection. --- .../telepathy-glib/telepathy-glib-docs.sgml | 1 - .../telepathy-glib/telepathy-glib-sections.txt | 39 +- examples/cm/call/conn.c | 27 +- examples/cm/call/conn.h | 2 - examples/cm/channelspecific/conn.c | 26 +- examples/cm/channelspecific/conn.h | 2 - examples/cm/contactlist/conn.c | 53 +-- examples/cm/contactlist/conn.h | 2 - examples/cm/echo-message-parts/conn.c | 26 +- examples/cm/echo-message-parts/conn.h | 2 - examples/cm/extended/conn.c | 22 - examples/cm/extended/conn.h | 2 - telepathy-glib/Makefile.am | 2 - telepathy-glib/base-connection.c | 393 +++++++++++++++-- telepathy-glib/base-connection.h | 29 +- telepathy-glib/base-contact-list.c | 260 +++++------ telepathy-glib/base-contact-list.h | 8 +- telepathy-glib/contacts-mixin.c | 473 --------------------- telepathy-glib/contacts-mixin.h | 117 ----- telepathy-glib/introspection.am | 1 - telepathy-glib/presence-mixin.c | 87 ++-- telepathy-glib/presence-mixin.h | 8 +- telepathy-glib/telepathy-glib.h | 1 - tests/lib/broken-client-types-conn.c | 22 +- tests/lib/contacts-conn.c | 165 +++---- tests/lib/contacts-conn.h | 4 - 26 files changed, 655 insertions(+), 1119 deletions(-) delete mode 100644 telepathy-glib/contacts-mixin.c delete mode 100644 telepathy-glib/contacts-mixin.h diff --git a/docs/reference/telepathy-glib/telepathy-glib-docs.sgml b/docs/reference/telepathy-glib/telepathy-glib-docs.sgml index acb1b1e..d8049f9 100644 --- a/docs/reference/telepathy-glib/telepathy-glib-docs.sgml +++ b/docs/reference/telepathy-glib/telepathy-glib-docs.sgml @@ -76,7 +76,6 @@ - diff --git a/docs/reference/telepathy-glib/telepathy-glib-sections.txt b/docs/reference/telepathy-glib/telepathy-glib-sections.txt index e7c96f7..cb86701 100644 --- a/docs/reference/telepathy-glib/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib/telepathy-glib-sections.txt @@ -61,9 +61,13 @@ tp_base_connection_disconnect_with_dbus_error_vardict tp_base_connection_finish_shutdown tp_base_connection_add_interfaces TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED -tp_base_connection_register_with_contacts_mixin tp_base_connection_add_possible_client_interest tp_base_connection_add_client_interest +tp_base_connection_dup_contact_attributes_hash + +TpContactAttributeMap +tp_contact_attribute_map_set +tp_contact_attribute_map_take_sliced_gvalue TpChannelManagerIter tp_base_connection_channel_manager_iter_init @@ -1669,35 +1673,6 @@ TpBaseRoomConfigPrivate
telepathy-glib/telepathy-glib.h -contacts-mixin - -TpContactsMixin -TpContactsMixin -TpContactsMixinClass -tp_contacts_mixin_add_contact_attributes_iface -tp_contacts_mixin_class_init -tp_contacts_mixin_finalize -tp_contacts_mixin_iface_init -tp_contacts_mixin_init -tp_contacts_mixin_set_contact_attribute -tp_contacts_mixin_get_contact_attributes -TpContactsMixinFillContactAttributesFunc - -TP_CONTACTS_MIXIN_CLASS_OFFSET -TP_CONTACTS_MIXIN_CLASS_OFFSET_QUARK -TP_CONTACTS_MIXIN_OFFSET -TP_CONTACTS_MIXIN_OFFSET_QUARK -tp_contacts_mixin_class_get_offset_quark -tp_contacts_mixin_get_offset_quark -TpContactsMixinClassPrivate -TpContactsMixinPrivate - -TP_CONTACTS_MIXIN_CLASS -TP_CONTACTS_MIXIN -
- -
-telepathy-glib/telepathy-glib.h presence-mixin TpPresenceStatusOptionalArgumentSpec TpPresenceStatusSpec @@ -1718,7 +1693,7 @@ tp_presence_mixin_emit_presence_update tp_presence_mixin_emit_one_presence_update tp_presence_mixin_iface_init tp_presence_mixin_init_dbus_properties -tp_presence_mixin_register_with_contacts_mixin +tp_presence_mixin_fill_contact_attributes TP_PRESENCE_MIXIN_CLASS_OFFSET_QUARK TP_PRESENCE_MIXIN_CLASS_OFFSET @@ -5045,7 +5020,6 @@ tp_svc_channel_type_server_tls_connection1_get_type TpBaseContactList TpBaseContactListClass tp_base_contact_list_mixin_class_init -tp_base_contact_list_mixin_register_with_contacts_mixin tp_base_contact_list_mixin_list_iface_init tp_base_contact_list_mixin_groups_iface_init tp_base_contact_list_mixin_blocking_iface_init @@ -5071,6 +5045,7 @@ TpBaseContactListAsyncFinishFunc tp_base_contact_list_download_async tp_base_contact_list_download_finish tp_base_contact_list_get_download_at_connection +tp_base_contact_list_fill_contact_attributes TP_TYPE_MUTABLE_CONTACT_LIST TpMutableContactListInterface diff --git a/examples/cm/call/conn.c b/examples/cm/call/conn.c index c3a736f..2ef63c8 100644 --- a/examples/cm/call/conn.c +++ b/examples/cm/call/conn.c @@ -34,8 +34,6 @@ G_DEFINE_TYPE_WITH_CODE (ExampleCallConnection, example_call_connection, TP_TYPE_BASE_CONNECTION, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, - tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE1, tp_presence_mixin_iface_init)) @@ -124,7 +122,6 @@ finalize (GObject *object) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object); - tp_contacts_mixin_finalize (object); g_free (self->priv->account); g_free (self->priv->presence_message); @@ -215,20 +212,14 @@ shut_down (TpBaseConnection *conn) static void constructed (GObject *object) { - TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*chain_up) (GObject *) = G_OBJECT_CLASS (example_call_connection_parent_class)->constructed; if (chain_up != NULL) chain_up (object); - tp_contacts_mixin_init (object, - G_STRUCT_OFFSET (ExampleCallConnection, contacts_mixin)); - tp_base_connection_register_with_contacts_mixin (base); - tp_presence_mixin_init (object, G_STRUCT_OFFSET (ExampleCallConnection, presence_mixin)); - tp_presence_mixin_register_with_contacts_mixin (object); } static gboolean @@ -390,6 +381,20 @@ get_interfaces_always_present (TpBaseConnection *base) } static void +example_call_connection_fill_contact_attributes (TpBaseConnection *conn, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes) +{ + if (tp_presence_mixin_fill_contact_attributes (G_OBJECT (conn), + dbus_interface, contact, attributes)) + return; + + ((TpBaseConnectionClass *) example_call_connection_parent_class)-> + fill_contact_attributes (conn, dbus_interface, contact, attributes); +} + +static void example_call_connection_class_init ( ExampleCallConnectionClass *klass) { @@ -410,6 +415,8 @@ example_call_connection_class_init ( base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->get_interfaces_always_present = get_interfaces_always_present; + base_class->fill_contact_attributes = + example_call_connection_fill_contact_attributes; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, @@ -429,8 +436,6 @@ example_call_connection_class_init ( G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); - tp_contacts_mixin_class_init (object_class, - G_STRUCT_OFFSET (ExampleCallConnectionClass, contacts_mixin)); tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleCallConnectionClass, presence_mixin), status_available, get_contact_statuses, set_own_status, diff --git a/examples/cm/call/conn.h b/examples/cm/call/conn.h index b9e98ad..56a2526 100644 --- a/examples/cm/call/conn.h +++ b/examples/cm/call/conn.h @@ -28,7 +28,6 @@ typedef struct _ExampleCallConnectionClassPrivate struct _ExampleCallConnectionClass { TpBaseConnectionClass parent_class; TpPresenceMixinClass presence_mixin; - TpContactsMixinClass contacts_mixin; ExampleCallConnectionClassPrivate *priv; }; @@ -36,7 +35,6 @@ struct _ExampleCallConnectionClass { struct _ExampleCallConnection { TpBaseConnection parent; TpPresenceMixin presence_mixin; - TpContactsMixin contacts_mixin; ExampleCallConnectionPrivate *priv; }; diff --git a/examples/cm/channelspecific/conn.c b/examples/cm/channelspecific/conn.c index 7e48435..1c1b854 100644 --- a/examples/cm/channelspecific/conn.c +++ b/examples/cm/channelspecific/conn.c @@ -21,11 +21,9 @@ #include "protocol.h" #include "room-manager.h" -G_DEFINE_TYPE_WITH_CODE (ExampleCSHConnection, +G_DEFINE_TYPE (ExampleCSHConnection, example_csh_connection, - TP_TYPE_BASE_CONNECTION, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, - tp_contacts_mixin_iface_init)) + TP_TYPE_BASE_CONNECTION) /* type definition stuff */ @@ -99,7 +97,6 @@ finalize (GObject *object) { ExampleCSHConnection *self = EXAMPLE_CSH_CONNECTION (object); - tp_contacts_mixin_finalize (object); g_free (self->priv->account); G_OBJECT_CLASS (example_csh_connection_parent_class)->finalize (object); @@ -219,21 +216,6 @@ shut_down (TpBaseConnection *conn) tp_base_connection_finish_shutdown (conn); } -static void -constructed (GObject *object) -{ - TpBaseConnection *base = TP_BASE_CONNECTION (object); - void (*chain_up) (GObject *) = - G_OBJECT_CLASS (example_csh_connection_parent_class)->constructed; - - if (chain_up != NULL) - chain_up (object); - - tp_contacts_mixin_init (object, - G_STRUCT_OFFSET (ExampleCSHConnection, contacts_mixin)); - tp_base_connection_register_with_contacts_mixin (base); -} - static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_REQUESTS, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, @@ -270,7 +252,6 @@ example_csh_connection_class_init (ExampleCSHConnectionClass *klass) GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; - object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->finalize = finalize; @@ -294,7 +275,4 @@ example_csh_connection_class_init (ExampleCSHConnectionClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); - - tp_contacts_mixin_class_init (object_class, - G_STRUCT_OFFSET (ExampleCSHConnectionClass, contacts_mixin)); } diff --git a/examples/cm/channelspecific/conn.h b/examples/cm/channelspecific/conn.h index dc056e5..473ed99 100644 --- a/examples/cm/channelspecific/conn.h +++ b/examples/cm/channelspecific/conn.h @@ -23,12 +23,10 @@ typedef struct _ExampleCSHConnectionPrivate ExampleCSHConnectionPrivate; struct _ExampleCSHConnectionClass { TpBaseConnectionClass parent_class; - TpContactsMixinClass contacts_mixin; }; struct _ExampleCSHConnection { TpBaseConnection parent; - TpContactsMixin contacts_mixin; ExampleCSHConnectionPrivate *priv; }; diff --git a/examples/cm/contactlist/conn.c b/examples/cm/contactlist/conn.c index e3ddd33..f0f77b3 100644 --- a/examples/cm/contactlist/conn.c +++ b/examples/cm/contactlist/conn.c @@ -30,8 +30,6 @@ G_DEFINE_TYPE_WITH_CODE (ExampleContactListConnection, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING1, init_aliasing); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, - tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST1, tp_base_contact_list_mixin_list_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS1, @@ -119,7 +117,6 @@ finalize (GObject *object) ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); - tp_contacts_mixin_finalize (object); g_free (self->priv->account); G_OBJECT_CLASS (example_contact_list_connection_parent_class)->finalize ( @@ -235,42 +232,47 @@ shut_down (TpBaseConnection *conn) } static void -aliasing_fill_contact_attributes (GObject *object, - const GArray *contacts, - GHashTable *attributes) +example_contact_list_connection_fill_contact_attributes (TpBaseConnection *conn, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes) { ExampleContactListConnection *self = - EXAMPLE_CONTACT_LIST_CONNECTION (object); - guint i; + EXAMPLE_CONTACT_LIST_CONNECTION (conn); - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, TP_IFACE_CONNECTION_INTERFACE_ALIASING1)) { - TpHandle contact = g_array_index (contacts, guint, i); - - tp_contacts_mixin_set_contact_attribute (attributes, contact, + tp_contact_attribute_map_set (attributes, contact, TP_TOKEN_CONNECTION_INTERFACE_ALIASING1_ALIAS, - tp_g_value_slice_new_string ( + g_variant_new_string ( example_contact_list_get_alias (self->priv->contact_list, contact))); + return; } + + if (tp_base_contact_list_fill_contact_attributes ( + TP_BASE_CONTACT_LIST (self->priv->contact_list), + dbus_interface, contact, attributes)) + return; + + if (tp_presence_mixin_fill_contact_attributes (G_OBJECT (conn), + dbus_interface, contact, attributes)) + return; + + ((TpBaseConnectionClass *) example_contact_list_connection_parent_class)-> + fill_contact_attributes (conn, dbus_interface, contact, attributes); } static void constructed (GObject *object) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); - TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*chain_up) (GObject *) = G_OBJECT_CLASS (example_contact_list_connection_parent_class)->constructed; if (chain_up != NULL) chain_up (object); - tp_contacts_mixin_init (object, - G_STRUCT_OFFSET (ExampleContactListConnection, contacts_mixin)); - - tp_base_connection_register_with_contacts_mixin (base); - self->priv->contact_list = EXAMPLE_CONTACT_LIST (g_object_new ( EXAMPLE_TYPE_CONTACT_LIST, "connection", self, @@ -282,16 +284,8 @@ constructed (GObject *object) g_signal_connect (self->priv->contact_list, "presence-updated", G_CALLBACK (presence_updated_cb), self); - tp_base_contact_list_mixin_register_with_contacts_mixin ( - TP_BASE_CONTACT_LIST (self->priv->contact_list), base); - - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_ALIASING1, - aliasing_fill_contact_attributes); - tp_presence_mixin_init (object, G_STRUCT_OFFSET (ExampleContactListConnection, presence_mixin)); - tp_presence_mixin_register_with_contacts_mixin (object); } static gboolean @@ -468,6 +462,8 @@ example_contact_list_connection_class_init ( base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->get_interfaces_always_present = get_interfaces_always_present; + base_class->fill_contact_attributes = + example_contact_list_connection_fill_contact_attributes; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, @@ -481,9 +477,6 @@ example_contact_list_connection_class_init ( g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); - tp_contacts_mixin_class_init (object_class, - G_STRUCT_OFFSET (ExampleContactListConnectionClass, contacts_mixin)); - tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListConnectionClass, presence_mixin), status_available, get_contact_statuses, set_own_status, diff --git a/examples/cm/contactlist/conn.h b/examples/cm/contactlist/conn.h index 725eb50..b545245 100644 --- a/examples/cm/contactlist/conn.h +++ b/examples/cm/contactlist/conn.h @@ -26,14 +26,12 @@ typedef struct _ExampleContactListConnectionPrivate struct _ExampleContactListConnectionClass { TpBaseConnectionClass parent_class; TpPresenceMixinClass presence_mixin; - TpContactsMixinClass contacts_mixin; TpDBusPropertiesMixinClass properties_mixin; }; struct _ExampleContactListConnection { TpBaseConnection parent; TpPresenceMixin presence_mixin; - TpContactsMixin contacts_mixin; ExampleContactListConnectionPrivate *priv; }; diff --git a/examples/cm/echo-message-parts/conn.c b/examples/cm/echo-message-parts/conn.c index 3223a04..bc444ef 100644 --- a/examples/cm/echo-message-parts/conn.c +++ b/examples/cm/echo-message-parts/conn.c @@ -19,11 +19,9 @@ #include "im-manager.h" #include "protocol.h" -G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Connection, +G_DEFINE_TYPE (ExampleEcho2Connection, example_echo_2_connection, - TP_TYPE_BASE_CONNECTION, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, - tp_contacts_mixin_iface_init)) + TP_TYPE_BASE_CONNECTION) enum { @@ -84,7 +82,6 @@ finalize (GObject *object) { ExampleEcho2Connection *self = EXAMPLE_ECHO_2_CONNECTION (object); - tp_contacts_mixin_finalize (object); g_free (self->priv->account); G_OBJECT_CLASS (example_echo_2_connection_parent_class)->finalize (object); @@ -189,21 +186,6 @@ get_interfaces_always_present (TpBaseConnection *base) } static void -constructed (GObject *object) -{ - TpBaseConnection *base = TP_BASE_CONNECTION (object); - void (*chain_up) (GObject *) = - G_OBJECT_CLASS (example_echo_2_connection_parent_class)->constructed; - - if (chain_up != NULL) - chain_up (object); - - tp_contacts_mixin_init (object, - G_STRUCT_OFFSET (ExampleEcho2Connection, contacts_mixin)); - tp_base_connection_register_with_contacts_mixin (base); -} - -static void example_echo_2_connection_class_init (ExampleEcho2ConnectionClass *klass) { TpBaseConnectionClass *base_class = @@ -211,7 +193,6 @@ example_echo_2_connection_class_init (ExampleEcho2ConnectionClass *klass) GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; - object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->finalize = finalize; @@ -228,7 +209,4 @@ example_echo_2_connection_class_init (ExampleEcho2ConnectionClass *klass) "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); - - tp_contacts_mixin_class_init (object_class, - G_STRUCT_OFFSET (ExampleEcho2ConnectionClass, contacts_mixin)); } diff --git a/examples/cm/echo-message-parts/conn.h b/examples/cm/echo-message-parts/conn.h index 12f0036..4f4073e 100644 --- a/examples/cm/echo-message-parts/conn.h +++ b/examples/cm/echo-message-parts/conn.h @@ -23,12 +23,10 @@ typedef struct _ExampleEcho2ConnectionPrivate ExampleEcho2ConnectionPrivate; struct _ExampleEcho2ConnectionClass { TpBaseConnectionClass parent_class; - TpContactsMixinClass contacts_mixin; }; struct _ExampleEcho2Connection { TpBaseConnection parent; - TpContactsMixin contacts_mixin; ExampleEcho2ConnectionPrivate *priv; }; diff --git a/examples/cm/extended/conn.c b/examples/cm/extended/conn.c index c535449..c8dd22e 100644 --- a/examples/cm/extended/conn.c +++ b/examples/cm/extended/conn.c @@ -28,8 +28,6 @@ static void _hats_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleExtendedConnection, example_extended_connection, TP_TYPE_BASE_CONNECTION, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, - tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (EXAMPLE_TYPE_SVC_CONNECTION_INTERFACE_HATS, _hats_iface_init)) @@ -103,7 +101,6 @@ finalize (GObject *object) { ExampleExtendedConnection *self = EXAMPLE_EXTENDED_CONNECTION (object); - tp_contacts_mixin_finalize (object); g_free (self->priv->account); g_free (self->priv->hat_color); g_hash_table_unref (self->priv->hat_properties); @@ -175,21 +172,6 @@ shut_down (TpBaseConnection *conn) tp_base_connection_finish_shutdown (conn); } -static void -constructed (GObject *object) -{ - TpBaseConnection *base = TP_BASE_CONNECTION (object); - void (*chain_up) (GObject *) = - G_OBJECT_CLASS (example_extended_connection_parent_class)->constructed; - - if (chain_up != NULL) - chain_up (object); - - tp_contacts_mixin_init (object, - G_STRUCT_OFFSET (ExampleExtendedConnection, contacts_mixin)); - tp_base_connection_register_with_contacts_mixin (base); -} - static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_REQUESTS, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, @@ -227,7 +209,6 @@ example_extended_connection_class_init (ExampleExtendedConnectionClass *klass) GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; - object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->finalize = finalize; @@ -245,9 +226,6 @@ example_extended_connection_class_init (ExampleExtendedConnectionClass *klass) "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); - - tp_contacts_mixin_class_init (object_class, - G_STRUCT_OFFSET (ExampleExtendedConnectionClass, contacts_mixin)); } static void diff --git a/examples/cm/extended/conn.h b/examples/cm/extended/conn.h index ba0888c..dcf7ff5 100644 --- a/examples/cm/extended/conn.h +++ b/examples/cm/extended/conn.h @@ -23,12 +23,10 @@ typedef struct _ExampleExtendedConnectionPrivate ExampleExtendedConnectionPrivat struct _ExampleExtendedConnectionClass { TpBaseConnectionClass parent_class; - TpContactsMixinClass contacts_mixin; }; struct _ExampleExtendedConnection { TpBaseConnection parent; - TpContactsMixin contacts_mixin; ExampleExtendedConnectionPrivate *priv; }; diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am index dffe6bf..fb38044 100644 --- a/telepathy-glib/Makefile.am +++ b/telepathy-glib/Makefile.am @@ -84,7 +84,6 @@ tpginclude_HEADERS = \ contact.h \ contact-operations.h \ base-contact-list.h \ - contacts-mixin.h \ dbus.h \ dbus-daemon.h \ dbus-properties-mixin.h \ @@ -276,7 +275,6 @@ libtelepathy_glib_main_internal_la_SOURCES = \ base-contact-list.c \ cm-message.c \ cm-message-internal.h \ - contacts-mixin.c \ dbus.c \ dbus-daemon.c \ dbus-internal.h \ diff --git a/telepathy-glib/base-connection.c b/telepathy-glib/base-connection.c index 006be9c..65ad97b 100644 --- a/telepathy-glib/base-connection.c +++ b/telepathy-glib/base-connection.c @@ -176,6 +176,12 @@ * @create_channel_managers: Create an array of channel managers for this * Connection. This must be set by subclasses to a non-%NULL * value. Since: 0.7.15 + * @fill_contact_attributes: If @dbus_interface is recognised by this + * object, fill in any contact attribute tokens for @contact in @attributes + * by using tp_contact_attribute_map_set() + * or tp_contact_attribute_map_take_sliced_gvalue, and return. Otherwise, + * chain up to the superclass' implementation. + * Since: 0.UNRELEASED * * The class of a #TpBaseConnection. Many members are virtual methods etc. * to be filled in in the subclass' class_init function. @@ -234,7 +240,6 @@ #include #include -#include #include #include #include @@ -251,6 +256,7 @@ static void conn_iface_init (gpointer, gpointer); static void requests_iface_init (gpointer, gpointer); +static void contacts_iface_init (TpSvcConnectionInterfaceContactsClass *); G_DEFINE_ABSTRACT_TYPE_WITH_CODE(TpBaseConnection, tp_base_connection, @@ -259,6 +265,8 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE(TpBaseConnection, conn_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, + contacts_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_REQUESTS, requests_iface_init)) @@ -1120,6 +1128,47 @@ tp_base_connection_get_interfaces_always_present (TpBaseConnection *self) return interfaces; } +/* this is not really gtk-doc - it's for gobject-introspection */ +/** + * TpBaseConnectionClass::fill_contact_attributes: + * @self: a connection + * @dbus_interface: a D-Bus interface + * @contact: a contact + * @attributes: used to return the attributes + * + * If @dbus_interface is recognised by this object, fill in any contact + * attribute tokens for @contact in @attributes by using + * tp_contact_attribute_map_set() or + * tp_contact_attribute_map_take_sliced_gvalue, and return. Otherwise, + * chain up to the superclass' implementation. + * + * Since: 0.UNRELEASED + */ + +static void +_tp_base_connection_fill_contact_attributes (TpBaseConnection *self, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes) +{ + const gchar *tmp; + + if (tp_strdiff (dbus_interface, TP_IFACE_CONNECTION)) + { + DEBUG ("contact #%u: interface '%s' unhandled", contact, dbus_interface); + return; + } + + tmp = tp_handle_inspect (self->priv->handles[TP_HANDLE_TYPE_CONTACT], + contact); + g_assert (tmp != NULL); + + /* this is always included */ + tp_contact_attribute_map_take_sliced_gvalue (attributes, + contact, TP_TOKEN_CONNECTION_CONTACT_ID, + tp_g_value_slice_new_string (tmp)); +} + static void tp_base_connection_class_init (TpBaseConnectionClass *klass) { @@ -1147,6 +1196,7 @@ tp_base_connection_class_init (TpBaseConnectionClass *klass) klass->get_interfaces_always_present = tp_base_connection_get_interfaces_always_present; + klass->fill_contact_attributes = _tp_base_connection_fill_contact_attributes; /** * TpBaseConnection:protocol: (skip) @@ -2855,49 +2905,6 @@ tp_base_connection_channel_manager_iter_next (TpChannelManagerIter *iter, return TRUE; } - -static void -tp_base_connection_fill_contact_attributes (GObject *obj, - const GArray *contacts, GHashTable *attributes_hash) -{ - TpBaseConnection *self = TP_BASE_CONNECTION (obj); - TpBaseConnectionPrivate *priv = self->priv; - guint i; - - for (i = 0; i < contacts->len; i++) - { - TpHandle handle; - const gchar *tmp; - - handle = g_array_index (contacts, TpHandle, i); - tmp = tp_handle_inspect (priv->handles[TP_HANDLE_TYPE_CONTACT], handle); - g_assert (tmp != NULL); - - tp_contacts_mixin_set_contact_attribute (attributes_hash, - handle, TP_TOKEN_CONNECTION_CONTACT_ID, - tp_g_value_slice_new_string (tmp)); - } -} - -/** - * tp_base_connection_register_with_contacts_mixin: (skip) - * @self: An instance of the #TpBaseConnections that uses the Contacts - * mixin - * - * Register the Connection interface with the Contacts interface to make it - * inspectable. The Contacts mixin should be initialized before this function - * is called - */ -void -tp_base_connection_register_with_contacts_mixin (TpBaseConnection *self) -{ - g_return_if_fail (TP_IS_BASE_CONNECTION (self)); - - tp_contacts_mixin_add_contact_attributes_iface (G_OBJECT (self), - TP_IFACE_CONNECTION, - tp_base_connection_fill_contact_attributes); -} - /** * tp_base_connection_get_dbus_daemon: (skip) * @self: the connection manager @@ -2990,3 +2997,301 @@ tp_base_connection_get_object_path (TpBaseConnection *self) return self->priv->object_path; } + +/** + * TpContactAttributeMap: + * + * Opaque structure representing a map from #TpHandle to + * maps from contact attribute tokens to variants. + * + * This structure cannot currently be copied, freed or read via + * public API. + * + * Since: 0.UNRELEASED + */ + +/* Implementation detail: there is no such thing as a TpContactAttributeMap, + * it's just a GHashTable>. */ + +/** + * tp_contact_attribute_map_set: + * @map: an opaque map from contacts to their attributes + * @contact: a contact + * @token: a contact attribute + * @value: the value of the attribute. If it is floating, ownership + * will be taken, as if via g_variant_ref_sink(). + * + * Put a contact attribute in @self. It is an error to use this function + * for a @contact that was not requested. + * + * Since: 0.UNRELEASED + */ +void +tp_contact_attribute_map_set (TpContactAttributeMap *map, + TpHandle contact, + const gchar *token, + GVariant *value) +{ + GValue *gv = g_slice_new0 (GValue); + + g_variant_ref_sink (value); + dbus_g_value_parse_g_variant (value, gv); + tp_contact_attribute_map_take_sliced_gvalue (map, contact, token, gv); + g_variant_unref (value); +} + +/** + * tp_contact_attribute_map_take_sliced_gvalue: (skip) + * @map: an opaque map from contacts to their attributes + * @contact: a contact + * @token: a contact attribute + * @value: (transfer full): a slice-allocated #GValue, for instance + * from tp_g_value_slice_new(). Ownership is taken by @self. + * + * Put a contact attribute in @self. It is an error to use this function + * for a @contact that was not requested. + * + * This version of tp_contact_attribute_map_set() isn't + * introspectable, but is close to the API that "Telepathy 0" + * connection managers used. + * + * Since: 0.UNRELEASED + */ +void +tp_contact_attribute_map_take_sliced_gvalue (TpContactAttributeMap *map, + TpHandle contact, + const gchar *token, + GValue *value) +{ + GHashTable *auasv = (GHashTable *) map; + GHashTable *asv; + + g_return_if_fail (map != NULL); + + asv = g_hash_table_lookup (auasv, GUINT_TO_POINTER (contact)); + + if (G_UNLIKELY (asv == NULL)) + { + /* This is a programmer error; I'm not using g_return_if_fail + * to give a better diagnostic */ + CRITICAL ("contact %u not in TpContactAttributeMap", contact); + return; + } + + g_return_if_fail (G_IS_VALUE (value)); + + g_hash_table_insert (asv, g_strdup (token), value); +} + +static const gchar * const contacts_always_included_interfaces[] = { + TP_IFACE_CONNECTION, + NULL +}; + +/** + * tp_base_connection_dup_contact_attributes_hash: (skip) + * @self: A connection instance that uses this mixin. The connection must + * be connected. + * @handles: List of handles to retrieve contacts for. Any invalid handles + * will be dropped from the returned mapping. + * @interfaces: (allow-none) (array zero-terminated=1) (element-type utf8): an + * array of user-requested interfaces + * @assumed_interfaces: (allow-none) (array zero-terminated=1) (element-type utf8): + * A list of additional interfaces to retrieve attributes + * from. This can be used for interfaces documented as automatically included, + * like %TP_IFACE_CONNECTION for GetContactAttributes, + * or %TP_IFACE_CONNECTION and %TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST for + * GetContactListAttributes. + * + * Get contact attributes for the given contacts. Provide attributes for + * all requested interfaces. If contact attributes are not immediately known, + * the behaviour is defined by the interface; the attribute should either + * be omitted from the result or replaced with a default value. + * + * Returns: (element-type guint GLib.HashTable): a map from #TpHandle + * to #GHashTable, where the values are maps from string to #GValue + * Since: 0.UNRELEASED + */ +GHashTable * +tp_base_connection_dup_contact_attributes_hash (TpBaseConnection *self, + const GArray *handles, + const gchar * const *interfaces, + const gchar * const *assumed_interfaces) +{ + GHashTable *result; + guint i; + TpHandleRepoIface *contact_repo; + GArray *valid_handles; + TpBaseConnectionClass *klass; + + g_return_val_if_fail (TP_IS_BASE_CONNECTION (self), NULL); + g_return_val_if_fail (tp_base_connection_check_connected (self, NULL), NULL); + + contact_repo = tp_base_connection_get_handles (self, TP_HANDLE_TYPE_CONTACT); + klass = TP_BASE_CONNECTION_GET_CLASS (self); + g_return_val_if_fail (klass->fill_contact_attributes != NULL, NULL); + + /* Setup handle array and hash with valid handles */ + valid_handles = g_array_sized_new (TRUE, TRUE, sizeof (TpHandle), + handles->len); + result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, + (GDestroyNotify) g_hash_table_unref); + + DEBUG ("%u contact(s)", handles->len); + + for (i = 0; assumed_interfaces != NULL && assumed_interfaces[i] != NULL; i++) + { + DEBUG ("\tassumed interface : '%s'", assumed_interfaces[i]); + } + + for (i = 0; interfaces != NULL && interfaces[i] != NULL; i++) + { + DEBUG ("\tselected interface: '%s'", interfaces[i]); + } + + for (i = 0; i < handles->len; i++) + { + TpHandle h; + GHashTable *attr_hash; + guint j; + + h = g_array_index (handles, TpHandle, i); + + DEBUG ("\tcontact #%u", h); + + if (!tp_handle_is_valid (contact_repo, h, NULL)) + { + DEBUG ("\t\tinvalid"); + continue; + } + + attr_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, g_free, (GDestroyNotify) tp_g_value_slice_free); + g_array_append_val (valid_handles, h); + g_hash_table_insert (result, GUINT_TO_POINTER (h), attr_hash); + + for (j = 0; assumed_interfaces != NULL && assumed_interfaces[j] != NULL; j++) + { + klass->fill_contact_attributes (self, assumed_interfaces[j], h, + (TpContactAttributeMap *) result); + } + + for (j = 0; interfaces != NULL && interfaces[j] != NULL; j++) + { + klass->fill_contact_attributes (self, interfaces[j], h, + (TpContactAttributeMap *) result); + } + } + + g_array_unref (valid_handles); + + return result; +} + +static void +contacts_get_contact_attributes_impl (TpSvcConnectionInterfaceContacts *iface, + const GArray *handles, + const char **interfaces, + DBusGMethodInvocation *context) +{ + TpBaseConnection *conn = TP_BASE_CONNECTION (iface); + GHashTable *result; + + TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); + + result = tp_base_connection_dup_contact_attributes_hash (conn, + handles, + (const gchar * const *) interfaces, + contacts_always_included_interfaces); + + tp_svc_connection_interface_contacts_return_from_get_contact_attributes ( + context, result); + + g_hash_table_unref (result); +} + +typedef struct +{ + TpBaseConnection *conn; + GStrv interfaces; + DBusGMethodInvocation *context; +} GetContactByIdData; + +static void +ensure_handle_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TpHandleRepoIface *contact_repo = (TpHandleRepoIface *) source; + GetContactByIdData *data = user_data; + TpHandle handle; + GArray *handles; + GHashTable *attributes; + GHashTable *ret; + GError *error = NULL; + + handle = tp_handle_ensure_finish (contact_repo, result, &error); + + if (handle == 0) + { + dbus_g_method_return_error (data->context, error); + g_clear_error (&error); + goto out; + } + + handles = g_array_new (FALSE, FALSE, sizeof (TpHandle)); + g_array_append_val (handles, handle); + + attributes = tp_base_connection_dup_contact_attributes_hash (data->conn, + handles, (const gchar * const *) data->interfaces, + contacts_always_included_interfaces); + + ret = g_hash_table_lookup (attributes, GUINT_TO_POINTER (handle)); + g_assert (ret != NULL); + + tp_svc_connection_interface_contacts_return_from_get_contact_by_id ( + data->context, handle, ret); + + g_array_unref (handles); + g_hash_table_unref (attributes); + +out: + g_object_unref (data->conn); + g_strfreev (data->interfaces); + g_slice_free (GetContactByIdData, data); +} + +static void +contacts_get_contact_by_id_impl (TpSvcConnectionInterfaceContacts *iface, + const gchar *id, + const gchar **interfaces, + DBusGMethodInvocation *context) +{ + TpBaseConnection *conn = TP_BASE_CONNECTION (iface); + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, + TP_HANDLE_TYPE_CONTACT); + GetContactByIdData *data; + + TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); + + DEBUG ("%s: '%s', %u interfaces", conn->priv->object_path, id, + (interfaces == NULL ? 0 : g_strv_length ((GStrv) interfaces))); + + data = g_slice_new0 (GetContactByIdData); + data->conn = g_object_ref (conn); + data->interfaces = g_strdupv ((gchar **) interfaces); + data->context = context; + + tp_handle_ensure_async (contact_repo, conn, id, NULL, + ensure_handle_cb, data); +} + +static void +contacts_iface_init (TpSvcConnectionInterfaceContactsClass *klass) +{ +#define IMPLEMENT(x) tp_svc_connection_interface_contacts_implement_##x ( \ + klass, contacts_##x##_impl) + IMPLEMENT (get_contact_attributes); + IMPLEMENT (get_contact_by_id); +#undef IMPLEMENT +} diff --git a/telepathy-glib/base-connection.h b/telepathy-glib/base-connection.h index 668ff1a..49f3437 100644 --- a/telepathy-glib/base-connection.h +++ b/telepathy-glib/base-connection.h @@ -41,6 +41,8 @@ G_BEGIN_DECLS typedef struct _TpBaseConnectionClass TpBaseConnectionClass; typedef struct _TpBaseConnectionPrivate TpBaseConnectionPrivate; +typedef struct _TpContactAttributeMap TpContactAttributeMap; + typedef void (*TpBaseConnectionProc) (TpBaseConnection *self); typedef gboolean (*TpBaseConnectionStartConnectingImpl) ( @@ -93,6 +95,11 @@ struct _TpBaseConnectionClass { TpBaseConnectionGetInterfacesImpl get_interfaces_always_present; + void (*fill_contact_attributes) (TpBaseConnection *self, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes); + /**/ gpointer _future3; gpointer _future4; @@ -155,9 +162,6 @@ void tp_base_connection_finish_shutdown (TpBaseConnection *self); void tp_base_connection_add_interfaces (TpBaseConnection *self, const gchar **interfaces); -void tp_base_connection_register_with_contacts_mixin (TpBaseConnection *self); - - typedef struct _TpChannelManagerIter TpChannelManagerIter; struct _TpChannelManagerIter { @@ -213,6 +217,25 @@ void tp_base_connection_add_client_interest (TpBaseConnection *self, void tp_base_connection_add_possible_client_interest (TpBaseConnection *self, GQuark token); +_TP_AVAILABLE_IN_UNRELEASED +GHashTable *tp_base_connection_dup_contact_attributes_hash ( + TpBaseConnection *self, + const GArray *handles, + const gchar * const *interfaces, + const gchar * const *assumed_interfaces); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_contact_attribute_map_set (TpContactAttributeMap *map, + TpHandle contact, + const gchar *token, + GVariant *value); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_contact_attribute_map_take_sliced_gvalue (TpContactAttributeMap *map, + TpHandle contact, + const gchar *token, + GValue *value); + G_END_DECLS #endif /* #ifndef __TP_BASE_CONNECTION_H__*/ diff --git a/telepathy-glib/base-contact-list.c b/telepathy-glib/base-contact-list.c index d803ac5..96dde02 100644 --- a/telepathy-glib/base-contact-list.c +++ b/telepathy-glib/base-contact-list.c @@ -23,13 +23,13 @@ #include -#include #include #include #include #include #include #include +#include #include #include @@ -65,24 +65,32 @@ * ]| * * - * in the class_init method, call - * tp_base_contact_list_mixin_class_init() after - * tp_contacts_mixin_class_init(): + * in the #TpBaseConnectionClass.fill_contact_attributes + * implementation, call tp_base_contact_list_fill_contact_attributes() + * and do not chain up if it returns %TRUE: + * * |[ * // ... - * tp_contacts_mixin_class_init (object_class, - * G_STRUCT_OFFSET (MyConnectionClass, contacts_mixin)); - * tp_base_contact_list_mixin_class_init (base_connection_class); - * // ... + * if (!tp_strdiff (dbus_interface, MY_IFACE_CONNECTION_INTERFACE_HATS)) + * { + * // ... fill in Hats attributes ... + * return; + * } + * + * if (tp_base_contact_list_fill_contact_attributes (self->priv->contact_list, + * dbus_interface, contact, attributes)) + * { + * return; + * } + * + * ((TpBaseConnectionClass *) my_connection_parent_class)-> + * fill_contact_attributes (self, dbus_interface, contact, attributes); * ]| - * and include %TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST1 in - * the output of - * #TpBaseConnectionClass.get_interfaces_always_present; * * - * in the constructed method, call - * tp_base_contact_list_mixin_register_with_contacts_mixin() on the - * connection. + * include %TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST1 in + * the output of + * #TpBaseConnectionClass.get_interfaces_always_present * * * @@ -3578,11 +3586,9 @@ tp_base_contact_list_mixin_get_contact_list_attributes ( { TpBaseContactList *self = g_object_get_qdata ((GObject *) svc, BASE_CONTACT_LIST); - TpContactsMixin *contacts_mixin = TP_CONTACTS_MIXIN (svc); GError *error = NULL; g_return_if_fail (TP_IS_BASE_CONTACT_LIST (self)); - g_return_if_fail (contacts_mixin != NULL); if (tp_base_contact_list_get_state (self, &error) != TP_CONTACT_LIST_STATE_SUCCESS) @@ -3600,8 +3606,8 @@ tp_base_contact_list_mixin_get_contact_list_attributes ( set = tp_base_contact_list_dup_contacts (self); contacts = tp_handle_set_to_array (set); - result = tp_contacts_mixin_get_contact_attributes ( - (GObject *) self->priv->conn, contacts, interfaces, assumed); + result = tp_base_connection_dup_contact_attributes_hash ( + self->priv->conn, contacts, interfaces, assumed); tp_svc_connection_interface_contact_list1_return_from_get_contact_list_attributes ( context, result); @@ -4115,39 +4121,47 @@ tp_base_contact_list_get_list_dbus_property (GObject *conn, } } -static void -tp_base_contact_list_fill_list_contact_attributes (GObject *obj, - const GArray *contacts, - GHashTable *attributes_hash) +/** + * tp_base_contact_list_fill_contact_attributes: + * @self: a contact list + * @dbus_interface: a D-Bus interface + * @contact: a contact + * @attributes: used to return attributes + * + * If @dbus_interface is an interface that is relevant for this + * object, fill @attributes with the attributes for @contact + * and return %TRUE. + * + * Returns: %TRUE if @dbus_interface was recognised + */ +gboolean +tp_base_contact_list_fill_contact_attributes (TpBaseContactList *self, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes) { - TpBaseContactList *self = g_object_get_qdata (obj, BASE_CONTACT_LIST); - guint i; - - g_return_if_fail (TP_IS_BASE_CONTACT_LIST (self)); - g_return_if_fail (self->priv->conn != NULL); - - /* just omit the attributes if the contact list hasn't come in yet */ - if (self->priv->state != TP_CONTACT_LIST_STATE_SUCCESS) - return; + g_return_val_if_fail (TP_IS_BASE_CONTACT_LIST (self), FALSE); + g_return_val_if_fail (self->priv->conn != NULL, FALSE); - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST1)) { TpSubscriptionState subscribe = TP_SUBSCRIPTION_STATE_NO; TpSubscriptionState publish = TP_SUBSCRIPTION_STATE_NO; gchar *publish_request = NULL; - TpHandle handle; - handle = g_array_index (contacts, TpHandle, i); + /* just omit the attributes if the contact list hasn't come in yet */ + if (self->priv->state != TP_CONTACT_LIST_STATE_SUCCESS) + return TRUE; - tp_base_contact_list_dup_states (self, handle, + tp_base_contact_list_dup_states (self, contact, &subscribe, &publish, &publish_request); - tp_contacts_mixin_set_contact_attribute (attributes_hash, - handle, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_LIST1_PUBLISH, + tp_contact_attribute_map_take_sliced_gvalue (attributes, + contact, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_LIST1_PUBLISH, tp_g_value_slice_new_uint (publish)); - tp_contacts_mixin_set_contact_attribute (attributes_hash, - handle, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_LIST1_SUBSCRIBE, + tp_contact_attribute_map_take_sliced_gvalue (attributes, + contact, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_LIST1_SUBSCRIBE, tp_g_value_slice_new_uint (subscribe)); if (tp_str_empty (publish_request) || @@ -4157,11 +4171,56 @@ tp_base_contact_list_fill_list_contact_attributes (GObject *obj, } else { - tp_contacts_mixin_set_contact_attribute (attributes_hash, - handle, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_LIST1_PUBLISH_REQUEST, + tp_contact_attribute_map_take_sliced_gvalue (attributes, + contact, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_LIST1_PUBLISH_REQUEST, tp_g_value_slice_new_take_string (publish_request)); } + + return TRUE; } + + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS1) && + TP_IS_CONTACT_GROUP_LIST (self)) + { + if (self->priv->state == TP_CONTACT_LIST_STATE_SUCCESS) + { + tp_contact_attribute_map_take_sliced_gvalue (attributes, + contact, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_GROUPS1_GROUPS, + tp_g_value_slice_new_take_boxed (G_TYPE_STRV, + tp_base_contact_list_dup_contact_groups (self, contact))); + } + /* else just omit the attributes */ + + return TRUE; + } + + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_CONTACT_BLOCKING1) && + TP_IS_BLOCKABLE_CONTACT_LIST (self)) + { + if (self->priv->state == TP_CONTACT_LIST_STATE_SUCCESS) + { + /* FIXME: this would be more efficient if we had a + * contact_is_blocked() vfunc */ + TpHandleSet *blocked = tp_base_contact_list_dup_blocked_contacts (self); + gboolean is_blocked; + + is_blocked = tp_handle_set_is_member (blocked, contact); + + tp_contact_attribute_map_take_sliced_gvalue (attributes, + contact, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_BLOCKING1_BLOCKED, + tp_g_value_slice_new_boolean (is_blocked)); + + tp_handle_set_destroy (blocked); + } + /* else just omit the attributes */ + + return TRUE; + } + + /* not our interface */ + return FALSE; } static void @@ -4637,71 +4696,6 @@ tp_base_contact_list_get_group_dbus_property (GObject *conn, } } -static void -tp_base_contact_list_fill_groups_contact_attributes (GObject *obj, - const GArray *contacts, - GHashTable *attributes_hash) -{ - TpBaseContactList *self = g_object_get_qdata (obj, BASE_CONTACT_LIST); - guint i; - - g_return_if_fail (TP_IS_BASE_CONTACT_LIST (self)); - g_return_if_fail (TP_IS_CONTACT_GROUP_LIST (self)); - g_return_if_fail (self->priv->conn != NULL); - - /* just omit the attributes if the contact list hasn't come in yet */ - if (self->priv->state != TP_CONTACT_LIST_STATE_SUCCESS) - return; - - for (i = 0; i < contacts->len; i++) - { - TpHandle handle; - - handle = g_array_index (contacts, TpHandle, i); - - tp_contacts_mixin_set_contact_attribute (attributes_hash, - handle, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_GROUPS1_GROUPS, - tp_g_value_slice_new_take_boxed (G_TYPE_STRV, - tp_base_contact_list_dup_contact_groups (self, handle))); - } -} - -static void -tp_base_contact_list_fill_blocking_contact_attributes (GObject *obj, - const GArray *contacts, - GHashTable *attributes_hash) -{ - TpBaseContactList *self = g_object_get_qdata (obj, BASE_CONTACT_LIST); - guint i; - TpHandleSet *blocked; - - g_return_if_fail (TP_IS_BASE_CONTACT_LIST (self)); - g_return_if_fail (TP_IS_BLOCKABLE_CONTACT_LIST (self)); - g_return_if_fail (self->priv->conn != NULL); - - /* just omit the attributes if the contact list hasn't come in yet */ - if (self->priv->state != TP_CONTACT_LIST_STATE_SUCCESS) - return; - - blocked = tp_base_contact_list_dup_blocked_contacts (self); - - for (i = 0; i < contacts->len; i++) - { - TpHandle handle; - gboolean is_blocked; - - handle = g_array_index (contacts, TpHandle, i); - - is_blocked = tp_handle_set_is_member (blocked, handle); - - tp_contacts_mixin_set_contact_attribute (attributes_hash, - handle, TP_TOKEN_CONNECTION_INTERFACE_CONTACT_BLOCKING1_BLOCKED, - tp_g_value_slice_new_boolean (is_blocked)); - } - - tp_handle_set_destroy (blocked); -} - /** * tp_base_contact_list_mixin_groups_iface_init: * @klass: the service-side D-Bus interface, @@ -4948,7 +4942,6 @@ tp_base_contact_list_mixin_class_init (TpBaseConnectionClass *cls) GObjectClass *obj_cls = (GObjectClass *) cls; g_return_if_fail (TP_IS_BASE_CONNECTION_CLASS (cls)); - g_return_if_fail (TP_CONTACTS_MIXIN_CLASS (cls) != NULL); g_return_if_fail (g_type_is_a (type, TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST1)); @@ -4975,59 +4968,6 @@ tp_base_contact_list_mixin_class_init (TpBaseConnectionClass *cls) } /** - * tp_base_contact_list_mixin_register_with_contacts_mixin: - * @self: a contact list - * @conn: An instance of #TpBaseConnection that uses a #TpContactsMixin, - * and implements #TpSvcConnectionInterfaceContactList1 using - * #TpBaseContactList - * - * Register the ContactList interface with the Contacts interface to make it - * inspectable. Before this function is called, the #TpContactsMixin must be - * initialized with tp_contacts_mixin_init(). - * - * If the connection implements #TpSvcConnectionInterfaceContactGroups1 - * the #TpBaseContactList implements %TP_TYPE_CONTACT_GROUP_LIST, - * this function automatically also registers the ContactGroups interface - * with the contacts mixin. - * - * Since: 0.13.0 - */ -void -tp_base_contact_list_mixin_register_with_contacts_mixin ( - TpBaseContactList *self, - TpBaseConnection *conn) -{ - GType type = G_OBJECT_TYPE (conn); - GObject *object = (GObject *) conn; - - g_return_if_fail (TP_IS_BASE_CONTACT_LIST (self)); - g_return_if_fail (TP_IS_BASE_CONNECTION (conn)); - g_return_if_fail (self != NULL); - g_return_if_fail (g_type_is_a (type, - TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST1)); - - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST1, - tp_base_contact_list_fill_list_contact_attributes); - - if (g_type_is_a (type, TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS1) - && TP_IS_CONTACT_GROUP_LIST (self)) - { - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS1, - tp_base_contact_list_fill_groups_contact_attributes); - } - - if (g_type_is_a (type, TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_BLOCKING1) - && TP_IS_BLOCKABLE_CONTACT_LIST (self)) - { - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_CONTACT_BLOCKING1, - tp_base_contact_list_fill_blocking_contact_attributes); - } -} - -/** * tp_base_contact_list_get_state: * @self: a contact list * @error: used to raise an error if something other than diff --git a/telepathy-glib/base-contact-list.h b/telepathy-glib/base-contact-list.h index 29c8bf6..1a6486b 100644 --- a/telepathy-glib/base-contact-list.h +++ b/telepathy-glib/base-contact-list.h @@ -586,13 +586,17 @@ struct _TpMutableContactGroupListInterface { /* ---- Mixin-like functionality for our parent TpBaseConnection ---- */ void tp_base_contact_list_mixin_class_init (TpBaseConnectionClass *cls); -void tp_base_contact_list_mixin_register_with_contacts_mixin ( - TpBaseContactList *self, TpBaseConnection *conn); void tp_base_contact_list_mixin_list_iface_init (gpointer klass); void tp_base_contact_list_mixin_groups_iface_init (gpointer klass); _TP_AVAILABLE_IN_0_16 void tp_base_contact_list_mixin_blocking_iface_init (gpointer klass); +_TP_AVAILABLE_IN_UNRELEASED +gboolean tp_base_contact_list_fill_contact_attributes (TpBaseContactList *self, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes); + G_END_DECLS #endif diff --git a/telepathy-glib/contacts-mixin.c b/telepathy-glib/contacts-mixin.c deleted file mode 100644 index f47f113..0000000 --- a/telepathy-glib/contacts-mixin.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * contacts-mixin.c - Source for TpContactsMixin - * Copyright © 2008-2010 Collabora Ltd. - * Copyright © 2008 Nokia Corporation - * @author Sjoerd Simons - * - * This library 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 2.1 of the License, or (at your option) any later version. - * - * This library 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 this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * SECTION:contacts-mixin - * @title: TpContactsMixin - * @short_description: a mixin implementation of the contacts connection - * interface - * @see_also: #TpSvcConnectionInterfaceContacts - * - * This mixin can be added to a #TpBaseConnection subclass to implement the - * Contacts interface in a generic way. - * - * To use the contacts mixin, include a #TpContactsMixinClass somewhere in - * your class structure and a #TpContactsMixin somewhere in your instance - * structure, and call tp_contacts_mixin_class_init() from your class_init - * function, tp_contacts_mixin_init() from your init function or constructor, - * and tp_contacts_mixin_finalize() from your dispose or finalize function. - * - * To use the contacts mixin as the implementation of - * #TpSvcConnectionInterfaceContacts, in the function you pass to - * G_IMPLEMENT_INTERFACE, you should call tp_contacts_mixin_iface_init. - * TpContactsMixin implements all of the D-Bus methods and properties in the - * Contacts interface. - * - * To add interfaces with contact attributes to this interface use - * tp_contacts_mixin_add_contact_attributes_iface: - * - * Since: 0.7.14 - * - */ - -#include "config.h" - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_FLAG TP_DEBUG_CONNECTION - -#include "debug-internal.h" - -struct _TpContactsMixinPrivate -{ - /* String interface name -> FillContactAttributes func */ - GHashTable *interfaces; -}; - -static const gchar *always_included_interfaces[] = { - TP_IFACE_CONNECTION, - NULL -}; - -/** - * tp_contacts_mixin_class_get_offset_quark: (skip) - * - * - * - * Returns: the quark used for storing mixin offset on a GObjectClass - * - * Since: 0.7.14 - * - */ -GQuark -tp_contacts_mixin_class_get_offset_quark () -{ - static GQuark offset_quark = 0; - - if (G_UNLIKELY (offset_quark == 0)) - offset_quark = g_quark_from_static_string ( - "TpContactsMixinClassOffsetQuark"); - - return offset_quark; -} - -/** - * tp_contacts_mixin_get_offset_quark: (skip) - * - * - * - * Returns: the quark used for storing mixin offset on a GObject - * - * Since: 0.7.14 - * - */ -GQuark -tp_contacts_mixin_get_offset_quark () -{ - static GQuark offset_quark = 0; - - if (G_UNLIKELY (offset_quark == 0)) - offset_quark = g_quark_from_static_string ("TpContactsMixinOffsetQuark"); - - return offset_quark; -} - - -/** - * tp_contacts_mixin_class_init: (skip) - * @obj_cls: The class of the implementation that uses this mixin - * @offset: The byte offset of the TpContactsMixinClass within the class - * structure - * - * Initialize the contacts mixin. Should be called from the implementation's - * class_init function like so: - * - * - * tp_contacts_mixin_class_init ((GObjectClass *) klass, - * G_STRUCT_OFFSET (SomeObjectClass, contacts_mixin)); - * - * - * Since: 0.7.14 - * - */ - -void -tp_contacts_mixin_class_init (GObjectClass *obj_cls, glong offset) -{ - g_assert (G_IS_OBJECT_CLASS (obj_cls)); - - g_type_set_qdata (G_OBJECT_CLASS_TYPE (obj_cls), - TP_CONTACTS_MIXIN_CLASS_OFFSET_QUARK, - GINT_TO_POINTER (offset)); -} - - -/** - * tp_contacts_mixin_init: (skip) - * @obj: An instance of the implementation that uses this mixin - * @offset: The byte offset of the TpContactsMixin within the object structure - * - * Initialize the contacts mixin. Should be called from the implementation's - * instance init function like so: - * - * - * tp_contacts_mixin_init ((GObject *) self, - * G_STRUCT_OFFSET (SomeObject, contacts_mixin)); - * - * - * Since: 0.7.14 - * - */ -void -tp_contacts_mixin_init (GObject *obj, gsize offset) -{ - TpContactsMixin *mixin; - - g_assert (G_IS_OBJECT (obj)); - - g_type_set_qdata (G_OBJECT_TYPE (obj), - TP_CONTACTS_MIXIN_OFFSET_QUARK, - GSIZE_TO_POINTER (offset)); - - mixin = TP_CONTACTS_MIXIN (obj); - - mixin->priv = g_slice_new0 (TpContactsMixinPrivate); - mixin->priv->interfaces = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); -} - -/** - * tp_contacts_mixin_finalize: (skip) - * @obj: An object with this mixin. - * - * Free resources held by the contacts mixin. - * - * Since: 0.7.14 - * - */ -void -tp_contacts_mixin_finalize (GObject *obj) -{ - TpContactsMixin *mixin = TP_CONTACTS_MIXIN (obj); - - DEBUG ("%p", obj); - - /* free any data held directly by the object here */ - g_hash_table_unref (mixin->priv->interfaces); - g_slice_free (TpContactsMixinPrivate, mixin->priv); -} - -/** - * tp_contacts_mixin_get_contact_attributes: (skip) - * @obj: A connection instance that uses this mixin. The connection must be connected. - * @handles: List of handles to retrieve contacts for. Any invalid handles will be - * dropped from the returned mapping. - * @interfaces: A list of interfaces to retrieve attributes from. - * @assumed_interfaces: A list of additional interfaces to retrieve attributes - * from. This can be used for interfaces documented as automatically included, - * like %TP_IFACE_CONNECTION for GetContactAttributes, - * or %TP_IFACE_CONNECTION and %TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST for - * GetContactListAttributes. - * - * Get contact attributes for the given contacts. Provide attributes for all requested - * interfaces. If contact attributes are not immediately known, the behaviour is defined - * by the interface; the attribute should either be omitted from the result or replaced - * with a default value. - * - * Returns: A dictionary mapping the contact handles to contact attributes. - * - */ -GHashTable * -tp_contacts_mixin_get_contact_attributes (GObject *obj, - const GArray *handles, - const gchar **interfaces, - const gchar **assumed_interfaces) -{ - GHashTable *result; - guint i; - TpBaseConnection *conn = TP_BASE_CONNECTION (obj); - TpContactsMixin *self = TP_CONTACTS_MIXIN (obj); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); - GArray *valid_handles; - TpContactsMixinFillContactAttributesFunc func; - - g_return_val_if_fail (TP_IS_BASE_CONNECTION (obj), NULL); - g_return_val_if_fail (TP_CONTACTS_MIXIN_OFFSET (obj) != 0, NULL); - g_return_val_if_fail (tp_base_connection_check_connected (conn, NULL), NULL); - - /* Setup handle array and hash with valid handles, optionally holding them */ - valid_handles = g_array_sized_new (TRUE, TRUE, sizeof (TpHandle), - handles->len); - result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) g_hash_table_unref); - - for (i = 0 ; i < handles->len ; i++) - { - TpHandle h; - h = g_array_index (handles, TpHandle, i); - if (tp_handle_is_valid (contact_repo, h, NULL)) - { - GHashTable *attr_hash = g_hash_table_new_full (g_str_hash, - g_str_equal, g_free, (GDestroyNotify) tp_g_value_slice_free); - g_array_append_val (valid_handles, h); - g_hash_table_insert (result, GUINT_TO_POINTER(h), attr_hash); - } - } - - for (i = 0; assumed_interfaces != NULL && assumed_interfaces[i] != NULL; i++) - { - func = g_hash_table_lookup (self->priv->interfaces, assumed_interfaces[i]); - - if (func == NULL) - DEBUG ("non-inspectable assumed interface %s given; ignoring", - assumed_interfaces[i]); - else - func (obj, valid_handles, result); - } - - for (i = 0; interfaces != NULL && interfaces[i] != NULL; i++) - { - - func = g_hash_table_lookup (self->priv->interfaces, interfaces[i]); - - if (func == NULL) - DEBUG ("non-inspectable interface %s given; ignoring", interfaces[i]); - else - func (obj, valid_handles, result); - } - - g_array_unref (valid_handles); - - return result; -} - -static void -tp_contacts_mixin_get_contact_attributes_impl ( - TpSvcConnectionInterfaceContacts *iface, - const GArray *handles, - const char **interfaces, - DBusGMethodInvocation *context) -{ - TpBaseConnection *conn = TP_BASE_CONNECTION (iface); - GHashTable *result; - - TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); - - result = tp_contacts_mixin_get_contact_attributes (G_OBJECT (conn), - handles, interfaces, always_included_interfaces); - - tp_svc_connection_interface_contacts_return_from_get_contact_attributes ( - context, result); - - g_hash_table_unref (result); -} - -typedef struct -{ - TpBaseConnection *conn; - GStrv interfaces; - DBusGMethodInvocation *context; -} GetContactByIdData; - -static void -ensure_handle_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - TpHandleRepoIface *contact_repo = (TpHandleRepoIface *) source; - GetContactByIdData *data = user_data; - TpHandle handle; - GArray *handles; - GHashTable *attributes; - GHashTable *ret; - GError *error = NULL; - - handle = tp_handle_ensure_finish (contact_repo, result, &error); - if (handle == 0) - { - dbus_g_method_return_error (data->context, error); - g_clear_error (&error); - goto out; - } - - handles = g_array_new (FALSE, FALSE, sizeof (TpHandle)); - g_array_append_val (handles, handle); - - attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (data->conn), - handles, (const gchar **) data->interfaces, always_included_interfaces); - - ret = g_hash_table_lookup (attributes, GUINT_TO_POINTER (handle)); - g_assert (ret != NULL); - - tp_svc_connection_interface_contacts_return_from_get_contact_by_id ( - data->context, handle, ret); - - g_array_unref (handles); - g_hash_table_unref (attributes); - -out: - g_object_unref (data->conn); - g_strfreev (data->interfaces); - g_slice_free (GetContactByIdData, data); -} - -static void -tp_contacts_mixin_get_contact_by_id_impl ( - TpSvcConnectionInterfaceContacts *iface, - const gchar *id, - const gchar **interfaces, - DBusGMethodInvocation *context) -{ - TpBaseConnection *conn = TP_BASE_CONNECTION (iface); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); - GetContactByIdData *data; - - TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); - - data = g_slice_new0 (GetContactByIdData); - data->conn = g_object_ref (conn); - data->interfaces = g_strdupv ((gchar **) interfaces); - data->context = context; - - tp_handle_ensure_async (contact_repo, conn, id, NULL, - ensure_handle_cb, data); -} - -/** - * tp_contacts_mixin_iface_init: (skip) - * @g_iface: A pointer to the #TpSvcConnectionInterfaceContacts in an object - * class - * @iface_data: Ignored - * - * Fill in the vtable entries needed to implement the contacts interface - * using this mixin. This function should usually be called via - * G_IMPLEMENT_INTERFACE. - * - * Since: 0.7.14 - * - */ -void -tp_contacts_mixin_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcConnectionInterfaceContactsClass *klass = - (TpSvcConnectionInterfaceContactsClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_connection_interface_contacts_implement_##x ( \ - klass, tp_contacts_mixin_##x##_impl) - IMPLEMENT(get_contact_attributes); - IMPLEMENT(get_contact_by_id); -#undef IMPLEMENT -} - -/** - * tp_contacts_mixin_add_contact_attributes_iface: (skip) - * @obj: An instance of the implementation that uses this mixin - * @interface: Name of the interface that has ContactAttributes - * @fill_contact_attributes: Contact attribute filler function - * - * Declare that the given interface has contact attributes which can be added - * to the attributes hash using the filler function. All the handles in the - * handle array passed to the filler function are guaranteed to be valid and - * referenced. - * - * Since: 0.7.14 - * - */ - -void -tp_contacts_mixin_add_contact_attributes_iface (GObject *obj, - const gchar *interface, - TpContactsMixinFillContactAttributesFunc fill_contact_attributes) -{ - TpContactsMixin *self = TP_CONTACTS_MIXIN (obj); - - g_assert (g_hash_table_lookup (self->priv->interfaces, interface) == NULL); - g_assert (fill_contact_attributes != NULL); - - g_hash_table_insert (self->priv->interfaces, g_strdup (interface), - fill_contact_attributes); -} - -/** - * tp_contacts_mixin_set_contact_attribute: (skip) - * @contact_attributes: contacts attribute hash as passed to - * TpContactsMixinFillContactAttributesFunc - * @handle: Handle to set the attribute on - * @attribute: attribute name - * @value: slice allocated GValue containing the value of the attribute, for - * instance with tp_g_value_slice_new. Ownership of the GValue is taken over by - * the mixin - * - * Utility function to set attribute for handle to value in the attributes hash - * as passed to a TpContactsMixinFillContactAttributesFunc. - * - * Since: 0.7.14 - * - */ - -void -tp_contacts_mixin_set_contact_attribute (GHashTable *contact_attributes, - TpHandle handle, const gchar *attribute, GValue *value) -{ - GHashTable *attributes; - - attributes = g_hash_table_lookup (contact_attributes, - GUINT_TO_POINTER (handle)); - - g_assert (attributes != NULL); - g_assert (G_IS_VALUE (value)); - - g_hash_table_insert (attributes, g_strdup (attribute), value); -} - diff --git a/telepathy-glib/contacts-mixin.h b/telepathy-glib/contacts-mixin.h deleted file mode 100644 index 6aa2625..0000000 --- a/telepathy-glib/contacts-mixin.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * contacts-mixin.h - Header for TpContactsMixin - * Copyright (C) 2008 Collabora Ltd. - * Copyright (C) 2008 Nokia Corporation - * - * This library 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 2.1 of the License, or (at your option) any later version. - * - * This library 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 this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#if !defined (_TP_GLIB_H_INSIDE) && !defined (_TP_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __TP_CONTACTS_MIXIN_H__ -#define __TP_CONTACTS_MIXIN_H__ - -#include - -#include "util.h" - -G_BEGIN_DECLS - -typedef struct _TpContactsMixinClass TpContactsMixinClass; -typedef struct _TpContactsMixinClassPrivate TpContactsMixinClassPrivate; -typedef struct _TpContactsMixin TpContactsMixin; -typedef struct _TpContactsMixinPrivate TpContactsMixinPrivate; - -/** - * TpContactsMixinFillContactAttributesFunc: - * @obj: An object implementing the Contacts interface with this mixin - * @contacts: The contact handles for which attributes are requested - * @attributes_hash: hash of handle => hash of attributes, containing all the - * contacts in the contacts array - * - * This function is called to supply contact attributes pertaining to - * a particular interface, for a list of contacts. - * All the handles in @contacts are guaranteed to be valid and - * referenced. - */ -typedef void (*TpContactsMixinFillContactAttributesFunc) (GObject *obj, - const GArray *contacts, GHashTable *attributes_hash); - -/** - * TpContactsMixinClass: - * - * Structure to be included in the class structure of objects that - * use this mixin. Initialize it with tp_contacts_mixin_class_init(). - * - * There are no public fields. - */ -struct _TpContactsMixinClass { - /**/ - TpContactsMixinClassPrivate *priv; -}; - -/** - * TpContactsMixin: - * - * Structure to be included in the instance structure of objects that - * use this mixin. Initialize it with tp_contacts_mixin_init(). - * - * There are no public fields. - */ -struct _TpContactsMixin { - /**/ - TpContactsMixinPrivate *priv; -}; - -/* TYPE MACROS */ -#define TP_CONTACTS_MIXIN_CLASS_OFFSET_QUARK \ - (tp_contacts_mixin_class_get_offset_quark ()) -#define TP_CONTACTS_MIXIN_CLASS_OFFSET(o) \ - tp_mixin_class_get_offset (o, TP_CONTACTS_MIXIN_CLASS_OFFSET_QUARK) -#define TP_CONTACTS_MIXIN_CLASS(o) \ - ((TpContactsMixinClass *) tp_mixin_offset_cast (o, \ - TP_CONTACTS_MIXIN_CLASS_OFFSET (o))) - -#define TP_CONTACTS_MIXIN_OFFSET_QUARK (tp_contacts_mixin_get_offset_quark ()) -#define TP_CONTACTS_MIXIN_OFFSET(o) \ - tp_mixin_instance_get_offset (o, TP_CONTACTS_MIXIN_OFFSET_QUARK) -#define TP_CONTACTS_MIXIN(o) \ - ((TpContactsMixin *) tp_mixin_offset_cast (o, TP_CONTACTS_MIXIN_OFFSET (o))) - -GQuark tp_contacts_mixin_class_get_offset_quark (void); -GQuark tp_contacts_mixin_get_offset_quark (void); - -void tp_contacts_mixin_class_init (GObjectClass *obj_cls, glong offset); - -void tp_contacts_mixin_init (GObject *obj, gsize offset); -void tp_contacts_mixin_finalize (GObject *obj); - -void tp_contacts_mixin_iface_init (gpointer g_iface, gpointer iface_data); - -void tp_contacts_mixin_add_contact_attributes_iface (GObject *obj, - const gchar *interface, - TpContactsMixinFillContactAttributesFunc fill_contact_attributes); - -void tp_contacts_mixin_set_contact_attribute (GHashTable *contact_attributes, - TpHandle handle, const gchar *attribute, GValue *value); - -GHashTable *tp_contacts_mixin_get_contact_attributes (GObject *obj, - const GArray *handles, const gchar **interfaces, const gchar **assumed_interfaces); - -G_END_DECLS - -#endif /* #ifndef __TP_CONTACTS_MIXIN_H__ */ diff --git a/telepathy-glib/introspection.am b/telepathy-glib/introspection.am index 1bee4b4..59c202c 100644 --- a/telepathy-glib/introspection.am +++ b/telepathy-glib/introspection.am @@ -51,7 +51,6 @@ TelepathyGLib_1_gir_FILES = \ $(srcdir)/simple-handler.c $(srcdir)/simple-handler.h \ $(srcdir)/simple-observer.c $(srcdir)/simple-observer.h \ $(srcdir)/dbus-properties-mixin.c $(srcdir)/dbus-properties-mixin.h \ - $(srcdir)/contacts-mixin.c $(srcdir)/contacts-mixin.h \ $(srcdir)/group-mixin.c $(srcdir)/group-mixin.h \ $(srcdir)/presence-mixin.c $(srcdir)/presence-mixin.h \ $(srcdir)/channel-dispatch-operation.c $(srcdir)/channel-dispatch-operation.h \ diff --git a/telepathy-glib/presence-mixin.c b/telepathy-glib/presence-mixin.c index 44e57eb..0db0af1 100644 --- a/telepathy-glib/presence-mixin.c +++ b/telepathy-glib/presence-mixin.c @@ -64,13 +64,30 @@ * * * - * - * call tp_presence_mixin_register_with_contacts_mixin() - * in the #GObjectClass constructed function. + * in the #TpBaseConnectionClass.fill_contact_attributes + * implementation, call tp_presence_mixin_fill_contact_attributes() + * and do not chain up if it returns %TRUE: * - * - * - * + * |[ + * // ... + * if (!tp_strdiff (dbus_interface, MY_IFACE_CONNECTION_INTERFACE_HATS)) + * { + * // ... fill in Hats attributes ... + * return; + * } + * + * if (tp_presence_mixin_fill_contact_attributes (G_OBJECT (self), + * dbus_interface, contact, attributes)) + * { + * return; + * } + * + * ((TpBaseConnectionClass *) my_connection_parent_class)-> + * fill_contact_attributes (self, dbus_interface, contact, attributes); + * ]| + * + * + * *
* * Since: 0.5.13 @@ -256,7 +273,6 @@ #include #include #include -#include #include #define DEBUG_FLAG TP_DEBUG_PRESENCE @@ -878,15 +894,38 @@ tp_presence_mixin_iface_init (gpointer g_iface, #undef IMPLEMENT } -static void +/** + * tp_presence_mixin_fill_contact_attributes: + * @obj: an object with a #TpPresenceMixin + * @dbus_interface: a D-Bus interface + * @contact: a contact + * @attributes: used to return attributes + * + * If @dbus_interface is an interface that is relevant for this + * object, fill @attributes with the attributes for @contact + * and return %TRUE. + * + * Returns: %TRUE if @dbus_interface was recognised + */ +gboolean tp_presence_mixin_fill_contact_attributes (GObject *obj, - const GArray *contacts, GHashTable *attributes_hash) + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes) { TpPresenceMixinClass *mixin_cls = TP_PRESENCE_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj)); GHashTable *contact_statuses; + GArray *handles; + + if (tp_strdiff (dbus_interface, TP_IFACE_CONNECTION_INTERFACE_PRESENCE1)) + return FALSE; + + handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); + g_array_append_val (handles, contact); - contact_statuses = mixin_cls->get_contact_statuses (obj, contacts); + /* FIXME: this would now be more efficient if it was singular */ + contact_statuses = mixin_cls->get_contact_statuses (obj, handles); if (contact_statuses == NULL) { g_warning ("get_contact_statuses returned NULL"); @@ -904,32 +943,22 @@ tp_presence_mixin_fill_contact_attributes (GObject *obj, { TpHandle handle = GPOINTER_TO_UINT (key); TpPresenceStatus *status = value; - GValueArray *presence = construct_presence_value_array ( + GValueArray *presence; + + if (handle != contact) + g_warning ("get_contact_statuses returned someone else's status"); + + presence = construct_presence_value_array ( status, mixin_cls->statuses); - tp_contacts_mixin_set_contact_attribute (attributes_hash, handle, + tp_contact_attribute_map_take_sliced_gvalue (attributes, contact, TP_TOKEN_CONNECTION_INTERFACE_PRESENCE1_PRESENCE, tp_g_value_slice_new_take_boxed (type, presence)); } g_hash_table_unref (contact_statuses); } -} -/** - * tp_presence_mixin_register_with_contacts_mixin: (skip) - * @obj: An instance that of the implementation that uses both the Contacts - * mixin and this mixin - * - * Register the Presence interface with the Contacts interface to make it - * inspectable. The Contacts mixin should be initialized before this function - * is called - */ -void -tp_presence_mixin_register_with_contacts_mixin (GObject *obj) -{ - tp_contacts_mixin_add_contact_attributes_iface (obj, - TP_IFACE_CONNECTION_INTERFACE_PRESENCE1, - tp_presence_mixin_fill_contact_attributes); + g_array_unref (handles); + return TRUE; } - diff --git a/telepathy-glib/presence-mixin.h b/telepathy-glib/presence-mixin.h index f94bf65..59f55ff 100644 --- a/telepathy-glib/presence-mixin.h +++ b/telepathy-glib/presence-mixin.h @@ -27,6 +27,7 @@ #include #include +#include #include "util.h" G_BEGIN_DECLS @@ -146,8 +147,11 @@ void tp_presence_mixin_emit_one_presence_update (GObject *obj, void tp_presence_mixin_iface_init (gpointer g_iface, gpointer iface_data); void tp_presence_mixin_init_dbus_properties (GObjectClass *cls); -void tp_presence_mixin_register_with_contacts_mixin ( - GObject *obj); +_TP_AVAILABLE_IN_UNRELEASED +gboolean tp_presence_mixin_fill_contact_attributes (GObject *obj, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes); G_END_DECLS diff --git a/telepathy-glib/telepathy-glib.h b/telepathy-glib/telepathy-glib.h index fee79b8..fa4f485 100644 --- a/telepathy-glib/telepathy-glib.h +++ b/telepathy-glib/telepathy-glib.h @@ -74,7 +74,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/lib/broken-client-types-conn.c b/tests/lib/broken-client-types-conn.c index 1829869..6148f37 100644 --- a/tests/lib/broken-client-types-conn.c +++ b/tests/lib/broken-client-types-conn.c @@ -30,19 +30,18 @@ tp_tests_broken_client_types_connection_init ( } static void -broken_fill_client_types ( - GObject *object, - const GArray *contacts, - GHashTable *attributes) +fill_contact_attributes (TpBaseConnection *base, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes) { - guint i; G_GNUC_BEGIN_IGNORE_DEPRECATIONS GType type = G_TYPE_VALUE_ARRAY; G_GNUC_END_IGNORE_DEPRECATIONS - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES1)) { - TpHandle handle = g_array_index (contacts, guint, i); /* Muahaha. Actually we add Presence information. */ GValueArray *presence = tp_value_array_build (3, G_TYPE_UINT, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, @@ -50,8 +49,8 @@ broken_fill_client_types ( G_TYPE_STRING, "hi mum!", G_TYPE_INVALID); - tp_contacts_mixin_set_contact_attribute (attributes, - handle, + tp_contact_attribute_map_take_sliced_gvalue (attributes, + contact, TP_TOKEN_CONNECTION_INTERFACE_PRESENCE1_PRESENCE, tp_g_value_slice_new_take_boxed (type, presence)); } @@ -61,8 +60,7 @@ static void tp_tests_broken_client_types_connection_class_init ( TpTestsBrokenClientTypesConnectionClass *klass) { - TpTestsContactsConnectionClass *cc_class = - TP_TESTS_CONTACTS_CONNECTION_CLASS (klass); + TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS (klass); - cc_class->fill_client_types = broken_fill_client_types; + base_class->fill_contact_attributes = fill_contact_attributes; } diff --git a/tests/lib/contacts-conn.c b/tests/lib/contacts-conn.c index 5ebc35f..46028b8 100644 --- a/tests/lib/contacts-conn.c +++ b/tests/lib/contacts-conn.c @@ -40,8 +40,6 @@ G_DEFINE_TYPE_WITH_CODE (TpTestsContactsConnection, TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_CAPABILITIES1, NULL) G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO1, init_contact_info) - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, - tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST1, tp_base_contact_list_mixin_list_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS1, @@ -161,7 +159,6 @@ finalize (GObject *object) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); - tp_contacts_mixin_finalize (object); g_hash_table_unref (self->priv->aliases); g_hash_table_unref (self->priv->avatars); g_hash_table_unref (self->priv->presence_statuses); @@ -177,125 +174,110 @@ finalize (GObject *object) } static void -aliasing_fill_contact_attributes (GObject *object, - const GArray *contacts, - GHashTable *attributes) +tp_tests_contacts_connection_fill_contact_attributes (TpBaseConnection *base, + const gchar *dbus_interface, + TpHandle contact, + TpContactAttributeMap *attributes) { - guint i; - TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); - TpBaseConnection *base = TP_BASE_CONNECTION (object); + TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (base); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_ALIASING1)) { - TpHandle handle = g_array_index (contacts, guint, i); const gchar *alias = g_hash_table_lookup (self->priv->aliases, - GUINT_TO_POINTER (handle)); + GUINT_TO_POINTER (contact)); if (alias == NULL) { - alias = tp_handle_inspect (contact_repo, handle); + alias = tp_handle_inspect (contact_repo, contact); } - tp_contacts_mixin_set_contact_attribute (attributes, handle, + tp_contact_attribute_map_take_sliced_gvalue (attributes, contact, TP_IFACE_CONNECTION_INTERFACE_ALIASING1 "/alias", tp_g_value_slice_new_string (alias)); - } -} -static void -avatars_fill_contact_attributes (GObject *object, - const GArray *contacts, - GHashTable *attributes) -{ - guint i; - TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); + return; + } - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_AVATARS1)) { - TpHandle handle = g_array_index (contacts, guint, i); AvatarData *a = g_hash_table_lookup (self->priv->avatars, - GUINT_TO_POINTER (handle)); + GUINT_TO_POINTER (contact)); if (a != NULL && a->token != NULL) { - tp_contacts_mixin_set_contact_attribute (attributes, handle, + tp_contact_attribute_map_take_sliced_gvalue (attributes, contact, TP_IFACE_CONNECTION_INTERFACE_AVATARS1 "/token", tp_g_value_slice_new_string (a->token)); } - } -} -static void -location_fill_contact_attributes (GObject *object, - const GArray *contacts, - GHashTable *attributes) -{ - guint i; - TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); + return; + } - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_LOCATION1)) { - TpHandle handle = g_array_index (contacts, guint, i); GHashTable *location = g_hash_table_lookup (self->priv->locations, - GUINT_TO_POINTER (handle)); + GUINT_TO_POINTER (contact)); if (location != NULL) { - tp_contacts_mixin_set_contact_attribute (attributes, handle, + tp_contact_attribute_map_take_sliced_gvalue (attributes, contact, TP_IFACE_CONNECTION_INTERFACE_LOCATION1 "/location", tp_g_value_slice_new_boxed (TP_HASH_TYPE_LOCATION, location)); } - } -} -static void -contact_caps_fill_contact_attributes (GObject *object, - const GArray *contacts, - GHashTable *attributes) -{ - guint i; - TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); + return; + } - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES1)) { - TpHandle handle = g_array_index (contacts, guint, i); GPtrArray *caps = g_hash_table_lookup (self->priv->capabilities, - GUINT_TO_POINTER (handle)); + GUINT_TO_POINTER (contact)); if (caps != NULL) { - tp_contacts_mixin_set_contact_attribute (attributes, handle, + tp_contact_attribute_map_take_sliced_gvalue (attributes, contact, TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES1 "/capabilities", tp_g_value_slice_new_boxed ( TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, caps)); } - } -} -static void -contact_info_fill_contact_attributes (GObject *object, - const GArray *contacts, - GHashTable *attributes) -{ - guint i; - TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); + return; + } - for (i = 0; i < contacts->len; i++) + if (!tp_strdiff (dbus_interface, + TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO1)) { - TpHandle handle = g_array_index (contacts, guint, i); GPtrArray *info = g_hash_table_lookup (self->priv->contact_info, - GUINT_TO_POINTER (handle)); + GUINT_TO_POINTER (contact)); if (info != NULL) { - tp_contacts_mixin_set_contact_attribute (attributes, handle, + tp_contact_attribute_map_take_sliced_gvalue (attributes, contact, TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO1 "/info", tp_g_value_slice_new_boxed (TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST, info)); } + + return; } + + if (tp_base_contact_list_fill_contact_attributes ( + TP_BASE_CONTACT_LIST (self->priv->list_manager), + dbus_interface, contact, attributes)) + return; + + if (tp_presence_mixin_fill_contact_attributes (G_OBJECT (self), + dbus_interface, contact, attributes)) + return; + + ((TpBaseConnectionClass *) tp_tests_contacts_connection_parent_class)-> + fill_contact_attributes (base, dbus_interface, contact, attributes); } static TpDBusPropertiesMixinPropImpl conn_contact_info_properties[] = { @@ -365,27 +347,9 @@ conn_contact_info_properties_getter (GObject *object, } static void -client_types_fill_contact_attributes ( - GObject *object, - const GArray *contacts, - GHashTable *attributes) -{ - TpTestsContactsConnectionClass *klass = - TP_TESTS_CONTACTS_CONNECTION_GET_CLASS (object); - - if (klass->fill_client_types != NULL) - klass->fill_client_types (object, contacts, attributes); - /* …else do nothing: a no-op implementation is valid, relatively speaking. - * The spec sez the /client-types attribute should be “omitted from the - * result if the contact's client types are not known.” - */ -} - -static void constructed (GObject *object) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); - TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*parent_impl) (GObject *) = G_OBJECT_CLASS (tp_tests_contacts_connection_parent_class)->constructed; @@ -395,36 +359,8 @@ constructed (GObject *object) self->priv->list_manager = g_object_new (TP_TESTS_TYPE_CONTACT_LIST_MANAGER, "connection", self, NULL); - tp_contacts_mixin_init (object, - G_STRUCT_OFFSET (TpTestsContactsConnection, contacts_mixin)); - tp_base_connection_register_with_contacts_mixin (base); - if (self->priv->list_manager) - { - tp_base_contact_list_mixin_register_with_contacts_mixin ( - TP_BASE_CONTACT_LIST (self->priv->list_manager), base); - } - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_ALIASING1, - aliasing_fill_contact_attributes); - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_AVATARS1, - avatars_fill_contact_attributes); - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_LOCATION1, - location_fill_contact_attributes); - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES1, - contact_caps_fill_contact_attributes); - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO1, - contact_info_fill_contact_attributes); - tp_contacts_mixin_add_contact_attributes_iface (object, - TP_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES1, - client_types_fill_contact_attributes); - tp_presence_mixin_init (object, G_STRUCT_OFFSET (TpTestsContactsConnection, presence_mixin)); - tp_presence_mixin_register_with_contacts_mixin (object); } static const TpPresenceStatusOptionalArgumentSpec can_have_message[] = { @@ -613,9 +549,8 @@ tp_tests_contacts_connection_class_init (TpTestsContactsConnectionClass *klass) base_class->get_interfaces_always_present = tp_tests_contacts_get_interfaces_always_present; base_class->create_channel_managers = create_channel_managers; - - tp_contacts_mixin_class_init (object_class, - G_STRUCT_OFFSET (TpTestsContactsConnectionClass, contacts_mixin)); + base_class->fill_contact_attributes = + tp_tests_contacts_connection_fill_contact_attributes; tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsContactsConnectionClass, presence_mixin), diff --git a/tests/lib/contacts-conn.h b/tests/lib/contacts-conn.h index 679b0eb..aaa826e 100644 --- a/tests/lib/contacts-conn.h +++ b/tests/lib/contacts-conn.h @@ -28,17 +28,13 @@ struct _TpTestsContactsConnectionClass { TpTestsSimpleConnectionClass parent_class; TpPresenceMixinClass presence_mixin; - TpContactsMixinClass contacts_mixin; TpDBusPropertiesMixinClass properties_class; - - TpContactsMixinFillContactAttributesFunc fill_client_types; }; struct _TpTestsContactsConnection { TpTestsSimpleConnection parent; TpPresenceMixin presence_mixin; - TpContactsMixin contacts_mixin; TpTestsContactsConnectionPrivate *priv; }; -- 1.8.4.2