]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-individual-store.c
Merge branch 'sasl'
[empathy.git] / libempathy-gtk / empathy-individual-store.c
index e72b7ec9e6516df12ec217ebcc9b88137447bf4f..4b07131a60ac1691ce63cf3398ab01e08b306a7b 100644 (file)
@@ -154,27 +154,62 @@ individual_can_audio_video_call (FolksIndividual *individual,
   *can_video_call = can_video;
 }
 
+static const gchar * const *
+individual_get_client_types (FolksIndividual *individual)
+{
+  GList *personas, *l;
+  const gchar * const *types = NULL;
+  FolksPresenceType presence_type = FOLKS_PRESENCE_TYPE_UNSET;
+
+  personas = folks_individual_get_personas (individual);
+  for (l = personas; l != NULL; l = l->next)
+    {
+      FolksPresence *presence;
+
+      /* We only want personas which implement FolksPresence */
+      if (!FOLKS_IS_PRESENCE (l->data))
+        continue;
+
+      presence = FOLKS_PRESENCE (l->data);
+
+      if (folks_presence_typecmp (folks_presence_get_presence_type (presence),
+              presence_type) > 0)
+        {
+          TpContact *tp_contact;
+
+          presence_type = folks_presence_get_presence_type (presence);
+
+          tp_contact = tpf_persona_get_contact (TPF_PERSONA (l->data));
+          types = tp_contact_get_client_types (tp_contact);
+        }
+    }
+
+  return types;
+}
+
 static void
 add_individual_to_store (GtkTreeStore *self,
     GtkTreeIter *iter,
     GtkTreeIter *parent,
-    FolksIndividual *individual,
-    EmpathyIndividualManagerFlags flags)
+    FolksIndividual *individual)
 {
   gboolean can_audio_call, can_video_call;
+  const gchar * const *types;
 
   individual_can_audio_video_call (individual, &can_audio_call,
       &can_video_call);
 
+  types = individual_get_client_types (individual);
+
   gtk_tree_store_insert_with_values (self, iter, parent, 0,
       EMPATHY_INDIVIDUAL_STORE_COL_NAME,
-      folks_individual_get_alias (individual),
+      folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
       EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, individual,
       EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, FALSE,
       EMPATHY_INDIVIDUAL_STORE_COL_IS_SEPARATOR, FALSE,
-      EMPATHY_INDIVIDUAL_STORE_COL_FLAGS, flags,
       EMPATHY_INDIVIDUAL_STORE_COL_CAN_AUDIO_CALL, can_audio_call,
       EMPATHY_INDIVIDUAL_STORE_COL_CAN_VIDEO_CALL, can_video_call,
+      EMPATHY_INDIVIDUAL_STORE_COL_CLIENT_TYPES, types,
       -1);
 }
 
@@ -326,6 +361,13 @@ individual_store_find_contact (EmpathyIndividualStore *self,
   return l;
 }
 
+static void
+free_iters (GList *iters)
+{
+  g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
+  g_list_free (iters);
+}
+
 static void
 individual_store_remove_individual (EmpathyIndividualStore *self,
     FolksIndividual *individual)
@@ -362,8 +404,7 @@ individual_store_remove_individual (EmpathyIndividualStore *self,
         }
     }
 
-  g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
-  g_list_free (iters);
+  free_iters (iters);
 }
 
 static void
@@ -376,24 +417,21 @@ individual_store_add_individual (EmpathyIndividualStore *self,
   GList *groups = NULL, *l;
   EmpathyContact *contact;
   TpConnection *connection;
-  EmpathyIndividualManagerFlags flags = 0;
   gchar *protocol_name;
 
   priv = GET_PRIV (self);
 
-  if (EMP_STR_EMPTY (folks_individual_get_alias (individual)))
+  if (EMP_STR_EMPTY (folks_aliasable_get_alias (FOLKS_ALIASABLE (individual))))
     return;
 
   if (priv->show_groups)
     {
-      group_set = folks_individual_get_groups (individual);
+      group_set = folks_groupable_get_groups (FOLKS_GROUPABLE (individual));
       groups = g_hash_table_get_keys (group_set);
     }
 
   contact = empathy_contact_dup_from_folks_individual (individual);
   connection = empathy_contact_get_connection (contact);
-  flags = empathy_individual_manager_get_flags_for_connection (priv->manager,
-      connection);
 
   tp_connection_parse_object_path (connection, &protocol_name, NULL);
 
@@ -420,7 +458,7 @@ individual_store_add_individual (EmpathyIndividualStore *self,
         }
 
       add_individual_to_store (GTK_TREE_STORE (self), &iter, parent,
-          individual, flags);
+          individual);
     }
 
   g_free (protocol_name);
@@ -434,11 +472,9 @@ individual_store_add_individual (EmpathyIndividualStore *self,
           FALSE);
 
       add_individual_to_store (GTK_TREE_STORE (self), &iter, &iter_group,
-          individual, flags);
+          individual);
     }
   g_list_free (groups);
-  if (group_set != NULL)
-    g_hash_table_unref (group_set);
 
   if (priv->show_groups &&
       folks_favourite_get_is_favourite (FOLKS_FAVOURITE (individual)))
@@ -450,7 +486,7 @@ individual_store_add_individual (EmpathyIndividualStore *self,
           &iter_group, NULL, NULL, TRUE);
 
       add_individual_to_store (GTK_TREE_STORE (self), &iter, &iter_group,
-          individual, flags);
+          individual);
     }
 
   individual_store_contact_update (self, individual);
@@ -490,9 +526,7 @@ individual_store_contact_set_active (EmpathyIndividualStore *self,
         }
     }
 
-  g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
-  g_list_free (iters);
-
+  free_iters (iters);
 }
 
 static void individual_store_contact_active_free (ShowActiveData *data);
@@ -523,7 +557,8 @@ individual_store_contact_active_new (EmpathyIndividualStore *self,
   ShowActiveData *data;
 
   DEBUG ("Individual'%s' now active, and %s be removed",
-      folks_individual_get_alias (individual), remove_ ? "WILL" : "WILL NOT");
+      folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
+      remove_ ? "WILL" : "WILL NOT");
 
   data = g_slice_new0 (ShowActiveData);
 
@@ -567,12 +602,12 @@ individual_store_contact_active_cb (ShowActiveData *data)
   if (data->remove)
     {
       DEBUG ("Individual'%s' active timeout, removing item",
-          folks_individual_get_alias (data->individual));
+          folks_aliasable_get_alias (FOLKS_ALIASABLE (data->individual)));
       individual_store_remove_individual (data->self, data->individual);
     }
 
   DEBUG ("Individual'%s' no longer active",
-      folks_individual_get_alias (data->individual));
+      folks_aliasable_get_alias (FOLKS_ALIASABLE (data->individual)));
 
   individual_store_contact_set_active (data->self,
       data->individual, FALSE, TRUE);
@@ -601,7 +636,7 @@ individual_avatar_pixbuf_received_cb (FolksIndividual *individual,
   if (error != NULL)
     {
       DEBUG ("failed to retrieve pixbuf for individual %s: %s",
-          folks_individual_get_alias (individual),
+          folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
           error->message);
       g_clear_error (&error);
     }
@@ -616,6 +651,8 @@ individual_avatar_pixbuf_received_cb (FolksIndividual *individual,
               EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR, pixbuf,
               -1);
         }
+
+      free_iters (iters);
     }
 
   /* Free things */
@@ -629,6 +666,7 @@ individual_avatar_pixbuf_received_cb (FolksIndividual *individual,
           data->cancellable);
     }
 
+  tp_clear_object (&pixbuf);
   g_object_unref (data->cancellable);
   g_slice_free (LoadAvatarData, data);
 }
@@ -667,12 +705,12 @@ individual_store_contact_update (EmpathyIndividualStore *self,
     }
 
   /* Get online state now. */
-  now_online = folks_individual_is_online (individual);
+  now_online = folks_presence_is_online (FOLKS_PRESENCE (individual));
 
   if (!in_list)
     {
       DEBUG ("Individual'%s' in list:NO, should be:YES",
-          folks_individual_get_alias (individual));
+          folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)));
 
       individual_store_add_individual (self, individual);
 
@@ -686,7 +724,7 @@ individual_store_contact_update (EmpathyIndividualStore *self,
   else
     {
       DEBUG ("Individual'%s' in list:YES, should be:YES",
-          folks_individual_get_alias (individual));
+          folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)));
 
       /* Get online state before. */
       if (iters && g_list_length (iters) > 0)
@@ -744,25 +782,29 @@ individual_store_contact_update (EmpathyIndividualStore *self,
   for (l = iters; l && set_model; l = l->next)
     {
       gboolean can_audio_call, can_video_call;
+      const gchar * const *types;
 
       individual_can_audio_video_call (individual, &can_audio_call,
           &can_video_call);
 
+      types = individual_get_client_types (individual);
+
       gtk_tree_store_set (GTK_TREE_STORE (self), l->data,
           EMPATHY_INDIVIDUAL_STORE_COL_ICON_STATUS, pixbuf_status,
           EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR_VISIBLE, show_avatar,
           EMPATHY_INDIVIDUAL_STORE_COL_NAME,
-            folks_individual_get_alias (individual),
+            folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
           EMPATHY_INDIVIDUAL_STORE_COL_PRESENCE_TYPE,
-            folks_individual_get_presence_type (individual),
+            folks_presence_get_presence_type (FOLKS_PRESENCE (individual)),
           EMPATHY_INDIVIDUAL_STORE_COL_STATUS,
-            folks_individual_get_presence_message (individual),
+            folks_presence_get_presence_message (FOLKS_PRESENCE (individual)),
           EMPATHY_INDIVIDUAL_STORE_COL_COMPACT, priv->is_compact,
           EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, FALSE,
           EMPATHY_INDIVIDUAL_STORE_COL_IS_ONLINE, now_online,
           EMPATHY_INDIVIDUAL_STORE_COL_IS_SEPARATOR, FALSE,
           EMPATHY_INDIVIDUAL_STORE_COL_CAN_AUDIO_CALL, can_audio_call,
           EMPATHY_INDIVIDUAL_STORE_COL_CAN_VIDEO_CALL, can_video_call,
+          EMPATHY_INDIVIDUAL_STORE_COL_CLIENT_TYPES, types,
           -1);
     }
 
@@ -786,8 +828,7 @@ individual_store_contact_update (EmpathyIndividualStore *self,
    * timeout removes the user from the contact list, really we
    * should remove the first timeout.
    */
-  g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
-  g_list_free (iters);
+  free_iters (iters);
 }
 
 static void
@@ -796,7 +837,7 @@ individual_store_individual_updated_cb (FolksIndividual *individual,
     EmpathyIndividualStore *self)
 {
   DEBUG ("Individual'%s' updated, checking roster is in sync...",
-      folks_individual_get_alias (individual));
+      folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)));
 
   individual_store_contact_update (self, individual);
 }
@@ -819,24 +860,19 @@ individual_store_contact_updated_cb (EmpathyContact *contact,
 }
 
 static void
-individual_store_add_individual_and_connect (EmpathyIndividualStore *self,
-    FolksIndividual *individual)
+individual_personas_changed_cb (FolksIndividual *individual,
+    GList *added,
+    GList *removed,
+    EmpathyIndividualStore *self)
 {
-  GList *personas, *l;
+  GList *l;
 
-  g_signal_connect (individual, "notify::avatar",
-      G_CALLBACK (individual_store_individual_updated_cb), self);
-  g_signal_connect (individual, "notify::presence-type",
-      G_CALLBACK (individual_store_individual_updated_cb), self);
-  g_signal_connect (individual, "notify::presence-message",
-      G_CALLBACK (individual_store_individual_updated_cb), self);
-  g_signal_connect (individual, "notify::alias",
-      G_CALLBACK (individual_store_individual_updated_cb), self);
+  DEBUG ("Individual '%s' personas-changed.",
+      folks_individual_get_id (individual));
 
   /* FIXME: libfolks hasn't grown capabilities support yet, so we have to go
    * through the EmpathyContacts for them. */
-  personas = folks_individual_get_personas (individual);
-  for (l = personas; l != NULL; l = l->next)
+  for (l = removed; l != NULL; l = l->next)
     {
       TpContact *tp_contact;
       EmpathyContact *contact;
@@ -848,29 +884,14 @@ individual_store_add_individual_and_connect (EmpathyIndividualStore *self,
       contact = empathy_contact_dup_from_tp_contact (tp_contact);
       empathy_contact_set_persona (contact, FOLKS_PERSONA (l->data));
 
-      g_object_set_data (G_OBJECT (contact), "individual", individual);
-      g_signal_connect (contact, "notify::capabilities",
-          G_CALLBACK (individual_store_contact_updated_cb), self);
+      g_object_set_data (G_OBJECT (contact), "individual", NULL);
+      g_signal_handlers_disconnect_by_func (contact,
+          (GCallback) individual_store_contact_updated_cb, self);
 
       g_object_unref (contact);
     }
 
-  individual_store_add_individual (self, individual);
-}
-
-static void
-individual_store_disconnect_individual (EmpathyIndividualStore *self,
-    FolksIndividual *individual)
-{
-  GList *personas, *l;
-
-  g_signal_handlers_disconnect_by_func (individual,
-      G_CALLBACK (individual_store_individual_updated_cb), self);
-
-  /* FIXME: libfolks hasn't grown capabilities support yet, so we have to go
-   * through the EmpathyContacts for them. */
-  personas = folks_individual_get_personas (individual);
-  for (l = personas; l != NULL; l = l->next)
+  for (l = added; l != NULL; l = l->next)
     {
       TpContact *tp_contact;
       EmpathyContact *contact;
@@ -882,13 +903,50 @@ individual_store_disconnect_individual (EmpathyIndividualStore *self,
       contact = empathy_contact_dup_from_tp_contact (tp_contact);
       empathy_contact_set_persona (contact, FOLKS_PERSONA (l->data));
 
-      g_signal_handlers_disconnect_by_func (contact,
-          G_CALLBACK (individual_store_contact_updated_cb), self);
+      g_object_set_data (G_OBJECT (contact), "individual", individual);
+      g_signal_connect (contact, "notify::capabilities",
+          (GCallback) individual_store_contact_updated_cb, self);
+      g_signal_connect (contact, "notify::client-types",
+          (GCallback) individual_store_contact_updated_cb, self);
 
       g_object_unref (contact);
     }
 }
 
+static void
+individual_store_add_individual_and_connect (EmpathyIndividualStore *self,
+    FolksIndividual *individual)
+{
+  individual_store_add_individual (self, individual);
+
+  g_signal_connect (individual, "notify::avatar",
+      (GCallback) individual_store_individual_updated_cb, self);
+  g_signal_connect (individual, "notify::presence-type",
+      (GCallback) individual_store_individual_updated_cb, self);
+  g_signal_connect (individual, "notify::presence-message",
+      (GCallback) individual_store_individual_updated_cb, self);
+  g_signal_connect (individual, "notify::alias",
+      (GCallback) individual_store_individual_updated_cb, self);
+  g_signal_connect (individual, "personas-changed",
+      (GCallback) individual_personas_changed_cb, self);
+
+  individual_personas_changed_cb (individual,
+      folks_individual_get_personas (individual), NULL, self);
+}
+
+static void
+individual_store_disconnect_individual (EmpathyIndividualStore *self,
+    FolksIndividual *individual)
+{
+  individual_personas_changed_cb (individual, NULL,
+      folks_individual_get_personas (individual), self);
+
+  g_signal_handlers_disconnect_by_func (individual,
+      (GCallback) individual_store_individual_updated_cb, self);
+  g_signal_handlers_disconnect_by_func (individual,
+      (GCallback) individual_personas_changed_cb, self);
+}
+
 static void
 individual_store_remove_individual_and_disconnect (
     EmpathyIndividualStore *self,
@@ -1329,8 +1387,9 @@ individual_store_contact_sort (FolksIndividual *individual_a,
   g_return_val_if_fail (individual_a != NULL || individual_b != NULL, 0);
 
   /* alias */
-  ret_val = g_utf8_collate (folks_individual_get_alias (individual_a),
-      folks_individual_get_alias (individual_b));
+  ret_val = g_utf8_collate (
+      folks_aliasable_get_alias (FOLKS_ALIASABLE (individual_a)),
+      folks_aliasable_get_alias (FOLKS_ALIASABLE (individual_b)));
 
   if (ret_val != 0)
     goto out;
@@ -1340,6 +1399,9 @@ individual_store_contact_sort (FolksIndividual *individual_a,
   account_a = empathy_contact_get_account (contact_a);
   account_b = empathy_contact_get_account (contact_b);
 
+  g_assert (account_a != NULL);
+  g_assert (account_b != NULL);
+
   /* protocol */
   ret_val = g_strcmp0 (tp_account_get_protocol (account_a),
       tp_account_get_protocol (account_b));
@@ -1401,8 +1463,10 @@ individual_store_state_sort_func (GtkTreeModel *model,
   /* If we managed to get this far, we can start looking at
    * the presences.
    */
-  folks_presence_type_a = folks_individual_get_presence_type (individual_a);
-  folks_presence_type_b = folks_individual_get_presence_type (individual_b);
+  folks_presence_type_a =
+      folks_presence_get_presence_type (FOLKS_PRESENCE (individual_a));
+  folks_presence_type_b =
+      folks_presence_get_presence_type (FOLKS_PRESENCE (individual_b));
   tp_presence_a = empathy_folks_presence_type_to_tp (folks_presence_type_a);
   tp_presence_b = empathy_folks_presence_type_to_tp (folks_presence_type_b);
 
@@ -1455,6 +1519,8 @@ individual_store_name_sort_func (GtkTreeModel *model,
 
   tp_clear_object (&individual_a);
   tp_clear_object (&individual_b);
+  g_free (name_a);
+  g_free (name_b);
 
   return ret_val;
 }
@@ -1478,8 +1544,8 @@ individual_store_setup (EmpathyIndividualStore *self)
     G_TYPE_BOOLEAN,             /* Is separator */
     G_TYPE_BOOLEAN,             /* Can make audio calls */
     G_TYPE_BOOLEAN,             /* Can make video calls */
-    EMPATHY_TYPE_INDIVIDUAL_MANAGER_FLAGS,      /* Flags */
     G_TYPE_BOOLEAN,             /* Is a fake group */
+    G_TYPE_STRV,                /* Client types */
   };
 
   priv = GET_PRIV (self);
@@ -1810,7 +1876,7 @@ empathy_individual_store_get_parent_group (GtkTreeModel *model,
   GtkTreeIter parent_iter, iter;
   gchar *name = NULL;
   gboolean is_group;
-  gboolean fake;
+  gboolean fake = FALSE;
 
   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);