aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy/empathy-dispatch-operation.c
diff options
context:
space:
mode:
authorSjoerd Simons <sjoerd.simons@collabora.co.uk>2009-01-10 00:12:07 +0800
committerXavier Claessens <xclaesse@src.gnome.org>2009-01-10 00:12:07 +0800
commit9940bfed4c589710add05be776b7b1817bf9d48d (patch)
treea60db33d3e746612c1c502006d151fd40407dc33 /libempathy/empathy-dispatch-operation.c
parent9d4e38bf73836e75dd4a86b3929317b612236f1f (diff)
downloadgsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar
gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.gz
gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.bz2
gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.lz
gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.xz
gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.zst
gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.zip
Start reworking the dispatcher
Rework the channel dispatche so it's model is somewhat similar to the ChannelDispatcher in the telepathy-spec. Which allows for a much cleaner and extensible implementation containg no ugly hacks. Currently it's only able to do Text Channels and a lot of the other functionality is temporary disabled Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk> svn path=/trunk/; revision=2130
Diffstat (limited to 'libempathy/empathy-dispatch-operation.c')
-rw-r--r--libempathy/empathy-dispatch-operation.c519
1 files changed, 519 insertions, 0 deletions
diff --git a/libempathy/empathy-dispatch-operation.c b/libempathy/empathy-dispatch-operation.c
new file mode 100644
index 000000000..7f3357b8f
--- /dev/null
+++ b/libempathy/empathy-dispatch-operation.c
@@ -0,0 +1,519 @@
+/*
+ * empathy-dispatch-operation.c - Source for EmpathyDispatchOperation
+ * Copyright (C) 2008 Collabora Ltd.
+ * @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
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "empathy-dispatch-operation.h"
+#include <libempathy/empathy-enum-types.h>
+#include <libempathy/empathy-tp-chat.h>
+#include <libempathy/empathy-tp-call.h>
+
+#include "empathy-marshal.h"
+
+#define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
+#include <libempathy/empathy-debug.h>
+
+G_DEFINE_TYPE(EmpathyDispatchOperation, empathy_dispatch_operation,
+ G_TYPE_OBJECT)
+
+static void empathy_dispatch_operation_set_status (
+ EmpathyDispatchOperation *self, EmpathyDispatchOperationState status);
+static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
+ const GError *error, gpointer user_data);
+
+/* signal enum */
+enum
+{
+ /* Ready for dispatching */
+ READY,
+ /* Approved by an approver, can only happens on incoming operations */
+ APPROVED,
+ /* Claimed by a handler */
+ CLAIMED,
+ /* Error, channel went away, inspecting it failed etc */
+ INVALIDATED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+/* properties */
+enum {
+ PROP_CONNECTION = 1,
+ PROP_CHANNEL,
+ PROP_CHANNEL_WRAPPER,
+ PROP_CONTACT,
+ PROP_INCOMING,
+ PROP_STATUS,
+};
+
+/* private structure */
+typedef struct _EmpathyDispatchOperationPriv \
+ EmpathyDispatchOperationPriv;
+
+struct _EmpathyDispatchOperationPriv
+{
+ gboolean dispose_has_run;
+ TpConnection *connection;
+ TpChannel *channel;
+ GObject *channel_wrapper;
+ EmpathyContact *contact;
+ EmpathyDispatchOperationState status;
+ gboolean incoming;
+ gboolean approved;
+ gulong invalidated_handler;
+};
+
+#define GET_PRIV(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_DISPATCH_OPERATION, \
+ EmpathyDispatchOperationPriv))
+
+static void
+empathy_dispatch_operation_init (EmpathyDispatchOperation *obj)
+{
+ //EmpathyDispatchOperationPriv *priv =
+ // GET_PRIV (obj);
+
+ /* allocate any data required by the object here */
+}
+
+static void empathy_dispatch_operation_dispose (GObject *object);
+static void empathy_dispatch_operation_finalize (GObject *object);
+
+static void
+empathy_dispatch_operation_set_property (GObject *object,
+ guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ priv->connection = g_value_dup_object (value);
+ break;
+ case PROP_CHANNEL:
+ priv->channel = g_value_dup_object (value);
+ break;
+ case PROP_CHANNEL_WRAPPER:
+ priv->channel_wrapper = g_value_dup_object (value);
+ break;
+ case PROP_CONTACT:
+ if (priv->contact != NULL)
+ g_object_unref (priv->contact);
+ priv->contact = g_value_dup_object (value);
+ break;
+ case PROP_INCOMING:
+ priv->incoming = g_value_get_boolean (value);
+ break;
+ }
+}
+
+static void
+empathy_dispatch_operation_get_property (GObject *object,
+ guint property_id, GValue *value, GParamSpec *pspec)
+{
+ EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ g_value_set_object (value, priv->connection);
+ break;
+ case PROP_CHANNEL:
+ g_value_set_object (value, priv->channel);
+ break;
+ case PROP_CHANNEL_WRAPPER:
+ g_value_set_object (value, priv->channel_wrapper);
+ break;
+ case PROP_CONTACT:
+ g_value_set_object (value, priv->contact);
+ break;
+ case PROP_INCOMING:
+ g_value_set_boolean (value, priv->incoming);
+ break;
+ case PROP_STATUS:
+ g_value_set_enum (value, priv->status);
+ break;
+ }
+}
+
+static void
+empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain,
+ gint code, char *message, EmpathyDispatchOperation *self)
+{
+ empathy_dispatch_operation_set_status (self,
+ EMPATHY_DISPATCHER_OPERATION_STATE_INVALIDATED);
+
+ g_signal_emit (self, signals[INVALIDATED], 0, domain, code, message);
+}
+
+static void
+empathy_dispatch_operation_constructed (GObject *object)
+{
+ EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
+
+ empathy_dispatch_operation_set_status (self,
+ EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
+
+ priv->invalidated_handler =
+ g_signal_connect (priv->channel, "invalidated",
+ G_CALLBACK (empathy_dispatch_operation_invalidated), self);
+
+ tp_channel_call_when_ready (priv->channel,
+ empathy_dispatch_operation_channel_ready_cb, self);
+}
+
+static void
+empathy_dispatch_operation_class_init (
+ EmpathyDispatchOperationClass *empathy_dispatch_operation_class)
+{
+ GObjectClass *object_class =
+ G_OBJECT_CLASS (empathy_dispatch_operation_class);
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (empathy_dispatch_operation_class,
+ sizeof (EmpathyDispatchOperationPriv));
+
+ object_class->set_property = empathy_dispatch_operation_set_property;
+ object_class->get_property = empathy_dispatch_operation_get_property;
+
+ object_class->dispose = empathy_dispatch_operation_dispose;
+ object_class->finalize = empathy_dispatch_operation_finalize;
+ object_class->constructed = empathy_dispatch_operation_constructed;
+
+ signals[READY] = g_signal_new ("ready",
+ G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[APPROVED] = g_signal_new ("approved",
+ G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[CLAIMED] = g_signal_new ("claimed",
+ G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[INVALIDATED] = g_signal_new ("invalidated",
+ G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ _empathy_marshal_VOID__UINT_INT_STRING,
+ G_TYPE_NONE, 0);
+
+ param_spec = g_param_spec_object ("connection",
+ "connection", "The telepathy connection",
+ TP_TYPE_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 ("channel",
+ "channel", "The telepathy channel",
+ TP_TYPE_CHANNEL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CHANNEL,
+ param_spec);
+
+ param_spec = g_param_spec_object ("channel-wrapper",
+ "channel wrapper", "The empathy specific channel wrapper",
+ G_TYPE_OBJECT,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CHANNEL_WRAPPER,
+ param_spec);
+
+ param_spec = g_param_spec_object ("contact",
+ "contact", "The empathy contact",
+ EMPATHY_TYPE_CONTACT,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CONTACT,
+ param_spec);
+
+ param_spec = g_param_spec_boolean ("incoming",
+ "incoming", "Whether or not the channel is incoming",
+ FALSE,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INCOMING,
+ param_spec);
+
+ param_spec = g_param_spec_enum ("status",
+ "status", "Status of the dispatch operation",
+ EMPATHY_TYPE_DISPATCH_OPERATION_STATE, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_STATUS, param_spec);
+}
+
+void
+empathy_dispatch_operation_dispose (GObject *object)
+{
+ EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
+ EmpathyDispatchOperationPriv *priv =
+ GET_PRIV (self);
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ g_object_unref (priv->connection);
+
+ g_signal_handler_disconnect (priv->channel, priv->invalidated_handler);
+ g_object_unref (priv->channel);
+
+ if (priv->contact != NULL)
+ g_object_unref (priv->contact);
+
+ if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose)
+ G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose (object);
+}
+
+void
+empathy_dispatch_operation_finalize (GObject *object)
+{
+ /* free any data held directly by the object here */
+ G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->finalize (object);
+}
+
+static void
+empathy_dispatch_operation_set_status (EmpathyDispatchOperation *self,
+ EmpathyDispatchOperationState status)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
+
+ g_assert (status >= priv->status);
+
+
+ if (priv->status != status)
+ {
+ DEBUG ("Dispatch operation %s status: %d -> %d",
+ empathy_dispatch_operation_get_object_path (self),
+ priv->status, status);
+
+ priv->status = status;
+ g_object_notify (G_OBJECT (self), "status");
+
+ if (status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING)
+ g_signal_emit (self, signals[READY], 0);
+ }
+}
+
+static void
+empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
+ const GError *error, gpointer user_data)
+{
+ EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
+ GQuark channel_type;
+
+ g_assert (channel == priv->channel);
+
+ if (priv->channel_wrapper != NULL)
+ goto out;
+
+ channel_type = tp_channel_get_channel_type_id (channel);
+
+ if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
+ {
+ EmpathyTpChat *chat= empathy_tp_chat_new (channel);
+ priv->channel_wrapper = G_OBJECT (chat);
+ }
+ else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA)
+ {
+ EmpathyTpCall *call = empathy_tp_call_new (channel);
+ priv->channel_wrapper = G_OBJECT (call);
+ }
+
+out:
+ empathy_dispatch_operation_set_status (self,
+ EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
+}
+
+EmpathyDispatchOperation *
+empathy_dispatch_operation_new (TpConnection *connection, TpChannel *channel,
+ EmpathyContact *contact, gboolean incoming)
+{
+ return empathy_dispatch_operation_new_with_wrapper (connection, channel,
+ contact, incoming, NULL);
+}
+
+EmpathyDispatchOperation *
+empathy_dispatch_operation_new_with_wrapper (TpConnection *connection,
+ TpChannel *channel, EmpathyContact *contact, gboolean incoming,
+ GObject *wrapper)
+{
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (channel != NULL, NULL);
+
+ return EMPATHY_DISPATCH_OPERATION (
+ g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION,
+ "connection", connection,
+ "channel", channel,
+ "channel-wrapper", wrapper,
+ "contact", contact,
+ "incoming", incoming,
+ NULL));
+}
+
+void
+empathy_dispatch_operation_start (EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+ g_return_if_fail (
+ priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
+
+ if (priv->incoming && !priv->approved)
+ empathy_dispatch_operation_set_status (operation,
+ EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING);
+ else
+ empathy_dispatch_operation_set_status (operation,
+ EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
+}
+
+void
+empathy_dispatch_operation_approve (EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
+ {
+ DEBUG ("Approving operation %s",
+ empathy_dispatch_operation_get_object_path (operation));
+
+ empathy_dispatch_operation_set_status (operation,
+ EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
+
+ g_signal_emit (operation, signals[APPROVED], 0);
+ }
+ else
+ {
+ DEBUG ("Pre-approving operation %s",
+ empathy_dispatch_operation_get_object_path (operation));
+ priv->approved = TRUE;
+ }
+}
+
+/* Returns whether or not the operation was successfully claimed */
+gboolean
+empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
+ return FALSE;
+
+ empathy_dispatch_operation_set_status (operation,
+ EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED);
+
+ g_signal_emit (operation, signals[CLAIMED], 0);
+
+ return TRUE;
+}
+
+TpConnection *
+empathy_dispatch_operation_get_tp_connection (
+ EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ return g_object_ref (priv->connection);
+}
+
+TpChannel *
+empathy_dispatch_operation_get_channel (EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ return TP_CHANNEL (g_object_ref (priv->channel));
+}
+
+GObject *
+empathy_dispatch_operation_get_channel_wrapper (
+ EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ if (priv->channel_wrapper != NULL)
+ g_object_ref (priv->channel_wrapper);
+
+ return priv->channel_wrapper;
+}
+
+const gchar *
+empathy_dispatch_operation_get_channel_type (
+ EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ return tp_channel_get_channel_type (priv->channel);
+}
+
+GQuark
+empathy_dispatch_operation_get_channel_type_id (
+ EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ return tp_channel_get_channel_type_id (priv->channel);
+}
+
+const gchar *
+empathy_dispatch_operation_get_object_path (
+ EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ return tp_proxy_get_object_path (TP_PROXY (priv->channel));
+}
+
+EmpathyDispatchOperationState
+empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ return priv->status;
+}
+
+gboolean
+empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation)
+{
+ EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
+
+ return priv->incoming;
+}