]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-tp-chat.c
Updated Dutch translation master
[empathy.git] / libempathy / empathy-tp-chat.c
index 65a7dd8882f1b7d52b4faf695f79c379c5cf9f3c..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-tp-contact-factory.h"
 #include "empathy-request-util.h"
-#include "empathy-time.h"
 #include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CHAT
@@ -60,6 +55,7 @@ struct _EmpathyTpChatPrivate
 
   /* GSimpleAsyncResult used when preparing EMPATHY_TP_CHAT_FEATURE_CORE */
   GSimpleAsyncResult *ready_result;
+  gboolean preparing_password;
 };
 
 enum
@@ -77,7 +73,6 @@ enum
 {
   MESSAGE_RECEIVED,
   SEND_ERROR,
-  CHAT_STATE_CHANGED,
   MESSAGE_ACKNOWLEDGED,
   SIG_MEMBER_RENAMED,
   SIG_MEMBERS_CHANGED,
@@ -137,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
@@ -174,36 +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);
-
-      req = tp_account_channel_request_new (self->priv->account, props,
+      channels[0] = tp_proxy_get_object_path (self);
+
+      account = empathy_tp_chat_get_account (self);
+
+      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
     {
@@ -493,54 +510,12 @@ message_send_cb (GObject *source,
   g_free (token);
 }
 
-typedef struct {
-  EmpathyTpChat *chat;
-  TpChannelChatState state;
-} StateChangedData;
-
-static void
-tp_chat_state_changed_got_contact_cb (TpConnection *connection,
-    EmpathyContact *contact,
-    const GError *error,
-    gpointer user_data,
-    GObject *chat)
-{
-  TpChannelChatState state;
-
-  if (error != NULL)
-    {
-      DEBUG ("Error: %s", error->message);
-      return;
-    }
-
-  state = GPOINTER_TO_UINT (user_data);
-  DEBUG ("Chat state changed for %s (%d): %d",
-    empathy_contact_get_alias (contact),
-    empathy_contact_get_handle (contact), state);
-
-  g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state);
-}
-
-static void
-tp_chat_state_changed_cb (TpChannel *channel,
-    TpHandle handle,
-    TpChannelChatState state,
-    EmpathyTpChat *self)
-{
-  TpConnection *connection = tp_channel_borrow_connection (
-    (TpChannel *) self);
-
-  empathy_tp_contact_factory_get_from_handle (connection, handle,
-    tp_chat_state_changed_got_contact_cb, GUINT_TO_POINTER (state),
-    NULL, G_OBJECT (self));
-}
-
 static void
 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))
     {
@@ -549,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,7 +678,6 @@ tp_chat_dispose (GObject *object)
 {
   EmpathyTpChat *self = EMPATHY_TP_CHAT (object);
 
-  tp_clear_object (&self->priv->account);
   tp_clear_object (&self->priv->remote_contact);
   tp_clear_object (&self->priv->user);
 
@@ -745,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. */
@@ -765,11 +742,6 @@ check_almost_ready (EmpathyTpChat *self)
   tp_g_signal_connect_object (self, "message-sent",
     G_CALLBACK (message_sent_cb), self, 0);
 
-  /* TODO: use the TpContact signal once it's released
-   * (fdo #49215) */
-  tp_g_signal_connect_object (self, "chat-state-changed",
-    G_CALLBACK (tp_chat_state_changed_cb), self, 0);
-
   check_ready (self);
 }
 
@@ -954,9 +926,6 @@ tp_chat_get_property (GObject *object,
 
   switch (param_id)
     {
-      case PROP_ACCOUNT:
-        g_value_set_object (value, self->priv->account);
-        break;
       case PROP_SELF_CONTACT:
         g_value_set_object (value, self->priv->user);
         break;
@@ -981,25 +950,6 @@ tp_chat_get_property (GObject *object,
     };
 }
 
-static void
-tp_chat_set_property (GObject *object,
-    guint param_id,
-    const GValue *value,
-    GParamSpec   *pspec)
-{
-  EmpathyTpChat *self = EMPATHY_TP_CHAT (object);
-
-  switch (param_id)
-    {
-      case PROP_ACCOUNT:
-        self->priv->account = g_value_dup_object (value);
-        break;
-      default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-        break;
-    };
-}
-
 enum {
   FEAT_READY,
   N_FEAT
@@ -1009,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;
@@ -1035,18 +986,9 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
   object_class->dispose = tp_chat_dispose;
   object_class->finalize = tp_chat_finalize;
   object_class->get_property = tp_chat_get_property;
-  object_class->set_property = tp_chat_set_property;
 
   proxy_class->list_features = tp_chat_list_features;
 
-  g_object_class_install_property (object_class, PROP_ACCOUNT,
-      g_param_spec_object ("account", "TpAccount",
-        "the account associated with the chat",
-        TP_TYPE_ACCOUNT,
-        G_PARAM_READWRITE |
-        G_PARAM_CONSTRUCT_ONLY |
-        G_PARAM_STATIC_STRINGS));
-
   /**
    * EmpathyTpChat:self-contact:
    *
@@ -1103,15 +1045,6 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
       G_TYPE_NONE,
       3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
 
-  signals[CHAT_STATE_CHANGED] = g_signal_new ("chat-state-changed-empathy",
-      G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      0,
-      NULL, NULL,
-      g_cclosure_marshal_generic,
-      G_TYPE_NONE,
-      2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT);
-
   signals[MESSAGE_ACKNOWLEDGED] = g_signal_new ("message-acknowledged",
       G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST,
@@ -1153,23 +1086,18 @@ empathy_tp_chat_init (EmpathyTpChat *self)
 
 EmpathyTpChat *
 empathy_tp_chat_new (TpSimpleClientFactory *factory,
-    TpAccount *account,
     TpConnection *conn,
     const gchar *object_path,
     const GHashTable *immutable_properties)
 {
-  TpProxy *conn_proxy = (TpProxy *) conn;
-
-  g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
   g_return_val_if_fail (TP_IS_CONNECTION (conn), NULL);
   g_return_val_if_fail (immutable_properties != NULL, NULL);
 
   return g_object_new (EMPATHY_TYPE_TP_CHAT,
       "factory", factory,
-       "account", account,
        "connection", conn,
-       "dbus-daemon", conn_proxy->dbus_daemon,
-       "bus-name", conn_proxy->bus_name,
+       "dbus-daemon", tp_proxy_get_dbus_daemon (conn),
+       "bus-name", tp_proxy_get_bus_name (conn),
        "object-path", object_path,
        "channel-properties", immutable_properties,
        NULL);
@@ -1183,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);
@@ -1203,9 +1131,13 @@ empathy_tp_chat_get_remote_contact (EmpathyTpChat *self)
 TpAccount *
 empathy_tp_chat_get_account (EmpathyTpChat *self)
 {
+  TpConnection *connection;
+
   g_return_val_if_fail (EMPATHY_IS_TP_CHAT (self), NULL);
 
-  return self->priv->account;
+  connection = tp_channel_get_connection (TP_CHANNEL (self));
+
+  return tp_connection_get_account (connection);
 }
 
 void
@@ -1319,8 +1251,8 @@ TpChannelChatState
 empathy_tp_chat_get_chat_state (EmpathyTpChat *self,
     EmpathyContact *contact)
 {
-  return tp_channel_get_chat_state ((TpChannel *) self,
-    empathy_contact_get_handle (contact));
+  return tp_text_channel_get_chat_state ((TpTextChannel *) self,
+    empathy_contact_get_tp_contact (contact));
 }
 
 EmpathyContact *
@@ -1338,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);
+
+  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 };
 
-  connection = tp_channel_borrow_connection (channel);
+      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))
@@ -1461,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);
+}