[evolution-data-server] Merge utility functions into Google Contacts backend



commit 83acb8b4833ea364fd053f730404900b3b4e0820
Author: Philip Withnall <philip tecnocode co uk>
Date:   Tue Jul 20 20:19:15 2010 +0100

    Merge utility functions into Google Contacts backend

 addressbook/backends/google/Makefile.am            |    2 -
 .../backends/google/e-book-backend-google.c        | 1171 +++++++++++++++++++-
 addressbook/backends/google/util.c                 | 1183 --------------------
 addressbook/backends/google/util.h                 |   42 -
 4 files changed, 1166 insertions(+), 1232 deletions(-)
---
diff --git a/addressbook/backends/google/Makefile.am b/addressbook/backends/google/Makefile.am
index c7912de..3e903a7 100644
--- a/addressbook/backends/google/Makefile.am
+++ b/addressbook/backends/google/Makefile.am
@@ -12,8 +12,6 @@ libebookbackendgoogle_la_CPPFLAGS = \
 	$(GDATA_CFLAGS)
 
 libebookbackendgoogle_la_SOURCES = \
-	util.h				\
-	util.c				\
 	e-book-backend-google-factory.c	\
 	e-book-backend-google.h		\
 	e-book-backend-google.c
diff --git a/addressbook/backends/google/e-book-backend-google.c b/addressbook/backends/google/e-book-backend-google.c
index 057d0de..f5ee105 100644
--- a/addressbook/backends/google/e-book-backend-google.c
+++ b/addressbook/backends/google/e-book-backend-google.c
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  * Author: Joergen Scheibengruber <joergen.scheibengruber AT googlemail.com>
+ *         Philip Withnall <philip tecnocode co uk>
  */
 
 #include <config.h>
@@ -25,18 +26,15 @@
 #include <errno.h>
 
 #include <libedataserver/e-proxy.h>
+#include <libebook/e-vcard.h>
 #include <libebook/e-contact.h>
 #include <libedata-book/e-data-book.h>
 #include <libedata-book/e-data-book-view.h>
 #include <libedata-book/e-book-backend-sexp.h>
 #include <libedata-book/e-book-backend-cache.h>
-#include <gdata/gdata-service.h>
-#include <gdata/services/contacts/gdata-contacts-service.h>
-#include <gdata/services/contacts/gdata-contacts-query.h>
-#include <gdata/services/contacts/gdata-contacts-contact.h>
+#include <gdata/gdata.h>
 
 #include "e-book-backend-google.h"
-#include "util.h"
 
 #define URI_GET_CONTACTS "://www.google.com/m8/feeds/contacts/default/full"
 
@@ -82,9 +80,18 @@ struct _EBookBackendGooglePrivate {
 };
 
 gboolean __e_book_backend_google_debug__;
+#define __debug__(...) (__e_book_backend_google_debug__ ? g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, __VA_ARGS__) : (void) 0)
 
 static void data_book_error_from_gdata_error (GError **dest_err, GError *error);
 
+static GDataEntry *_gdata_entry_new_from_e_contact (EContact *contact);
+static gboolean _gdata_entry_update_from_e_contact (GDataEntry *entry, EContact *contact);
+
+static EContact *_e_contact_new_from_gdata_entry (GDataEntry *entry);
+static void _e_contact_add_gdata_entry_xml (EContact *contact, GDataEntry *entry);
+static void _e_contact_remove_gdata_entry_xml (EContact *contact);
+static const gchar *_e_contact_get_gdata_entry_xml (EContact *contact, const gchar **edit_link);
+
 static void
 cache_init (EBookBackend *backend, gboolean on_disk)
 {
@@ -1515,3 +1522,1157 @@ data_book_error_from_gdata_error (GError **dest_err, GError *error)
 	g_propagate_error (dest_err, e_data_book_create_error (E_DATA_BOOK_STATUS_OTHER_ERROR, error->message));
 }
 
+#define GOOGLE_PRIMARY_PARAM "X-EVOLUTION-UI-SLOT"
+#define GOOGLE_LABEL_PARAM "X-GOOGLE-LABEL"
+#define GDATA_ENTRY_XML_ATTR "X-GDATA-ENTRY-XML"
+#define GDATA_ENTRY_LINK_ATTR "X-GDATA-ENTRY-LINK"
+
+static void add_attribute_from_gdata_gd_email_address (EVCard *vcard, GDataGDEmailAddress *email);
+static void add_attribute_from_gdata_gd_im_address (EVCard *vcard, GDataGDIMAddress *im);
+static void add_attribute_from_gdata_gd_phone_number (EVCard *vcard, GDataGDPhoneNumber *number);
+static void add_attribute_from_gdata_gd_postal_address (EVCard *vcard, GDataGDPostalAddress *address);
+static void add_attribute_from_gdata_gd_organization (EVCard *vcard, GDataGDOrganization *org);
+
+static GDataGDEmailAddress *gdata_gd_email_address_from_attribute (EVCardAttribute *attr, gboolean *primary);
+static GDataGDIMAddress *gdata_gd_im_address_from_attribute (EVCardAttribute *attr, gboolean *primary);
+static GDataGDPhoneNumber *gdata_gd_phone_number_from_attribute (EVCardAttribute *attr, gboolean *primary);
+static GDataGDPostalAddress *gdata_gd_postal_address_from_attribute (EVCardAttribute *attr, gboolean *primary);
+static GDataGDOrganization *gdata_gd_organization_from_attribute (EVCardAttribute *attr, gboolean *primary);
+
+static gboolean is_known_google_im_protocol (const gchar *protocol);
+
+static GDataEntry *
+_gdata_entry_new_from_e_contact (EContact *contact)
+{
+	GDataEntry *entry = GDATA_ENTRY (gdata_contacts_contact_new (NULL));
+
+	if (_gdata_entry_update_from_e_contact (entry, contact))
+		return entry;
+
+	g_object_unref (entry);
+
+	return NULL;
+}
+
+#ifdef HAVE_GDATA_07
+static void
+remove_anniversary (GDataContactsContact *contact)
+{
+	GList *events, *itr;
+
+	events = gdata_contacts_contact_get_events (contact);
+	if (!events)
+		return;
+
+	events = g_list_copy (events);
+	g_list_foreach (events, (GFunc) g_object_ref, NULL);
+
+	gdata_contacts_contact_remove_all_events (contact);
+	for (itr = events; itr; itr = itr->next) {
+		GDataGContactEvent *event = itr->data;
+
+		if (g_strcmp0 (gdata_gcontact_event_get_relation_type (event), GDATA_GCONTACT_EVENT_ANNIVERSARY) != 0)
+			gdata_contacts_contact_add_event (contact, event);
+	}
+
+	g_list_foreach (events, (GFunc) g_object_unref, NULL);
+	g_list_free (events);
+}
+
+static void
+remove_websites (GDataContactsContact *contact)
+{
+	GList *websites, *itr;
+
+	websites = gdata_contacts_contact_get_websites (contact);
+	if (!websites)
+		return;
+
+	websites = g_list_copy (websites);
+	g_list_foreach (websites, (GFunc) g_object_ref, NULL);
+
+	gdata_contacts_contact_remove_all_websites (contact);
+	for (itr = websites; itr; itr = itr->next) {
+		GDataGContactWebsite *website = itr->data;
+
+		if (g_strcmp0 (gdata_gcontact_website_get_relation_type (website), GDATA_GCONTACT_WEBSITE_HOME_PAGE) != 0 &&
+		    g_strcmp0 (gdata_gcontact_website_get_relation_type (website), GDATA_GCONTACT_WEBSITE_BLOG) != 0)
+			gdata_contacts_contact_add_website (contact, website);
+	}
+
+	g_list_foreach (websites, (GFunc) g_object_unref, NULL);
+	g_list_free (websites);
+}
+#endif
+
+static gboolean
+_gdata_entry_update_from_e_contact (GDataEntry *entry, EContact *contact)
+{
+	GList *attributes, *iter;
+	EContactName *name_struct = NULL;
+	gboolean have_email_primary = FALSE;
+	gboolean have_im_primary = FALSE;
+	gboolean have_phone_primary = FALSE;
+	gboolean have_postal_primary = FALSE;
+	gboolean have_org_primary = FALSE;
+	const gchar *title, *role, *note;
+	#ifdef HAVE_GDATA_07
+	EContactDate *bdate;
+	const gchar *url;
+	#endif
+
+	attributes = e_vcard_get_attributes (E_VCARD (contact));
+
+	/* N and FN */
+	name_struct = e_contact_get (contact, E_CONTACT_NAME);
+	if (name_struct) {
+		GDataGDName *name;
+		const gchar *given = NULL, *family = NULL;
+
+		if (name_struct->given && *(name_struct->given) != '\0')
+			given = name_struct->given;
+		if (name_struct->family && *(name_struct->family) != '\0')
+			family = name_struct->family;
+
+		name = gdata_gd_name_new (given, family);
+		if (name_struct->additional && *(name_struct->additional) != '\0')
+			gdata_gd_name_set_additional_name (name, name_struct->additional);
+		if (name_struct->prefixes && *(name_struct->prefixes) != '\0')
+			gdata_gd_name_set_prefix (name, name_struct->prefixes);
+		if (name_struct->suffixes && *(name_struct->suffixes) != '\0')
+			gdata_gd_name_set_suffix (name, name_struct->suffixes);
+		gdata_gd_name_set_full_name (name, e_contact_get (contact, E_CONTACT_FULL_NAME));
+
+		gdata_contacts_contact_set_name (GDATA_CONTACTS_CONTACT (entry), name);
+		g_object_unref (name);
+	}
+
+	/* NOTE */
+	note = e_contact_get (contact, E_CONTACT_NOTE);
+	if (note)
+		gdata_entry_set_content (entry, note);
+	else
+		gdata_entry_set_content (entry, NULL);
+
+	/* Clear out all the old attributes */
+	gdata_contacts_contact_remove_all_email_addresses (GDATA_CONTACTS_CONTACT (entry));
+	gdata_contacts_contact_remove_all_phone_numbers (GDATA_CONTACTS_CONTACT (entry));
+	gdata_contacts_contact_remove_all_postal_addresses (GDATA_CONTACTS_CONTACT (entry));
+	gdata_contacts_contact_remove_all_im_addresses (GDATA_CONTACTS_CONTACT (entry));
+	gdata_contacts_contact_remove_all_organizations (GDATA_CONTACTS_CONTACT (entry));
+
+	/* We walk them in reverse order, so we can find
+	 * the correct primaries */
+	iter = g_list_last (attributes);
+	for (; iter; iter = iter->prev) {
+		EVCardAttribute *attr;
+		const gchar *name;
+
+		attr = iter->data;
+		name = e_vcard_attribute_get_name (attr);
+
+		if (0 == g_ascii_strcasecmp (name, EVC_UID) ||
+		    0 == g_ascii_strcasecmp (name, EVC_N) ||
+		    0 == g_ascii_strcasecmp (name, EVC_FN) ||
+		    0 == g_ascii_strcasecmp (name, EVC_LABEL) ||
+		    0 == g_ascii_strcasecmp (name, EVC_VERSION) ||
+		    0 == g_ascii_strcasecmp (name, EVC_X_FILE_AS) ||
+		    0 == g_ascii_strcasecmp (name, EVC_TITLE) ||
+		    0 == g_ascii_strcasecmp (name, EVC_ROLE) ||
+		    0 == g_ascii_strcasecmp (name, EVC_NOTE)) {
+			/* Ignore UID, VERSION, X-EVOLUTION-FILE-AS, N, FN, LABEL, TITLE, ROLE, NOTE */
+		} else if (0 == g_ascii_strcasecmp (name, EVC_EMAIL)) {
+			/* EMAIL */
+			GDataGDEmailAddress *email;
+
+			email = gdata_gd_email_address_from_attribute (attr, &have_email_primary);
+			if (email) {
+				gdata_contacts_contact_add_email_address (GDATA_CONTACTS_CONTACT (entry), email);
+				g_object_unref (email);
+			}
+		} else if (0 == g_ascii_strcasecmp (name, EVC_TEL)) {
+			/* TEL */
+			GDataGDPhoneNumber *number;
+
+			number = gdata_gd_phone_number_from_attribute (attr, &have_phone_primary);
+			if (number) {
+				gdata_contacts_contact_add_phone_number (GDATA_CONTACTS_CONTACT (entry), number);
+				g_object_unref (number);
+			}
+		} else if (0 == g_ascii_strcasecmp (name, EVC_ADR)) {
+			/* ADR (we ignore LABEL, since it should be the same as ADR, and ADR is more structured) */
+			GDataGDPostalAddress *address;
+
+			address = gdata_gd_postal_address_from_attribute (attr, &have_postal_primary);
+			if (address) {
+				gdata_contacts_contact_add_postal_address (GDATA_CONTACTS_CONTACT (entry), address);
+				g_object_unref (address);
+			}
+		} else if (0 == g_ascii_strcasecmp (name, EVC_ORG)) {
+			/* ORG */
+			GDataGDOrganization *org;
+
+			org = gdata_gd_organization_from_attribute (attr, &have_org_primary);
+			if (org) {
+				gdata_contacts_contact_add_organization (GDATA_CONTACTS_CONTACT (entry), org);
+				g_object_unref (org);
+			}
+		} else if (0 == g_ascii_strncasecmp (name, "X-", 2) && is_known_google_im_protocol (name + 2)) {
+			/* X-IM */
+			GDataGDIMAddress *im;
+
+			im = gdata_gd_im_address_from_attribute (attr, &have_im_primary);
+			if (im) {
+				gdata_contacts_contact_add_im_address (GDATA_CONTACTS_CONTACT (entry), im);
+				g_object_unref (im);
+			}
+		} else if (e_vcard_attribute_is_single_valued (attr)) {
+			gchar *value;
+
+			/* Add the attribute as an extended property */
+			value = e_vcard_attribute_get_value (attr);
+			gdata_contacts_contact_set_extended_property (GDATA_CONTACTS_CONTACT (entry), name, value);
+			g_free (value);
+		} else {
+			GList *values;
+
+			values = e_vcard_attribute_get_values (attr);
+			if (values && values->data && ((gchar *)values->data)[0])
+				__debug__ ("unsupported vcard field: %s: %s", name, (gchar *)values->data);
+		}
+	}
+
+	/* TITLE and ROLE */
+	title = e_contact_get (contact, E_CONTACT_TITLE);
+	role = e_contact_get (contact, E_CONTACT_ROLE);
+	if (title || role) {
+		GDataGDOrganization *org = NULL;
+
+		/* Find an appropriate org: try to add them to the primary organization, but fall back to the first listed organization if none
+		 * are marked as primary. */
+		if (have_org_primary) {
+			org = gdata_contacts_contact_get_primary_organization (GDATA_CONTACTS_CONTACT (entry));
+		} else {
+			GList *orgs = gdata_contacts_contact_get_organizations (GDATA_CONTACTS_CONTACT (entry));
+			if (orgs)
+				org = orgs->data;
+		}
+
+		/* Set the title and role */
+		if (org && title)
+			gdata_gd_organization_set_title (org, title);
+		if (org && role)
+			gdata_gd_organization_set_job_description (org, role);
+	}
+
+	#ifdef HAVE_GDATA_07
+	remove_websites (GDATA_CONTACTS_CONTACT (entry));
+
+	url = e_contact_get_const (contact, E_CONTACT_HOMEPAGE_URL);
+	if (url && *url) {
+		GDataGContactWebsite *website = gdata_gcontact_website_new (url, GDATA_GCONTACT_WEBSITE_HOME_PAGE, NULL, FALSE);
+		if (website) {
+			gdata_contacts_contact_add_website (GDATA_CONTACTS_CONTACT (entry), website);
+			g_object_unref (website);
+		}
+	}
+
+	url = e_contact_get_const (contact, E_CONTACT_BLOG_URL);
+	if (url && *url) {
+		GDataGContactWebsite *website = gdata_gcontact_website_new (url, GDATA_GCONTACT_WEBSITE_BLOG, NULL, FALSE);
+		if (website) {
+			gdata_contacts_contact_add_website (GDATA_CONTACTS_CONTACT (entry), website);
+			g_object_unref (website);
+		}
+	}
+
+	gdata_contacts_contact_set_birthday (GDATA_CONTACTS_CONTACT (entry), NULL, TRUE);
+	bdate = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
+	if (bdate) {
+		GDate *gdate = g_date_new_dmy (bdate->day, bdate->month, bdate->year);
+
+		if (gdate) {
+			gdata_contacts_contact_set_birthday (GDATA_CONTACTS_CONTACT (entry), gdate, TRUE);
+			g_date_free (gdate);
+		}
+		e_contact_date_free (bdate);
+	}
+
+	remove_anniversary (GDATA_CONTACTS_CONTACT (entry));
+	bdate = e_contact_get (contact, E_CONTACT_ANNIVERSARY);
+	if (bdate) {
+		GDate *gdate = g_date_new_dmy (bdate->day, bdate->month, bdate->year);
+
+		if (gdate) {
+			GDataGContactEvent *anni = gdata_gcontact_event_new (gdate, GDATA_GCONTACT_EVENT_ANNIVERSARY, NULL);
+
+			if (anni) {
+				gdata_contacts_contact_add_event (GDATA_CONTACTS_CONTACT (entry), anni);
+				g_object_unref (anni);
+			}
+
+			g_date_free (gdate);
+		}
+		e_contact_date_free (bdate);
+	}
+	#endif
+
+	return TRUE;
+}
+
+static void
+foreach_extended_props_cb (const gchar *name, const gchar *value, EVCard *vcard)
+{
+	EVCardAttribute *attr;
+
+	attr = e_vcard_attribute_new (NULL, name);
+	e_vcard_add_attribute_with_value (vcard, attr, value);
+}
+
+static EContact *
+_e_contact_new_from_gdata_entry (GDataEntry *entry)
+{
+	EVCard *vcard;
+	EVCardAttribute *attr;
+	GList *email_addresses, *im_addresses, *phone_numbers, *postal_addresses, *orgs;
+	const gchar *uid, *note;
+	GList *itr;
+	GDataGDName *name;
+	GDataGDEmailAddress *email;
+	GDataGDIMAddress *im;
+	GDataGDPhoneNumber *phone_number;
+	GDataGDPostalAddress *postal_address;
+	GDataGDOrganization *org;
+	GHashTable *extended_props;
+	#ifdef HAVE_GDATA_07
+	GList *websites, *events;
+	GDate bdate;
+	gboolean bdate_has_year;
+	#endif
+
+	uid = gdata_entry_get_id (entry);
+	if (NULL == uid)
+		return NULL;
+
+	vcard = E_VCARD (e_contact_new ());
+
+	/* UID */
+	attr = e_vcard_attribute_new (NULL, EVC_UID);
+	e_vcard_add_attribute_with_value (vcard, attr, uid);
+
+	/* FN, N */
+	name = gdata_contacts_contact_get_name (GDATA_CONTACTS_CONTACT (entry));
+	if (name) {
+		EContactName name_struct;
+
+		/* Set the full name */
+		e_contact_set (E_CONTACT (vcard), E_CONTACT_FULL_NAME, gdata_gd_name_get_full_name (name));
+
+		/* We just need to set the E_CONTACT_NAME field, and all the other name attribute values
+		 * in the EContact will be populated automatically from that */
+		name_struct.family = (gchar *) gdata_gd_name_get_family_name (name);
+		name_struct.given = (gchar *) gdata_gd_name_get_given_name (name);
+		name_struct.additional = (gchar *) gdata_gd_name_get_additional_name (name);
+		name_struct.prefixes = (gchar *) gdata_gd_name_get_prefix (name);
+		name_struct.suffixes = (gchar *) gdata_gd_name_get_suffix (name);
+
+		e_contact_set (E_CONTACT (vcard), E_CONTACT_NAME, &name_struct);
+	}
+
+	/* NOTE */
+	note = gdata_entry_get_content (entry);
+	if (note)
+		e_contact_set (E_CONTACT (vcard), E_CONTACT_NOTE, note);
+
+	/* EMAIL - primary first */
+	email = gdata_contacts_contact_get_primary_email_address (GDATA_CONTACTS_CONTACT (entry));
+	add_attribute_from_gdata_gd_email_address (vcard, email);
+
+	email_addresses = gdata_contacts_contact_get_email_addresses (GDATA_CONTACTS_CONTACT (entry));
+	for (itr = email_addresses; itr; itr = itr->next) {
+		email = itr->data;
+		if (gdata_gd_email_address_is_primary (email) == TRUE)
+			continue;
+		add_attribute_from_gdata_gd_email_address (vcard, email);
+	}
+
+	/* X-IM - primary first */
+	im = gdata_contacts_contact_get_primary_im_address (GDATA_CONTACTS_CONTACT (entry));
+	add_attribute_from_gdata_gd_im_address (vcard, im);
+
+	im_addresses = gdata_contacts_contact_get_im_addresses (GDATA_CONTACTS_CONTACT (entry));
+	for (itr = im_addresses; itr; itr = itr->next) {
+		im = itr->data;
+		if (gdata_gd_im_address_is_primary (im) == TRUE)
+			continue;
+		add_attribute_from_gdata_gd_im_address (vcard, im);
+	}
+
+	/* TEL - primary first */
+	phone_number = gdata_contacts_contact_get_primary_phone_number (GDATA_CONTACTS_CONTACT (entry));
+	add_attribute_from_gdata_gd_phone_number (vcard, phone_number);
+
+	phone_numbers = gdata_contacts_contact_get_phone_numbers (GDATA_CONTACTS_CONTACT (entry));
+	for (itr = phone_numbers; itr; itr = itr->next) {
+		phone_number = itr->data;
+		if (gdata_gd_phone_number_is_primary (phone_number) == TRUE)
+			continue;
+		add_attribute_from_gdata_gd_phone_number (vcard, phone_number);
+	}
+
+	/* LABEL and ADR - primary first */
+	postal_address = gdata_contacts_contact_get_primary_postal_address (GDATA_CONTACTS_CONTACT (entry));
+	add_attribute_from_gdata_gd_postal_address (vcard, postal_address);
+
+	postal_addresses = gdata_contacts_contact_get_postal_addresses (GDATA_CONTACTS_CONTACT (entry));
+	for (itr = postal_addresses; itr; itr = itr->next) {
+		postal_address = itr->data;
+		if (gdata_gd_postal_address_is_primary (postal_address) == TRUE)
+			continue;
+		add_attribute_from_gdata_gd_postal_address (vcard, postal_address);
+	}
+
+	/* ORG - primary first */
+	org = gdata_contacts_contact_get_primary_organization (GDATA_CONTACTS_CONTACT (entry));
+	orgs = gdata_contacts_contact_get_organizations (GDATA_CONTACTS_CONTACT (entry));
+	add_attribute_from_gdata_gd_organization (vcard, org);
+
+	if (org || orgs) {
+		if (!org)
+			org = orgs->data;
+
+		/* EVC_TITLE and EVC_ROLE from the primary organization (or the first organization in the list if there isn't a primary org) */
+		attr = e_vcard_attribute_new (NULL, EVC_TITLE);
+		e_vcard_add_attribute_with_value (vcard, attr, gdata_gd_organization_get_title (org));
+
+		attr = e_vcard_attribute_new (NULL, EVC_ROLE);
+		e_vcard_add_attribute_with_value (vcard, attr, gdata_gd_organization_get_job_description (org));
+	}
+
+	for (itr = orgs; itr; itr = itr->next) {
+		org = itr->data;
+		if (gdata_gd_organization_is_primary (org) == TRUE)
+			continue;
+		add_attribute_from_gdata_gd_organization (vcard, org);
+	}
+
+	/* Extended properties */
+	extended_props = gdata_contacts_contact_get_extended_properties (GDATA_CONTACTS_CONTACT (entry));
+	g_hash_table_foreach (extended_props, (GHFunc) foreach_extended_props_cb, vcard);
+
+	#ifdef HAVE_GDATA_07
+	websites = gdata_contacts_contact_get_websites (GDATA_CONTACTS_CONTACT (entry));
+	for (itr = websites; itr != NULL; itr = itr->next) {
+		GDataGContactWebsite *website = itr->data;
+		const gchar *uri, *reltype;
+
+		if (!website)
+			continue;
+
+		uri = gdata_gcontact_website_get_uri (website);
+		reltype = gdata_gcontact_website_get_relation_type (website);
+
+		if (!uri || !*uri || !reltype)
+			continue;
+
+		if (g_str_equal (reltype, GDATA_GCONTACT_WEBSITE_HOME_PAGE))
+			e_contact_set (E_CONTACT (vcard), E_CONTACT_HOMEPAGE_URL, uri);
+		else if (g_str_equal (reltype, GDATA_GCONTACT_WEBSITE_BLOG))
+			e_contact_set (E_CONTACT (vcard), E_CONTACT_BLOG_URL, uri);
+	}
+
+	g_date_clear (&bdate, 1);
+	bdate_has_year = gdata_contacts_contact_get_birthday (GDATA_CONTACTS_CONTACT (entry), &bdate);
+	if (!bdate_has_year) {
+		GTimeVal curr_time = { 0 };
+		GDate tmp_date;
+
+		g_get_current_time (&curr_time);
+		g_date_clear (&tmp_date, 1);
+		g_date_set_time_val (&tmp_date, &curr_time);
+
+		g_date_set_year (&bdate, g_date_get_year (&tmp_date));
+	}
+
+	if (g_date_valid (&bdate)) {
+		EContactDate *date = e_contact_date_new ();
+
+		if (date) {
+			date->day = g_date_get_day (&bdate);
+			date->month = g_date_get_month (&bdate);
+			date->year = g_date_get_year (&bdate);
+
+			e_contact_set (E_CONTACT (vcard), E_CONTACT_BIRTH_DATE, date);
+			e_contact_date_free (date);
+		}
+	}
+
+	events = gdata_contacts_contact_get_events (GDATA_CONTACTS_CONTACT (entry));
+	for (itr = events; itr; itr = itr->next) {
+		GDataGContactEvent *event = itr->data;
+
+		if (!event)
+			continue;
+
+		if (!gdata_gcontact_event_get_relation_type (event) ||
+		    !g_str_equal (gdata_gcontact_event_get_relation_type (event), GDATA_GCONTACT_EVENT_ANNIVERSARY))
+			continue;
+
+		g_date_clear (&bdate, 1);
+		gdata_gcontact_event_get_date (event, &bdate);
+
+		if (g_date_valid (&bdate)) {
+			EContactDate *date = e_contact_date_new ();
+
+			if (date) {
+				date->day = g_date_get_day (&bdate);
+				date->month = g_date_get_month (&bdate);
+				date->year = g_date_get_year (&bdate);
+
+				e_contact_set (E_CONTACT (vcard), E_CONTACT_ANNIVERSARY, date);
+				e_contact_date_free (date);
+			}
+		}
+
+		break;
+	}
+	#endif
+
+	return E_CONTACT (vcard);
+}
+
+static void
+_e_contact_add_gdata_entry_xml (EContact *contact, GDataEntry *entry)
+{
+	EVCardAttribute *attr;
+	gchar *entry_xml;
+	GDataLink *link;
+
+	/* Cache the XML representing the entry */
+	entry_xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
+	attr = e_vcard_attribute_new ("", GDATA_ENTRY_XML_ATTR);
+	e_vcard_attribute_add_value (attr, entry_xml);
+	e_vcard_add_attribute (E_VCARD (contact), attr);
+	g_free (entry_xml);
+
+	/* Also add the update URI for the entry, since that's not serialised by gdata_parsable_get_xml */
+	link = gdata_entry_look_up_link (entry, GDATA_LINK_EDIT);
+	if (link != NULL) {
+		attr = e_vcard_attribute_new ("", GDATA_ENTRY_LINK_ATTR);
+		e_vcard_attribute_add_value (attr, gdata_link_get_uri (link));
+		e_vcard_add_attribute (E_VCARD (contact), attr);
+	}
+}
+
+static void
+_e_contact_remove_gdata_entry_xml (EContact *contact)
+{
+	e_vcard_remove_attributes (E_VCARD (contact), NULL, GDATA_ENTRY_XML_ATTR);
+	e_vcard_remove_attributes (E_VCARD (contact), NULL, GDATA_ENTRY_LINK_ATTR);
+}
+
+static const gchar *
+_e_contact_get_gdata_entry_xml (EContact *contact, const gchar **edit_link)
+{
+	EVCardAttribute *attr;
+	GList *values = NULL;
+
+	/* Return the edit link if asked */
+	if (edit_link != NULL) {
+		attr = e_vcard_get_attribute (E_VCARD (contact), GDATA_ENTRY_LINK_ATTR);
+		if (attr != NULL)
+			values = e_vcard_attribute_get_values (attr);
+		if (values != NULL)
+			*edit_link = values->data;
+	}
+
+	/* Return the entry's XML */
+	attr = e_vcard_get_attribute (E_VCARD (contact), GDATA_ENTRY_XML_ATTR);
+	values = e_vcard_attribute_get_values (attr);
+
+	return values ? values->data : NULL;
+}
+
+struct RelTypeMap {
+	const gchar *rel;
+	const gchar *types[2];
+};
+
+/* NOTE: These maps must be kept ordered with the one-to-many types first */
+static const struct RelTypeMap rel_type_map_phone[] = {
+	{ "home", { "HOME", "VOICE" }},
+	{ "home_fax", { "HOME", "FAX" }},
+	{ "work", { "WORK", "VOICE" }},
+	{ "work_fax", { "WORK", "FAX" }},
+	{ "work_mobile", { "WORK", "CELL" }},
+	{ "work_pager", { "WORK", "PAGER" }},
+	{ "assistant", { EVC_X_ASSISTANT, NULL }},
+	{ "callback", { EVC_X_CALLBACK, NULL }},
+	{ "car", { "CAR", NULL }},
+	{ "company_main", {EVC_X_COMPANY, NULL }},
+	{ "fax", { "FAX", NULL }},
+	{ "isdn", { "ISDN", NULL }},
+	{ "main", { "PREF", NULL }},
+	{ "mobile", { "CELL", NULL }},
+	{ "other", { "VOICE", NULL }},
+	{ "other_fax", { "FAX", NULL }},
+	{ "pager", { "PAGER", NULL }},
+	{ "radio", { EVC_X_RADIO, NULL }},
+	{ "telex", { EVC_X_TELEX, NULL }},
+	{ "tty_tdd", { EVC_X_TTYTDD, NULL }}
+};
+
+static const struct RelTypeMap rel_type_map_im[] = {
+	{ "home", { "HOME", NULL }},
+	{ "netmeeting", { "NETMEETING", NULL }},
+	{ "other", { "OTHER", NULL }},
+	{ "work", { "WORK", NULL }},
+};
+
+static const struct RelTypeMap rel_type_map_others[] = {
+	{ "home", { "HOME", NULL }},
+	{ "other", { "OTHER", NULL }},
+	{ "work", { "WORK", NULL }},
+};
+
+static gboolean
+_add_type_param_from_google_rel (EVCardAttribute *attr, const struct RelTypeMap rel_type_map[], guint map_len, const gchar *rel)
+{
+	const gchar * field;
+	guint i;
+
+	field = strstr (rel ? rel : "", "#");
+	if (NULL == field)
+		return FALSE;
+
+	field++;
+	for (i = 0; i < map_len; i++) {
+		if (0 == g_ascii_strcasecmp (rel_type_map[i].rel, field)) {
+			EVCardAttributeParam *param;
+			param = e_vcard_attribute_param_new ("TYPE");
+			e_vcard_attribute_param_add_value (param, rel_type_map[i].types[0]);
+			if (rel_type_map[i].types[1])
+				e_vcard_attribute_param_add_value (param, rel_type_map[i].types[1]);
+			e_vcard_attribute_add_param (attr, param);
+			return TRUE;
+		}
+	}
+	g_warning ("Unknown relationship '%s'", rel);
+
+	return TRUE;
+}
+
+static gboolean
+add_type_param_from_google_rel_phone (EVCardAttribute *attr, const gchar *rel)
+{
+	return _add_type_param_from_google_rel (attr, rel_type_map_phone, G_N_ELEMENTS (rel_type_map_phone), rel);
+}
+
+static gboolean
+add_type_param_from_google_rel_im (EVCardAttribute *attr, const gchar *rel)
+{
+	return _add_type_param_from_google_rel (attr, rel_type_map_im, G_N_ELEMENTS (rel_type_map_im), rel);
+}
+
+static gboolean
+add_type_param_from_google_rel (EVCardAttribute *attr, const gchar *rel)
+{
+	return _add_type_param_from_google_rel (attr, rel_type_map_others, G_N_ELEMENTS (rel_type_map_others), rel);
+}
+
+static void
+add_label_param (EVCardAttribute *attr, const gchar *label)
+{
+	if (label && label[0] != '\0') {
+		EVCardAttributeParam *param;
+		param = e_vcard_attribute_param_new (GOOGLE_LABEL_PARAM);
+		e_vcard_attribute_add_param_with_value (attr, param, label);
+	}
+}
+
+static gchar *
+_google_rel_from_types (GList *types, const struct RelTypeMap rel_type_map[], guint map_len)
+{
+	const gchar format[] = "http://schemas.google.com/g/2005#%s";;
+	guint i;
+
+	/* For each of the entries in the map... */
+	for (i = 0; i < map_len; i++) {
+		GList *cur;
+		gboolean first_matched = FALSE, second_matched = rel_type_map[i].types[1] ? FALSE : TRUE;
+
+		/* ...iterate through all the vCard's types and see if two of them match the types in the current map entry. */
+		for (cur = types; cur != NULL; cur = cur->next) {
+			if (0 == g_ascii_strcasecmp (rel_type_map[i].types[0], cur->data))
+				first_matched = TRUE;
+			else if (!rel_type_map[i].types[1] || 0 == g_ascii_strcasecmp (rel_type_map[i].types[1], cur->data))
+				second_matched = TRUE;
+
+			/* If they do, return the rel value from that entry... */
+			if (first_matched && second_matched)
+				return g_strdup_printf (format, rel_type_map[i].rel);
+		}
+	}
+
+	/* ...otherwise return an "other" result. */
+	return g_strdup_printf (format, "other");
+}
+
+static gchar *
+google_rel_from_types (GList *types)
+{
+	return _google_rel_from_types (types, rel_type_map_others, G_N_ELEMENTS (rel_type_map_others));
+}
+
+static gchar *
+google_rel_from_types_phone (GList *types)
+{
+	return _google_rel_from_types (types, rel_type_map_phone, G_N_ELEMENTS (rel_type_map_phone));
+}
+
+static gboolean
+is_known_google_im_protocol (const gchar *protocol)
+{
+	const gchar *known_protocols[] = {
+		"AIM", "MSN", "YAHOO", "SKYPE", "QQ",
+		"GOOGLE_TALK", "ICQ", "JABBER"
+	};
+	guint i;
+
+	if (NULL == protocol)
+		return FALSE;
+
+	for (i = 0; i < G_N_ELEMENTS (known_protocols); i++) {
+		if (0 == g_ascii_strcasecmp (known_protocols[i], protocol))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gchar *
+field_name_from_google_im_protocol (const gchar *google_protocol)
+{
+	gchar *protocol;
+	if (!google_protocol)
+		return NULL;
+
+	protocol = g_strrstr (google_protocol, "#");
+	if (!protocol)
+		return NULL;
+
+	return g_strdup_printf ("X-%s", protocol + 1);
+}
+
+static gchar *
+google_im_protocol_from_field_name (const gchar *field_name)
+{
+	const gchar format[] = "http://schemas.google.com/g/2005#%s";;
+
+	if (!field_name || strlen (field_name) < 3)
+		return NULL;
+
+	return g_strdup_printf (format, field_name + 2);
+}
+
+static void
+add_primary_param (EVCardAttribute *attr, gboolean has_type)
+{
+	EVCardAttributeParam *param = e_vcard_attribute_param_new (GOOGLE_PRIMARY_PARAM);
+	e_vcard_attribute_add_param_with_value (attr, param, "1");
+
+	if (!has_type) {
+		param = e_vcard_attribute_param_new ("TYPE");
+		e_vcard_attribute_add_param_with_value (attr, param, "PREF");
+	}
+}
+
+static GList *
+get_google_primary_type_label (EVCardAttribute *attr, gboolean *primary, const gchar **label)
+{
+	GList *params;
+	GList *types = NULL;
+
+	*primary = FALSE;
+	*label = NULL;
+	params = e_vcard_attribute_get_params (attr);
+
+	while (params) {
+		const gchar *name;
+
+		name = e_vcard_attribute_param_get_name (params->data);
+		if (g_ascii_strcasecmp (name, GOOGLE_PRIMARY_PARAM) == 0) {
+			GList *values;
+
+			values = e_vcard_attribute_param_get_values (params->data);
+			if (values && values->data &&
+				(((const gchar *)values->data)[0] == '1' ||
+				 0 == g_ascii_strcasecmp (values->data, "yes"))) {
+				*primary = TRUE;
+			}
+		}
+
+		if (g_ascii_strcasecmp (name, GOOGLE_LABEL_PARAM) == 0) {
+			GList *values;
+
+			values = e_vcard_attribute_param_get_values (params->data);
+			*label = values ? values->data : NULL;
+		}
+
+		if (g_ascii_strcasecmp (name, "TYPE") == 0)
+			types = e_vcard_attribute_param_get_values (params->data);
+		params = params->next;
+	}
+
+	return types;
+}
+
+static void
+add_attribute_from_gdata_gd_email_address (EVCard *vcard, GDataGDEmailAddress *email)
+{
+	EVCardAttribute *attr;
+	gboolean has_type;
+
+	if (!email || !gdata_gd_email_address_get_address (email))
+		return;
+
+	attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
+	has_type = add_type_param_from_google_rel (attr, gdata_gd_email_address_get_relation_type (email));
+	if (gdata_gd_email_address_is_primary (email))
+		add_primary_param (attr, has_type);
+	add_label_param (attr, gdata_gd_email_address_get_label (email));
+
+	e_vcard_attribute_add_value (attr, gdata_gd_email_address_get_address (email));
+
+	if (attr)
+		e_vcard_add_attribute (vcard, attr);
+}
+
+static void
+add_attribute_from_gdata_gd_im_address (EVCard *vcard, GDataGDIMAddress *im)
+{
+	EVCardAttribute *attr;
+	gboolean has_type;
+	gchar *field_name;
+
+	if (!im || !gdata_gd_im_address_get_address (im))
+		return;
+
+	field_name = field_name_from_google_im_protocol (gdata_gd_im_address_get_protocol (im));
+	if (!field_name)
+		return;
+
+	attr = e_vcard_attribute_new (NULL, field_name);
+	has_type = add_type_param_from_google_rel_im (attr, gdata_gd_im_address_get_relation_type (im));
+	if (gdata_gd_im_address_is_primary (im))
+		add_primary_param (attr, has_type);
+	add_label_param (attr, gdata_gd_im_address_get_label (im));
+
+	e_vcard_attribute_add_value (attr, gdata_gd_im_address_get_address (im));
+
+	if (attr)
+		e_vcard_add_attribute (vcard, attr);
+}
+
+static void
+add_attribute_from_gdata_gd_phone_number (EVCard *vcard, GDataGDPhoneNumber *number)
+{
+	EVCardAttribute *attr;
+	gboolean has_type;
+
+	if (!number || !gdata_gd_phone_number_get_number (number))
+		return;
+
+	attr = e_vcard_attribute_new (NULL, EVC_TEL);
+	has_type = add_type_param_from_google_rel_phone (attr, gdata_gd_phone_number_get_relation_type (number));
+	if (gdata_gd_phone_number_is_primary (number))
+		add_primary_param (attr, has_type);
+	add_label_param (attr, gdata_gd_phone_number_get_label (number));
+
+	e_vcard_attribute_add_value (attr, gdata_gd_phone_number_get_number (number));
+
+	if (attr)
+		e_vcard_add_attribute (vcard, attr);
+}
+
+static void
+add_attribute_from_gdata_gd_postal_address (EVCard *vcard, GDataGDPostalAddress *address)
+{
+	EVCardAttribute *attr;
+	gboolean has_type;
+
+	if (!address || !gdata_gd_postal_address_get_address (address))
+		return;
+
+	/* Add the LABEL */
+	attr = e_vcard_attribute_new (NULL, EVC_LABEL);
+	has_type = add_type_param_from_google_rel (attr, gdata_gd_postal_address_get_relation_type (address));
+	if (gdata_gd_postal_address_is_primary (address))
+		add_primary_param (attr, has_type);
+	add_label_param (attr, gdata_gd_postal_address_get_label (address));
+
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_address (address));
+
+	if (attr)
+		e_vcard_add_attribute (vcard, attr);
+
+	/* Add the ADR */
+	attr = e_vcard_attribute_new (NULL, EVC_ADR);
+	has_type = add_type_param_from_google_rel (attr, gdata_gd_postal_address_get_relation_type (address));
+	if (gdata_gd_postal_address_is_primary (address))
+		add_primary_param (attr, has_type);
+	add_label_param (attr, gdata_gd_postal_address_get_label (address));
+
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_po_box (address));
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_house_name (address));
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_street (address));
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_city (address));
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_region (address));
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_postcode (address));
+	e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_country (address));
+
+	/* The following bits of data provided by the Google Contacts API can't be fitted into the vCard format:
+	 *   gdata_gd_postal_address_get_mail_class
+	 *   gdata_gd_postal_address_get_usage
+	 *   gdata_gd_postal_address_get_agent
+	 *   gdata_gd_postal_address_get_neighborhood
+	 *   gdata_gd_postal_address_get_subregion
+	 *   gdata_gd_postal_address_get_country_code */
+
+	if (attr)
+		e_vcard_add_attribute (vcard, attr);
+}
+
+static void
+add_attribute_from_gdata_gd_organization (EVCard *vcard, GDataGDOrganization *org)
+{
+	EVCardAttribute *attr;
+	gboolean has_type;
+
+	if (!org || !gdata_gd_organization_get_name (org))
+		return;
+
+	/* Add the LABEL */
+	attr = e_vcard_attribute_new (NULL, EVC_ORG);
+	has_type = add_type_param_from_google_rel (attr, gdata_gd_organization_get_relation_type (org));
+	if (gdata_gd_organization_is_primary (org))
+		add_primary_param (attr, has_type);
+	add_label_param (attr, gdata_gd_organization_get_label (org));
+
+	e_vcard_attribute_add_value (attr, gdata_gd_organization_get_name (org));
+	e_vcard_attribute_add_value (attr, gdata_gd_organization_get_department (org));
+
+	/* The following bits of data provided by the Google Contacts API can't be fitted into the vCard format:
+	 *   gdata_gd_organization_get_title
+	 *   gdata_gd_organization_get_job_description
+	 *   gdata_gd_organization_get_symbol
+	 *   gdata_gd_organization_get_location */
+
+	if (attr)
+		e_vcard_add_attribute (vcard, attr);
+}
+
+static GDataGDEmailAddress *
+gdata_gd_email_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+{
+	GDataGDEmailAddress *email = NULL;
+	GList *values;
+
+	values = e_vcard_attribute_get_values (attr);
+	if (values) {
+		GList *types;
+		gchar *rel;
+		const gchar *label;
+		gboolean primary;
+
+		types = get_google_primary_type_label (attr, &primary, &label);
+		if (!*have_primary)
+			*have_primary = primary;
+		else
+			primary = FALSE;
+
+		rel = google_rel_from_types (types);
+		email = gdata_gd_email_address_new (values->data, rel, label, primary);
+		g_free (rel);
+
+		__debug__ ("New %semail entry %s (%s/%s)",
+			   gdata_gd_email_address_is_primary (email) ? "primary " : "",
+			   gdata_gd_email_address_get_address (email),
+			   gdata_gd_email_address_get_relation_type (email),
+			   gdata_gd_email_address_get_label (email));
+	}
+
+	return email;
+}
+
+static GDataGDIMAddress *
+gdata_gd_im_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+{
+	GDataGDIMAddress *im = NULL;
+	GList *values;
+	const gchar *name;
+
+	name = e_vcard_attribute_get_name (attr);
+
+	values = e_vcard_attribute_get_values (attr);
+	if (values) {
+		GList *types;
+		gchar *protocol, *rel;
+		const gchar *label;
+		gboolean primary;
+
+		types = get_google_primary_type_label (attr, &primary, &label);
+		if (!*have_primary)
+			*have_primary = primary;
+		else
+			primary = FALSE;
+
+		rel = google_rel_from_types (types);
+		protocol = google_im_protocol_from_field_name (name);
+		im = gdata_gd_im_address_new (values->data, protocol, rel, label, primary);
+		g_free (rel);
+		g_free (protocol);
+
+		__debug__ ("New %s%s entry %s (%s/%s)",
+			   gdata_gd_im_address_is_primary (im) ? "primary " : "",
+			   gdata_gd_im_address_get_protocol (im),
+			   gdata_gd_im_address_get_address (im),
+			   gdata_gd_im_address_get_relation_type (im),
+			   gdata_gd_im_address_get_label (im));
+	}
+
+	return im;
+}
+
+static GDataGDPhoneNumber *
+gdata_gd_phone_number_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+{
+	GDataGDPhoneNumber *number = NULL;
+	GList *values;
+
+	values = e_vcard_attribute_get_values (attr);
+	if (values) {
+		GList *types;
+		gboolean primary;
+		gchar *rel;
+		const gchar *label;
+
+		types = get_google_primary_type_label (attr, &primary, &label);
+		if (!*have_primary)
+			*have_primary = primary;
+		else
+			primary = FALSE;
+
+		rel = google_rel_from_types_phone (types);
+		number = gdata_gd_phone_number_new (values->data, rel, label, NULL, primary);
+		g_free (rel);
+
+		__debug__ ("New %sphone-number entry %s (%s/%s)",
+			   gdata_gd_phone_number_is_primary (number) ? "primary " : "",
+			   gdata_gd_phone_number_get_number (number),
+			   gdata_gd_phone_number_get_relation_type (number),
+			   gdata_gd_phone_number_get_label (number));
+	}
+
+	return number;
+}
+
+static GDataGDPostalAddress *
+gdata_gd_postal_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+{
+	GDataGDPostalAddress *address = NULL;
+	GList *values;
+
+	values = e_vcard_attribute_get_values (attr);
+	if (values) {
+		GList *types, *value;
+		gchar *rel;
+		const gchar *label;
+		gboolean primary;
+
+		types = get_google_primary_type_label (attr, &primary, &label);
+		if (!*have_primary)
+			*have_primary = primary;
+		else
+			primary = FALSE;
+
+		rel = google_rel_from_types (types);
+		address = gdata_gd_postal_address_new (rel, label, primary);
+		g_free (rel);
+
+		__debug__ ("New %spostal address entry %s (%s/%s)",
+			   gdata_gd_postal_address_is_primary (address) ? "primary " : "",
+			   gdata_gd_postal_address_get_address (address),
+			   gdata_gd_postal_address_get_relation_type (address),
+			   gdata_gd_postal_address_get_label (address));
+
+		/* Set the components of the address from the vCard's attribute values */
+		value = values;
+		if (!value)
+			return address;
+		gdata_gd_postal_address_set_po_box (address, (*((gchar *) value->data) != '\0') ? value->data : NULL);
+		value = value->next;
+		if (!value)
+			return address;
+		gdata_gd_postal_address_set_house_name (address, (*((gchar *) value->data) != '\0') ? value->data : NULL);
+		value = value->next;
+		if (!value)
+			return address;
+		gdata_gd_postal_address_set_street (address, (*((gchar *) value->data) != '\0') ? value->data : NULL);
+		value = value->next;
+		if (!value)
+			return address;
+		gdata_gd_postal_address_set_city (address, (*((gchar *) value->data) != '\0') ? value->data : NULL);
+		value = value->next;
+		if (!value)
+			return address;
+		gdata_gd_postal_address_set_region (address, (*((gchar *) value->data) != '\0') ? value->data : NULL);
+		value = value->next;
+		if (!value)
+			return address;
+		gdata_gd_postal_address_set_postcode (address, (*((gchar *) value->data) != '\0') ? value->data : NULL);
+		value = value->next;
+		if (!value)
+			return address;
+		gdata_gd_postal_address_set_country (address, (*((gchar *) value->data) != '\0') ? value->data : NULL, NULL);
+	}
+
+	return address;
+}
+
+static GDataGDOrganization *
+gdata_gd_organization_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+{
+	GDataGDOrganization *org = NULL;
+	GList *values;
+
+	values = e_vcard_attribute_get_values (attr);
+	if (values) {
+		GList *types;
+		gboolean primary;
+		gchar *rel;
+		const gchar *label;
+
+		types = get_google_primary_type_label (attr, &primary, &label);
+		if (!*have_primary)
+			*have_primary = primary;
+		else
+			primary = FALSE;
+
+		rel = google_rel_from_types (types);
+		org = gdata_gd_organization_new (values->data, NULL, rel, label, primary);
+		if (values->next)
+			gdata_gd_organization_set_department (org, values->next->data);
+		g_free (rel);
+
+		/* TITLE and ROLE are dealt with separately in _gdata_entry_update_from_e_contact() */
+
+		__debug__ ("New %sorganization entry %s (%s/%s)",
+			   gdata_gd_organization_is_primary (org) ? "primary " : "",
+			   gdata_gd_organization_get_name (org),
+			   gdata_gd_organization_get_relation_type (org),
+			   gdata_gd_organization_get_label (org));
+	}
+
+	return org;
+}



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