]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-tp-chat.c
sort contacts by most recent event
[empathy.git] / libempathy / empathy-tp-chat.c
index 03014ea01d1380db6f4c8b3d93208847d0d49aa9..92e634ed2ade9bf2be930600143eda4c04cedbfd 100644 (file)
  * Authors: Xavier Claessens <xclaesse@gmail.com>
  */
 
-#include <config.h>
-
-#include <string.h>
-
-#include <telepathy-glib/telepathy-glib.h>
+#include "config.h"
+#include "empathy-tp-chat.h"
 
-#include <extensions/extensions.h>
+#include <tp-account-widgets/tpaw-utils.h>
+#include <telepathy-glib/telepathy-glib-dbus.h>
 
-#include "empathy-tp-chat.h"
 #include "empathy-request-util.h"
-#include "empathy-time.h"
 #include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CHAT
@@ -59,6 +55,7 @@ struct _EmpathyTpChatPrivate
 
   /* GSimpleAsyncResult used when preparing EMPATHY_TP_CHAT_FEATURE_CORE */
   GSimpleAsyncResult *ready_result;
+  gboolean preparing_password;
 };
 
 enum
@@ -135,19 +132,46 @@ tp_chat_async_cb (TpChannel *proxy,
     DEBUG ("Error %s: %s", (gchar *) user_data, error->message);
 }
 
+static void
+update_config_cb (TpChannel *proxy,
+    const GError *error,
+    gpointer user_data,
+    GObject *weak_object)
+{
+  if (error != NULL)
+    DEBUG ("Failed to change config of the room: %s", error->message);
+}
+
 static void
 create_conference_cb (GObject *source,
     GAsyncResult *result,
     gpointer user_data)
 {
+  TpChannel *channel;
   GError *error = NULL;
+  GHashTable *props;
 
-  if (!tp_account_channel_request_create_channel_finish (
-      TP_ACCOUNT_CHANNEL_REQUEST (source), result, &error))
+  channel = tp_account_channel_request_create_and_observe_channel_finish (
+      TP_ACCOUNT_CHANNEL_REQUEST (source), result, &error);
+  if (channel == NULL)
     {
       DEBUG ("Failed to create conference channel: %s", error->message);
       g_error_free (error);
+      return;
     }
+
+  /* Make the channel more confidential as only people invited are supposed to
+   * join it. */
+  props = tp_asv_new (
+      "Private", G_TYPE_BOOLEAN, TRUE,
+      "InviteOnly", G_TYPE_BOOLEAN, TRUE,
+      NULL);
+
+  tp_cli_channel_interface_room_config_call_update_configuration (channel, -1,
+      props, update_config_cb, NULL, NULL, NULL);
+
+  g_object_unref (channel);
+  g_hash_table_unref (props);
 }
 
 void
@@ -172,39 +196,31 @@ empathy_tp_chat_add (EmpathyTpChat *self,
   else if (self->priv->can_upgrade_to_muc)
     {
       TpAccountChannelRequest *req;
-      GHashTable *props;
-      const char *object_path;
-      GPtrArray channels = { (gpointer *) &object_path, 1 };
+      const gchar *channels[2] = { NULL, };
       const char *invitees[2] = { NULL, };
       TpAccount *account;
 
       invitees[0] = empathy_contact_get_id (contact);
-      object_path = tp_proxy_get_object_path (self);
-
-      props = tp_asv_new (
-          TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
-              TP_IFACE_CHANNEL_TYPE_TEXT,
-          TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
-              TP_HANDLE_TYPE_NONE,
-          TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_CHANNELS,
-              TP_ARRAY_TYPE_OBJECT_PATH_LIST, &channels,
-          TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS,
-              G_TYPE_STRV, invitees,
-          /* FIXME: InvitationMessage ? */
-          NULL);
+      channels[0] = tp_proxy_get_object_path (self);
 
       account = empathy_tp_chat_get_account (self);
 
-      req = tp_account_channel_request_new (account, props,
+      req = tp_account_channel_request_new_text (account,
         TP_USER_ACTION_TIME_NOT_USER_ACTION);
 
+      tp_account_channel_request_set_conference_initial_channels (req,
+          channels);
+
+      tp_account_channel_request_set_initial_invitee_ids (req, invitees);
+
+      /* FIXME: InvitationMessage ? */
+
       /* Although this is a MUC, it's anonymous, so CreateChannel is
        * valid. */
-      tp_account_channel_request_create_channel_async (req,
-          EMPATHY_CHAT_BUS_NAME, NULL, create_conference_cb, NULL);
+      tp_account_channel_request_create_and_observe_channel_async (req,
+          EMPATHY_CHAT_TP_BUS_NAME, NULL, create_conference_cb, NULL);
 
       g_object_unref (req);
-      g_hash_table_unref (props);
     }
   else
     {
@@ -499,7 +515,7 @@ list_pending_messages (EmpathyTpChat *self)
 {
   GList *messages, *l;
 
-  messages = tp_text_channel_get_pending_messages (TP_TEXT_CHANNEL (self));
+  messages = tp_text_channel_dup_pending_messages (TP_TEXT_CHANNEL (self));
 
   for (l = messages; l != NULL; l = g_list_next (l))
     {
@@ -508,7 +524,7 @@ list_pending_messages (EmpathyTpChat *self)
       handle_incoming_message (self, message, FALSE);
     }
 
-  g_list_free (messages);
+  g_list_free_full (messages, g_object_unref);
 }
 
 static void
@@ -703,6 +719,9 @@ check_almost_ready (EmpathyTpChat *self)
   if (self->priv->user == NULL)
     return;
 
+  if (self->priv->preparing_password)
+    return;
+
   /* We need either the members (room) or the remote contact (private chat).
    * If the chat is protected by a password we can't get these information so
    * consider the chat as ready so it can be presented to the user. */
@@ -940,13 +959,14 @@ static const TpProxyFeature *
 tp_chat_list_features (TpProxyClass *cls G_GNUC_UNUSED)
 {
   static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
-  static GQuark need[2] = {0, 0};
+  static GQuark need[3] = {0, 0, 0};
 
   if (G_LIKELY (features[0].name != 0))
     return features;
 
   features[FEAT_READY].name = EMPATHY_TP_CHAT_FEATURE_READY;
   need[0] = TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES;
+  need[1] = TP_CHANNEL_FEATURE_CONTACTS;
   features[FEAT_READY].depends_on = need;
   features[FEAT_READY].prepare_async =
     tp_chat_prepare_ready_async;
@@ -1091,7 +1111,7 @@ empathy_tp_chat_get_id (EmpathyTpChat *self)
   g_return_val_if_fail (EMPATHY_IS_TP_CHAT (self), NULL);
 
   id = tp_channel_get_identifier ((TpChannel *) self);
-  if (!EMP_STR_EMPTY (id))
+  if (!TPAW_STR_EMPTY (id))
     return id;
   else if (self->priv->remote_contact)
     return empathy_contact_get_id (self->priv->remote_contact);
@@ -1115,7 +1135,7 @@ empathy_tp_chat_get_account (EmpathyTpChat *self)
 
   g_return_val_if_fail (EMPATHY_IS_TP_CHAT (self), NULL);
 
-  connection = tp_channel_borrow_connection (TP_CHANNEL (self));
+  connection = tp_channel_get_connection (TP_CHANNEL (self));
 
   return tp_connection_get_account (connection);
 }
@@ -1250,21 +1270,47 @@ empathy_tp_chat_get_feature_ready (void)
 }
 
 static void
-tp_chat_prepare_ready_async (TpProxy *proxy,
-  const TpProxyFeature *feature,
-  GAsyncReadyCallback callback,
-  gpointer user_data)
+password_feature_prepare_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
 {
-  EmpathyTpChat *self = (EmpathyTpChat *) proxy;
-  TpChannel *channel = (TpChannel *) proxy;
+  EmpathyTpChat *self = user_data;
+  GError *error = NULL;
+
+  if (!tp_proxy_prepare_finish (source, result, &error))
+    {
+      DEBUG ("Failed to prepare Password: %s", error->message);
+      g_error_free (error);
+    }
+
+  self->priv->preparing_password = FALSE;
+
+  check_almost_ready (self);
+}
+
+static void
+continue_preparing (EmpathyTpChat *self)
+{
+  TpChannel *channel = (TpChannel *) self;
   TpConnection *connection;
   gboolean listen_for_dbus_properties_changed = FALSE;
 
-  g_assert (self->priv->ready_result == NULL);
-  self->priv->ready_result = g_simple_async_result_new (G_OBJECT (self),
-    callback, user_data, tp_chat_prepare_ready_async);
+  connection = tp_channel_get_connection (channel);
 
-  connection = tp_channel_borrow_connection (channel);
+  if (tp_proxy_has_interface_by_id (self,
+        TP_IFACE_QUARK_CHANNEL_INTERFACE_PASSWORD))
+    {
+      /* The password feature can't be a hard dep on our own feature has we
+       * depend on it only if the channel implements the
+       * Password interface.
+       */
+      GQuark features[] = { TP_CHANNEL_FEATURE_PASSWORD , 0 };
+
+      self->priv->preparing_password = TRUE;
+
+      tp_proxy_prepare_async (self, features, password_feature_prepare_cb,
+          self);
+    }
 
   if (tp_proxy_has_interface_by_id (self,
             TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP))
@@ -1373,3 +1419,49 @@ tp_chat_prepare_ready_async (TpProxy *proxy,
                         G_OBJECT (self), NULL);
     }
 }
+
+static void
+conn_connected_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  EmpathyTpChat *self = user_data;
+  GError *error = NULL;
+
+  if (!tp_proxy_prepare_finish (source, result, &error))
+    {
+      DEBUG ("Failed to prepare Connected: %s", error->message);
+      g_simple_async_result_take_error (self->priv->ready_result, error);
+      g_simple_async_result_complete (self->priv->ready_result);
+      tp_clear_object (&self->priv->ready_result);
+      return;
+    }
+
+  continue_preparing (self);
+}
+
+static void
+tp_chat_prepare_ready_async (TpProxy *proxy,
+  const TpProxyFeature *feature,
+  GAsyncReadyCallback callback,
+  gpointer user_data)
+{
+  EmpathyTpChat *self = (EmpathyTpChat *) proxy;
+  TpChannel *channel = (TpChannel *) proxy;
+  TpConnection *connection;
+  GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
+
+  g_assert (self->priv->ready_result == NULL);
+
+  self->priv->ready_result = g_simple_async_result_new (G_OBJECT (self),
+    callback, user_data, tp_chat_prepare_ready_async);
+
+  connection = tp_channel_get_connection (channel);
+
+  /* First we have to make sure that TP_CONNECTION_FEATURE_CONNECTED is
+   * prepared as we rely on TpConnection::self-contact
+   * in continue_preparing().
+   *
+   * It would be nice if tp-glib could do this for us: fdo#59126 */
+  tp_proxy_prepare_async (connection, features, conn_connected_cb, proxy);
+}