[evolution-data-server] Bug #652173 - libebook: Delay client-side vCard parsing



commit b4e498e53e058872f524552b2508d918fa531c01
Author: Christophe Dumez <christophe dumez intel com>
Date:   Wed Jun 22 16:18:21 2011 +0200

    Bug #652173 - libebook: Delay client-side vCard parsing

 addressbook/libebook/e-contact.c |  111 +++++++++++++++++++++++--------------
 addressbook/libebook/e-vcard.c   |   66 +++++++++++++++++++---
 addressbook/libebook/e-vcard.h   |    2 +
 3 files changed, 128 insertions(+), 51 deletions(-)
---
diff --git a/addressbook/libebook/e-contact.c b/addressbook/libebook/e-contact.c
index f486eb5..9fd6982 100644
--- a/addressbook/libebook/e-contact.c
+++ b/addressbook/libebook/e-contact.c
@@ -87,6 +87,8 @@ static gpointer  fn_getter (EContact *contact, EVCardAttribute *attr);
 static void fn_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
 static gpointer  n_getter (EContact *contact, EVCardAttribute *attr);
 static void n_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
+static gpointer  fileas_getter (EContact *contact, EVCardAttribute *attr);
+static void fileas_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
 static gpointer  adr_getter (EContact *contact, EVCardAttribute *attr);
 static void adr_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
 static gpointer  date_getter (EContact *contact, EVCardAttribute *attr);
@@ -112,7 +114,9 @@ static void cert_setter (EContact *contact, EVCardAttribute *attr, gpointer data
 static const EContactFieldInfo field_info[] = {
 	{0,}, /* Dummy row as EContactField starts from 1 */
 	STRING_FIELD (E_CONTACT_UID,        EVC_UID,       "id",         N_("Unique ID"),  FALSE),
-	STRING_FIELD (E_CONTACT_FILE_AS,    EVC_X_FILE_AS, "file_as",    N_("File Under"),    FALSE),
+	/* FILE_AS is not really a structured field - we use a getter/setter
+           so we can generate its value if necessary in the getter */
+	GETSET_FIELD (E_CONTACT_FILE_AS,    EVC_X_FILE_AS, "file_as",    N_("File Under"),    FALSE, fileas_getter, fileas_setter),
 	/* URI of the book to which the contact belongs to */
 	STRING_FIELD (E_CONTACT_BOOK_URI, EVC_X_BOOK_URI, "book_uri", N_("Book URI"), FALSE),
 
@@ -540,6 +544,68 @@ fn_setter (EContact *contact, EVCardAttribute *attr, gpointer data)
 	}
 }
 
+static gpointer
+fileas_getter (EContact *contact, EVCardAttribute *attr)
+{
+	if (!attr) {
+		/* Generate a FILE_AS field */
+		EContactName *name;
+		gchar* new_file_as = NULL;
+
+		name = e_contact_get (contact, E_CONTACT_NAME);
+
+		/* Use name if available */
+		if (name) {
+			gchar *strings[3], **stringptr;
+
+			stringptr = strings;
+			if (name->family && *name->family)
+				*(stringptr++) = name->family;
+			if (name->given && *name->given)
+				*(stringptr++) = name->given;
+			if (stringptr != strings) {
+				*stringptr = NULL;
+				new_file_as = g_strjoinv (", ", strings);
+			}
+
+			e_contact_name_free (name);
+		}
+
+		/* Use org as fallback */
+		if (!new_file_as) {
+			const gchar *org = e_contact_get_const (contact, E_CONTACT_ORG);
+
+			if (org && *org) {
+				new_file_as = g_strdup (org);
+			}
+		}
+
+		/* Add the FILE_AS attribute to the vcard */
+		if (new_file_as) {
+			attr = e_vcard_attribute_new (NULL, EVC_X_FILE_AS);
+			e_vcard_add_attribute_with_value (E_VCARD (contact), attr, new_file_as);
+
+			g_free (new_file_as);
+		}
+	}
+
+	if (attr) {
+		GList *p = e_vcard_attribute_get_values (attr);
+
+		return p && p->data ? p->data : (gpointer) "";
+	} else {
+		return NULL;
+	}
+}
+
+static void
+fileas_setter (EContact *contact, EVCardAttribute *attr, gpointer data)
+{
+	/* Default implementation */
+	const gchar* file_as = data;
+	e_vcard_attribute_add_value (attr, file_as ? : "");
+}
+
 
 
 static gpointer
@@ -1214,49 +1280,11 @@ EContact*
 e_contact_new_from_vcard  (const gchar *vcard)
 {
 	EContact *contact;
-	const gchar *file_as;
-
 	g_return_val_if_fail (vcard != NULL, NULL);
 
 	contact = g_object_new (E_TYPE_CONTACT, NULL);
 	e_vcard_construct (E_VCARD (contact), vcard);
 
-	/* Generate a FILE_AS field if needed */
-
-	file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
-	if (!file_as || !*file_as) {
-		EContactName *name;
-		const gchar *org;
-		gchar *file_as_new = NULL;
-		gchar *strings[4];
-		gchar **strings_p = strings;
-
-		name = e_contact_get (contact, E_CONTACT_NAME);
-		org = e_contact_get_const (contact, E_CONTACT_ORG);
-
-		if (name) {
-			if (name->family && *name->family)
-				*(strings_p++) = name->family;
-			if (name->given && *name->given)
-				*(strings_p++) = name->given;
-
-			if (strings_p != strings) {
-				*strings_p = NULL;
-				file_as_new = g_strjoinv (", ", strings);
-			}
-
-			e_contact_name_free (name);
-		}
-
-		if (!file_as_new && org && *org)
-			file_as_new = g_strdup (org);
-
-		if (file_as_new) {
-			e_contact_set (contact, E_CONTACT_FILE_AS, file_as_new);
-			g_free (file_as_new);
-		}
-	}
-
 	return contact;
 }
 
@@ -1488,15 +1516,14 @@ e_contact_get (EContact *contact, EContactField field_id)
 		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
 		gpointer rv = NULL;
 
-		if (attr)
-			rv = info->struct_getter (contact, attr);
+		rv = info->struct_getter (contact, attr);
 
 		if (info->t & E_CONTACT_FIELD_TYPE_STRUCT)
 			return (gpointer) info->boxed_type_getter ();
 		else if (!rv)
 			return NULL;
 		else
-			return g_strstrip (g_strdup (rv));
+			return rv ? g_strstrip (g_strdup (rv)) : NULL;
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) {
 		switch (info->field_id) {
diff --git a/addressbook/libebook/e-vcard.c b/addressbook/libebook/e-vcard.c
index 28fcb88..6b308d6 100644
--- a/addressbook/libebook/e-vcard.c
+++ b/addressbook/libebook/e-vcard.c
@@ -46,6 +46,7 @@ typedef enum {
 
 struct _EVCardPrivate {
 	GList *attributes;
+	gchar *vcard;
 };
 
 struct _EVCardAttribute {
@@ -71,10 +72,12 @@ e_vcard_dispose (GObject *object)
 	EVCard *evc = E_VCARD (object);
 
 	if (evc->priv) {
-
+		/* Directly access priv->attributes and don't call e_vcard_ensure_attributes(),
+		 * since it is pointless to start vCard parsing that late. */
 		g_list_foreach (evc->priv->attributes, (GFunc) e_vcard_attribute_free, NULL);
 		g_list_free (evc->priv->attributes);
 
+		g_free (evc->priv->vcard);
 		g_free (evc->priv);
 		evc->priv = NULL;
 	}
@@ -652,6 +655,24 @@ parse (EVCard *evc, const gchar *str)
 	evc->priv->attributes = g_list_reverse (evc->priv->attributes);
 }
 
+static GList*
+e_vcard_ensure_attributes (EVCard *evc)
+{
+        if (evc->priv->vcard) {
+                gchar *vcs = evc->priv->vcard;
+
+                /* detach vCard to avoid loops */
+                evc->priv->vcard = NULL;
+
+                /* Parse the vCard */
+                parse (evc, vcs);
+                g_free (vcs);
+        }
+
+        return evc->priv->attributes;
+}
+
+
 /**
  * e_vcard_escape_string:
  * @s: the string to escape
@@ -746,9 +767,12 @@ e_vcard_construct (EVCard *evc, const gchar *str)
 {
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (str != NULL);
+	g_return_if_fail (evc->priv->vcard == NULL);
+	g_return_if_fail (evc->priv->attributes == NULL);
 
+	/* Lazy construction */
 	if (*str)
-		parse (evc, str);
+		evc->priv->vcard = g_strdup (str);
 }
 
 /**
@@ -809,7 +833,7 @@ e_vcard_to_string_vcard_30 (EVCard *evc)
 	   vcard might contain */
 	g_string_append (str, "VERSION:3.0" CRLF);
 
-	for (l = evc->priv->attributes; l; l = l->next) {
+	for (l = e_vcard_ensure_attributes (evc); l; l = l->next) {
 		GList *list;
 		EVCardAttribute *attr = l->data;
 		GString *attr_str;
@@ -949,6 +973,12 @@ e_vcard_to_string (EVCard *evc, EVCardFormat format)
 {
 	g_return_val_if_fail (E_IS_VCARD (evc), NULL);
 
+	/* If the vcard is not parsed yet, return it 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)
+		return g_strdup (evc->priv->vcard);
+
 	switch (format) {
 	case EVC_FORMAT_VCARD_21:
 		return e_vcard_to_string_vcard_21 (evc);
@@ -977,7 +1007,7 @@ e_vcard_dump_structure (EVCard *evc)
 	g_return_if_fail (E_IS_VCARD (evc));
 
 	printf ("vCard\n");
-	for (a = evc->priv->attributes; a; a = a->next) {
+	for (a = e_vcard_ensure_attributes (evc); a; a = a->next) {
 		GList *p;
 		EVCardAttribute *attr = a->data;
 		printf ("+-- %s\n", attr->name);
@@ -1114,7 +1144,7 @@ e_vcard_remove_attributes (EVCard *evc, const gchar *attr_group, const gchar *at
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (attr_name != NULL);
 
-	attr = evc->priv->attributes;
+	attr = e_vcard_ensure_attributes (evc);
 	while (attr) {
 		GList *next_attr;
 		EVCardAttribute *a = attr->data;
@@ -1148,6 +1178,8 @@ e_vcard_remove_attribute (EVCard *evc, EVCardAttribute *attr)
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (attr != NULL);
 
+	/* No need to call e_vcard_ensure_attributes() here. It has already been
+           called if this is a valid call and attr is among our attributes */
 	evc->priv->attributes = g_list_remove (evc->priv->attributes, attr);
 	e_vcard_attribute_free (attr);
 }
@@ -1167,7 +1199,7 @@ e_vcard_append_attribute (EVCard *evc, EVCardAttribute *attr)
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (attr != NULL);
 
-	evc->priv->attributes = g_list_append (evc->priv->attributes, attr);
+	evc->priv->attributes = g_list_append (e_vcard_ensure_attributes (evc), attr);
 }
 
 /**
@@ -1237,7 +1269,7 @@ e_vcard_add_attribute (EVCard *evc, EVCardAttribute *attr)
 	g_return_if_fail (E_IS_VCARD (evc));
 	g_return_if_fail (attr != NULL);
 
-	evc->priv->attributes = g_list_prepend (evc->priv->attributes, attr);
+	evc->priv->attributes = g_list_prepend (e_vcard_ensure_attributes (evc), attr);
 }
 
 /**
@@ -1808,7 +1840,7 @@ e_vcard_get_attributes (EVCard *evcard)
 {
 	g_return_val_if_fail (E_IS_VCARD (evcard), NULL);
 
-	return evcard->priv->attributes;
+	return e_vcard_ensure_attributes (evcard);
 }
 
 /**
@@ -1831,7 +1863,7 @@ e_vcard_get_attribute (EVCard     *evc,
 	g_return_val_if_fail (E_IS_VCARD (evc), NULL);
 	g_return_val_if_fail (name != NULL, NULL);
 
-	attrs = e_vcard_get_attributes (evc);
+	attrs = e_vcard_ensure_attributes (evc);
 	for (l = attrs; l; l = l->next) {
 		EVCardAttribute *attr;
 
@@ -2094,6 +2126,22 @@ e_vcard_attribute_get_param (EVCardAttribute *attr, const gchar *name)
 }
 
 /**
+ * e_vcard_is_parsed:
+ * @evc: an #EVCard
+ *
+ * Check if the @evc has been parsed already. Used for debugging.
+ *
+ * Return value: %TRUE if @evc has been parsed, %FALSE otherwise.
+ **/
+gboolean
+e_vcard_is_parsed (EVCard *evc)
+{
+        g_return_val_if_fail (E_IS_VCARD (evc), FALSE);
+        return (!evc->priv->vcard && evc->priv->attributes);
+}
+
+
+/**
  * e_vcard_attribute_param_get_name:
  * @param: an #EVCardAttributeParam
  *
diff --git a/addressbook/libebook/e-vcard.h b/addressbook/libebook/e-vcard.h
index 696d0af..544dff4 100644
--- a/addressbook/libebook/e-vcard.h
+++ b/addressbook/libebook/e-vcard.h
@@ -159,6 +159,8 @@ void    e_vcard_construct                    (EVCard *evc, const gchar *str);
 EVCard* e_vcard_new                          (void);
 EVCard* e_vcard_new_from_string              (const gchar *str);
 
+gboolean e_vcard_is_parsed (EVCard *evc);
+
 gchar *   e_vcard_to_string                    (EVCard *evc, EVCardFormat format);
 
 /* mostly for debugging */



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