commit eb226464c13cf505aad01e93e871dcaf892ef8ad
Author: Tristan Van Berkom <tristan.van.berkom@gmail.com>
Date:   Sun Jun 26 12:05:54 2011 -0400

    Handle fields-of-interest for the UID field in the file backend.
    
    This patch modifies the local file addressbook backend to notify
    with shallow vcards bearing only the UID if
    e_book_client_view_set_fields_of_interest() has been called with
    only the UID field requested.
    
    Additionally, the patch adds a filtering algorithm in
    e_book_backend_notify_update() to automatically filter vcard
    notifications in response to a client adding or modifying a contact.

diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index 596c829..773b758 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -633,6 +633,46 @@ get_closure (EDataBookView *book_view)
 	return g_object_get_data (G_OBJECT (book_view), "EBookBackendFile.BookView::closure");
 }
 
+static void
+notify_update_vcard (EDataBookView *book_view,
+		     gboolean       uid_only,
+		     gboolean       prefiltered,
+		     const gchar   *id,
+		     const gchar   *vcard)
+{
+	gchar *final_vcard;
+
+	if (uid_only) {
+		/* Create a shallow version of the contacts for views that are
+		 * only interested in the uid. */
+		EContact *shallow = e_contact_new ();
+
+		e_contact_set (shallow, E_CONTACT_UID, id);
+		final_vcard = e_vcard_to_string (E_VCARD (shallow), EVC_FORMAT_VCARD_30);
+		g_object_unref (shallow);
+	} else {
+		final_vcard = g_strdup (vcard);
+	}
+
+	if (prefiltered)
+		e_data_book_view_notify_update_prefiltered_vcard (book_view, id, final_vcard);
+	else
+		e_data_book_view_notify_update_vcard (book_view, final_vcard);
+}
+
+static gboolean
+view_wants_uid_only (EDataBookView *book_view)
+{
+	GHashTable *fields = e_data_book_view_get_fields_of_interest (book_view);
+
+	if (fields &&
+	    g_hash_table_size (fields) == 1 &&
+	    g_hash_table_lookup (fields, e_contact_field_name (E_CONTACT_UID)))
+	    return TRUE;
+
+	return FALSE;
+}
+
 static gpointer
 book_view_thread (gpointer data)
 {
@@ -643,7 +683,7 @@ book_view_thread (gpointer data)
 	DB  *db;
 	DBT id_dbt, vcard_dbt;
 	gint db_error;
-	gboolean allcontacts;
+	gboolean allcontacts, uid_only;
 
 	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (data), NULL);
 
@@ -672,6 +712,9 @@ book_view_thread (gpointer data)
 		allcontacts = FALSE;
 	}
 
+	/* Check if the view only wants UID in the fields-of-interest */
+	uid_only = view_wants_uid_only (book_view);
+
 	d(printf ("signalling parent thread\n"));
 	e_flag_set (closure->running);
 
@@ -689,6 +732,11 @@ book_view_thread (gpointer data)
 			if (!e_flag_is_set (closure->running))
 				break;
 
+			if (uid_only) {
+				notify_update_vcard (book_view, uid_only, TRUE, id, NULL);
+				continue;
+			}
+
 			string_to_dbt (id, &id_dbt);
 			memset (&vcard_dbt, 0, sizeof (vcard_dbt));
 			vcard_dbt.flags = DB_DBT_MALLOC;
@@ -696,7 +744,7 @@ book_view_thread (gpointer data)
 			db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
 
 			if (db_error == 0) {
-				e_data_book_view_notify_update_prefiltered_vcard (book_view, id, vcard_dbt.data);
+				notify_update_vcard (book_view, uid_only, TRUE, id, vcard_dbt.data);
 			}
 			else {
 				g_warning (G_STRLOC ": db->get failed with %s", db_strerror (db_error));
@@ -724,10 +772,8 @@ book_view_thread (gpointer data)
 
 				/* don't include the version in the list of cards */
 				if (strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) {
-					if (allcontacts)
-						e_data_book_view_notify_update_prefiltered_vcard (book_view, id_dbt.data, vcard_dbt.data);
-					else
-						e_data_book_view_notify_update_vcard (book_view, vcard_dbt.data);
+					notify_update_vcard (book_view, uid_only, allcontacts, 
+							     id_dbt.data, vcard_dbt.data);
 				} else {
 					g_free (vcard_dbt.data);
 				}
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c
index 358f489..8850106 100644
--- a/addressbook/libedata-book/e-book-backend.c
+++ b/addressbook/libedata-book/e-book-backend.c
@@ -804,7 +804,9 @@ e_book_backend_remove_client (EBookBackend *backend,
  * @callback returns %FALSE to stop further processing.
  **/
 void
-e_book_backend_foreach_view (EBookBackend *backend, gboolean (* callback) (EDataBookView *view, gpointer user_data), gpointer user_data)
+e_book_backend_foreach_view (EBookBackend *backend, 
+			     gboolean (* callback) (EDataBookView *view, gpointer user_data), 
+			     gpointer user_data)
 {
 	const GSList *views;
 	EDataBookView *view;
@@ -1026,10 +1028,59 @@ e_book_backend_sync (EBookBackend *backend)
 
 
 
+
+typedef struct {	
+	EContact   *contact;
+	EContact   *shallow;
+} FilterContactData;
+
+static void
+foreach_filter_contact (const gchar       *field,
+			gpointer           present,
+			FilterContactData *data)
+{
+	GList          *attributes;
+	EContactField   field_id;
+
+	field_id   = e_contact_field_id (field);
+	attributes = e_contact_get_attributes (data->contact, field_id);
+
+	if (attributes)
+		e_contact_set_attributes (data->shallow, field_id, attributes);
+
+	g_list_foreach (attributes, (GFunc)e_vcard_attribute_free, NULL);
+	g_list_free (attributes);
+}
+
 static gboolean
-view_notify_update (EDataBookView *view, gpointer contact)
+view_notify_update (EDataBookView *view, gpointer data)
 {
-	e_data_book_view_notify_update (view, contact);
+	EContact   *contact = data;
+	GHashTable *fields;
+
+	fields = e_data_book_view_get_fields_of_interest (view);
+	if (fields && g_hash_table_size (fields) > 0) {
+		FilterContactData data = { 0, };
+		EContact         *shallow = e_contact_new ();
+		gchar            *vcard;
+
+
+		/* Set the UID unconditionally */
+		e_contact_set (shallow, E_CONTACT_UID, e_contact_get_const (contact, E_CONTACT_UID));
+
+		/* Transfer any attributes for the fields-of-interest */
+		data.contact = contact;
+		data.shallow = shallow;
+		g_hash_table_foreach (fields, (GHFunc)foreach_filter_contact, &data);
+
+		vcard = e_vcard_to_string (E_VCARD (shallow), EVC_FORMAT_VCARD_30);
+		g_object_unref (shallow);
+
+		/* Notify with a stripped vcard holding only the fields-of-interest */
+		e_data_book_view_notify_update_vcard (view, vcard);
+	} else {
+		e_data_book_view_notify_update (view, contact);
+	}
 
 	return TRUE;
 }
