diff options
Diffstat (limited to 'qt4/tests/lib/glib/contactlist/contact-list.c')
-rw-r--r-- | qt4/tests/lib/glib/contactlist/contact-list.c | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/qt4/tests/lib/glib/contactlist/contact-list.c b/qt4/tests/lib/glib/contactlist/contact-list.c new file mode 100644 index 000000000..82aa6e52e --- /dev/null +++ b/qt4/tests/lib/glib/contactlist/contact-list.c @@ -0,0 +1,636 @@ +/* + * An example ContactList channel with handle type LIST or GROUP + * + * Copyright © 2009 Collabora Ltd. <http://www.collabora.co.uk/> + * Copyright © 2009 Nokia Corporation + * + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. + */ + +#include "contact-list.h" + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/channel-iface.h> +#include <telepathy-glib/exportable-channel.h> +#include <telepathy-glib/svc-channel.h> + +#include "contact-list-manager.h" + +static void channel_iface_init (gpointer iface, gpointer data); +static void list_channel_iface_init (gpointer iface, gpointer data); +static void group_channel_iface_init (gpointer iface, gpointer data); + +/* Abstract base class */ +G_DEFINE_TYPE_WITH_CODE (ExampleContactListBase, example_contact_list_base, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_CONTACT_LIST, NULL); + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, + tp_group_mixin_iface_init); + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, + tp_dbus_properties_mixin_iface_init); + G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); + G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)) + +/* Subclass for handle type LIST */ +G_DEFINE_TYPE_WITH_CODE (ExampleContactList, example_contact_list, + EXAMPLE_TYPE_CONTACT_LIST_BASE, + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, list_channel_iface_init)) + +/* Subclass for handle type GROUP */ +G_DEFINE_TYPE_WITH_CODE (ExampleContactGroup, example_contact_group, + EXAMPLE_TYPE_CONTACT_LIST_BASE, + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, group_channel_iface_init)) + +static const gchar *contact_list_interfaces[] = { + TP_IFACE_CHANNEL_INTERFACE_GROUP, + NULL +}; + +enum +{ + PROP_OBJECT_PATH = 1, + PROP_CHANNEL_TYPE, + PROP_HANDLE_TYPE, + PROP_HANDLE, + PROP_TARGET_ID, + PROP_REQUESTED, + PROP_INITIATOR_HANDLE, + PROP_INITIATOR_ID, + PROP_CONNECTION, + PROP_MANAGER, + PROP_INTERFACES, + PROP_CHANNEL_DESTROYED, + PROP_CHANNEL_PROPERTIES, + N_PROPS +}; + +struct _ExampleContactListBasePrivate +{ + TpBaseConnection *conn; + ExampleContactListManager *manager; + gchar *object_path; + TpHandleType handle_type; + TpHandle handle; + + /* These are really booleans, but gboolean is signed. Thanks, GLib */ + unsigned closed:1; + unsigned disposed:1; +}; + +struct _ExampleContactListPrivate +{ + int dummy:1; +}; + +struct _ExampleContactGroupPrivate +{ + int dummy:1; +}; + +static void +example_contact_list_base_init (ExampleContactListBase *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + EXAMPLE_TYPE_CONTACT_LIST_BASE, ExampleContactListBasePrivate); +} + +static void +example_contact_list_init (ExampleContactList *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST, + ExampleContactListPrivate); +} + +static void +example_contact_group_init (ExampleContactGroup *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_GROUP, + ExampleContactGroupPrivate); +} + +static void +constructed (GObject *object) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) example_contact_list_base_parent_class)->constructed; + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles + (self->priv->conn, TP_HANDLE_TYPE_CONTACT); + TpHandle self_handle = self->priv->conn->self_handle; + TpHandleRepoIface *handle_repo = tp_base_connection_get_handles + (self->priv->conn, self->priv->handle_type); + + if (chain_up != NULL) + chain_up (object); + + g_assert (TP_IS_BASE_CONNECTION (self->priv->conn)); + g_assert (EXAMPLE_IS_CONTACT_LIST_MANAGER (self->priv->manager)); + + tp_dbus_daemon_register_object ( + tp_base_connection_get_dbus_daemon (self->priv->conn), + self->priv->object_path, self); + + tp_handle_ref (handle_repo, self->priv->handle); + tp_group_mixin_init (object, G_STRUCT_OFFSET (ExampleContactListBase, group), + contact_repo, self_handle); + /* Both the subclasses have full support for telepathy-spec 0.17.6. */ + tp_group_mixin_change_flags (object, + TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); +} + +static void +list_constructed (GObject *object) +{ + ExampleContactList *self = EXAMPLE_CONTACT_LIST (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) example_contact_list_parent_class)->constructed; + + if (chain_up != NULL) + chain_up (object); + + g_assert (self->parent.priv->handle_type == TP_HANDLE_TYPE_LIST); + + switch (self->parent.priv->handle) + { + case EXAMPLE_CONTACT_LIST_PUBLISH: + /* We can stop publishing presence to people, but we can't + * start sending people our presence unless they ask for it. + * + * (We can accept people's requests to see our presence - but that's + * always allowed, so there's no flag.) + */ + tp_group_mixin_change_flags (object, + TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, 0); + break; + case EXAMPLE_CONTACT_LIST_STORED: + case EXAMPLE_CONTACT_LIST_DENY: + /* We can add people to our roster (not that that's very useful without + * also adding them to subscribe), and we can remove them altogether + * (which implicitly removes them from subscribe, publish, and all + * user-defined groups). + * + * Similarly, we can block and unblock people (i.e. add/remove them + * to/from the deny list) + */ + tp_group_mixin_change_flags (object, + TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, 0); + break; + case EXAMPLE_CONTACT_LIST_SUBSCRIBE: + /* We can ask people to show us their presence, attaching a message. + * We can also cancel (rescind) requests that they haven't replied to, + * and stop receiving their presence after they allow it. + */ + tp_group_mixin_change_flags (object, + TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD | + TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | + TP_CHANNEL_GROUP_FLAG_CAN_RESCIND, + 0); + break; + default: + g_assert_not_reached (); + } +} + +static void +group_constructed (GObject *object) +{ + ExampleContactGroup *self = EXAMPLE_CONTACT_GROUP (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) example_contact_group_parent_class)->constructed; + + if (chain_up != NULL) + chain_up (object); + + g_assert (self->parent.priv->handle_type == TP_HANDLE_TYPE_GROUP); + + /* We can add people to user-defined groups, and also remove them. */ + tp_group_mixin_change_flags (object, + TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, 0); +} + + +static void +get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + + switch (property_id) + { + case PROP_OBJECT_PATH: + g_value_set_string (value, self->priv->object_path); + break; + case PROP_CHANNEL_TYPE: + g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST); + break; + case PROP_HANDLE_TYPE: + g_value_set_uint (value, self->priv->handle_type); + break; + case PROP_HANDLE: + g_value_set_uint (value, self->priv->handle); + break; + case PROP_TARGET_ID: + { + TpHandleRepoIface *handle_repo = tp_base_connection_get_handles ( + self->priv->conn, self->priv->handle_type); + + g_value_set_string (value, + tp_handle_inspect (handle_repo, self->priv->handle)); + } + break; + case PROP_REQUESTED: + g_value_set_boolean (value, FALSE); + break; + case PROP_INITIATOR_HANDLE: + g_value_set_uint (value, 0); + break; + case PROP_INITIATOR_ID: + g_value_set_static_string (value, ""); + break; + case PROP_CONNECTION: + g_value_set_object (value, self->priv->conn); + break; + case PROP_MANAGER: + g_value_set_object (value, self->priv->manager); + break; + case PROP_INTERFACES: + g_value_set_boxed (value, contact_list_interfaces); + break; + case PROP_CHANNEL_DESTROYED: + g_value_set_boolean (value, self->priv->closed); + break; + case PROP_CHANNEL_PROPERTIES: + g_value_take_boxed (value, + tp_dbus_properties_mixin_make_properties_hash (object, + TP_IFACE_CHANNEL, "ChannelType", + TP_IFACE_CHANNEL, "TargetHandleType", + TP_IFACE_CHANNEL, "TargetHandle", + TP_IFACE_CHANNEL, "TargetID", + TP_IFACE_CHANNEL, "InitiatorHandle", + TP_IFACE_CHANNEL, "InitiatorID", + TP_IFACE_CHANNEL, "Requested", + TP_IFACE_CHANNEL, "Interfaces", + NULL)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + + switch (property_id) + { + case PROP_OBJECT_PATH: + g_free (self->priv->object_path); + self->priv->object_path = g_value_dup_string (value); + break; + case PROP_HANDLE: + /* we don't ref it here because we don't necessarily have access to the + * repository (or even type) yet - instead we ref it in the constructor. + */ + self->priv->handle = g_value_get_uint (value); + break; + case PROP_HANDLE_TYPE: + self->priv->handle_type = g_value_get_uint (value); + break; + case PROP_CHANNEL_TYPE: + /* this property is writable in the interface, but not actually + * meaningfully changable on this channel, so we do nothing */ + break; + case PROP_CONNECTION: + self->priv->conn = g_value_get_object (value); + break; + case PROP_MANAGER: + self->priv->manager = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + + if (self->priv->disposed) + return; + + self->priv->disposed = TRUE; + + if (!self->priv->closed) + { + self->priv->closed = TRUE; + tp_svc_channel_emit_closed (self); + } + + ((GObjectClass *) example_contact_list_base_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + TpHandleRepoIface *handle_repo = tp_base_connection_get_handles + (self->priv->conn, self->priv->handle_type); + + tp_handle_unref (handle_repo, self->priv->handle); + g_free (self->priv->object_path); + tp_group_mixin_finalize (object); + + ((GObjectClass *) example_contact_list_base_parent_class)->finalize (object); +} + +static gboolean +group_add_member (GObject *object, + TpHandle handle, + const gchar *message, + GError **error) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + + return example_contact_list_manager_add_to_group (self->priv->manager, + object, self->priv->handle, handle, message, error); +} + +static gboolean +group_remove_member (GObject *object, + TpHandle handle, + const gchar *message, + GError **error) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + + return example_contact_list_manager_remove_from_group (self->priv->manager, + object, self->priv->handle, handle, message, error); +} + +static gboolean +list_add_member (GObject *object, + TpHandle handle, + const gchar *message, + GError **error) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + + return example_contact_list_manager_add_to_list (self->priv->manager, + object, self->priv->handle, handle, message, error); +} + +static gboolean +list_remove_member (GObject *object, + TpHandle handle, + const gchar *message, + GError **error) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); + + return example_contact_list_manager_remove_from_list (self->priv->manager, + object, self->priv->handle, handle, message, error); +} + +static void +example_contact_list_base_class_init (ExampleContactListBaseClass *klass) +{ + static TpDBusPropertiesMixinPropImpl channel_props[] = { + { "TargetHandleType", "handle-type", NULL }, + { "TargetHandle", "handle", NULL }, + { "ChannelType", "channel-type", NULL }, + { "Interfaces", "interfaces", NULL }, + { "TargetID", "target-id", NULL }, + { "Requested", "requested", NULL }, + { "InitiatorHandle", "initiator-handle", NULL }, + { "InitiatorID", "initiator-id", NULL }, + { NULL } + }; + static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { + { TP_IFACE_CHANNEL, + tp_dbus_properties_mixin_getter_gobject_properties, + NULL, + channel_props, + }, + { NULL } + }; + GObjectClass *object_class = (GObjectClass *) klass; + GParamSpec *param_spec; + + g_type_class_add_private (klass, sizeof (ExampleContactListBasePrivate)); + + object_class->constructed = constructed; + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + g_object_class_override_property (object_class, PROP_OBJECT_PATH, + "object-path"); + g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, + "channel-type"); + g_object_class_override_property (object_class, PROP_HANDLE_TYPE, + "handle-type"); + g_object_class_override_property (object_class, PROP_HANDLE, "handle"); + + g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, + "channel-destroyed"); + g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, + "channel-properties"); + + param_spec = g_param_spec_object ("connection", "TpBaseConnection object", + "Connection object that owns this channel", + TP_TYPE_BASE_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); + + param_spec = g_param_spec_object ("manager", "ExampleContactListManager", + "ExampleContactListManager object that owns this channel", + EXAMPLE_TYPE_CONTACT_LIST_MANAGER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_MANAGER, param_spec); + + param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", + "Additional Channel.Interface.* interfaces", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); + + param_spec = g_param_spec_string ("target-id", "Chatroom's ID", + "The string obtained by inspecting the MUC's handle", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); + + param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", + "The contact who initiated the channel", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, + param_spec); + + param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", + "The string obtained by inspecting the initiator-handle", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INITIATOR_ID, + param_spec); + + param_spec = g_param_spec_boolean ("requested", "Requested?", + "True if this channel was requested by the local user", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); + + klass->dbus_properties_class.interfaces = prop_interfaces; + tp_dbus_properties_mixin_class_init (object_class, + G_STRUCT_OFFSET (ExampleContactListBaseClass, dbus_properties_class)); + + /* Group mixin is initialized separately for each subclass - they have + * different callbacks */ +} + +static void +example_contact_list_class_init (ExampleContactListClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + g_type_class_add_private (klass, sizeof (ExampleContactListPrivate)); + + object_class->constructed = list_constructed; + + tp_group_mixin_class_init (object_class, + G_STRUCT_OFFSET (ExampleContactListBaseClass, group_class), + list_add_member, + list_remove_member); + tp_group_mixin_init_dbus_properties (object_class); +} + +static void +example_contact_group_class_init (ExampleContactGroupClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + g_type_class_add_private (klass, sizeof (ExampleContactGroupPrivate)); + + object_class->constructed = group_constructed; + + tp_group_mixin_class_init (object_class, + G_STRUCT_OFFSET (ExampleContactListBaseClass, group_class), + group_add_member, + group_remove_member); + tp_group_mixin_init_dbus_properties (object_class); +} + +static void +list_channel_close (TpSvcChannel *iface G_GNUC_UNUSED, + DBusGMethodInvocation *context) +{ + GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + "ContactList channels with handle type LIST may not be closed" }; + + dbus_g_method_return_error (context, &e); +} + +static void +group_channel_close (TpSvcChannel *iface, + DBusGMethodInvocation *context) +{ + ExampleContactGroup *self = EXAMPLE_CONTACT_GROUP (iface); + ExampleContactListBase *base = EXAMPLE_CONTACT_LIST_BASE (iface); + + if (tp_handle_set_size (base->group.members) > 0) + { + GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + "Non-empty groups may not be deleted (closed)" }; + + dbus_g_method_return_error (context, &e); + return; + } + + if (!base->priv->closed) + { + /* If this was a real connection manager we'd delete the group here, + * if such a concept existed in the protocol (in XMPP, it doesn't). + * + * Afterwards, close the channel: + */ + base->priv->closed = TRUE; + tp_svc_channel_emit_closed (self); + } + + tp_svc_channel_return_from_close (context); +} + +static void +channel_get_channel_type (TpSvcChannel *iface G_GNUC_UNUSED, + DBusGMethodInvocation *context) +{ + tp_svc_channel_return_from_get_channel_type (context, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST); +} + +static void +channel_get_handle (TpSvcChannel *iface, + DBusGMethodInvocation *context) +{ + ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (iface); + + tp_svc_channel_return_from_get_handle (context, self->priv->handle_type, + self->priv->handle); +} + +static void +channel_get_interfaces (TpSvcChannel *iface G_GNUC_UNUSED, + DBusGMethodInvocation *context) +{ + tp_svc_channel_return_from_get_interfaces (context, + contact_list_interfaces); +} + +static void +channel_iface_init (gpointer iface, + gpointer data) +{ + TpSvcChannelClass *klass = iface; + +#define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) + /* close is implemented in subclasses, so don't IMPLEMENT (close); */ + IMPLEMENT (get_channel_type); + IMPLEMENT (get_handle); + IMPLEMENT (get_interfaces); +#undef IMPLEMENT +} + +static void +list_channel_iface_init (gpointer iface, + gpointer data G_GNUC_UNUSED) +{ + TpSvcChannelClass *klass = iface; + +#define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, list_channel_##x) + IMPLEMENT (close); +#undef IMPLEMENT +} + +static void +group_channel_iface_init (gpointer iface, + gpointer data G_GNUC_UNUSED) +{ + TpSvcChannelClass *klass = iface; + +#define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, group_channel_##x) + IMPLEMENT (close); +#undef IMPLEMENT +} |