[evolution-data-server] addressbook: Optimizations to avoid vcard parsing



commit 124fe0e1e377103c31f120e2f8b4d0abb47db750
Author: Christophe Dumez <christophe dumez intel com>
Date:   Wed Sep 21 15:57:41 2011 +0300

    addressbook: Optimizations to avoid vcard parsing
    
    Now that vcards are lazily parsed, it makes sense to optimize
    the rest of the code to avoid vcard parsing as much as possible.
    
    In particular, it is now possible the pass the vcard UID when
    constructing an EVCard object by using e_vcard_construct_with_uid().
    This will avoid useless vcard parsing whenever getting the vcard
    UID later. Moreover, setting the UID attribute on a EContact no
    longer requires vcard parsing.

 addressbook/backends/file/e-book-backend-file.c    |   11 +--
 addressbook/backends/vcf/e-book-backend-vcf.c      |    3 +-
 .../backends/webdav/e-book-backend-webdav.c        |   12 +--
 addressbook/libebook/e-book-client-view.c          |   10 +-
 addressbook/libebook/e-book-client.c               |    2 +-
 addressbook/libebook/e-book-view.c                 |   10 +-
 addressbook/libebook/e-book.c                      |    2 +-
 addressbook/libebook/e-contact.c                   |  109 ++++++++++++--------
 addressbook/libebook/e-contact.h                   |    1 +
 addressbook/libebook/e-vcard.c                     |  107 ++++++++++++++++---
 addressbook/libebook/e-vcard.h                     |    2 +
 addressbook/libedata-book/e-book-backend-cache.c   |    2 +-
 .../libedata-book/e-book-backend-db-cache.c        |    2 +-
 .../libedata-book/e-book-backend-sqlitedb.c        |    2 +-
 addressbook/libedata-book/e-data-book-view.c       |   33 ++++---
 addressbook/libedata-book/e-data-book-view.h       |    2 +-
 16 files changed, 207 insertions(+), 103 deletions(-)
---
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index 7f2f330..0e889f8 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -170,11 +170,7 @@ static EContact *
 create_contact (const gchar *uid,
                 const gchar *vcard)
 {
-	EContact *contact = e_contact_new_from_vcard (vcard);
-	if (!e_contact_get_const (contact, E_CONTACT_UID))
-		e_contact_set (contact, E_CONTACT_UID, uid);
-
-	return contact;
+	return e_contact_new_from_vcard_with_uid (vcard, uid);
 }
 
 static gchar *
@@ -320,8 +316,7 @@ do_create (EBookBackendFile *bf,
 
 	string_to_dbt (id, &id_dbt);
 
-	*contact = e_contact_new_from_vcard (vcard_req);
-	e_contact_set (*contact, E_CONTACT_UID, id);
+	*contact = e_contact_new_from_vcard_with_uid (vcard_req, id);
 	rev = e_contact_get_const (*contact,  E_CONTACT_REV);
 	if (!(rev && *rev))
 		set_revision (*contact);
@@ -779,7 +774,7 @@ notify_update_vcard (EDataBookView *book_view,
 	if (prefiltered)
 		e_data_book_view_notify_update_prefiltered_vcard (book_view, id, vcard);
 	else
-		e_data_book_view_notify_update_vcard (book_view, vcard);
+		e_data_book_view_notify_update_vcard (book_view, id, vcard);
 }
 
 static gpointer
diff --git a/addressbook/backends/vcf/e-book-backend-vcf.c b/addressbook/backends/vcf/e-book-backend-vcf.c
index ff92b8c..48b8aac 100644
--- a/addressbook/backends/vcf/e-book-backend-vcf.c
+++ b/addressbook/backends/vcf/e-book-backend-vcf.c
@@ -246,8 +246,7 @@ do_create (EBookBackendVCF *bvcf,
 	g_mutex_lock (bvcf->priv->mutex);
 	id = e_book_backend_vcf_create_unique_id ();
 
-	contact = e_contact_new_from_vcard (vcard_req);
-	e_contact_set (contact, E_CONTACT_UID, id);
+	contact = e_contact_new_from_vcard_with_uid (vcard_req, id);
 	g_free (id);
 
 	rev = e_contact_get_const (contact,  E_CONTACT_REV);
diff --git a/addressbook/backends/webdav/e-book-backend-webdav.c b/addressbook/backends/webdav/e-book-backend-webdav.c
index 0a40fa8..a399441 100644
--- a/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -168,16 +168,15 @@ download_contact (EBookBackendWebdav *webdav,
 
 	etag = soup_message_headers_get(message->response_headers, "ETag");
 
-	contact = e_contact_new_from_vcard (message->response_body->data);
+	/* we use our URI as UID */
+	contact = e_contact_new_from_vcard_with_uid (message->response_body->data, uri);
 	if (contact == NULL) {
 		g_warning("Invalid vcard at '%s'", uri);
 		g_object_unref (message);
 		return NULL;
 	}
 
-	/* we use our URI as UID
-	 * the etag is rememebered in the revision field */
-	e_contact_set (contact, E_CONTACT_UID, (gconstpointer) uri);
+	/* the etag is remembered in the revision field */
 	if (etag != NULL) {
 		e_contact_set (contact, E_CONTACT_REV, (gconstpointer) etag);
 	}
@@ -320,13 +319,12 @@ e_book_backend_webdav_create_contact (EBookBackend *backend,
 		return;
 	}
 
-	contact = e_contact_new_from_vcard (vcard);
-
 	/* do 3 rand() calls to construct a unique ID... poor way but should be
 	 * good enough for us */
 	uid = g_strdup_printf("%s%08X-%08X-%08X.vcf", priv->uri, rand(), rand(),
 			      rand ());
-	e_contact_set (contact, E_CONTACT_UID, uid);
+			      
+	contact = e_contact_new_from_vcard_with_uid (vcard, uid);
 
 	/* kill revision field (might have been set by some other backend) */
 	e_contact_set (contact, E_CONTACT_REV, NULL);
diff --git a/addressbook/libebook/e-book-client-view.c b/addressbook/libebook/e-book-client-view.c
index 6e1b096..6ec3633 100644
--- a/addressbook/libebook/e-book-client-view.c
+++ b/addressbook/libebook/e-book-client-view.c
@@ -63,8 +63,9 @@ objects_added_cb (EGdbusBookView *object,
 	if (!view->priv->running)
 		return;
 
-	for (p = vcards; *p; p++) {
-		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (*p));
+	/* array contains both UID and vcard */
+	for (p = vcards; *p; p += 2) {
+		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
 	}
 
 	contacts = g_slist_reverse (contacts);
@@ -86,8 +87,9 @@ objects_modified_cb (EGdbusBookView *object,
 	if (!view->priv->running)
 		return;
 
-	for (p = vcards; *p; p++) {
-		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (*p));
+	/* array contains both UID and vcard */
+	for (p = vcards; *p; p += 2) {
+		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
 	}
 	contacts = g_slist_reverse (contacts);
 
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index af19914..90df80e 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -1910,7 +1910,7 @@ e_book_client_get_contact_sync (EBookClient *client,
 	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), safe_uid, &vcard, cancellable, error, e_gdbus_book_call_get_contact_sync);
 
 	if (vcard && res)
-		*contact = e_contact_new_from_vcard (vcard);
+		*contact = e_contact_new_from_vcard_with_uid (vcard, safe_uid);
 	else
 		*contact = NULL;
 
diff --git a/addressbook/libebook/e-book-view.c b/addressbook/libebook/e-book-view.c
index e6c00d6..4305f82 100644
--- a/addressbook/libebook/e-book-view.c
+++ b/addressbook/libebook/e-book-view.c
@@ -58,8 +58,9 @@ objects_added_cb (EGdbusBookView *object,
 	if (!book_view->priv->running)
 		return;
 
-	for (p = vcards; *p; p++) {
-		contacts = g_list_prepend (contacts, e_contact_new_from_vcard (*p));
+	/* array contains both UID and vcard */
+	for (p = vcards; *p; p += 2) {
+		contacts = g_list_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
 	}
 
 	contacts = g_list_reverse (contacts);
@@ -81,8 +82,9 @@ objects_modified_cb (EGdbusBookView *object,
 	if (!book_view->priv->running)
 		return;
 
-	for (p = vcards; *p; p++) {
-		contacts = g_list_prepend (contacts, e_contact_new_from_vcard (*p));
+	/* array contains both UID and vcard */
+	for (p = vcards; *p; p += 2) {
+		contacts = g_list_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
 	}
 	contacts = g_list_reverse (contacts);
 
diff --git a/addressbook/libebook/e-book.c b/addressbook/libebook/e-book.c
index 6eb11a1..5f4f525 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -1400,7 +1400,7 @@ e_book_get_contact (EBook *book,
 	g_free (gdbus_id);
 
 	if (vcard) {
-		*contact = e_contact_new_from_vcard (vcard);
+		*contact = e_contact_new_from_vcard_with_uid (vcard, id);
 		g_free (vcard);
 	}
 
diff --git a/addressbook/libebook/e-contact.c b/addressbook/libebook/e-contact.c
index b9fdf41..943f3b0 100644
--- a/addressbook/libebook/e-contact.c
+++ b/addressbook/libebook/e-contact.c
@@ -387,27 +387,6 @@ e_contact_init (EContact *ec)
 	ec->priv = g_new0 (EContactPrivate, 1);
 }
 
-static EVCardAttribute *
-e_contact_get_first_attr (EContact *contact,
-                          const gchar *attr_name)
-{
-	GList *attrs, *l;
-
-	attrs = e_vcard_get_attributes (E_VCARD (contact));
-
-	for (l = attrs; l; l = l->next) {
-		EVCardAttribute *attr = l->data;
-		const gchar *name;
-
-		name = e_vcard_attribute_get_name (attr);
-
-		if (!g_ascii_strcasecmp (name, attr_name))
-			return attr;
-	}
-
-	return NULL;
-}
-
 
 
 static gpointer
@@ -548,7 +527,7 @@ fn_setter (EContact *contact,
 
 	e_vcard_attribute_add_value (attr, name_str);
 
-	attr = e_contact_get_first_attr (contact, EVC_N);
+	attr = e_vcard_get_attribute (E_VCARD (contact), EVC_N);
 	if (!attr) {
 		EContactName *name = e_contact_name_from_string ((gchar *) data);
 
@@ -647,7 +626,7 @@ n_getter (EContact *contact,
 		name->suffixes   = g_strdup (p && p->data ? p->data : "");
 	}
 
-	new_attr = e_contact_get_first_attr (contact, EVC_FN);
+	new_attr = e_vcard_get_attribute (E_VCARD (contact), EVC_FN);
 	if (!new_attr) {
 		new_attr = e_vcard_attribute_new (NULL, EVC_FN);
 		e_vcard_append_attribute (E_VCARD (contact), new_attr);
@@ -673,7 +652,7 @@ n_setter (EContact *contact,
 	e_vcard_attribute_add_value (attr, name->suffixes ? name->suffixes : "");
 
 	/* now find the attribute for FileAs.  if it's not present, fill it in */
-	attr = e_contact_get_first_attr (contact, EVC_X_FILE_AS);
+	attr = e_vcard_get_attribute (E_VCARD (contact), EVC_X_FILE_AS);
 	if (!attr) {
 		gchar *strings[3], **stringptr;
 		gchar *string;
@@ -1010,7 +989,7 @@ e_contact_set_property (GObject *object,
 			}
 		}
 		else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) {
-			EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+			EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 			GList *values;
 			GList *p;
 			const gchar *sval = g_value_get_string (value);
@@ -1045,7 +1024,7 @@ e_contact_set_property (GObject *object,
 		else {
 			switch (info->field_id) {
 			case E_CONTACT_CATEGORIES: {
-				EVCardAttribute *attr = e_contact_get_first_attr (contact, EVC_CATEGORIES);
+				EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), EVC_CATEGORIES);
 				gchar **split, **s;
 				const gchar *str;
 
@@ -1082,7 +1061,7 @@ e_contact_set_property (GObject *object,
 		}
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT || info->t & E_CONTACT_FIELD_TYPE_GETSET) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 		gpointer data = info->t & E_CONTACT_FIELD_TYPE_STRUCT ? g_value_get_boxed (value) : (gchar *) g_value_get_string (value);
 
 		if (attr) {
@@ -1116,7 +1095,7 @@ e_contact_set_property (GObject *object,
 		EVCardAttribute *attr;
 
 		/* first we search for an attribute we can overwrite */
-		attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 		if (attr) {
 			d(printf ("setting %s to `%s'\n", info->vcard_field_name, g_value_get_string (value)));
 			e_vcard_attribute_remove_values (attr);
@@ -1134,7 +1113,16 @@ e_contact_set_property (GObject *object,
 		const gchar *sval = g_value_get_string (value);
 
 		/* first we search for an attribute we can overwrite */
-		attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		if (sval == NULL || g_ascii_strcasecmp (info->vcard_field_name, EVC_UID) != 0) {
+			attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
+		} else {
+			/* Avoid useless vcard parsing when trying to set a new non-empty UID.
+			 * Parsing the vcard is pointless in this particular case because even
+			 * if there is a UID in the unparsed vcard, it is going to be ignored
+			 * upon parsing if we already have a UID for the vcard */
+			attr = e_vcard_get_attribute_if_parsed (E_VCARD (contact), EVC_UID);
+		}
+
 		if (attr) {
 			d(printf ("setting %s to `%s'\n", info->vcard_field_name, sval));
 			e_vcard_attribute_remove_values (attr);
@@ -1152,7 +1140,7 @@ e_contact_set_property (GObject *object,
 			/* and if we don't find one we create a new attribute */
 			e_vcard_append_attribute_with_value (E_VCARD (contact),
 							  e_vcard_attribute_new (NULL, info->vcard_field_name),
-							  g_value_get_string (value));
+							  sval);
 		}
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
@@ -1161,7 +1149,7 @@ e_contact_set_property (GObject *object,
 
 		values = g_value_get_pointer (value);
 
-		attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 
 		if (attr) {
 			e_vcard_attribute_remove_values (attr);
@@ -1326,6 +1314,27 @@ e_contact_new_from_vcard (const gchar *vcard)
 }
 
 /**
+ * e_contact_new_from_vcard_with_uid:
+ * @vcard: a string representing a vcard
+ * @uid: a contact UID
+ *
+ * Creates a new #EContact based on a vcard and a predefined UID.
+ *
+ * Returns: A new #EContact.
+ **/
+EContact *
+e_contact_new_from_vcard_with_uid (const gchar *vcard, const gchar *uid)
+{
+	EContact *contact;
+	g_return_val_if_fail (vcard != NULL, NULL);
+
+	contact = g_object_new (E_TYPE_CONTACT, NULL);
+	e_vcard_construct_with_uid (E_VCARD (contact), vcard, uid);
+
+	return contact;
+}
+
+/**
  * e_contact_duplicate:
  * @contact: an #EContact
  *
@@ -1471,7 +1480,7 @@ e_contact_get (EContact *contact,
 	info = &field_info[field_id];
 
 	if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 		gboolean rv = FALSE;
 
 		if (attr) {
@@ -1481,7 +1490,7 @@ e_contact_get (EContact *contact,
 		}
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 
 		if (attr) {
 			GList *list = g_list_copy (e_vcard_attribute_get_values (attr));
@@ -1493,7 +1502,7 @@ e_contact_get (EContact *contact,
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) {
 		if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
-			EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+			EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 
 			if (attr) {
 				GList *v;
@@ -1546,12 +1555,12 @@ e_contact_get (EContact *contact,
 
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 		if (attr)
 			return info->struct_getter (contact, attr);
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_GETSET) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
 		gpointer rv = NULL;
 
 		rv = info->struct_getter (contact, attr);
@@ -1585,7 +1594,7 @@ e_contact_get (EContact *contact,
 			return str ? g_strstrip (g_strdup (str)) : NULL;
 		}
 		case E_CONTACT_CATEGORIES: {
-			EVCardAttribute *attr = e_contact_get_first_attr (contact, EVC_CATEGORIES);
+			EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), EVC_CATEGORIES);
 			gchar *rv = NULL;
 
 			if (attr) {
@@ -1607,6 +1616,25 @@ e_contact_get (EContact *contact,
 			break;
 		}
 	}
+	else if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
+		EVCardAttribute *attr;
+		const char *cv = NULL;
+		GList *v = NULL;
+		
+		/* Do our best to avoid vcard parsing by not calling
+		 * e_vcard_get_attributes */
+
+		cv = contact->priv->cached_strings[field_id];
+		if (cv)
+			return g_strdup (cv);
+
+		attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
+
+		if (attr)
+			v = e_vcard_attribute_get_values (attr);
+
+		return ((v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL);
+	}
 	else {
 		GList *attrs, *l;
 		GList *rv = NULL; /* used for multi attribute lists */
@@ -1623,12 +1651,7 @@ e_contact_get (EContact *contact,
 				GList *v;
 				v = e_vcard_attribute_get_values (attr);
 
-				if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
-					return (v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL;
-				}
-				else {
-					rv = g_list_append (rv, (v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL);
-				}
+				rv = g_list_append (rv, (v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL);
 			}
 		}
 		return rv;
diff --git a/addressbook/libebook/e-contact.h b/addressbook/libebook/e-contact.h
index bd65ce4..cdc1fe7 100644
--- a/addressbook/libebook/e-contact.h
+++ b/addressbook/libebook/e-contact.h
@@ -311,6 +311,7 @@ GType                   e_contact_get_type (void);
 
 EContact *               e_contact_new              (void);
 EContact *               e_contact_new_from_vcard   (const gchar *vcard);
+EContact *               e_contact_new_from_vcard_with_uid (const gchar *vcard, const gchar *uid);
 
 EContact *               e_contact_duplicate        (EContact *contact);
 
diff --git a/addressbook/libebook/e-vcard.c b/addressbook/libebook/e-vcard.c
index 712549d..7ba41d7 100644
--- a/addressbook/libebook/e-vcard.c
+++ b/addressbook/libebook/e-vcard.c
@@ -614,7 +614,8 @@ make_valid_utf8 (const gchar *name)
  */
 static void
 parse (EVCard *evc,
-       const gchar *str)
+       const gchar *str,
+       gboolean ignore_uid)
 {
 	gchar *buf;
 	gchar *p;
@@ -636,19 +637,23 @@ parse (EVCard *evc,
 	if (attr && !g_ascii_strcasecmp (attr->name, "begin")) {
 		e_vcard_attribute_free (attr);
 		attr = NULL;
-	} else if (attr)
-		e_vcard_add_attribute (evc, attr);
-
+	} else if (attr) {
+		if (!ignore_uid || g_ascii_strcasecmp (attr->name, EVC_UID) != 0)
+			e_vcard_add_attribute (evc, attr);
+	}
 	while (*p) {
 		EVCardAttribute *next_attr = read_attribute (&p);
 
 		if (next_attr) {
 			attr = next_attr;
 
-			if (g_ascii_strcasecmp (next_attr->name, "end"))
-				e_vcard_add_attribute (evc, next_attr);
-			else
+			if (g_ascii_strcasecmp (next_attr->name, "end") == 0)
 				break;
+			
+			if (ignore_uid && g_ascii_strcasecmp (attr->name, EVC_UID) == 0)
+				continue;
+				
+			e_vcard_add_attribute (evc, next_attr);
 		}
 	}
 
@@ -668,13 +673,14 @@ static GList *
 e_vcard_ensure_attributes (EVCard *evc)
 {
 	if (evc->priv->vcard) {
+		gboolean have_uid = (evc->priv->attributes != NULL);
 		gchar *vcs = evc->priv->vcard;
 
 		/* detach vCard to avoid loops */
 		evc->priv->vcard = NULL;
 
 		/* Parse the vCard */
-		parse (evc, vcs);
+		parse (evc, vcs, have_uid);
 		g_free (vcs);
 	}
 
@@ -776,6 +782,14 @@ void
 e_vcard_construct (EVCard *evc,
                    const gchar *str)
 {
+	e_vcard_construct_with_uid (evc, str, NULL);
+}
+
+void
+e_vcard_construct_with_uid (EVCard *evc,
+                            const gchar *str,
+                            const gchar *uid)
+{
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (str != NULL);
 	g_return_if_fail (evc->priv->vcard == NULL);
@@ -784,6 +798,16 @@ e_vcard_construct (EVCard *evc,
 	/* Lazy construction */
 	if (*str)
 		evc->priv->vcard = g_strdup (str);
+		
+	/* Add UID attribute */
+	if (uid) {
+		EVCardAttribute *attr;
+
+		attr = e_vcard_attribute_new (NULL, EVC_UID);
+		e_vcard_attribute_add_value (attr, uid);
+
+		evc->priv->attributes = g_list_prepend (evc->priv->attributes, attr);
+	}
 }
 
 /**
@@ -985,10 +1009,11 @@ e_vcard_to_string (EVCard *evc,
 {
 	g_return_val_if_fail (E_IS_VCARD (evc), NULL);
 
-	/* If the vcard is not parsed yet, return it directly */
+	/* If the vcard is not parsed yet, and if we don't have a UID in priv->attributes
+	return priv->vcard directly */
 	/* XXX: The format is ignored but it does not really matter
 	 * since only 3.0 is supported at the moment */
-	if (evc->priv->vcard)
+	if (evc->priv->vcard != NULL && evc->priv->attributes == NULL)
 		return g_strdup (evc->priv->vcard);
 
 	switch (format) {
@@ -1216,8 +1241,14 @@ e_vcard_append_attribute (EVCard *evc,
 {
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (attr != NULL);
-
-	evc->priv->attributes = g_list_append (e_vcard_ensure_attributes (evc), attr);
+	
+	/* Handle UID special case:
+	   No need to parse the vcard to append an UID attribute */
+	if (evc->priv->vcard != NULL && g_strcmp0 (attr->name, EVC_UID) == 0) {
+		evc->priv->attributes = g_list_append (evc->priv->attributes, attr);
+	} else {
+		evc->priv->attributes = g_list_append (e_vcard_ensure_attributes (evc), attr);
+	}
 }
 
 /**
@@ -1290,8 +1321,14 @@ e_vcard_add_attribute (EVCard *evc,
 {
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (attr != NULL);
-
-	evc->priv->attributes = g_list_prepend (e_vcard_ensure_attributes (evc), attr);
+	
+	/* Handle UID special case:
+	   No need to parse the vcard to append an UID attribute */
+	if (evc->priv->vcard != NULL && g_strcmp0 (attr->name, EVC_UID) == 0) {
+		evc->priv->attributes = g_list_prepend (evc->priv->attributes, attr);
+	} else {
+		evc->priv->attributes = g_list_prepend (e_vcard_ensure_attributes (evc), attr);
+	}
 }
 
 /**
@@ -1892,14 +1929,22 @@ e_vcard_get_attribute (EVCard *evc,
                        const gchar *name)
 {
 	GList *attrs, *l;
+	EVCardAttribute *attr;
 
 	g_return_val_if_fail (E_IS_VCARD (evc), NULL);
 	g_return_val_if_fail (name != NULL, NULL);
+	
+	/* Handle UID special case */
+	if (evc->priv->vcard != NULL && g_ascii_strcasecmp (name, EVC_UID) == 0) {
+		for (l = evc->priv->attributes; l != NULL; l = l->next) {
+			attr = (EVCardAttribute *) l->data;
+			if (g_ascii_strcasecmp (attr->name, name) == 0)
+				return attr;
+		}
+	}
 
 	attrs = e_vcard_ensure_attributes (evc);
 	for (l = attrs; l; l = l->next) {
-		EVCardAttribute *attr;
-
 		attr = (EVCardAttribute *) l->data;
 		if (g_ascii_strcasecmp (attr->name, name) == 0)
 			return attr;
@@ -1907,6 +1952,36 @@ e_vcard_get_attribute (EVCard *evc,
 
 	return NULL;
 }
+
+/**
+ * e_vcard_get_attribute_if_parsed:
+ * @evc: an #EVCard
+ * @name: the name of the attribute to get
+ *
+ * Similar to e_vcard_get_attribute() but this method will not attempt to
+ * parse the vcard if not already parsed.
+ *
+ * Returns: (transfer none): An #EVCardAttribute if found, or #NULL.
+ **/
+EVCardAttribute *
+e_vcard_get_attribute_if_parsed (EVCard *evc,
+                                 const gchar *name)
+{
+	GList *l;
+	EVCardAttribute *attr;
+	
+	g_return_val_if_fail (E_IS_VCARD (evc), NULL);
+	g_return_val_if_fail (name != NULL, NULL);
+	
+	for (l = evc->priv->attributes; l != NULL; l = l->next) {
+		attr = (EVCardAttribute *) l->data;
+		if (g_ascii_strcasecmp (attr->name, name) == 0)
+			return attr;
+	}
+	
+	return NULL;
+}
+
 /**
  * e_vcard_attribute_get_group:
  * @attr: an #EVCardAttribute
diff --git a/addressbook/libebook/e-vcard.h b/addressbook/libebook/e-vcard.h
index e03b881..fb384bd 100644
--- a/addressbook/libebook/e-vcard.h
+++ b/addressbook/libebook/e-vcard.h
@@ -195,6 +195,7 @@ struct _EVCardClass {
 GType   e_vcard_get_type                     (void);
 
 void    e_vcard_construct                    (EVCard *evc, const gchar *str);
+void    e_vcard_construct_with_uid           (EVCard *evc, const gchar *str, const gchar *uid);
 EVCard * e_vcard_new                          (void);
 EVCard * e_vcard_new_from_string              (const gchar *str);
 
@@ -247,6 +248,7 @@ void                  e_vcard_attribute_param_remove_values   (EVCardAttributePa
 /* EVCard* accessors.  nothing returned from these functions should be
  * freed by the caller. */
 EVCardAttribute *e_vcard_get_attribute        (EVCard *evc, const gchar *name);
+EVCardAttribute *e_vcard_get_attribute_if_parsed	(EVCard *evc, const gchar *name);
 GList *           e_vcard_get_attributes       (EVCard *evcard);
 const gchar *      e_vcard_attribute_get_group  (EVCardAttribute *attr);
 const gchar *      e_vcard_attribute_get_name   (EVCardAttribute *attr);
diff --git a/addressbook/libedata-book/e-book-backend-cache.c b/addressbook/libedata-book/e-book-backend-cache.c
index 070a8a8..2b4a875 100644
--- a/addressbook/libedata-book/e-book-backend-cache.c
+++ b/addressbook/libedata-book/e-book-backend-cache.c
@@ -89,7 +89,7 @@ e_book_backend_cache_get_contact (EBookBackendCache *cache,
 
 	vcard_str = e_file_cache_get_object (E_FILE_CACHE (cache), uid);
 	if (vcard_str) {
-		contact = e_contact_new_from_vcard (vcard_str);
+		contact = e_contact_new_from_vcard_with_uid (vcard_str, uid);
 
 	}
 
diff --git a/addressbook/libedata-book/e-book-backend-db-cache.c b/addressbook/libedata-book/e-book-backend-db-cache.c
index e51cd84..24eff63 100644
--- a/addressbook/libedata-book/e-book-backend-db-cache.c
+++ b/addressbook/libedata-book/e-book-backend-db-cache.c
@@ -144,7 +144,7 @@ e_book_backend_db_cache_get_contact (DB *db,
 		return NULL;
 	}
 
-	contact = e_contact_new_from_vcard ((const gchar *) vcard_dbt.data);
+	contact = e_contact_new_from_vcard_with_uid ((const gchar *) vcard_dbt.data, uid);
 	g_free (vcard_dbt.data);
 	return contact;
 }
diff --git a/addressbook/libedata-book/e-book-backend-sqlitedb.c b/addressbook/libedata-book/e-book-backend-sqlitedb.c
index 95ba3f4..e750103 100644
--- a/addressbook/libedata-book/e-book-backend-sqlitedb.c
+++ b/addressbook/libedata-book/e-book-backend-sqlitedb.c
@@ -868,7 +868,7 @@ e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
 	gchar *vcard = e_book_backend_sqlitedb_get_vcard_string (ebsdb, folderid, uid,
 								 fields_of_interest, with_all_required_fields, &err);
 	if (!err) {
-		contact = e_contact_new_from_vcard (vcard);
+		contact = e_contact_new_from_vcard_with_uid (vcard, uid);
 		g_free (vcard);
 	} else
 		g_propagate_error (error, err);
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index 68008e6..ca1e969 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -224,20 +224,24 @@ ensure_pending_flush_timeout (EDataBookView *view)
  */
 static void
 notify_change (EDataBookView *view,
+               const gchar *id,
                const gchar *vcard)
 {
 	EDataBookViewPrivate *priv = view->priv;
-	gchar *utf8_vcard;
+	gchar *utf8_vcard, *utf8_id;
 
 	send_pending_adds (view);
 	send_pending_removes (view);
 
-	if (priv->changes->len == THRESHOLD_ITEMS) {
+	if (priv->changes->len == THRESHOLD_ITEMS * 2) {
 		send_pending_changes (view);
 	}
 
 	utf8_vcard = e_util_utf8_make_valid (vcard);
+	utf8_id = e_util_utf8_make_valid (id);
+	
 	g_array_append_val (priv->changes, utf8_vcard);
+	g_array_append_val (priv->changes, utf8_id);
 
 	ensure_pending_flush_timeout (view);
 }
@@ -275,18 +279,21 @@ notify_add (EDataBookView *view,
             const gchar *vcard)
 {
 	EDataBookViewPrivate *priv = view->priv;
-	gchar *utf8_vcard;
+	gchar *utf8_vcard, *utf8_id;
 
 	send_pending_changes (view);
 	send_pending_removes (view);
 
-	if (priv->adds->len == THRESHOLD_ITEMS) {
+	if (priv->adds->len == THRESHOLD_ITEMS * 2) {
 		send_pending_adds (view);
 	}
 
 	utf8_vcard = e_util_utf8_make_valid (vcard);
+	utf8_id = e_util_utf8_make_valid (id);
+
 	g_array_append_val (priv->adds, utf8_vcard);
-	g_hash_table_insert (priv->ids, e_util_utf8_make_valid (id),
+	g_array_append_val (priv->adds, utf8_id);
+	g_hash_table_insert (priv->ids, g_strdup (utf8_id),
 			     GUINT_TO_POINTER (1));
 
 	ensure_pending_flush_timeout (view);
@@ -395,7 +402,7 @@ e_data_book_view_notify_update (EDataBookView *book_view,
 					   EVC_FORMAT_VCARD_30);
 
 		if (currently_in_view)
-			notify_change (book_view, vcard);
+			notify_change (book_view, id, vcard);
 		else
 			notify_add (book_view, id, vcard);
 
@@ -424,11 +431,11 @@ e_data_book_view_notify_update (EDataBookView *book_view,
  **/
 void
 e_data_book_view_notify_update_vcard (EDataBookView *book_view,
+                                      const gchar *id,
                                       gchar *vcard)
 {
 	EDataBookViewPrivate *priv = book_view->priv;
 	gboolean currently_in_view, want_in_view;
-	const gchar *id;
 	EContact *contact;
 
 	if (!priv->running) {
@@ -438,15 +445,14 @@ e_data_book_view_notify_update_vcard (EDataBookView *book_view,
 
 	g_mutex_lock (priv->pending_mutex);
 
-	contact = e_contact_new_from_vcard (vcard);
-	id = e_contact_get_const (contact, E_CONTACT_UID);
+	contact = e_contact_new_from_vcard_with_uid (vcard, id);
 	currently_in_view = id_is_in_view (book_view, id);
 	want_in_view =
 		e_book_backend_sexp_match_contact (priv->card_sexp, contact);
 
 	if (want_in_view) {
 		if (currently_in_view)
-			notify_change (book_view, vcard);
+			notify_change (book_view, id, vcard);
 		else
 			notify_add (book_view, id, vcard);
 	} else {
@@ -499,7 +505,7 @@ e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *book_view,
 	currently_in_view = id_is_in_view (book_view, id);
 
 	if (currently_in_view)
-		notify_change (book_view, vcard);
+		notify_change (book_view, id, vcard);
 	else
 		notify_add (book_view, id, vcard);
 
@@ -709,8 +715,9 @@ e_data_book_view_init (EDataBookView *book_view)
 	priv->running = FALSE;
 	priv->pending_mutex = g_mutex_new ();
 
-	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
-	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
+	/* THRESHOLD_ITEMS * 2 because we store UID and vcard */
+	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
+	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
 	priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
 
 	priv->ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
diff --git a/addressbook/libedata-book/e-data-book-view.h b/addressbook/libedata-book/e-data-book-view.h
index fc33d14..d535725 100644
--- a/addressbook/libedata-book/e-data-book-view.h
+++ b/addressbook/libedata-book/e-data-book-view.h
@@ -59,7 +59,7 @@ EBookBackendSExp *	e_data_book_view_get_card_sexp		(EDataBookView *book_view);
 EBookBackend *		e_data_book_view_get_backend		(EDataBookView *book_view);
 void			e_data_book_view_notify_update		(EDataBookView *book_view, const EContact *contact);
 
-void			e_data_book_view_notify_update_vcard	(EDataBookView *book_view, gchar *vcard);
+void			e_data_book_view_notify_update_vcard	(EDataBookView *book_view, const gchar *id, gchar *vcard);
 void			e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *book_view, const gchar *id, gchar *vcard);
 
 void			e_data_book_view_notify_remove		(EDataBookView *book_view, const gchar *id);



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