[libgdata] [gcontact] Add support for GDataGContactLanguage and hobbies



commit eab9685d23dcd6e809281a04e1eef33faa9adeee
Author: Philip Withnall <philip tecnocode co uk>
Date:   Tue Apr 6 19:00:24 2010 +0100

    [gcontact] Add support for GDataGContactLanguage and hobbies
    
    Closes: bgo#613551

 Makefile.am                                      |    2 +
 docs/reference/gdata-docs.xml                    |    1 +
 docs/reference/gdata-sections.txt                |   29 ++
 gdata/gcontact/gdata-gcontact-language.c         |  340 ++++++++++++++++++++++
 gdata/gcontact/gdata-gcontact-language.h         |   76 +++++
 gdata/gdata.h                                    |    1 +
 gdata/gdata.symbols                              |   13 +
 gdata/services/contacts/gdata-contacts-contact.c |  152 ++++++++++
 gdata/services/contacts/gdata-contacts-contact.h |    9 +
 gdata/tests/contacts.c                           |   52 ++++
 gdata/tests/general.c                            |   85 ++++++
 11 files changed, 760 insertions(+), 0 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 07fe640..e847909 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -194,6 +194,7 @@ gdatagcontactinclude_HEADERS = \
 	gdata/gcontact/gdata-gcontact-event.h		\
 	gdata/gcontact/gdata-gcontact-external-id.h	\
 	gdata/gcontact/gdata-gcontact-jot.h		\
+	gdata/gcontact/gdata-gcontact-language.h	\
 	gdata/gcontact/gdata-gcontact-relation.h	\
 	gdata/gcontact/gdata-gcontact-website.h
 
@@ -302,6 +303,7 @@ gdata_libgdata_la_SOURCES = \
 	gdata/gcontact/gdata-gcontact-event.c		\
 	gdata/gcontact/gdata-gcontact-external-id.c	\
 	gdata/gcontact/gdata-gcontact-jot.c		\
+	gdata/gcontact/gdata-gcontact-language.c	\
 	gdata/gcontact/gdata-gcontact-relation.c	\
 	gdata/gcontact/gdata-gcontact-website.c		\
 	\
diff --git a/docs/reference/gdata-docs.xml b/docs/reference/gdata-docs.xml
index 8a0b110..2c1cdee 100644
--- a/docs/reference/gdata-docs.xml
+++ b/docs/reference/gdata-docs.xml
@@ -72,6 +72,7 @@
 			<xi:include href="xml/gdata-gcontact-event.xml"/>
 			<xi:include href="xml/gdata-gcontact-external-id.xml"/>
 			<xi:include href="xml/gdata-gcontact-jot.xml"/>
+			<xi:include href="xml/gdata-gcontact-language.xml"/>
 			<xi:include href="xml/gdata-gcontact-relation.xml"/>
 			<xi:include href="xml/gdata-gcontact-website.xml"/>
 		</chapter>
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 86fb9cc..2bccd5d 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -392,6 +392,12 @@ gdata_contacts_contact_remove_all_calendars
 gdata_contacts_contact_add_external_id
 gdata_contacts_contact_get_external_ids
 gdata_contacts_contact_remove_all_external_ids
+gdata_contacts_contact_add_hobby
+gdata_contacts_contact_get_hobbies
+gdata_contacts_contact_remove_all_hobbies
+gdata_contacts_contact_add_language
+gdata_contacts_contact_get_languages
+gdata_contacts_contact_remove_all_languages
 gdata_contacts_contact_get_groups
 gdata_contacts_contact_add_group
 gdata_contacts_contact_remove_group
@@ -1967,3 +1973,26 @@ GDATA_TYPE_GCONTACT_EXTERNAL_ID
 <SUBSECTION Private>
 GDataGContactExternalIDPrivate
 </SECTION>
+
+<SECTION>
+<FILE>gdata-gcontact-language</FILE>
+<TITLE>GDataGContactLanguage</TITLE>
+GDataGContactLanguage
+GDataGContactLanguageClass
+gdata_gcontact_language_new
+gdata_gcontact_language_compare
+gdata_gcontact_language_get_code
+gdata_gcontact_language_set_code
+gdata_gcontact_language_get_label
+gdata_gcontact_language_set_label
+<SUBSECTION Standard>
+gdata_gcontact_language_get_type
+GDATA_GCONTACT_LANGUAGE
+GDATA_GCONTACT_LANGUAGE_CLASS
+GDATA_GCONTACT_LANGUAGE_GET_CLASS
+GDATA_IS_GCONTACT_LANGUAGE
+GDATA_IS_GCONTACT_LANGUAGE_CLASS
+GDATA_TYPE_GCONTACT_LANGUAGE
+<SUBSECTION Private>
+GDataGContactLanguagePrivate
+</SECTION>
diff --git a/gdata/gcontact/gdata-gcontact-language.c b/gdata/gcontact/gdata-gcontact-language.c
new file mode 100644
index 0000000..84796c8
--- /dev/null
+++ b/gdata/gcontact/gdata-gcontact-language.c
@@ -0,0 +1,340 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2010 <philip tecnocode co uk>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdata-gcontact-language
+ * @short_description: gContact language element
+ * @stability: Unstable
+ * @include: gdata/gcontact/gdata-gcontact-language.h
+ *
+ * #GDataGContactLanguage represents a "language" element from the
+ * <ulink type="http" url="http://code.google.com/apis/contacts/docs/3.0/reference.html#gcLanguage";>gContact specification</ulink>.
+ *
+ * Since: 0.7.0
+ **/
+
+#include <glib.h>
+#include <libxml/parser.h>
+
+#include "gdata-gcontact-language.h"
+#include "gdata-parsable.h"
+#include "gdata-parser.h"
+
+static void gdata_gcontact_language_finalize (GObject *object);
+static void gdata_gcontact_language_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+static void gdata_gcontact_language_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error);
+static void pre_get_xml (GDataParsable *parsable, GString *xml_string);
+static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
+
+struct _GDataGContactLanguagePrivate {
+	gchar *code;
+	gchar *label;
+};
+
+enum {
+	PROP_CODE = 1,
+	PROP_LABEL
+};
+
+G_DEFINE_TYPE (GDataGContactLanguage, gdata_gcontact_language, GDATA_TYPE_PARSABLE)
+
+static void
+gdata_gcontact_language_class_init (GDataGContactLanguageClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GDataGContactLanguagePrivate));
+
+	gobject_class->get_property = gdata_gcontact_language_get_property;
+	gobject_class->set_property = gdata_gcontact_language_set_property;
+	gobject_class->finalize = gdata_gcontact_language_finalize;
+
+	parsable_class->pre_parse_xml = pre_parse_xml;
+	parsable_class->pre_get_xml = pre_get_xml;
+	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "language";
+	parsable_class->element_namespace = "gContact";
+
+	/**
+	 * GDataGContactLanguage:code:
+	 *
+	 * A code identifying the language, conforming to the IETF BCP 47 specification. It is mutually exclusive with #GDataGContactLanguage:label.
+	 *
+	 * For more information, see the
+	 * <ulink type="http" url="http://code.google.com/apis/contacts/docs/3.0/reference.html#gcLanguage";>gContact specification</ulink>.
+	 *
+	 * Since: 0.7.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_CODE,
+				g_param_spec_string ("code",
+					"Code", "A code identifying the language, conforming to the IETF BCP 47 specification.",
+					NULL,
+					G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * GDataGContactLanguage:label:
+	 *
+	 * A free-form string that identifies the language. It is mutually exclusive with #GDataGContactLanguage:code.
+	 *
+	 * For more information, see the
+	 * <ulink type="http" url="http://code.google.com/apis/contacts/docs/3.0/reference.html#gcLanguage";>gContact specification</ulink>.
+	 *
+	 * Since: 0.7.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_LABEL,
+				g_param_spec_string ("label",
+					"Label", "A free-form string that identifies the language.",
+					NULL,
+					G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_gcontact_language_init (GDataGContactLanguage *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_GCONTACT_LANGUAGE, GDataGContactLanguagePrivate);
+}
+
+static void
+gdata_gcontact_language_finalize (GObject *object)
+{
+	GDataGContactLanguagePrivate *priv = GDATA_GCONTACT_LANGUAGE (object)->priv;
+
+	g_free (priv->code);
+	g_free (priv->label);
+
+	/* Chain up to the parent class */
+	G_OBJECT_CLASS (gdata_gcontact_language_parent_class)->finalize (object);
+}
+
+static void
+gdata_gcontact_language_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	GDataGContactLanguagePrivate *priv = GDATA_GCONTACT_LANGUAGE (object)->priv;
+
+	switch (property_id) {
+		case PROP_CODE:
+			g_value_set_string (value, priv->code);
+			break;
+		case PROP_LABEL:
+			g_value_set_string (value, priv->label);
+			break;
+		default:
+			/* We don't have any other property... */
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static void
+gdata_gcontact_language_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	GDataGContactLanguage *self = GDATA_GCONTACT_LANGUAGE (object);
+
+	switch (property_id) {
+		case PROP_CODE:
+			gdata_gcontact_language_set_code (self, g_value_get_string (value));
+			break;
+		case PROP_LABEL:
+			gdata_gcontact_language_set_label (self, g_value_get_string (value));
+			break;
+		default:
+			/* We don't have any other property... */
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static gboolean
+pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error)
+{
+	xmlChar *code, *label;
+	GDataGContactLanguagePrivate *priv = GDATA_GCONTACT_LANGUAGE (parsable)->priv;
+
+	code = xmlGetProp (root_node, (xmlChar*) "code");
+	label = xmlGetProp (root_node, (xmlChar*) "label");
+	if ((code == NULL || *code == '\0') && (label == NULL || *label == '\0')) {
+		xmlFree (code);
+		xmlFree (label);
+		return gdata_parser_error_required_property_missing (root_node, "code", error);
+	} else if (code != NULL && label != NULL) {
+		/* Can't have both set at once */
+		xmlFree (code);
+		xmlFree (label);
+		return gdata_parser_error_mutexed_properties (root_node, "code", "label", error);
+	}
+
+	priv->code = (gchar*) code;
+	priv->label = (gchar*) label;
+
+	return TRUE;
+}
+
+static void
+pre_get_xml (GDataParsable *parsable, GString *xml_string)
+{
+	GDataGContactLanguagePrivate *priv = GDATA_GCONTACT_LANGUAGE (parsable)->priv;
+
+	if (priv->code != NULL)
+		g_string_append_printf (xml_string, " code='%s'", priv->code);
+	else if (priv->label != NULL)
+		gdata_parser_string_append_escaped (xml_string, " label='", priv->label, "'");
+	else
+		g_assert_not_reached ();
+}
+
+static void
+get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
+{
+	g_hash_table_insert (namespaces, (gchar*) "gContact", (gchar*) "http://schemas.google.com/contact/2008";);
+}
+
+/**
+ * gdata_gcontact_language_new:
+ * @code: the language code, or %NULL
+ * @label: a free-form label for the language, or %NULL
+ *
+ * Creates a new #GDataGContactLanguage. More information is available in the <ulink type="http"
+ * url="http://code.google.com/apis/contacts/docs/3.0/reference.html#gcLanguage";>gContact specification</ulink>.
+ *
+ * Exactly one of @code and @label should be provided; the other must be %NULL.
+ *
+ * Return value: a new #GDataGContactLanguage; unref with g_object_unref()
+ *
+ * Since: 0.7.0
+ **/
+GDataGContactLanguage *
+gdata_gcontact_language_new (const gchar *code, const gchar *label)
+{
+	g_return_val_if_fail ((code != NULL && *code != '\0' && label == NULL) || (code == NULL && label != NULL && *label != '\0'), NULL);
+	return g_object_new (GDATA_TYPE_GCONTACT_LANGUAGE, "code", code, "label", label, NULL);
+}
+
+/**
+ * gdata_gcontact_language_compare:
+ * @a: a #GDataGContactLanguage, or %NULL
+ * @b: another #GDataGContactLanguage, or %NULL
+ *
+ * Compares the two languages in a strcmp() fashion. %NULL values are handled gracefully, with
+ * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
+ * and <code class="literal">1</code> if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @code and @label properties of the #GDataGContactLanguage<!-- -->s.
+ *
+ * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
+ * appropriate otherwise
+ *
+ * Since: 0.7.0
+ **/
+gint
+gdata_gcontact_language_compare (const GDataGContactLanguage *a, const GDataGContactLanguage *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (a != NULL && b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+
+	if (g_strcmp0 (a->priv->code, b->priv->code) == 0 && g_strcmp0 (a->priv->label, b->priv->label) == 0)
+		return 0;
+	return 1;
+}
+
+/**
+ * gdata_gcontact_language_get_code:
+ * @self: a #GDataGContactLanguage
+ *
+ * Gets the #GDataGContactLanguage:code property.
+ *
+ * Return value: the language's code, or %NULL
+ *
+ * Since: 0.7.0
+ **/
+const gchar *
+gdata_gcontact_language_get_code (GDataGContactLanguage *self)
+{
+	g_return_val_if_fail (GDATA_IS_GCONTACT_LANGUAGE (self), NULL);
+	return self->priv->code;
+}
+
+/**
+ * gdata_gcontact_language_set_code:
+ * @self: a #GDataGContactLanguage
+ * @code: the new code for the language, or %NULL
+ *
+ * Sets the #GDataGContactLanguage:code property to @code.
+ *
+ * If @code is %NULL, the code will be unset. When the #GDataGContactLanguage is used in a query, however,
+ * exactly one of #GDataGContactLanguage:code and #GDataGContactLanguage:label must be %NULL.
+ *
+ * Since: 0.7.0
+ **/
+void
+gdata_gcontact_language_set_code (GDataGContactLanguage *self, const gchar *code)
+{
+	g_return_if_fail (GDATA_IS_GCONTACT_LANGUAGE (self));
+	g_return_if_fail (code == NULL || *code != '\0');
+
+	g_free (self->priv->code);
+	self->priv->code = g_strdup (code);
+	g_object_notify (G_OBJECT (self), "code");
+}
+
+/**
+ * gdata_gcontact_language_get_label:
+ * @self: a #GDataGContactLanguage
+ *
+ * Gets the #GDataGContactLanguage:label property.
+ *
+ * Return value: a free-form label for the language, or %NULL
+ *
+ * Since: 0.7.0
+ **/
+const gchar *
+gdata_gcontact_language_get_label (GDataGContactLanguage *self)
+{
+	g_return_val_if_fail (GDATA_IS_GCONTACT_LANGUAGE (self), NULL);
+	return self->priv->label;
+}
+
+/**
+ * gdata_gcontact_language_set_label:
+ * @self: a #GDataGContactLanguage
+ * @label: the new free-form label for the language, or %NULL
+ *
+ * Sets the #GDataGContactLanguage:label property to @label.
+ *
+ * If @label is %NULL, the label will be unset. When the #GDataGContactLanguage is used in a query, however,
+ * exactly one of #GDataGContactLanguage:code and #GDataGContactLanguage:label must be %NULL.
+ *
+ * Since: 0.7.0
+ **/
+void
+gdata_gcontact_language_set_label (GDataGContactLanguage *self, const gchar *label)
+{
+	g_return_if_fail (GDATA_IS_GCONTACT_LANGUAGE (self));
+	g_return_if_fail (label == NULL || *label != '\0');
+
+	g_free (self->priv->label);
+	self->priv->label = g_strdup (label);
+	g_object_notify (G_OBJECT (self), "label");
+}
diff --git a/gdata/gcontact/gdata-gcontact-language.h b/gdata/gcontact/gdata-gcontact-language.h
new file mode 100644
index 0000000..af2e0ff
--- /dev/null
+++ b/gdata/gcontact/gdata-gcontact-language.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2010 <philip tecnocode co uk>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GDATA_GCONTACT_LANGUAGE_H
+#define GDATA_GCONTACT_LANGUAGE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-parsable.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_GCONTACT_LANGUAGE		(gdata_gcontact_language_get_type ())
+#define GDATA_GCONTACT_LANGUAGE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_GCONTACT_LANGUAGE, GDataGContactLanguage))
+#define GDATA_GCONTACT_LANGUAGE_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_GCONTACT_LANGUAGE, GDataGContactLanguageClass))
+#define GDATA_IS_GCONTACT_LANGUAGE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_GCONTACT_LANGUAGE))
+#define GDATA_IS_GCONTACT_LANGUAGE_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_GCONTACT_LANGUAGE))
+#define GDATA_GCONTACT_LANGUAGE_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_GCONTACT_LANGUAGE, GDataGContactLanguageClass))
+
+typedef struct _GDataGContactLanguagePrivate	GDataGContactLanguagePrivate;
+
+/**
+ * GDataGContactLanguage:
+ *
+ * All the fields in the #GDataGContactLanguage structure are private and should never be accessed directly.
+ *
+ * Since: 0.7.0
+ **/
+typedef struct {
+	GDataParsable parent;
+	GDataGContactLanguagePrivate *priv;
+} GDataGContactLanguage;
+
+/**
+ * GDataGContactLanguageClass:
+ *
+ * All the fields in the #GDataGContactLanguageClass structure are private and should never be accessed directly.
+ *
+ * Since: 0.7.0
+ **/
+typedef struct {
+	/*< private >*/
+	GDataParsableClass parent;
+} GDataGContactLanguageClass;
+
+GType gdata_gcontact_language_get_type (void) G_GNUC_CONST;
+
+GDataGContactLanguage *gdata_gcontact_language_new (const gchar *code, const gchar *label) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+gint gdata_gcontact_language_compare (const GDataGContactLanguage *a, const GDataGContactLanguage *b);
+
+const gchar *gdata_gcontact_language_get_code (GDataGContactLanguage *self);
+void gdata_gcontact_language_set_code (GDataGContactLanguage *self, const gchar *code);
+
+const gchar *gdata_gcontact_language_get_label (GDataGContactLanguage *self);
+void gdata_gcontact_language_set_label (GDataGContactLanguage *self, const gchar *label);
+
+G_END_DECLS
+
+#endif /* !GDATA_GCONTACT_LANGUAGE_H */
diff --git a/gdata/gdata.h b/gdata/gdata.h
index 825948c..eea2021 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -58,6 +58,7 @@
 #include <gdata/gcontact/gdata-gcontact-event.h>
 #include <gdata/gcontact/gdata-gcontact-external-id.h>
 #include <gdata/gcontact/gdata-gcontact-jot.h>
+#include <gdata/gcontact/gdata-gcontact-language.h>
 #include <gdata/gcontact/gdata-gcontact-relation.h>
 #include <gdata/gcontact/gdata-gcontact-website.h>
 
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 5716d03..83938a2 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -817,3 +817,16 @@ gdata_gcontact_external_id_set_label
 gdata_contacts_contact_add_external_id
 gdata_contacts_contact_get_external_ids
 gdata_contacts_contact_remove_all_external_ids
+gdata_contacts_contact_add_hobby
+gdata_contacts_contact_get_hobbies
+gdata_contacts_contact_remove_all_hobbies
+gdata_gcontact_language_get_type
+gdata_gcontact_language_new
+gdata_gcontact_language_compare
+gdata_gcontact_language_get_code
+gdata_gcontact_language_set_code
+gdata_gcontact_language_get_label
+gdata_gcontact_language_set_label
+gdata_contacts_contact_add_language
+gdata_contacts_contact_get_languages
+gdata_contacts_contact_remove_all_languages
diff --git a/gdata/services/contacts/gdata-contacts-contact.c b/gdata/services/contacts/gdata-contacts-contact.c
index 8aeeeda..65a6eec 100644
--- a/gdata/services/contacts/gdata-contacts-contact.c
+++ b/gdata/services/contacts/gdata-contacts-contact.c
@@ -97,6 +97,8 @@ struct _GDataContactsContactPrivate {
 	gchar *sensitivity;
 	gchar *short_name;
 	gchar *subject;
+	GList *hobbies; /* gchar* */
+	GList *languages; /* GDataGContactLanguage */
 };
 
 enum {
@@ -447,6 +449,7 @@ gdata_contacts_contact_dispose (GObject *object)
 	gdata_contacts_contact_remove_all_events (self);
 	gdata_contacts_contact_remove_all_calendars (self);
 	gdata_contacts_contact_remove_all_external_ids (self);
+	gdata_contacts_contact_remove_all_languages (self);
 
 	/* Chain up to the parent class */
 	G_OBJECT_CLASS (gdata_contacts_contact_parent_class)->dispose (object);
@@ -474,6 +477,11 @@ gdata_contacts_contact_finalize (GObject *object)
 	g_free (priv->short_name);
 	g_free (priv->subject);
 
+	if (priv->hobbies != NULL) {
+		g_list_foreach (priv->hobbies, (GFunc) g_free, NULL);
+		g_list_free (priv->hobbies);
+	}
+
 	/* Chain up to the parent class */
 	G_OBJECT_CLASS (gdata_contacts_contact_parent_class)->finalize (object);
 }
@@ -672,6 +680,8 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		                                             gdata_contacts_contact_add_calendar, self, &success, error) == TRUE ||
 		    gdata_parser_object_from_element_setter (node, "externalId", P_REQUIRED, GDATA_TYPE_GCONTACT_EXTERNAL_ID,
 		                                             gdata_contacts_contact_add_external_id, self, &success, error) == TRUE ||
+		    gdata_parser_object_from_element_setter (node, "language", P_REQUIRED, GDATA_TYPE_GCONTACT_LANGUAGE,
+		                                             gdata_contacts_contact_add_language, self, &success, error) == TRUE ||
 		    gdata_parser_string_from_element (node, "nickname", P_REQUIRED | P_NO_DUPES, &(self->priv->nickname), &success, error) == TRUE ||
 		    gdata_parser_string_from_element (node, "billingInformation", P_REQUIRED | P_NO_DUPES | P_NON_EMPTY,
 		                                      &(self->priv->billing_information), &success, error) == TRUE ||
@@ -701,6 +711,18 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 			}
 
 			self->priv->gender = (gchar*) value;
+		} else if (xmlStrcmp (node->name, (xmlChar*) "hobby") == 0) {
+			/* gContact:hobby */
+			xmlChar *hobby;
+
+			hobby = xmlNodeListGetString (doc, node->children, TRUE);
+			if (hobby == NULL || *hobby == '\0') {
+				xmlFree (hobby);
+				return gdata_parser_error_required_content_missing (node, error);
+			}
+
+			gdata_contacts_contact_add_hobby (self, (gchar*) hobby);
+			xmlFree (hobby);
 		} else if (xmlStrcmp (node->name, (xmlChar*) "userDefinedField") == 0) {
 			/* gContact:userDefinedField */
 			xmlChar *name, *value;
@@ -841,6 +863,12 @@ get_group_xml_cb (const gchar *href, gpointer deleted, GString *xml_string)
 }
 
 static void
+get_hobby_xml_cb (const gchar *hobby, GString *xml_string)
+{
+	gdata_parser_string_append_escaped (xml_string, "<gContact:hobby>", hobby, "</gContact:hobby>");
+}
+
+static void
 get_xml (GDataParsable *parsable, GString *xml_string)
 {
 	GDataContactsContactPrivate *priv = GDATA_CONTACTS_CONTACT (parsable)->priv;
@@ -863,6 +891,7 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 	get_child_xml (priv->events, xml_string);
 	get_child_xml (priv->calendars, xml_string);
 	get_child_xml (priv->external_ids, xml_string);
+	get_child_xml (priv->languages, xml_string);
 
 	/* Extended properties */
 	g_hash_table_foreach (priv->extended_properties, (GHFunc) get_extended_property_xml_cb, xml_string);
@@ -873,6 +902,9 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 	/* Group membership info */
 	g_hash_table_foreach (priv->groups, (GHFunc) get_group_xml_cb, xml_string);
 
+	/* Hobbies */
+	g_list_foreach (priv->hobbies, (GFunc) get_hobby_xml_cb, xml_string);
+
 	/* gContact:nickname */
 	if (priv->nickname != NULL)
 		gdata_parser_string_append_escaped (xml_string, "<gContact:nickname>", priv->nickname, "</gContact:nickname>");
@@ -2426,6 +2458,126 @@ gdata_contacts_contact_remove_all_external_ids (GDataContactsContact *self)
 }
 
 /**
+ * gdata_contacts_contact_add_hobby:
+ * @self: a #GDataContactsContact
+ * @hobby: a hobby to add
+ *
+ * Adds a hobby to the contact's list of hobbies, copying it in the process.
+ *
+ * Duplicate hobbies will not be added to the list.
+ *
+ * Since: 0.7.0
+ **/
+void
+gdata_contacts_contact_add_hobby (GDataContactsContact *self, const gchar *hobby)
+{
+	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
+	g_return_if_fail (hobby != NULL && *hobby != '\0');
+
+	if (g_list_find_custom (self->priv->hobbies, hobby, (GCompareFunc) g_strcmp0) == NULL)
+		self->priv->hobbies = g_list_append (self->priv->hobbies, g_strdup (hobby));
+}
+
+/**
+ * gdata_contacts_contact_get_hobbies:
+ * @self: a #GDataContactsContact
+ *
+ * Gets a list of the hobbies of the contact.
+ *
+ * Return value: a #GList of hobby strings, or %NULL
+ *
+ * Since: 0.7.0
+ **/
+GList *
+gdata_contacts_contact_get_hobbies (GDataContactsContact *self)
+{
+	g_return_val_if_fail (GDATA_IS_CONTACTS_CONTACT (self), NULL);
+	return self->priv->hobbies;
+}
+
+/**
+ * gdata_contacts_contact_remove_all_hobbies:
+ * @self: a #GDataContactsContact
+ *
+ * Removes all hobbies from the contact.
+ *
+ * Since: 0.7.0
+ **/
+void
+gdata_contacts_contact_remove_all_hobbies (GDataContactsContact *self)
+{
+	GDataContactsContactPrivate *priv = self->priv;
+
+	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
+
+	if (priv->hobbies != NULL) {
+		g_list_foreach (priv->hobbies, (GFunc) g_free, NULL);
+		g_list_free (priv->hobbies);
+	}
+	priv->hobbies = NULL;
+}
+
+/**
+ * gdata_contacts_contact_add_language:
+ * @self: a #GDataContactsContact
+ * @language: a #GDataGContactLanguage to add
+ *
+ * Adds a language to the contact's list of languages and increments its reference count.
+ *
+ * Duplicate languages will not be added to the list.
+ *
+ * Since: 0.7.0
+ **/
+void
+gdata_contacts_contact_add_language (GDataContactsContact *self, GDataGContactLanguage *language)
+{
+	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
+	g_return_if_fail (GDATA_IS_GCONTACT_LANGUAGE (language));
+
+	if (g_list_find_custom (self->priv->languages, language, (GCompareFunc) gdata_gcontact_language_compare) == NULL)
+		self->priv->languages = g_list_append (self->priv->languages, g_object_ref (language));
+}
+
+/**
+ * gdata_contacts_contact_get_languages:
+ * @self: a #GDataContactsContact
+ *
+ * Gets a list of the languages of the contact.
+ *
+ * Return value: a #GList of #GDataGContactLanguage<!-- -->s, or %NULL
+ *
+ * Since: 0.7.0
+ **/
+GList *
+gdata_contacts_contact_get_languages (GDataContactsContact *self)
+{
+	g_return_val_if_fail (GDATA_IS_CONTACTS_CONTACT (self), NULL);
+	return self->priv->languages;
+}
+
+/**
+ * gdata_contacts_contact_remove_all_languages:
+ * @self: a #GDataContactsContact
+ *
+ * Removes all languages from the contact.
+ *
+ * Since: 0.7.0
+ **/
+void
+gdata_contacts_contact_remove_all_languages (GDataContactsContact *self)
+{
+	GDataContactsContactPrivate *priv = self->priv;
+
+	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
+
+	if (priv->languages != NULL) {
+		g_list_foreach (priv->languages, (GFunc) g_object_unref, NULL);
+		g_list_free (priv->languages);
+	}
+	priv->languages = NULL;
+}
+
+/**
  * gdata_contacts_contact_get_extended_property:
  * @self: a #GDataContactsContact
  * @name: the property name; an arbitrary, unique string
diff --git a/gdata/services/contacts/gdata-contacts-contact.h b/gdata/services/contacts/gdata-contacts-contact.h
index e44e56f..03096bc 100644
--- a/gdata/services/contacts/gdata-contacts-contact.h
+++ b/gdata/services/contacts/gdata-contacts-contact.h
@@ -34,6 +34,7 @@
 #include <gdata/gcontact/gdata-gcontact-event.h>
 #include <gdata/gcontact/gdata-gcontact-external-id.h>
 #include <gdata/gcontact/gdata-gcontact-jot.h>
+#include <gdata/gcontact/gdata-gcontact-language.h>
 #include <gdata/gcontact/gdata-gcontact-relation.h>
 #include <gdata/gcontact/gdata-gcontact-website.h>
 
@@ -253,6 +254,14 @@ void gdata_contacts_contact_add_external_id (GDataContactsContact *self, GDataGC
 GList *gdata_contacts_contact_get_external_ids (GDataContactsContact *self);
 void gdata_contacts_contact_remove_all_external_ids (GDataContactsContact *self);
 
+void gdata_contacts_contact_add_hobby (GDataContactsContact *self, const gchar *hobby);
+GList *gdata_contacts_contact_get_hobbies (GDataContactsContact *self);
+void gdata_contacts_contact_remove_all_hobbies (GDataContactsContact *self);
+
+void gdata_contacts_contact_add_language (GDataContactsContact *self, GDataGContactLanguage *language);
+GList *gdata_contacts_contact_get_languages (GDataContactsContact *self);
+void gdata_contacts_contact_remove_all_languages (GDataContactsContact *self);
+
 const gchar *gdata_contacts_contact_get_extended_property (GDataContactsContact *self, const gchar *name);
 GHashTable *gdata_contacts_contact_get_extended_properties (GDataContactsContact *self);
 gboolean gdata_contacts_contact_set_extended_property (GDataContactsContact *self, const gchar *name, const gchar *value);
diff --git a/gdata/tests/contacts.c b/gdata/tests/contacts.c
index 423655c..72e976b 100644
--- a/gdata/tests/contacts.c
+++ b/gdata/tests/contacts.c
@@ -161,6 +161,7 @@ test_insert_simple (gconstpointer service)
 	GDataGContactEvent *event;
 	GDataGContactCalendar *calendar;
 	GDataGContactExternalID *external_id;
+	GDataGContactLanguage *language;
 	gchar *xml, *nickname, *billing_information, *directory_server, *gender, *initials, *maiden_name, *mileage, *occupation;
 	gchar *priority, *sensitivity, *short_name, *subject;
 	GList *list;
@@ -259,6 +260,12 @@ test_insert_simple (gconstpointer service)
 	gdata_contacts_contact_add_external_id (contact, external_id);
 	g_object_unref (external_id);
 
+	gdata_contacts_contact_add_hobby (contact, "Rowing");
+
+	language = gdata_gcontact_language_new ("en-GB", NULL);
+	gdata_contacts_contact_add_language (contact, language);
+	g_object_unref (language);
+
 	/* Add some extended properties */
 	g_assert (gdata_contacts_contact_set_extended_property (contact, "TITLE", NULL) == TRUE);
 	g_assert (gdata_contacts_contact_set_extended_property (contact, "ROLE", "") == TRUE);
@@ -362,10 +369,12 @@ test_insert_simple (gconstpointer service)
 				"<gContact:event rel='anniversary'><gd:when startTime='1900-01-01'/></gContact:event>"
 				"<gContact:calendarLink href='http://calendar.example.com/' rel='home' primary='true'/>"
 				"<gContact:externalId value='Number Six' rel='organization'/>"
+				"<gContact:language code='en-GB'/>"
 				"<gd:extendedProperty name='CALURI'>http://example.com/</gd:extendedProperty>"
 				"<gContact:userDefinedField key='Favourite colour' value='Blue'/>"
 				"<gContact:userDefinedField key='Owes me' value='£10'/>"
 				"<gContact:userDefinedField key='My notes' value=''/>"
+				"<gContact:hobby>Rowing</gContact:hobby>"
 				"<gContact:nickname>Big J</gContact:nickname>"
 				"<gContact:birthday when='--01-01'/>"
 				"<gContact:billingInformation>Big J Enterprises, Ltd.</gContact:billingInformation>"
@@ -480,6 +489,16 @@ test_insert_simple (gconstpointer service)
 	g_assert_cmpuint (g_list_length (list), ==, 1);
 	g_assert (GDATA_IS_GCONTACT_EXTERNAL_ID (list->data));
 
+	/* Languages */
+	list = gdata_contacts_contact_get_languages (new_contact);
+	g_assert_cmpuint (g_list_length (list), ==, 1);
+	g_assert (GDATA_IS_GCONTACT_LANGUAGE (list->data));
+
+	/* Hobbies */
+	list = gdata_contacts_contact_get_hobbies (new_contact);
+	g_assert_cmpuint (g_list_length (list), ==, 1);
+	g_assert_cmpstr (list->data, ==, "Rowing");
+
 	/* Extended properties */
 	g_assert_cmpstr (gdata_contacts_contact_get_extended_property (new_contact, "CALURI"), ==, "http://example.com/";);
 	g_assert (gdata_contacts_contact_get_extended_property (new_contact, "non-existent") == NULL);
@@ -547,6 +566,12 @@ test_insert_simple (gconstpointer service)
 	gdata_contacts_contact_remove_all_external_ids (new_contact);
 	g_assert (gdata_contacts_contact_get_external_ids (new_contact) == NULL);
 
+	gdata_contacts_contact_remove_all_languages (new_contact);
+	g_assert (gdata_contacts_contact_get_languages (new_contact) == NULL);
+
+	gdata_contacts_contact_remove_all_hobbies (new_contact);
+	g_assert (gdata_contacts_contact_get_hobbies (new_contact) == NULL);
+
 	g_free (edited);
 	g_object_unref (contact);
 	g_object_unref (new_contact);
@@ -718,6 +743,8 @@ test_parser_minimal (gconstpointer service)
 	g_assert (gdata_contacts_contact_get_calendars (contact) == NULL);
 	g_assert (gdata_contacts_contact_get_primary_calendar (contact) == NULL);
 	g_assert (gdata_contacts_contact_get_external_ids (contact) == NULL);
+	g_assert (gdata_contacts_contact_get_languages (contact) == NULL);
+	g_assert (gdata_contacts_contact_get_hobbies (contact) == NULL);
 
 	g_object_unref (contact);
 }
@@ -778,6 +805,11 @@ test_parser_normal (gconstpointer service)
 			"<gContact:calendarLink href='http://foo.com/calendar' rel='home'/>"
 			"<gContact:externalId value='Number Six' label='The Prisoner'/>"
 			"<gContact:externalId value='1545' rel='account'/>"
+			"<gContact:language label='Fresian'/>"
+			"<gContact:language code='en-US'/>"
+			"<gContact:hobby>Programming</gContact:hobby>"
+			"<gContact:hobby>Heavy metal</gContact:hobby>"
+			"<gContact:hobby>Heavy metal</gContact:hobby>" /* Test that duplicates get merged */
 		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_CONTACTS_CONTACT (contact));
@@ -921,6 +953,20 @@ test_parser_normal (gconstpointer service)
 	g_assert (GDATA_IS_GCONTACT_EXTERNAL_ID (list->data));
 	g_assert (GDATA_IS_GCONTACT_EXTERNAL_ID (list->next->data));
 
+	/* Languages */
+	list = gdata_contacts_contact_get_languages (contact);
+	g_assert_cmpuint (g_list_length (list), ==, 2);
+
+	g_assert (GDATA_IS_GCONTACT_LANGUAGE (list->data));
+	g_assert (GDATA_IS_GCONTACT_LANGUAGE (list->next->data));
+
+	/* Hobbies */
+	list = gdata_contacts_contact_get_hobbies (contact);
+	g_assert_cmpuint (g_list_length (list), ==, 2);
+
+	g_assert_cmpstr (list->data, ==, "Programming");
+	g_assert_cmpstr (list->next->data, ==, "Heavy metal");
+
 	g_object_unref (contact);
 }
 
@@ -1050,6 +1096,12 @@ test_parser_error_handling (gconstpointer service)
 	/* gContact:externalId */
 	TEST_XML_ERROR_HANDLING ("<gContact:externalId/>");
 
+	/* gContact:language */
+	TEST_XML_ERROR_HANDLING ("<gContact:language/>");
+
+	/* gContact:hobby */
+	TEST_XML_ERROR_HANDLING ("<gContact:hobby/>");
+
 #undef TEST_XML_ERROR_HANDLING
 }
 
diff --git a/gdata/tests/general.c b/gdata/tests/general.c
index 9c5eecc..c4a1bc8 100644
--- a/gdata/tests/general.c
+++ b/gdata/tests/general.c
@@ -2709,6 +2709,89 @@ test_gcontact_jot_error_handling (void)
 }
 
 static void
+test_gcontact_language (void)
+{
+	GDataGContactLanguage *language, *language2;
+	gchar *xml;
+	GError *error = NULL;
+
+	language = GDATA_GCONTACT_LANGUAGE (gdata_parsable_new_from_xml (GDATA_TYPE_GCONTACT_LANGUAGE,
+		"<gContact:language xmlns:gContact='http://schemas.google.com/contact/2008' code='en-GB'/>", -1, &error));
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_GCONTACT_LANGUAGE (language));
+	g_clear_error (&error);
+
+	/* Check the properties */
+	g_assert_cmpstr (gdata_gcontact_language_get_code (language), ==, "en-GB");
+	g_assert (gdata_gcontact_language_get_label (language) == NULL);
+
+	/* Compare it against another identical language */
+	language2 = gdata_gcontact_language_new ("en-GB", NULL);
+	g_assert_cmpint (gdata_gcontact_language_compare (language, language2), ==, 0);
+
+	/* â?¦and a different one */
+	gdata_gcontact_language_set_code (language2, "sv");
+	g_assert_cmpint (gdata_gcontact_language_compare (language, language2), !=, 0);
+	g_object_unref (language2);
+
+	/* More comparisons */
+	g_assert_cmpint (gdata_gcontact_language_compare (language, NULL), ==, 1);
+	g_assert_cmpint (gdata_gcontact_language_compare (NULL, language), ==, -1);
+	g_assert_cmpint (gdata_gcontact_language_compare (NULL, NULL), ==, 0);
+	g_assert_cmpint (gdata_gcontact_language_compare (language, language), ==, 0);
+
+	/* Check the outputted XML is the same */
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (language));
+	g_assert_cmpstr (xml, ==,
+			 "<gContact:language xmlns='http://www.w3.org/2005/Atom' xmlns:gContact='http://schemas.google.com/contact/2008' "
+				"code='en-GB'/>");
+	g_free (xml);
+	g_object_unref (language);
+
+	/* Now parse a language with less information available */
+	language = GDATA_GCONTACT_LANGUAGE (gdata_parsable_new_from_xml (GDATA_TYPE_GCONTACT_LANGUAGE,
+		"<gContact:language xmlns:gContact='http://schemas.google.com/contact/2008' label='Gobbledegook'/>",
+		-1, &error));
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_GCONTACT_LANGUAGE (language));
+	g_clear_error (&error);
+
+	/* Check the properties */
+	g_assert (gdata_gcontact_language_get_code (language) == NULL);
+	g_assert_cmpstr (gdata_gcontact_language_get_label (language), ==, "Gobbledegook");
+
+	/* Check the outputted XML is still OK */
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (language));
+	g_assert_cmpstr (xml, ==,
+			 "<gContact:language xmlns='http://www.w3.org/2005/Atom' xmlns:gContact='http://schemas.google.com/contact/2008' "
+				"label='Gobbledegook'/>");
+	g_free (xml);
+	g_object_unref (language);
+}
+
+static void
+test_gcontact_language_error_handling (void)
+{
+	GDataGContactLanguage *language;
+	GError *error = NULL;
+
+#define TEST_XML_ERROR_HANDLING(x) language = GDATA_GCONTACT_LANGUAGE (gdata_parsable_new_from_xml (GDATA_TYPE_GCONTACT_LANGUAGE,\
+		"<gContact:language xmlns:gContact='http://schemas.google.com/contact/2008' "\
+			x\
+		"/>", -1, &error));\
+	g_assert_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR);\
+	g_assert (language == NULL);\
+	g_clear_error (&error)
+
+	TEST_XML_ERROR_HANDLING (""); /* no code or label */
+	TEST_XML_ERROR_HANDLING ("code=''"); /* empty code */
+	TEST_XML_ERROR_HANDLING ("label=''"); /* empty label */
+	TEST_XML_ERROR_HANDLING ("code='en-GB' label='Other'"); /* code and label */
+
+#undef TEST_XML_ERROR_HANDLING
+}
+
+static void
 test_gcontact_relation (void)
 {
 	GDataGContactRelation *relation, *relation2;
@@ -2931,6 +3014,8 @@ main (int argc, char *argv[])
 	g_test_add_func ("/gcontact/external_id/error_handling", test_gcontact_external_id_error_handling);
 	g_test_add_func ("/gcontact/jot", test_gcontact_jot);
 	g_test_add_func ("/gcontact/jot/error_handling", test_gcontact_jot_error_handling);
+	g_test_add_func ("/gcontact/language", test_gcontact_language);
+	g_test_add_func ("/gcontact/language/error_handling", test_gcontact_language_error_handling);
 	g_test_add_func ("/gcontact/relation", test_gcontact_relation);
 	g_test_add_func ("/gcontact/relation/error_handling", test_gcontact_relation_error_handling);
 	g_test_add_func ("/gcontact/website", test_gcontact_website);



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