]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-ft-factory.c
Merge remote-tracking branch 'origin/gnome-3-8'
[empathy.git] / libempathy / empathy-ft-factory.c
index 97fe6022b7459101273af50d6cbc7601d23e9d38..855ddb98f549a56abd83ee229a8e6155a22195d2 100644 (file)
  *
  * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
  */
-/* empathy-ft-factory.c */
 
-#include <glib.h>
+/* empathy-ft-factory.c */
 
+#include "config.h"
 #include "empathy-ft-factory.h"
-#include "empathy-ft-handler.h"
-#include "empathy-marshal.h"
+
+#include "empathy-request-util.h"
 #include "empathy-utils.h"
 
-G_DEFINE_TYPE (EmpathyFTFactory, empathy_ft_factory, G_TYPE_OBJECT);
+/**
+ * SECTION:empathy-ft-factory
+ * @title:EmpathyFTFactory
+ * @short_description: creates #EmpathyFTHandler objects
+ * @include: libempathy/empathy-ft-factory.h
+ *
+ * #EmpathyFTFactory takes care of the creation of the #EmpathyFTHandler
+ * objects used for file transfer. As the creation of the handlers is
+ * async, a client will have to connect to the ::new-ft-handler signal
+ * to receive the handler.
+ * In case of an incoming file transfer, the handler will need the destination
+ * file before being useful; as this is usually decided by the user (e.g. with
+ * a file selector), a ::new-incoming-transfer is emitted by the factory when
+ * a destination file is needed, which can be set later with
+ * empathy_ft_factory_set_destination_for_incoming_handler().
+ */
 
-#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTFactory)
+G_DEFINE_TYPE (EmpathyFTFactory, empathy_ft_factory, G_TYPE_OBJECT);
 
 enum {
   NEW_FT_HANDLER,
@@ -41,24 +55,45 @@ enum {
 static EmpathyFTFactory *factory_singleton = NULL;
 static guint signals[LAST_SIGNAL] = { 0 };
 
+/* private structure */
+typedef struct {
+  TpBaseClient *handler;
+} EmpathyFTFactoryPriv;
+
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTFactory)
+
 static GObject *
 do_constructor (GType type,
-                guint n_props,
-                GObjectConstructParam *props)
+    guint n_props,
+    GObjectConstructParam *props)
 {
-       GObject *retval;
+  GObject *retval;
+
+  if (factory_singleton != NULL)
+    {
+      retval = g_object_ref (factory_singleton);
+    }
+  else
+    {
+      retval = G_OBJECT_CLASS (empathy_ft_factory_parent_class)->constructor
+        (type, n_props, props);
 
-       if (factory_singleton) {
-               retval = g_object_ref (factory_singleton);
-       } else {
-               retval = G_OBJECT_CLASS (empathy_ft_factory_parent_class)->constructor
-                       (type, n_props, props);
+      factory_singleton = EMPATHY_FT_FACTORY (retval);
+      g_object_add_weak_pointer (retval, (gpointer *) &factory_singleton);
+    }
+
+  return retval;
+}
+
+static void
+empathy_ft_factory_dispose (GObject *object)
+{
+  EmpathyFTFactory *self = (EmpathyFTFactory *) object;
+  EmpathyFTFactoryPriv *priv = GET_PRIV (self);
 
-               factory_singleton = EMPATHY_FT_FACTORY (retval);
-               g_object_add_weak_pointer (retval, (gpointer *) &factory_singleton);
-       }
+  tp_clear_object (&priv->handler);
 
-       return retval;
+  (G_OBJECT_CLASS (empathy_ft_factory_parent_class)->dispose) (object);
 }
 
 static void
@@ -66,104 +101,202 @@ empathy_ft_factory_class_init (EmpathyFTFactoryClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  g_type_class_add_private (klass, sizeof (EmpathyFTFactoryPriv));
+
   object_class->constructor = do_constructor;
+  object_class->dispose = empathy_ft_factory_dispose;
 
+  /**
+   * EmpathyFTFactory::new-ft-handler
+   * @factory: the object which received the signal
+   * @handler: the handler made available by the factory
+   * @error: a #GError or %NULL
+   *
+   * The signal is emitted when a new #EmpathyFTHandler is available.
+   * Note that @handler is never %NULL even if @error is set, as you might want
+   * to display the error in an UI; in that case, the handler won't support
+   * any transfer.
+   */
   signals[NEW_FT_HANDLER] =
     g_signal_new ("new-ft-handler",
       G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, 0,
       NULL, NULL,
-      _empathy_marshal_VOID__OBJECT_POINTER,
+      g_cclosure_marshal_generic,
       G_TYPE_NONE, 2, EMPATHY_TYPE_FT_HANDLER, G_TYPE_POINTER);
 
+  /**
+   * EmpathyFTFactory::new-incoming-transfer
+   * @factory: the object which received the signal
+   * @handler: the incoming handler being constructed
+   * @error: a #GError or %NULL
+   *
+   * The signal is emitted when a new incoming #EmpathyFTHandler is being
+   * constructed, and needs a destination #GFile to be useful.
+   * Clients that connect to this signal will have to call
+   * empathy_ft_factory_set_destination_for_incoming_handler() when they
+   * have a #GFile.
+   * Note that @handler is never %NULL even if @error is set, as you might want
+   * to display the error in an UI; in that case, the handler won't support
+   * any transfer.
+   */
   signals[NEW_INCOMING_TRANSFER] =
     g_signal_new ("new-incoming-transfer",
       G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, 0,
       NULL, NULL,
-      _empathy_marshal_VOID__OBJECT_POINTER,
+      g_cclosure_marshal_generic,
       G_TYPE_NONE, 2, EMPATHY_TYPE_FT_HANDLER, G_TYPE_POINTER);
 }
 
 static void
-empathy_ft_factory_init (EmpathyFTFactory *self)
+ft_handler_incoming_ready_cb (EmpathyFTHandler *handler,
+    GError *error,
+    gpointer user_data)
 {
-  /* do nothing */
+  EmpathyFTFactory *factory = user_data;
+
+  g_signal_emit (factory, signals[NEW_INCOMING_TRANSFER], 0, handler, error);
 }
 
 static void
-ft_handler_outgoing_ready_cb (EmpathyFTHandler *handler,
-                              GError *error,
-                              gpointer user_data)
+handle_channels_cb (TpSimpleHandler *handler,
+    TpAccount *account,
+    TpConnection *connection,
+    GList *channels,
+    GList *requests_satisfied,
+    gint64 user_action_time,
+    TpHandleChannelsContext *context,
+    gpointer user_data)
 {
-  EmpathyFTFactory *factory = user_data;
+  EmpathyFTFactory *self = user_data;
+  GList *l;
 
-  g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, error);
+  for (l = channels; l != NULL; l = g_list_next (l))
+    {
+      TpChannel *channel = l->data;
+
+      if (tp_proxy_get_invalidated (channel) != NULL)
+        continue;
+
+      if (!TP_IS_FILE_TRANSFER_CHANNEL (channel))
+        continue;
+
+      /* We handle only incoming FT */
+      empathy_ft_handler_new_incoming ((TpFileTransferChannel *) channel,
+          ft_handler_incoming_ready_cb, self);
+    }
+
+
+  tp_handle_channels_context_accept (context);
 }
 
 static void
-ft_handler_incoming_ready_cb (EmpathyFTHandler *handler,
-                              GError *error,
-                              gpointer user_data)
+empathy_ft_factory_init (EmpathyFTFactory *self)
 {
-  EmpathyFTFactory *factory = user_data;
+  EmpathyFTFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+    EMPATHY_TYPE_FT_FACTORY, EmpathyFTFactoryPriv);
+  TpAccountManager *am;
 
-  g_signal_emit (factory, signals[NEW_INCOMING_TRANSFER], 0, handler, error);
+  self->priv = priv;
+
+  am = tp_account_manager_dup ();
+
+  priv->handler = tp_simple_handler_new_with_am (am, FALSE, FALSE,
+      EMPATHY_FT_BUS_NAME_SUFFIX, FALSE, handle_channels_cb, self, NULL);
+
+  tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
+        TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+          TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER,
+        TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
+        /* Only handle *incoming* channels as outgoing FT channels has to be
+         * handled by the requester. */
+        TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, FALSE,
+        NULL));
+
+  g_object_unref (am);
+}
+
+static void
+ft_handler_outgoing_ready_cb (EmpathyFTHandler *handler,
+    GError *error,
+    gpointer user_data)
+{
+  EmpathyFTFactory *factory = EMPATHY_FT_FACTORY (user_data);
+
+  g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, error);
+
+  g_object_unref (factory);
 }
 
 /* public methods */
 
-EmpathyFTFactory*
+/**
+ * empathy_ft_factory_dup_singleton:
+ *
+ * Gives the caller a reference to the #EmpathyFTFactory singleton,
+ * (creating it if necessary).
+ *
+ * Return value: an #EmpathyFTFactory object
+ */
+EmpathyFTFactory *
 empathy_ft_factory_dup_singleton (void)
 {
   return g_object_new (EMPATHY_TYPE_FT_FACTORY, NULL);
 }
 
+/**
+ * empathy_ft_factory_new_transfer_outgoing:
+ * @factory: an #EmpathyFTFactory
+ * @contact: the #EmpathyContact destination of the transfer
+ * @source: the #GFile to be transferred to @contact
+ *
+ * Trigger the creation of an #EmpathyFTHandler object to send @source to
+ * the specified @contact.
+ */
 void
 empathy_ft_factory_new_transfer_outgoing (EmpathyFTFactory *factory,
-                                          EmpathyContact *contact,
-                                          GFile *source,
-                                          gboolean use_hash)
+    EmpathyContact *contact,
+    GFile *source,
+    gint64 action_time)
 {
   g_return_if_fail (EMPATHY_IS_FT_FACTORY (factory));
   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
   g_return_if_fail (G_IS_FILE (source));
 
-  empathy_ft_handler_new_outgoing (contact, source, use_hash,
-      ft_handler_outgoing_ready_cb, factory);
+  empathy_ft_handler_new_outgoing (contact, source, action_time,
+      ft_handler_outgoing_ready_cb, g_object_ref (factory));
 }
 
+/**
+ * empathy_ft_factory_set_destination_for_incoming_handler:
+ * @factory: an #EmpathyFTFactory
+ * @handler: the #EmpathyFTHandler to set the destination of
+ * @destination: the #GFile destination of the transfer
+ *
+ * Sets @destination as destination file for the transfer. After the call of
+ * this method, the ::new-ft-handler will be emitted for the incoming handler.
+ */
 void
-empathy_ft_factory_claim_channel (EmpathyFTFactory *factory,
-                                  EmpathyDispatchOperation *operation)
+empathy_ft_factory_set_destination_for_incoming_handler (
+    EmpathyFTFactory *factory,
+    EmpathyFTHandler *handler,
+    GFile *destination)
 {
-  EmpathyTpFile *tp_file;
-
   g_return_if_fail (EMPATHY_IS_FT_FACTORY (factory));
-  g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
-
-  /* own a reference to the EmpathyTpFile */
-  tp_file = EMPATHY_TP_FILE
-      ((empathy_dispatch_operation_get_channel_wrapper (operation)));
+  g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
+  g_return_if_fail (G_IS_FILE (destination));
 
-  empathy_ft_handler_new_incoming (tp_file, ft_handler_incoming_ready_cb,
-      factory);
+  empathy_ft_handler_incoming_set_destination (handler, destination);
 
-  empathy_dispatch_operation_claim (operation);
+  g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, NULL);
 }
 
-void
-empathy_ft_factory_set_destination_for_incoming_handler
-                                                 (EmpathyFTFactory *factory,
-                                                  EmpathyFTHandler *handler,
-                                                  GFile *destination,
-                                                  gboolean use_hash)
+gboolean
+empathy_ft_factory_register (EmpathyFTFactory *self,
+    GError **error)
 {
-  g_return_if_fail (EMPATHY_IS_FT_FACTORY (factory));
-  g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
-  g_return_if_fail (G_IS_FILE (destination));
-
-  empathy_ft_handler_incoming_set_destination (handler, destination, use_hash);
+  EmpathyFTFactoryPriv *priv = GET_PRIV (self);
 
-  g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, FALSE);
+  return tp_base_client_register (priv->handler, error);
 }