summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Hasselmann <hasselmm@gnome.org>2009-10-25 13:36:43 +0100
committerMathias Hasselmann <hasselmm@gnome.org>2009-10-25 13:36:43 +0100
commitbcea784a38f6bb23b51c83066eff1c5e222279ee (patch)
tree0b6fc5b489a7c31004cb4949d01e418dcdbc8988
parent52123a8d88a88d32070d07e196c073ebbbe79c28 (diff)
Implement presence interface for Facebook.
* src/facebook-connection.c (_presence_status_arguments, _presence_statuses, G_DEFINE_TYPE_WITH_CODE, _get_profile, _get_contact_alias, _get_contact_presence, _get_contact_status, _update_friends, _aliasing_fill_contact_attributes, _presence_get_contact_statuses, _presence_set_own_status, _constructor,gruschler_facebook_connection_class_init): Implement presence interface. Refactor profile utility functions. Move GObject overrides to have better access on interface methods. * src/facebook-connection.h (GruschlerFacebookPresenceStatus, GruschlerFacebookConnection, GruschlerFacebookConnectionClass): Add enumeration for Facebook's online presence states. Add presence mixins to GruschlerFacebookConnection.
-rw-r--r--src/facebook-connection.c512
-rw-r--r--src/facebook-connection.h18
2 files changed, 376 insertions, 154 deletions
diff --git a/src/facebook-connection.c b/src/facebook-connection.c
index 3254668..3d9273f 100644
--- a/src/facebook-connection.c
+++ b/src/facebook-connection.c
@@ -32,6 +32,7 @@
#include <telepathy-glib/handle-repo-dynamic.h>
#include <telepathy-glib/handle-repo-static.h>
#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/svc-generic.h>
#include <string.h>
@@ -41,18 +42,36 @@ enum {
PROP_PASSWORD,
};
-static const char *const _fixed_properties[] = {
+static const char *const
+_fixed_properties[] = {
TP_IFACE_CHANNEL ".ChannelType",
TP_IFACE_CHANNEL ".TargetHandleType",
NULL
};
-static const char *const _allowed_properties[] = {
+static const char *const
+_allowed_properties[] = {
TP_IFACE_CHANNEL ".TargetHandle",
TP_IFACE_CHANNEL ".TargetID",
NULL
};
+static const TpPresenceStatusOptionalArgumentSpec
+_presence_status_arguments[] = {
+ { "message", "s", NULL, NULL },
+ { NULL, NULL, NULL, NULL }
+};
+
+static const TpPresenceStatusSpec
+_presence_statuses[] = {
+ { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, _presence_status_arguments, NULL, NULL },
+ { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, _presence_status_arguments, NULL, NULL },
+ { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, _presence_status_arguments, NULL, NULL },
+ { "idle", TP_CONNECTION_PRESENCE_TYPE_AWAY, FALSE, _presence_status_arguments, NULL, NULL },
+ { "active", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, _presence_status_arguments, NULL, NULL },
+ { NULL, 0, FALSE, NULL, NULL, NULL }
+};
+
struct _GruschlerFacebookConnectionPrivate {
RestProxy *facebook;
SoupSession *session;
@@ -82,97 +101,19 @@ G_DEFINE_TYPE_WITH_CODE (GruschlerFacebookConnection,
G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
_channel_manager_iface_init);
-
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+ tp_dbus_properties_mixin_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
_aliasing_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
+ tp_contacts_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+ tp_presence_mixin_simple_presence_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
+ tp_presence_mixin_iface_init);
);
static void
-_set_property (GObject *object,
- unsigned prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GruschlerFacebookConnection *self;
-
- self = GRUSCHLER_FACEBOOK_CONNECTION (object);
-
- switch (prop_id)
- {
- case PROP_EMAIL:
- g_free (self->priv->email);
- self->priv->email = g_value_dup_string (value);
- break;
-
- case PROP_PASSWORD:
- g_free (self->priv->password);
- self->priv->password = g_value_dup_string (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-_get_property (GObject *object,
- unsigned prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GruschlerFacebookConnection *self;
-
- self = GRUSCHLER_FACEBOOK_CONNECTION (object);
-
- switch (prop_id)
- {
- case PROP_EMAIL:
- g_value_set_string (value, self->priv->email);
- break;
-
- case PROP_PASSWORD:
- g_value_set_string (value, self->priv->password);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-_finalize (GObject *object)
-{
- GObjectClass *object_class;
- GruschlerFacebookConnection *self;
-
- self = GRUSCHLER_FACEBOOK_CONNECTION (object);
-
- if (self->priv->facebook)
- g_object_unref (self->priv->facebook);
- if (self->priv->session)
- g_object_unref (self->priv->session);
- if (self->priv->contacts)
- g_object_unref (self->priv->contacts);
- if (self->priv->groups)
- g_object_unref (self->priv->groups);
- if (self->priv->lists)
- g_object_unref (self->priv->lists);
-
- g_hash_table_unref (self->priv->list_channels);
- g_hash_table_unref (self->priv->group_channels);
- g_hash_table_unref (self->priv->profiles);
-
- g_free (self->priv->email);
- g_free (self->priv->password);
- g_free (self->priv->token);
-
- object_class = G_OBJECT_CLASS (gruschler_facebook_connection_parent_class);
- object_class->finalize (object);
-}
-
-static void
_create_handle_repos (TpBaseConnection *connection,
TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
{
@@ -343,27 +284,63 @@ _get_unique_connection_name (TpBaseConnection *connection)
return tp_escape_as_identifier (self->priv->email);
}
-const char *
+static const char *
_get_self_uid (GruschlerFacebookConnection *self)
{
return tp_handle_inspect (self->priv->contacts,
TP_BASE_CONNECTION (self)->self_handle);
}
-const char *
+static RestXmlNode *
+_get_profile (GruschlerFacebookConnection *self,
+ TpHandle handle)
+{
+ return g_hash_table_lookup (self->priv->profiles,
+ GUINT_TO_POINTER (handle));
+}
+
+static const char *
_get_contact_alias (GruschlerFacebookConnection *self,
TpHandle handle)
{
RestXmlNode *profile, *node = NULL;
- profile = g_hash_table_lookup (self->priv->profiles,
- GUINT_TO_POINTER (handle));
+ if (NULL != (profile = _get_profile (self, handle)))
+ if (NULL != (node = rest_xml_node_find (profile, "name")) ||
+ NULL != (node = rest_xml_node_find (profile, "uid")))
+ return node->content;
+
+ return NULL;
+}
+
+static GruschlerFacebookPresenceStatus
+_get_contact_presence (GruschlerFacebookConnection *self,
+ TpHandle handle)
+{
+ RestXmlNode *node = NULL;
+ unsigned i;
+
+ if (NULL != (node = _get_profile (self, handle)) &&
+ NULL != (node = rest_xml_node_find (node, "online_presence")) &&
+ NULL != (node->content))
+ {
+ for (i = 0; _presence_statuses[i].name; ++i)
+ if (!strcmp (_presence_statuses[i].name, node->content))
+ return i;
+ }
- if (!profile)
- return NULL;
+ return GRUSCHLER_FACEBOOK_PRESENCE_UNKNOWN;
+}
- if (NULL != (node = rest_xml_node_find (profile, "name")) ||
- NULL != (node = rest_xml_node_find (profile, "uid")))
+static const char *
+_get_contact_status (GruschlerFacebookConnection *self,
+ TpHandle handle)
+{
+ RestXmlNode *node = NULL;
+
+ if (NULL != (node = _get_profile (self, handle)) &&
+ NULL != (node = rest_xml_node_find (node, "status")) &&
+ NULL != (node = rest_xml_node_find (node, "message")))
return node->content;
return NULL;
@@ -574,9 +551,9 @@ _update_friends (GruschlerFacebookConnection *self)
g_string_append_printf (queries,
"\"profiles\":"
- "\"SELECT uid,name,profile_update_time "
- "FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=%s)\"",
- _get_self_uid (self));
+ "\"SELECT uid,name,profile_update_time,online_presence,status "
+ "FROM user WHERE uid=%s OR uid IN (SELECT uid2 FROM friend WHERE uid1=%s)\"",
+ _get_self_uid (self), _get_self_uid (self));
/* TODO: "AND profile_update_time > 0" */
g_string_append_c (queries, '}');
@@ -664,7 +641,8 @@ _post_login_data_cb (SoupSession *session,
uri = soup_message_get_uri (message);
g_debug ("status=%d length=%lld", message->status_code, message->response_body->length);
-g_debug ("%s %s", uri->path, uri->query);
+g_debug ("uri=%s query=%s", uri->path, uri->query);
+g_file_set_contents ("/tmp/fb-login.html", message->response_body->data, message->response_body->length, NULL);
if (!g_strcmp0 (uri->path, "/login.php"))
{
@@ -908,59 +886,6 @@ _shut_down (TpBaseConnection *connection)
}
static void
-gruschler_facebook_connection_class_init (GruschlerFacebookConnectionClass *class)
-{
- static const char *interfaces[] = {
- TP_IFACE_CONNECTION_INTERFACE_ALIASING,
-#if 0
- TP_IFACE_CONNECTION_INTERFACE_AVATARS,
- TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
- TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
- TP_IFACE_CONNECTION_INTERFACE_LOCATION,
- RTCOM_TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
-#endif
- NULL
- };
-
- GParamSpec *pspec;
- GObjectClass *object_class;
- TpBaseConnectionClass *connection_class;
-
- object_class = G_OBJECT_CLASS (class);
- object_class->set_property = _set_property;
- object_class->get_property = _get_property;
- object_class->finalize = _finalize;
-
- connection_class = TP_BASE_CONNECTION_CLASS (class);
- connection_class->create_handle_repos = _create_handle_repos;
- connection_class->create_channel_managers = _create_channel_managers;
- connection_class->get_unique_connection_name = _get_unique_connection_name;
- connection_class->start_connecting = _start_connecting;
- connection_class->shut_down = _shut_down;
- connection_class->interfaces_always_present = interfaces;
-
- pspec = g_param_spec_string ("email",
- "Email",
- "Email address for accessing Facebook",
- GRUSCHLER_FACEBOOK_DEFAULT_EMAIL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
- G_PARAM_CONSTRUCT_ONLY);
-
- g_object_class_install_property (object_class, PROP_EMAIL, pspec);
-
- pspec = g_param_spec_string ("password",
- "Password",
- "Password for accessing Facebook",
- GRUSCHLER_FACEBOOK_DEFAULT_PASSWORD,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
- G_PARAM_CONSTRUCT_ONLY);
-
- g_object_class_install_property (object_class, PROP_PASSWORD, pspec);
-
- g_type_class_add_private (class, sizeof (GruschlerFacebookConnectionPrivate));
-}
-
-static void
_foreach_channel (TpChannelManager *manager,
TpExportableChannelFunc callback,
gpointer user_data)
@@ -1182,6 +1107,31 @@ _aliasing_set_aliases (TpSvcConnectionInterfaceAliasing *aliasing,
}
static void
+_aliasing_fill_contact_attributes (GObject *object,
+ const GArray *contacts,
+ GHashTable *attributes)
+{
+ GruschlerFacebookConnection *self;
+ unsigned i;
+
+ self = GRUSCHLER_FACEBOOK_CONNECTION (object);
+
+ for (i = 0; i < contacts->len; ++i)
+ {
+ TpHandle handle;
+ GValue *value;
+
+ value = tp_g_value_slice_new (G_TYPE_STRING);
+ handle = g_array_index (contacts, TpHandle, i);
+ g_value_set_string (value, _get_contact_alias (self, handle));
+
+ tp_contacts_mixin_set_contact_attribute (attributes, handle,
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING "/alias",
+ value);
+ }
+}
+
+static void
_aliasing_iface_init (TpSvcConnectionInterfaceAliasingClass *iface)
{
#define IMPLEMENT(x) \
@@ -1193,6 +1143,262 @@ _aliasing_iface_init (TpSvcConnectionInterfaceAliasingClass *iface)
#undef IMPLEMENT
}
+static GHashTable *
+_presence_get_contact_statuses (GObject *object,
+ const GArray *contacts,
+ GError **error)
+{
+ GruschlerFacebookConnection *self;
+ TpBaseConnection *base;
+ GHashTable *statuses;
+ unsigned i;
+
+ statuses = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
+ (GDestroyNotify) tp_presence_status_free);
+
+ self = GRUSCHLER_FACEBOOK_CONNECTION (object);
+ base = TP_BASE_CONNECTION (self);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpPresenceStatus *presence;
+ GruschlerFacebookPresenceStatus status = GRUSCHLER_FACEBOOK_PRESENCE_UNKNOWN;
+ const char *message = NULL;
+ GHashTable *parameters;
+ TpHandle handle;
+
+ handle = g_array_index (contacts, TpHandle, i);
+ status = _get_contact_presence (self, handle);
+ message = _get_contact_status (self, handle);
+ parameters = tp_asv_new (NULL, NULL);
+
+ if (message)
+ tp_asv_set_string (parameters, "message", message);
+
+ presence = tp_presence_status_new (status, parameters);
+ g_hash_table_unref (parameters);
+
+ g_hash_table_insert (statuses, GUINT_TO_POINTER (handle), presence);
+ }
+
+ return statuses;
+}
+
+static gboolean
+_presence_set_own_status (GObject *object,
+ const TpPresenceStatus *status,
+ GError **error)
+{
+/* FIXME: implement this */
+ g_warning ("%s: not implemented yet :-(", G_STRFUNC);
+ g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+ "Setting own presence status is not implemented yet");
+ return FALSE;
+}
+
+static GObject *
+_constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GruschlerFacebookConnection *self;
+ GObject *object;
+ GObjectClass *parent_class;
+ gsize offset;
+
+ parent_class = G_OBJECT_CLASS (gruschler_facebook_connection_parent_class);
+ object = parent_class->constructor (type, n_props, props);
+ self = GRUSCHLER_FACEBOOK_CONNECTION (object);
+
+ offset = G_STRUCT_OFFSET (GruschlerFacebookConnection, contacts);
+ tp_contacts_mixin_init (object, offset);
+
+ offset = G_STRUCT_OFFSET (GruschlerFacebookConnection, presence);
+ tp_presence_mixin_init (object, offset);
+
+ tp_base_connection_register_with_contacts_mixin (TP_BASE_CONNECTION (self));
+ tp_presence_mixin_simple_presence_register_with_contacts_mixin (object);
+
+ tp_contacts_mixin_add_contact_attributes_iface (object,
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING,
+ _aliasing_fill_contact_attributes);
+
+ return object;
+}
+
+static void
+_set_property (GObject *object,
+ unsigned prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GruschlerFacebookConnection *self;
+
+ self = GRUSCHLER_FACEBOOK_CONNECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMAIL:
+ g_free (self->priv->email);
+ self->priv->email = g_value_dup_string (value);
+ break;
+
+ case PROP_PASSWORD:
+ g_free (self->priv->password);
+ self->priv->password = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_get_property (GObject *object,
+ unsigned prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GruschlerFacebookConnection *self;
+
+ self = GRUSCHLER_FACEBOOK_CONNECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMAIL:
+ g_value_set_string (value, self->priv->email);
+ break;
+
+ case PROP_PASSWORD:
+ g_value_set_string (value, self->priv->password);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_finalize (GObject *object)
+{
+ GObjectClass *object_class;
+ GruschlerFacebookConnection *self;
+
+ self = GRUSCHLER_FACEBOOK_CONNECTION (object);
+
+ tp_contacts_mixin_finalize (object);
+ tp_presence_mixin_finalize (object);
+
+ if (self->priv->facebook)
+ g_object_unref (self->priv->facebook);
+ if (self->priv->session)
+ g_object_unref (self->priv->session);
+ if (self->priv->contacts)
+ g_object_unref (self->priv->contacts);
+ if (self->priv->groups)
+ g_object_unref (self->priv->groups);
+ if (self->priv->lists)
+ g_object_unref (self->priv->lists);
+
+ g_hash_table_unref (self->priv->list_channels);
+ g_hash_table_unref (self->priv->group_channels);
+ g_hash_table_unref (self->priv->profiles);
+
+ g_free (self->priv->email);
+ g_free (self->priv->password);
+ g_free (self->priv->token);
+
+ object_class = G_OBJECT_CLASS (gruschler_facebook_connection_parent_class);
+ object_class->finalize (object);
+}
+
+static void
+gruschler_facebook_connection_class_init (GruschlerFacebookConnectionClass *class)
+{
+ static const char *interfaces[] = {
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
+ TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+#if 0
+ TP_IFACE_CONNECTION_INTERFACE_AVATARS,
+ TP_IFACE_CONNECTION_INTERFACE_LOCATION,
+ RTCOM_TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
+#endif
+ NULL
+ };
+
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+#if 0
+ { TP_IFACE_CONNECTION_INTERFACE_LOCATION,
+ conn_location_properties_getter,
+ conn_location_properties_setter,
+ location_props,
+ },
+ { TP_IFACE_CONNECTION_INTERFACE_AVATARS,
+ conn_avatars_properties_getter,
+ NULL,
+ avatar_props,
+ },
+#endif
+ { NULL, }
+ };
+
+ GParamSpec *pspec;
+ GObjectClass *object_class;
+ TpBaseConnectionClass *connection_class;
+ gsize offset;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = _constructor;
+ object_class->set_property = _set_property;
+ object_class->get_property = _get_property;
+ object_class->finalize = _finalize;
+
+ connection_class = TP_BASE_CONNECTION_CLASS (class);
+ connection_class->create_handle_repos = _create_handle_repos;
+ connection_class->create_channel_managers = _create_channel_managers;
+ connection_class->get_unique_connection_name = _get_unique_connection_name;
+ connection_class->start_connecting = _start_connecting;
+ connection_class->shut_down = _shut_down;
+ connection_class->interfaces_always_present = interfaces;
+
+ pspec = g_param_spec_string ("email",
+ "Email",
+ "Email address for accessing Facebook",
+ GRUSCHLER_FACEBOOK_DEFAULT_EMAIL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_property (object_class, PROP_EMAIL, pspec);
+
+ pspec = g_param_spec_string ("password",
+ "Password",
+ "Password for accessing Facebook",
+ GRUSCHLER_FACEBOOK_DEFAULT_PASSWORD,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_property (object_class, PROP_PASSWORD, pspec);
+
+ class->properties_class.interfaces = prop_interfaces;
+ offset = G_STRUCT_OFFSET (GruschlerFacebookConnectionClass, properties_class);
+ tp_dbus_properties_mixin_class_init (object_class, offset);
+
+ offset = G_STRUCT_OFFSET (GruschlerFacebookConnectionClass, contacts_class);
+ tp_contacts_mixin_class_init (object_class, offset);
+
+ offset = G_STRUCT_OFFSET (GruschlerFacebookConnectionClass, presence_class);
+ tp_presence_mixin_class_init (object_class, offset, NULL,
+ _presence_get_contact_statuses,
+ _presence_set_own_status, _presence_statuses);
+ tp_presence_mixin_simple_presence_init_dbus_properties (object_class);
+
+ g_type_class_add_private (class, sizeof (GruschlerFacebookConnectionPrivate));
+}
+
static void
gruschler_facebook_connection_init (GruschlerFacebookConnection *self)
{
diff --git a/src/facebook-connection.h b/src/facebook-connection.h
index 2e389aa..80b7e45 100644
--- a/src/facebook-connection.h
+++ b/src/facebook-connection.h
@@ -19,6 +19,9 @@
#define __GRUSCHLER_FACEBOOK_CONNECTION_H__
#include <telepathy-glib/base-connection-manager.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
+#include <telepathy-glib/contacts-mixin.h>
+#include <telepathy-glib/presence-mixin.h>
G_BEGIN_DECLS
@@ -34,13 +37,26 @@ typedef struct _GruschlerFacebookConnectionClass GruschlerFacebookConnectionCl
typedef struct _GruschlerFacebookConnectionPrivate GruschlerFacebookConnectionPrivate;
typedef struct _GruschlerFacebookConnectionParams GruschlerFacebookConnectionParams;
+typedef enum {
+ GRUSCHLER_FACEBOOK_PRESENCE_UNKNOWN,
+ GRUSCHLER_FACEBOOK_PRESENCE_OFFLINE,
+ GRUSCHLER_FACEBOOK_PRESENCE_ERROR,
+ GRUSCHLER_FACEBOOK_PRESENCE_IDLE,
+ GRUSCHLER_FACEBOOK_PRESENCE_ACTIVE,
+} GruschlerFacebookPresenceStatus;
+
struct _GruschlerFacebookConnection {
TpBaseConnection parent_instance;
+ TpContactsMixin contacts;
+ TpPresenceMixin presence;
GruschlerFacebookConnectionPrivate *priv;
};
struct _GruschlerFacebookConnectionClass {
- TpBaseConnectionClass parent_class;
+ TpBaseConnectionClass parent_class;
+ TpContactsMixinClass contacts_class;
+ TpPresenceMixinClass presence_class;
+ TpDBusPropertiesMixinClass properties_class;
};
struct _GruschlerFacebookConnectionParams {