diff options
author | Sjoerd Simons <sjoerd@luon.net> | 2008-07-27 21:51:24 +0000 |
---|---|---|
committer | Sjoerd Simons <sjoerd@luon.net> | 2008-07-27 21:51:24 +0000 |
commit | 07b96f312cef5bfabd61eaff24bb40e65442495a (patch) | |
tree | 81d414df377a6dcfc497e8781d89fa31d023cb02 | |
parent | f88dbd1a63c7cda09fe01165e3f27284e5c030d3 (diff) | |
download | telepathy-glib-07b96f312cef5bfabd61eaff24bb40e65442495a.tar.gz |
Initial implementation of the contacts mixin
20080727215124-93b9a-526315a3c79afc2d656b4c33d63cceb655550b48.gz
-rw-r--r-- | spec/Connection_Interface_Contacts.xml | 3 | ||||
-rw-r--r-- | spec/all.xml | 2 | ||||
-rw-r--r-- | telepathy-glib/Makefile.am | 2 | ||||
-rw-r--r-- | telepathy-glib/connection.xml | 1 | ||||
-rw-r--r-- | telepathy-glib/contacts-mixin.c | 358 | ||||
-rw-r--r-- | telepathy-glib/contacts-mixin.h | 100 |
6 files changed, 463 insertions, 3 deletions
diff --git a/spec/Connection_Interface_Contacts.xml b/spec/Connection_Interface_Contacts.xml index 95fafa259..9c9af7b87 100644 --- a/spec/Connection_Interface_Contacts.xml +++ b/spec/Connection_Interface_Contacts.xml @@ -18,8 +18,7 @@ along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</p> </tp:license> - <interface name="org.freedesktop.Telepathy.Connection.Interface.Contacts.DRAFT" - tp:causes-havoc="experimental"> + <interface name="org.freedesktop.Telepathy.Connection.Interface.Contacts"> <tp:requires interface="org.freedesktop.Telepathy.Connection"/> <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> diff --git a/spec/all.xml b/spec/all.xml index 1a620d977..586beb331 100644 --- a/spec/all.xml +++ b/spec/all.xml @@ -3,7 +3,7 @@ xmlns:xi="http://www.w3.org/2001/XInclude"> <tp:title>Telepathy D-Bus Interface Specification</tp:title> -<tp:version>0.17.8</tp:version> +<tp:version>0.17.8.1</tp:version> <tp:copyright>Copyright (C) 2005-2008 Collabora Limited</tp:copyright> <tp:copyright>Copyright (C) 2005-2008 Nokia Corporation</tp:copyright> diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am index ed02e5ed0..0a0a459de 100644 --- a/telepathy-glib/Makefile.am +++ b/telepathy-glib/Makefile.am @@ -102,6 +102,7 @@ tpginclude_HEADERS = \ media-interfaces.h \ connection.h \ connection-manager.h \ + contacts-mixin.h \ dbus.h \ dbus-properties-mixin.h \ defs.h \ @@ -204,6 +205,7 @@ libtelepathy_glib_internal_la_SOURCES = \ channel-internal.h \ connection.c \ connection-manager.c \ + contacts-mixin.c \ dbus.c \ dbus-internal.h \ dbus-properties-mixin.c \ diff --git a/telepathy-glib/connection.xml b/telepathy-glib/connection.xml index f2790884b..d3df19242 100644 --- a/telepathy-glib/connection.xml +++ b/telepathy-glib/connection.xml @@ -11,5 +11,6 @@ <xi:include href="../spec/Connection_Interface_Capabilities.xml"/> <xi:include href="../spec/Connection_Interface_Simple_Presence.xml"/> <xi:include href="../spec/Connection_Interface_Presence.xml"/> +<xi:include href="../spec/Connection_Interface_Contacts.xml"/> </tp:spec> diff --git a/telepathy-glib/contacts-mixin.c b/telepathy-glib/contacts-mixin.c new file mode 100644 index 000000000..37f28fcb9 --- /dev/null +++ b/telepathy-glib/contacts-mixin.c @@ -0,0 +1,358 @@ +/* + * contacts-mixin.c - Source for TpContactsMixin + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008 Nokia Corporation + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * 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. FIXME + */ + +#include <telepathy-glib/contacts-mixin.h> + +#include <dbus/dbus-glib-lowlevel.h> +#include <dbus/dbus-glib.h> + +#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/dbus.h> +#include <telepathy-glib/enums.h> +#include <telepathy-glib/errors.h> +#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/interfaces.h> + +#define DEBUG_FLAG TP_DEBUG_CONNECTION + +#include "debug-internal.h" + +struct _TpContactsMixinPrivate +{ + /* String interface name -> GetAttributes func */ + GHashTable *interfaces; +}; + +enum { + MIXIN_DP_CONTACTS_INSPECTABLE_INTERFACES, + NUM_MIXIN_CONTACTS_DBUS_PROPERTIES +}; + +static TpDBusPropertiesMixinPropImpl known_contacts_props[] = { + { "InspectableInterfaces", NULL, NULL }, + { NULL } +}; + +static void +tp_presence_mixin_get_contacts_dbus_property (GObject *object, + GQuark interface, + GQuark name, + GValue *value, + gpointer unused + G_GNUC_UNUSED) +{ + static GQuark q[NUM_MIXIN_CONTACTS_DBUS_PROPERTIES] = { 0, }; + TpContactsMixin *self = TP_CONTACTS_MIXIN (object); + + DEBUG ("called."); + + if (G_UNLIKELY (q[0] == 0)) + { + q[MIXIN_DP_CONTACTS_INSPECTABLE_INTERFACES] = + g_quark_from_static_string ("InspectableInterfaces"); + } + + g_return_if_fail (object != NULL); + + if (name == q[MIXIN_DP_CONTACTS_INSPECTABLE_INTERFACES]) + { + gchar **interfaces; + GHashTableIter iter; + gpointer key; + int i = 0; + + g_assert (G_VALUE_HOLDS(value, G_TYPE_STRV)); + + /* FIXME, cache this when connected ? */ + interfaces = g_malloc0( + (g_hash_table_size (self->priv->interfaces) + 1) * sizeof (gchar *)); + + g_hash_table_iter_init (&iter, self->priv->interfaces); + while (g_hash_table_iter_next (&iter, &key, NULL)) + { + interfaces[i] = g_strdup ((gchar *) key); + i++; + } + g_value_set_boxed (value, interfaces); + } + else + { + g_assert_not_reached (); + } +} + + +/** + * tp_contacts_mixin_class_get_offset_quark: + * + * <!--no documentation beyond Returns: needed--> + * + * Returns: the quark used for storing mixin offset on a GObjectClass + */ +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: + * + * <!--no documentation beyond Returns: needed--> + * + * Returns: the quark used for storing mixin offset on a GObject + */ +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: + * @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: + * + * <informalexample><programlisting> + * tp_contacts_mixin_class_init ((GObjectClass *)klass, + * G_STRUCT_OFFSET (SomeObjectClass, contacts_mixin)); + * </programlisting></informalexample> + */ + +void +tp_contacts_mixin_class_init (GObjectClass *obj_cls, glong offset) +{ + TpContactsMixinClass *mixin_cls; + + 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)); + + mixin_cls = TP_CONTACTS_MIXIN_CLASS (obj_cls); + + tp_dbus_properties_mixin_implement_interface (obj_cls, + TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACTS, + tp_presence_mixin_get_contacts_dbus_property, + NULL, known_contacts_props); +} + + +/** + * tp_contacts_mixin_init: + * @obj: An instance of the implementation that uses this mixin + * @offset: The byte offset of the TpContactsMixin within the object structure + * + * Initialize the text mixin. Should be called from the implementation's + * instance init function like so: + * + * <informalexample><programlisting> + * tp_contacts_mixin_init ((GObject *)self, + * G_STRUCT_OFFSET (SomeObject, text_mixin)); + * </programlisting></informalexample> + */ +void +tp_contacts_mixin_init (GObject *obj, + glong offset) +{ + TpContactsMixin *mixin; + + g_assert (G_IS_OBJECT (obj)); + + g_type_set_qdata (G_OBJECT_TYPE (obj), + TP_CONTACTS_MIXIN_OFFSET_QUARK, + GINT_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: + * @obj: An object with this mixin. + * + * Free resources held by the text mixin. + */ +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_destroy (mixin->priv->interfaces); + g_slice_free (TpContactsMixinPrivate, mixin->priv); +} + +static void +tp_contacts_mixin_inspect_contacts ( + TpSvcConnectionInterfaceContacts *iface, const GArray *handles, + const char **interfaces, gboolean hold, DBusGMethodInvocation *context) +{ + TpContactsMixin *self = TP_CONTACTS_MIXIN (iface); + GHashTable *result; + guint i; + TpBaseConnection *conn = TP_BASE_CONNECTION (self); + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, + TP_HANDLE_TYPE_CONTACT); + GArray *valid_handles; + + TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context); + + /* first validate the given interfaces */ + for (i = 0; interfaces[i] != NULL; i++) { + if (g_hash_table_lookup (self->priv->interfaces, interfaces[i]) == NULL) + { + GError einval = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "Non-inspectable Interface given" }; + dbus_g_method_return_error (context, &einval); + return; + } + } + + + /* 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_destroy); + + 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); + } + } + + if (hold) + { + gchar *sender = dbus_g_method_get_sender (context); + tp_handles_client_hold (contact_repo, sender, valid_handles, NULL); + } + + /* ensure the handles don't dissappear while calling out to various functions + */ + tp_handles_ref (contact_repo, valid_handles); + + for (i = 0; interfaces[i] != NULL; i++) + { + TpContactsMixinGetAttributesFunc func; + + func = g_hash_table_lookup (self->priv->interfaces, interfaces[i]); + + g_assert (func != NULL); + + func (G_OBJECT(iface), valid_handles, result); + } + + tp_handles_unref (contact_repo, valid_handles); + + tp_svc_connection_interface_contacts_return_from_inspect_contacts (context, + result); +} + +/** + * tp_contacts_mixin_iface_init: + * @g_iface: A pointer to the #TpSvcConnectionInterfaceContacts in an object + * class + * @iface_data: Ignored + * + * FIXME + */ +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) + IMPLEMENT(inspect_contacts); +#undef IMPLEMENT +} + +void +tp_contacts_mixin_add_inspectable_iface (GObject *obj, const gchar *interface, + TpContactsMixinGetAttributesFunc get_attributes) +{ + TpContactsMixin *self = TP_CONTACTS_MIXIN (obj); + + g_assert (g_hash_table_lookup (self->priv->interfaces, interface) == NULL); + g_assert (get_attributes != NULL); + + g_hash_table_insert (self->priv->interfaces, g_strdup (interface), + get_attributes); +} + +void +tp_contacts_mixin_set_contact_attribute (GHashTable *contact_attributes, + TpHandle handle, gchar *attribute, GValue *value) +{ + GHashTable *attributes; + + attributes = g_hash_table_lookup (contact_attributes, + GUINT_TO_POINTER (handle)); + + g_assert (attributes != NULL); + + g_hash_table_insert (attributes, g_strdup (attribute), + tp_g_value_slice_dup (value)); + +} + diff --git a/telepathy-glib/contacts-mixin.h b/telepathy-glib/contacts-mixin.h new file mode 100644 index 000000000..b72533c74 --- /dev/null +++ b/telepathy-glib/contacts-mixin.h @@ -0,0 +1,100 @@ +/* + * text-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 + */ + +#ifndef __TP_CONTACTS_MIXIN_H__ +#define __TP_CONTACTS_MIXIN_H__ + +#include <telepathy-glib/svc-connection.h> +#include <telepathy-glib/handle-repo.h> + +#include "util.h" + +G_BEGIN_DECLS + +typedef struct _TpContactsMixinClass TpContactsMixinClass; +typedef struct _TpContactsMixinClassPrivate TpContactsMixinClassPrivate; +typedef struct _TpContactsMixin TpContactsMixin; +typedef struct _TpContactsMixinPrivate TpContactsMixinPrivate; + +typedef void (*TpContactsMixinGetAttributesFunc) (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 { + /*<private>*/ + 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 { + /*<private>*/ + 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) \ + (GPOINTER_TO_UINT (g_type_get_qdata (G_OBJECT_CLASS_TYPE (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) \ + (GPOINTER_TO_UINT (g_type_get_qdata (G_OBJECT_TYPE (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, glong 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_inspectable_iface (GObject *obj, + const gchar *interface, TpContactsMixinGetAttributesFunc get_attributes); + +void tp_contacts_mixin_set_contact_attribute (GHashTable *contact_attributes, + TpHandle handle, gchar *attribute, GValue *value); + +G_END_DECLS + +#endif /* #ifndef __TP_CONTACTS_MIXIN_H__ */ |