[libgdata] [contacts] Enforce use of the full projection in contact IDs



commit 268f9dd4a62da5b9ab8b811e3acd9921589e3a13
Author: Philip Withnall <philip tecnocode co uk>
Date:   Fri Jul 16 09:08:48 2010 +0100

    [contacts] Enforce use of the full projection in contact IDs
    
    The server can return contacts whose IDs use the base projection, which will
    cause problems if we then submit changes to those IDs. We need to hack the
    IDs to use the full projection as early as possible. Test case included.
    
    Helps: http://code.google.com/p/gdata-issues/issues/detail?id=2129

 gdata/services/contacts/gdata-contacts-contact.c |   34 +++++++++++++++++++++-
 gdata/tests/contacts.c                           |   32 ++++++++++++++++++++
 2 files changed, 65 insertions(+), 1 deletions(-)
---
diff --git a/gdata/services/contacts/gdata-contacts-contact.c b/gdata/services/contacts/gdata-contacts-contact.c
index 1b1a365..da51b50 100644
--- a/gdata/services/contacts/gdata-contacts-contact.c
+++ b/gdata/services/contacts/gdata-contacts-contact.c
@@ -615,6 +615,24 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 	if (gdata_parser_is_namespace (node, "http://www.w3.org/2007/app";) == TRUE &&
 	    gdata_parser_time_val_from_element (node, "edited", P_REQUIRED | P_NO_DUPES, &(self->priv->edited), &success, error) == TRUE) {
 		return success;
+	} else if (gdata_parser_is_namespace (node, "http://www.w3.org/2005/Atom";) == TRUE && xmlStrcmp (node->name, (xmlChar*) "id") == 0) {
+		/* We have to override <id> parsing to fix the projection. Modify it in-place so that the parser in GDataEntry will pick up
+		 * the changes. This fixes bugs caused by referring to contacts by the base projection, rather than the full projection;
+		 * such as http://code.google.com/p/gdata-issues/issues/detail?id=2129. */
+		gchar *base;
+		gchar *id = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
+
+		if (id != NULL) {
+			base = strstr (id, "/base/");
+			if (base != NULL) {
+				memcpy (base, "/full/", 6);
+				xmlNodeSetContent (node, (xmlChar*) id);
+			}
+		}
+
+		xmlFree (id);
+
+		return GDATA_PARSABLE_CLASS (gdata_contacts_contact_parent_class)->parse_xml (parsable, doc, node, user_data, error);
 	} else if (gdata_parser_is_namespace (node, "http://schemas.google.com/g/2005";) == TRUE) {
 		if (gdata_parser_object_from_element_setter (node, "email", P_REQUIRED, GDATA_TYPE_GD_EMAIL_ADDRESS,
 		                                             gdata_contacts_contact_add_email_address, self, &success, error) == TRUE ||
@@ -1009,7 +1027,21 @@ get_entry_uri (const gchar *id)
 GDataContactsContact *
 gdata_contacts_contact_new (const gchar *id)
 {
-	GDataContactsContact *contact = GDATA_CONTACTS_CONTACT (g_object_new (GDATA_TYPE_CONTACTS_CONTACT, "id", id, NULL));
+	GDataContactsContact *contact;
+	gchar *base, *_id;
+
+	_id = g_strdup (id);
+
+	/* Fix the ID to refer to the full projection, rather than the base projection. */
+	if (_id != NULL) {
+		base = strstr (_id, "/base/");
+		if (base != NULL)
+			memcpy (base, "/full/", 6);
+	}
+
+	contact = GDATA_CONTACTS_CONTACT (g_object_new (GDATA_TYPE_CONTACTS_CONTACT, "id", _id, NULL));
+
+	g_free (_id);
 
 	/* Set the edited property to the current time (creation time). We don't do this in *_init() since that would cause
 	 * setting it from parse_xml() to fail (duplicate element). */
diff --git a/gdata/tests/contacts.c b/gdata/tests/contacts.c
index 7a944da..c788f58 100644
--- a/gdata/tests/contacts.c
+++ b/gdata/tests/contacts.c
@@ -1448,6 +1448,37 @@ teardown_batch_async (BatchAsyncData *data, gconstpointer service)
 	g_object_unref (data->new_contact);
 }
 
+static void
+test_id (void)
+{
+	GDataContactsContact *contact;
+	GError *error = NULL;
+
+	/* Check that IDs are changed to the full projection when creating a new contactâ?¦ */
+	contact = gdata_contacts_contact_new ("http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/base/1b46cdd20bfbee3b");
+	g_assert_cmpstr (gdata_entry_get_id (GDATA_ENTRY (contact)), ==,
+	                 "http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/full/1b46cdd20bfbee3b");
+	g_object_unref (contact);
+
+	/* â?¦and when creating one from XML. */
+	contact = GDATA_CONTACTS_CONTACT (gdata_parsable_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT,
+		"<entry xmlns='http://www.w3.org/2005/Atom' "
+			"xmlns:gd='http://schemas.google.com/g/2005'>"
+			"<id>http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/base/1b46cdd20bfbee3b</id>"
+			"<updated>2009-04-25T15:21:53.688Z</updated>"
+			"<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/contact/2008#contact'/>"
+			"<title>Foobar</title>"
+		"</entry>", -1, &error));
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_CONTACTS_CONTACT (contact));
+	g_clear_error (&error);
+
+	g_assert_cmpstr (gdata_entry_get_id (GDATA_ENTRY (contact)), ==,
+	                 "http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/full/1b46cdd20bfbee3b");
+
+	g_object_unref (contact);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1478,6 +1509,7 @@ main (int argc, char *argv[])
 	g_test_add ("/contacts/batch/async", BatchAsyncData, service, setup_batch_async, test_batch_async, teardown_batch_async);
 	g_test_add ("/contacts/batch/async/cancellation", BatchAsyncData, service, setup_batch_async, test_batch_async_cancellation,
 	            teardown_batch_async);
+	g_test_add_func ("/contacts/id", test_id);
 
 	retval = g_test_run ();
 	g_object_unref (service);



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