[empathy] Rebase the favourites support upon the telepathy-logger instead of a specially-named favourites grou



commit c66e6c536d776414f6bfada650dc25d97dc95803
Author: Travis Reitter <treitter gmail com>
Date:   Fri Mar 5 18:58:17 2010 -0800

    Rebase the favourites support upon the telepathy-logger instead of a specially-named favourites group.

 extensions/Logger.xml                       |  179 ++++++++++++++++
 extensions/Makefile.am                      |    6 +-
 extensions/all.xml                          |    2 +
 extensions/misc.xml                         |    1 +
 libempathy-gtk/empathy-contact-list-store.c |   66 ++++++-
 libempathy-gtk/empathy-contact-list-view.c  |   10 +-
 libempathy/empathy-contact-list.c           |   11 +-
 libempathy/empathy-contact-list.h           |   19 ++-
 libempathy/empathy-contact-manager.c        |  291 +++++++++++++++++++++++++++
 9 files changed, 564 insertions(+), 21 deletions(-)
---
diff --git a/extensions/Logger.xml b/extensions/Logger.xml
new file mode 100644
index 0000000..a377829
--- /dev/null
+++ b/extensions/Logger.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" ?>
+<node name="/Logger"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0";>
+  <tp:copyright>Copyright © 2009 Collabora Ltd.</tp:copyright>
+  <tp:license xmlns="http://www.w3.org/1999/xhtml";>
+    <p>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.</p>
+
+<p>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.</p>
+
+<p>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 Street, Fifth Floor, Boston, MA 02110-1301, USA.</p>
+  </tp:license>
+  <interface name="org.freedesktop.Telepathy.Logger.DRAFT"
+    tp:causes-havoc="experimental">
+    <tp:added version="0.1">(as a draft)</tp:added>
+
+    <tp:docstring>
+      An interface for requesting information from the Telepathy Logger
+      service.
+    </tp:docstring>
+
+    <tp:struct name="Chat_Message" array-name="Chat_Message_List">
+      <tp:member type="s" name="Sender">
+        <tp:docstring>
+          The identifier of the contact who originated this message.
+        </tp:docstring>
+      </tp:member>
+
+      <tp:member type="s" name="Message">
+        <tp:docstring xmlns="http://www.w3.org/1999/xhtml";>
+        The body of the message sent to a 1-1 Chat or a Chat Room.
+        </tp:docstring>
+      </tp:member>
+
+      <tp:member type="x" name="Timestamp" tp:type="Unix_Timestamp64">
+        <tp:docstring xmlns="http://www.w3.org/1999/xhtml";>
+        Unix timestamp for the log entry
+        </tp:docstring>
+      </tp:member>
+
+      <tp:docstring xmlns="http://www.w3.org/1999/xhtml";>
+        <p>It represents a single message, received or sent.</p>
+        <p>The receiver is implicit in the request: if the sender is the user,
+        the receiver is the identifier in chat_id paramenter, if the sender is
+        not the user, the user is consequently the receiver of the message</p>
+      </tp:docstring>
+    </tp:struct>
+
+    <method name="GetRecentMessages"
+            tp:name-for-bindings="Get_Recent_Messages">
+      <arg direction="in" name="Account" type="o" tp:type="Account">
+        <tp:docstring>
+        The account path for the TpAccount to which the conversation is related
+        </tp:docstring>
+      </arg>
+
+      <arg direction="in" name="Identifier" type="s">
+        <tp:docstring>
+        The buddy's identifier for the conversation
+        </tp:docstring>
+      </arg>
+
+      <arg direction="in" name="Is_Chatroom" type="b">
+        <tp:docstring>
+        Whether the conversation is a chatroom (i.e., XMPP MUC) or not
+        </tp:docstring>
+      </arg>
+
+      <arg direction="in" name="Lines" type="u">
+        <tp:docstring>
+        how many entries will be returned.
+
+        NOTE: to retreive information that would generate high traffic, use
+        the library API approach instead of DBus.
+        </tp:docstring>
+      </arg>
+
+      <arg direction="out" name="Messages" type="a(ssx)"
+           tp:type="Chat_Message[]" />
+
+      <tp:docstring>
+        Request the last Lines entries of logs for the specified couple
+        Account+Identifier.
+      </tp:docstring>
+    </method>
+
+    <method name="GetFavouriteContacts"
+            tp:name-for-bindings="Get_Favourite_Contacts">
+      <arg direction="out" name="Favourite_Contacts" type="a(oas)">
+        <tp:docstring>
+        The favourite contacts, as an array of TpAccounts and their contact
+        identifiers.
+        </tp:docstring>
+      </arg>
+
+      <tp:docstring>
+        Returns the favourite contacts.
+      </tp:docstring>
+    </method>
+
+    <method name="AddFavouriteContact"
+            tp:name-for-bindings="Add_Favourite_Contact">
+      <arg direction="in" name="Account" type="o" tp:type="Account">
+        <tp:docstring>
+        The object path for the TpAccount to which the contact belongs
+        </tp:docstring>
+      </arg>
+
+      <arg direction="in" name="Identifier" type="s">
+        <tp:docstring>
+        The favourite contact's identifier
+        </tp:docstring>
+      </arg>
+
+      <tp:docstring>
+        Add a contact's designation as a favourite. This method may not be
+        called until the service is ready. See the <tp:dbus-ref
+        namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsReady</tp:dbus-ref> signal and <tp:dbus-ref
+        namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsIsReady</tp:dbus-ref> property.
+      </tp:docstring>
+    </method>
+
+    <method name="RemoveFavouriteContact"
+            tp:name-for-bindings="Remove_Favourite_Contact">
+      <arg direction="in" name="Account" type="o" tp:type="Account">
+        <tp:docstring>
+        The object path for the TpAccount to which the contact belongs
+        </tp:docstring>
+      </arg>
+
+      <arg direction="in" name="Identifier" type="s">
+        <tp:docstring>
+        The favourite contact's identifier
+        </tp:docstring>
+      </arg>
+
+      <tp:docstring>
+        Remove a contact's designation as a favourite. This method may not be
+        called until the service is ready. See the <tp:dbus-ref
+        namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsReady</tp:dbus-ref> signal and <tp:dbus-ref
+        namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsIsReady</tp:dbus-ref> property.
+      </tp:docstring>
+    </method>
+
+    <signal name="FavouriteContactsChanged"
+      tp:name-for-bindings="Favourite_Contacts_Changed">
+      <tp:docstring>
+        The set of favourite contacts has changed.
+      </tp:docstring>
+
+      <arg name="Account" type="o" tp:type="Account">
+        <tp:docstring>
+          An account associated with the contact.
+        </tp:docstring>
+      </arg>
+
+      <arg name="Added" type="as">
+        <tp:docstring>
+        List of contact identifiers of contacts which are now favourites.
+        </tp:docstring>
+      </arg>
+
+      <arg name="Removed" type="as">
+        <tp:docstring>
+        List of contact identifiers of contacts which are no longer favourites.
+        </tp:docstring>
+      </arg>
+    </signal>
+
+  </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index fc77796..8ea05ae 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -13,7 +13,9 @@ EXTRA_DIST = \
     generic-types.xml \
     misc.xml \
     Debug.xml \
-    Channel_Interface_Conference.xml
+    Channel_Interface_Conference.xml \
+    Logger.xml \
+    $(NULL)
 
 noinst_LTLIBRARIES = libemp-extensions.la
 
@@ -114,7 +116,7 @@ _gen/cli-misc-body.h _gen/cli-misc.h: _gen/misc.xml \
 		--subclass=TpProxy \
 		--subclass-assert=TP_IS_PROXY \
 		--iface-quark-prefix=EMP_IFACE_QUARK \
-		--tp-proxy-api=0.7.6 \
+		--tp-proxy-api=0.10.0 \
 		$< Emp_Cli _gen/cli-misc
 
 _gen/svc-misc.c _gen/svc-misc.h: _gen/misc.xml \
diff --git a/extensions/all.xml b/extensions/all.xml
index 1def2fb..d0b9173 100644
--- a/extensions/all.xml
+++ b/extensions/all.xml
@@ -14,6 +14,8 @@
     from="Telepathy specification"/>
   <tp:external-type name="Handle" type="u"
     from="Telepathy specification"/>
+  <tp:external-type name="Account" type="o"
+    from="Telepathy specification"/>
 </tp:generic-types>
 
 
diff --git a/extensions/misc.xml b/extensions/misc.xml
index f866663..6fe06d8 100644
--- a/extensions/misc.xml
+++ b/extensions/misc.xml
@@ -6,5 +6,6 @@
 
 <xi:include href="Debug.xml" />
 <xi:include href="Channel_Interface_Conference.xml" />
+<xi:include href="Logger.xml" />
 
 </tp:spec>
diff --git a/libempathy-gtk/empathy-contact-list-store.c b/libempathy-gtk/empathy-contact-list-store.c
index c68edb1..ca77668 100644
--- a/libempathy-gtk/empathy-contact-list-store.c
+++ b/libempathy-gtk/empathy-contact-list-store.c
@@ -105,6 +105,10 @@ static void             contact_list_store_members_changed_cb        (EmpathyCon
 								      gchar                         *message,
 								      gboolean                       is_member,
 								      EmpathyContactListStore       *store);
+static void             contact_list_store_favourites_changed_cb     (EmpathyContactList            *list_iface,
+								      EmpathyContact                *contact,
+								      gboolean                       is_favourite,
+								      EmpathyContactListStore       *store);
 static void             contact_list_store_member_renamed_cb         (EmpathyContactList            *list_iface,
 								      EmpathyContact                *old_contact,
 								      EmpathyContact                *new_contact,
@@ -192,6 +196,10 @@ contact_list_store_iface_setup (gpointer user_data)
 			  G_CALLBACK (contact_list_store_members_changed_cb),
 			  store);
 	g_signal_connect (priv->list,
+			  "favourites-changed",
+			  G_CALLBACK (contact_list_store_favourites_changed_cb),
+			  store);
+	g_signal_connect (priv->list,
 			  "groups-changed",
 			  G_CALLBACK (contact_list_store_groups_changed_cb),
 			  store);
@@ -338,6 +346,9 @@ contact_list_store_dispose (GObject *object)
 					      G_CALLBACK (contact_list_store_members_changed_cb),
 					      object);
 	g_signal_handlers_disconnect_by_func (priv->list,
+					      G_CALLBACK (contact_list_store_favourites_changed_cb),
+					      object);
+	g_signal_handlers_disconnect_by_func (priv->list,
 					      G_CALLBACK (contact_list_store_groups_changed_cb),
 					      object);
 	g_object_unref (priv->list);
@@ -918,6 +929,43 @@ contact_list_store_members_changed_cb (EmpathyContactList      *list_iface,
 }
 
 static void
+contact_list_store_change_contact_favourite_status (EmpathyContactListStore *store,
+                                                    EmpathyContact          *contact,
+                                                    gboolean                 is_favourite)
+{
+        GList *iters, *l;
+
+	iters = contact_list_store_find_contact (store, contact);
+        for (l = iters; l; l = l->next) {
+		gtk_tree_store_set (GTK_TREE_STORE (store), l->data,
+                                    EMPATHY_CONTACT_LIST_STORE_COL_IS_FAVOURITE,
+                                    is_favourite,
+                                    -1);
+        }
+
+	g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
+	g_list_free (iters);
+}
+
+static void
+contact_list_store_favourites_changed_cb (EmpathyContactList      *list_iface,
+                                          EmpathyContact          *contact,
+                                          gboolean                 is_favourite,
+                                          EmpathyContactListStore *store)
+{
+	EmpathyContactListStorePriv *priv;
+
+	priv = GET_PRIV (store);
+
+	DEBUG ("Contact %s (%d) is %s a favourite",
+		empathy_contact_get_id (contact),
+		empathy_contact_get_handle (contact),
+		is_favourite ? "now" : "no longer");
+
+        contact_list_store_change_contact_favourite_status (store, contact, is_favourite);
+}
+
+static void
 contact_list_store_member_renamed_cb (EmpathyContactList      *list_iface,
 				      EmpathyContact          *old_contact,
 				      EmpathyContact          *new_contact,
@@ -1104,7 +1152,7 @@ list_store_contact_is_favourite (EmpathyContactListStore *store,
 
 	priv = GET_PRIV (store);
 
-	return empathy_contact_list_contact_is_favourite (priv->list, contact);
+	return empathy_contact_list_is_favourite (priv->list, contact);
 }
 
 static void
@@ -1483,17 +1531,20 @@ contact_list_store_state_sort_func (GtkTreeModel *model,
 	gint            ret_val = 0;
 	gchar          *name_a, *name_b;
 	gboolean        is_separator_a, is_separator_b;
+	gboolean        is_favourite_a, is_favourite_b;
 	EmpathyContact *contact_a, *contact_b;
 
 	gtk_tree_model_get (model, iter_a,
 			    EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_a,
 			    EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_a,
 			    EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, &is_separator_a,
+			    EMPATHY_CONTACT_LIST_STORE_COL_IS_FAVOURITE, &is_favourite_a,
 			    -1);
 	gtk_tree_model_get (model, iter_b,
 			    EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_b,
 			    EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_b,
 			    EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, &is_separator_b,
+			    EMPATHY_CONTACT_LIST_STORE_COL_IS_FAVOURITE, &is_favourite_b,
 			    -1);
 
 	/* Separator, favourites group, or other group? */
@@ -1503,14 +1554,10 @@ contact_list_store_state_sort_func (GtkTreeModel *model,
 		} else if (is_separator_b) {
                         ret_val = 1;
 		}
-#if HAVE_FAVOURITE_CONTACTS
-	} else if (!contact_a && !g_strcmp0 (name_a,
-				EMPATHY_GROUP_FAVOURITES)) {
+	} else if (is_favourite_a && !is_favourite_b) {
 		ret_val = -1;
-	} else if (!contact_b && !g_strcmp0 (name_b,
-				EMPATHY_GROUP_FAVOURITES)) {
+	} else if (!is_favourite_a && is_favourite_b) {
 		ret_val = 1;
-#endif /* HAVE_FAVOURITE_CONTACTS */
 	} else if (!contact_a && contact_b) {
 		ret_val = 1;
 	} else if (contact_a && !contact_b) {
@@ -1559,18 +1606,21 @@ contact_list_store_name_sort_func (GtkTreeModel *model,
 {
 	gchar         *name_a, *name_b;
 	EmpathyContact *contact_a, *contact_b;
-	gboolean       is_separator_a, is_separator_b;
+	gboolean       is_separator_a = FALSE, is_separator_b = FALSE;
+	gboolean       is_favourite_a, is_favourite_b;
 	gint           ret_val;
 
 	gtk_tree_model_get (model, iter_a,
 			    EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_a,
 			    EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_a,
 			    EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, &is_separator_a,
+			    EMPATHY_CONTACT_LIST_STORE_COL_IS_FAVOURITE, &is_favourite_a,
 			    -1);
 	gtk_tree_model_get (model, iter_b,
 			    EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_b,
 			    EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_b,
 			    EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, &is_separator_b,
+			    EMPATHY_CONTACT_LIST_STORE_COL_IS_FAVOURITE, &is_favourite_b,
 			    -1);
 
 	/* If contact is NULL it means it's a group. */
diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c
index 15d0926..b95f055 100644
--- a/libempathy-gtk/empathy-contact-list-view.c
+++ b/libempathy-gtk/empathy-contact-list-view.c
@@ -34,6 +34,7 @@
 #include <telepathy-glib/account-manager.h>
 #include <telepathy-glib/util.h>
 
+#include <extensions/extensions.h>
 #include <libempathy/empathy-call-factory.h>
 #include <libempathy/empathy-tp-contact-factory.h>
 #include <libempathy/empathy-contact-list.h>
@@ -840,13 +841,10 @@ contact_list_view_favourite_toggled_cb (
 		return;
 
         list = empathy_contact_list_store_get_list_iface (priv->store);
-
-        if (empathy_contact_list_contact_is_favourite (list, contact)) {
-                empathy_contact_list_remove_from_group (list, contact,
-                                EMPATHY_GROUP_FAVOURITES);
+        if (empathy_contact_list_is_favourite (list, contact)) {
+                empathy_contact_list_remove_from_favourites (list, contact);
         } else {
-                empathy_contact_list_add_to_group (list, contact,
-                                EMPATHY_GROUP_FAVOURITES);
+                empathy_contact_list_add_to_favourites (list, contact);
         }
 
 	g_object_unref (contact);
diff --git a/libempathy/empathy-contact-list.c b/libempathy/empathy-contact-list.c
index 611a40f..7bd0047 100644
--- a/libempathy/empathy-contact-list.c
+++ b/libempathy/empathy-contact-list.c
@@ -73,6 +73,15 @@ contact_list_base_init (gpointer klass)
 			      5, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT,
 			      G_TYPE_UINT, G_TYPE_STRING, G_TYPE_BOOLEAN);
 
+		g_signal_new ("favourites-changed",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      _empathy_marshal_VOID__OBJECT_BOOLEAN,
+			      G_TYPE_NONE,
+			      2, EMPATHY_TYPE_CONTACT, G_TYPE_BOOLEAN);
+
 		g_signal_new ("pendings-changed",
 			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
@@ -287,5 +296,3 @@ empathy_contact_list_remove_from_favourites (EmpathyContactList *list,
 	}
 #endif /* HAVE_FAVOURITE_CONTACTS */
 }
-
-
diff --git a/libempathy/empathy-contact-list.h b/libempathy/empathy-contact-list.h
index 080a895..6d9427d 100644
--- a/libempathy/empathy-contact-list.h
+++ b/libempathy/empathy-contact-list.h
@@ -73,6 +73,12 @@ struct _EmpathyContactListIface {
 			 (*get_monitor)       (EmpathyContactList *list);
 	EmpathyContactListFlags
 			 (*get_flags)         (EmpathyContactList *list);
+	gboolean         (*is_favourite)      (EmpathyContactList *list,
+					       EmpathyContact     *contact);
+	void             (*add_favourite)     (EmpathyContactList *list,
+					       EmpathyContact     *contact);
+	void             (*remove_favourite)  (EmpathyContactList *list,
+                                               EmpathyContact     *contact);
 };
 
 GType    empathy_contact_list_get_type          (void) G_GNUC_CONST;
@@ -104,9 +110,16 @@ EmpathyContactMonitor *
 EmpathyContactListFlags
          empathy_contact_list_get_flags		(EmpathyContactList *list);
 
-gboolean empathy_contact_list_contact_is_favourite
-                                        (EmpathyContactList *list,
-                                         EmpathyContact     *contact);
+gboolean empathy_contact_list_is_favourite      (EmpathyContactList *list,
+                                                 EmpathyContact     *contact);
+
+void     empathy_contact_list_add_to_favourites (EmpathyContactList *list,
+                                                 EmpathyContact     *contact);
+
+void     empathy_contact_list_remove_from_favourites
+                                                (EmpathyContactList *list,
+                                                 EmpathyContact     *contact);
+
 
 G_END_DECLS
 
diff --git a/libempathy/empathy-contact-manager.c b/libempathy/empathy-contact-manager.c
index ee3b705..255387b 100644
--- a/libempathy/empathy-contact-manager.c
+++ b/libempathy/empathy-contact-manager.c
@@ -25,6 +25,10 @@
 
 #include <telepathy-glib/account-manager.h>
 #include <telepathy-glib/enums.h>
+#include <telepathy-glib/proxy-subclass.h>
+#include <telepathy-glib/util.h>
+
+#include <extensions/extensions.h>
 
 #include "empathy-contact-manager.h"
 #include "empathy-contact-monitor.h"
@@ -39,6 +43,9 @@ typedef struct {
 	GHashTable     *lists;
 	TpAccountManager *account_manager;
 	EmpathyContactMonitor *contact_monitor;
+	TpProxy *logger;
+	GHashTable *favourites;
+	TpProxySignalConnection *favourite_contacts_changed_signal;
 } EmpathyContactManagerPriv;
 
 static void contact_manager_iface_init         (EmpathyContactListIface    *iface);
@@ -188,15 +195,161 @@ contact_manager_validity_changed_cb (TpAccountManager *account_manager,
 	}
 }
 
+static gboolean
+contact_manager_is_favourite (EmpathyContactList *manager,
+			      EmpathyContact     *contact)
+{
+	EmpathyContactManagerPriv *priv;
+	TpAccount *account;
+	const gchar *account_name;
+	GHashTable *contact_hash;
+
+	g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), FALSE);
+	g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
+
+	priv = GET_PRIV (manager);
+
+	account = empathy_contact_get_account (contact);
+	account_name = tp_proxy_get_object_path (TP_PROXY (account));
+	contact_hash = g_hash_table_lookup (priv->favourites, account_name);
+
+	if (contact_hash != NULL) {
+		const gchar *contact_id = empathy_contact_get_id (contact);
+
+		if (g_hash_table_lookup (contact_hash, contact_id) != NULL)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+contact_manager_add_favourite (EmpathyContactList *manager,
+                EmpathyContact *contact)
+{
+	EmpathyContactManagerPriv *priv;
+	TpAccount *account;
+	const gchar *account_name;
+
+	g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
+	g_return_if_fail (EMPATHY_IS_CONTACT (contact));
+
+	priv = GET_PRIV (manager);
+
+	account = empathy_contact_get_account (contact);
+	account_name = tp_proxy_get_object_path (TP_PROXY (account));
+
+	emp_cli_logger_call_add_favourite_contact (priv->logger, -1,
+						   account_name,
+						   empathy_contact_get_id (contact),
+						   NULL, NULL, NULL, NULL);
+}
+
+static void
+contact_manager_remove_favourite (EmpathyContactList *manager,
+                EmpathyContact *contact)
+{
+	EmpathyContactManagerPriv *priv;
+	TpAccount *account;
+	const gchar *account_name;
+
+	g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
+	g_return_if_fail (EMPATHY_IS_CONTACT (contact));
+
+	priv = GET_PRIV (manager);
+
+	account = empathy_contact_get_account (contact);
+	account_name = tp_proxy_get_object_path (TP_PROXY (account));
+
+	emp_cli_logger_call_remove_favourite_contact (priv->logger, -1,
+						      account_name,
+						      empathy_contact_get_id (contact),
+						      NULL, NULL, NULL, NULL);
+}
+
+static void
+logger_favourite_contacts_add_from_value_array (GValueArray           *va,
+                                                EmpathyContactManager *manager)
+{
+	EmpathyContactManagerPriv *priv = GET_PRIV (manager);
+	guint i;
+
+	for (i = 0; i < va->n_values; i++) {
+		GValue *account_value;
+		const gchar *account;
+		GValue *contacts_value;
+		gchar **contacts;
+		guint j;
+		GHashTable *contact_hash;
+
+		account_value = g_value_array_get_nth (va, 0);
+		contacts_value = g_value_array_get_nth (va, 1);
+
+		account = g_value_get_boxed (account_value);
+		contacts = g_value_get_boxed (contacts_value);
+
+		contact_hash = g_hash_table_lookup (priv->favourites, account);
+		if (contact_hash == NULL) {
+			contact_hash = g_hash_table_new_full (g_str_hash,
+							      g_str_equal,
+							      g_free, NULL);
+			g_hash_table_insert (priv->favourites,
+					     g_strdup (account),
+					     g_hash_table_ref (contact_hash));
+		}
+
+		for (j = 0; contacts && contacts[j] != NULL; j++) {
+			g_hash_table_insert (contact_hash,
+					     g_strdup (contacts[j]),
+					     GINT_TO_POINTER (1));
+		}
+	}
+}
+
+static void
+logger_favourite_contacts_get_cb (TpProxy         *proxy,
+				  const GPtrArray *result,
+				  const GError    *error,
+				  gpointer         user_data,
+				  GObject         *weak_object)
+{
+	EmpathyContactManager *manager = EMPATHY_CONTACT_MANAGER (user_data);
+
+	if (error == NULL) {
+		g_ptr_array_foreach ((GPtrArray*) result,
+				(GFunc)
+				logger_favourite_contacts_add_from_value_array,
+				manager);
+	} else {
+		DEBUG ("Failed to get the FavouriteContacts property: %s",
+				error->message);
+	}
+}
+
+static void
+logger_favourite_contacts_setup (EmpathyContactManager *manager)
+{
+	EmpathyContactManagerPriv *priv = GET_PRIV (manager);
+
+	emp_cli_logger_call_get_favourite_contacts (priv->logger, -1,
+			logger_favourite_contacts_get_cb, manager, NULL,
+			G_OBJECT (manager));
+}
+
 static void
 contact_manager_finalize (GObject *object)
 {
 	EmpathyContactManagerPriv *priv = GET_PRIV (object);
 
+	tp_proxy_signal_connection_disconnect (priv->favourite_contacts_changed_signal);
+
+	g_object_unref (priv->logger);
+
 	g_hash_table_foreach (priv->lists,
 			      contact_manager_disconnect_foreach,
 			      object);
 	g_hash_table_destroy (priv->lists);
+	g_hash_table_destroy (priv->favourites);
 
 	g_object_unref (priv->account_manager);
 
@@ -291,22 +444,157 @@ account_manager_prepared_cb (GObject *source_object,
 			     G_OBJECT (manager));
 }
 
+static EmpathyContact *
+contact_manager_lookup_contact (EmpathyContactManager *manager,
+                                const gchar           *account_name,
+                                const gchar           *contact_id)
+{
+	EmpathyContact *retval = NULL;
+	GList *members, *l;
+
+	/* XXX: any more efficient way to do this (other than having to build
+	 * and maintain a hash)? */
+	members = empathy_contact_list_get_members (
+			EMPATHY_CONTACT_LIST (manager));
+	for (l = members; l; l = l->next) {
+		EmpathyContact *contact = l->data;
+		TpAccount *account = empathy_contact_get_account (contact);
+		const gchar *id_cur;
+		const gchar *name_cur;
+
+		id_cur = empathy_contact_get_id (contact);
+		name_cur = tp_proxy_get_object_path (TP_PROXY (account));
+
+		if (!tp_strdiff (contact_id, id_cur) &&
+			!tp_strdiff (account_name, name_cur)) {
+			retval = contact;
+			break;
+		}
+	}
+
+	g_list_free (members);
+
+	return retval;
+}
+
+static void
+logger_favourite_contacts_changed_cb (TpProxy      *proxy,
+                                      const gchar  *account_name,
+                                      const gchar **added,
+                                      const gchar **removed,
+                                      gpointer      user_data,
+                                      GObject      *weak_object)
+{
+	EmpathyContactManagerPriv *priv;
+	EmpathyContactManager *manager = EMPATHY_CONTACT_MANAGER (weak_object);
+	GHashTable *contact_hash;
+	EmpathyContact *contact;
+	gint i;
+
+	priv = GET_PRIV (manager);
+
+	contact_hash = g_hash_table_lookup (priv->favourites, account_name);
+
+	/* XXX: note that, at the time of this comment, there will always be
+	 * exactly one contact amongst added and removed, so the linear lookup
+	 * of each contact isn't as painful as it appears */
+
+	for (i = 0; added && added[i]; i++) {
+		if (contact_hash == NULL) {
+			contact_hash = g_hash_table_new_full (g_str_hash,
+							      g_str_equal,
+							      g_free, NULL);
+			g_hash_table_insert (priv->favourites,
+					     g_strdup (account_name),
+					     g_hash_table_ref (contact_hash));
+		}
+
+		g_hash_table_insert (contact_hash, g_strdup (added[i]),
+				     GINT_TO_POINTER (1));
+
+		contact = contact_manager_lookup_contact (manager, account_name,
+							  added[i]);
+		if (contact != NULL)
+			g_signal_emit_by_name (manager, "favourites-changed",
+					       contact, TRUE);
+		else
+			DEBUG ("failed to find contact for account %s, contact "
+			       "id %s", account_name, added[i]);
+	}
+
+	for (i = 0; removed && removed[i]; i++) {
+		contact_hash = g_hash_table_lookup (priv->favourites,
+						    account_name);
+
+		if (contact_hash != NULL) {
+			g_hash_table_remove (contact_hash, removed[i]);
+
+			if (g_hash_table_size (contact_hash) < 1) {
+				g_hash_table_remove (priv->favourites,
+						     account_name);
+			}
+		}
+
+		contact = contact_manager_lookup_contact (manager, account_name,
+							  removed[i]);
+		if (contact != NULL)
+			g_signal_emit_by_name (manager, "favourites-changed",
+					       contact, FALSE);
+		else
+			DEBUG ("failed to find contact for account %s, contact "
+			       "id %s", account_name, removed[i]);
+	}
+}
+
 static void
 empathy_contact_manager_init (EmpathyContactManager *manager)
 {
 	EmpathyContactManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
 		EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv);
+	TpDBusDaemon *bus;
+	GError *error = NULL;
 
 	manager->priv = priv;
 	priv->lists = g_hash_table_new_full (empathy_proxy_hash,
 					     empathy_proxy_equal,
 					     (GDestroyNotify) g_object_unref,
 					     (GDestroyNotify) g_object_unref);
+        priv->favourites = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                  (GDestroyNotify) g_free,
+                                                  (GDestroyNotify)
+                                                        g_hash_table_unref);
 	priv->account_manager = tp_account_manager_dup ();
 	priv->contact_monitor = NULL;
 
 	tp_account_manager_prepare_async (priv->account_manager, NULL,
 	    account_manager_prepared_cb, manager);
+
+	bus = tp_dbus_daemon_dup (&error);
+
+	if (error == NULL) {
+		priv->logger = g_object_new (TP_TYPE_PROXY,
+				"bus-name", "org.freedesktop.Telepathy.Logger",
+				"object-path",
+					"/org/freedesktop/Telepathy/Logger",
+				"dbus-daemon", bus,
+				NULL);
+		g_object_unref (bus);
+
+		tp_proxy_add_interface_by_id (priv->logger,
+				EMP_IFACE_QUARK_LOGGER);
+
+		logger_favourite_contacts_setup (manager);
+
+		priv->favourite_contacts_changed_signal =
+			emp_cli_logger_connect_to_favourite_contacts_changed (
+				priv->logger,
+				logger_favourite_contacts_changed_cb, NULL,
+				NULL, G_OBJECT (manager), NULL);
+	} else {
+		DEBUG ("Failed to get telepathy-logger proxy: %s",
+				error->message);
+		g_clear_error (&error);
+	}
 }
 
 EmpathyContactManager *
@@ -590,6 +878,9 @@ contact_manager_iface_init (EmpathyContactListIface *iface)
 	iface->remove_from_group = contact_manager_remove_from_group;
 	iface->rename_group      = contact_manager_rename_group;
 	iface->remove_group	 = contact_manager_remove_group;
+	iface->is_favourite      = contact_manager_is_favourite;
+	iface->remove_favourite  = contact_manager_remove_favourite;
+	iface->add_favourite     = contact_manager_add_favourite;
 }
 
 EmpathyContactListFlags



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]