[evolution-data-server] Bug #224687 - Create lists of lists
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug #224687 - Create lists of lists
- Date: Tue, 28 Jun 2011 09:40:29 +0000 (UTC)
commit 34fc3da219f5cb5ee1e4451e723259735c2fac7f
Author: Dan VrÃtil <dvratil redhat com>
Date: Tue Jun 28 11:39:54 2011 +0200
Bug #224687 - Create lists of lists
addressbook/libebook/e-destination.c | 306 +++++++++++++++++++++++++---------
addressbook/libebook/e-destination.h | 1 +
addressbook/libebook/e-vcard.h | 8 +-
3 files changed, 231 insertions(+), 84 deletions(-)
---
diff --git a/addressbook/libebook/e-destination.c b/addressbook/libebook/e-destination.c
index 5ed6b34..c7c569d 100644
--- a/addressbook/libebook/e-destination.c
+++ b/addressbook/libebook/e-destination.c
@@ -66,6 +66,7 @@ struct _EDestinationPrivate {
gboolean ignored;
GList *list_dests;
+ GList *list_alldests;
guint html_mail_override : 1;
guint wants_html_mail : 1;
@@ -87,6 +88,12 @@ enum {
LAST_SIGNAL
};
+enum CONTACT_TYPE {
+ NONE,
+ CONTACT,
+ CONTACT_LIST
+};
+
static guint signals[LAST_SIGNAL] = { 0 };
static GObjectClass *parent_class;
@@ -159,6 +166,8 @@ e_destination_init (EDestination *dest)
dest->priv->auto_recipient = FALSE;
dest->priv->ignored = FALSE;
+ dest->priv->list_dests = NULL;
+ dest->priv->list_alldests = NULL;
}
/**
@@ -248,6 +257,8 @@ e_destination_clear (EDestination *dest)
g_list_foreach (dest->priv->list_dests, (GFunc) g_object_unref, NULL);
g_list_free (dest->priv->list_dests);
dest->priv->list_dests = NULL;
+ g_list_free (dest->priv->list_alldests);
+ dest->priv->list_alldests = NULL;
}
static gboolean
@@ -357,11 +368,10 @@ e_destination_set_contact (EDestination *dest, EContact *contact, gint email_num
g_return_if_fail (contact && E_IS_CONTACT (contact));
if (dest->priv->contact != contact ) {
- g_object_ref (contact);
e_destination_clear (dest);
- dest->priv->contact = contact;
+ dest->priv->contact = e_contact_duplicate (contact);
dest->priv->contact_uid = e_contact_get (dest->priv->contact, E_CONTACT_UID);
@@ -371,56 +381,144 @@ e_destination_set_contact (EDestination *dest, EContact *contact, gint email_num
/* handle the mailing list case */
if (e_contact_get (dest->priv->contact, E_CONTACT_IS_LIST)) {
- GList *email = e_contact_get_attributes (dest->priv->contact, E_CONTACT_EMAIL);
+ gint list_length;
+ GList *attr, *attrs;
+ GHashTable *hash_table;
+ gint list_iterations = 0;
+ gint lists_count = 0;
- if (email) {
- GList *iter;
-
- for (iter = email; iter; iter = iter->next) {
- EVCardAttribute *attr = iter->data;
- GList *p;
- EDestination *list_dest = e_destination_new ();
- gchar *contact_uid = NULL;
- gchar *value;
- gint email_num = -1;
- gboolean html_pref = FALSE;
-
- for (p = e_vcard_attribute_get_params (attr); p; p = p->next) {
- EVCardAttributeParam *param = p->data;
- const gchar *param_name = e_vcard_attribute_param_get_name (param);
- if (!g_ascii_strcasecmp (param_name,
- EVC_X_DEST_CONTACT_UID)) {
- GList *v = e_vcard_attribute_param_get_values (param);
- contact_uid = v ? g_strdup (v->data) : NULL;
- }
- else if (!g_ascii_strcasecmp (param_name,
- EVC_X_DEST_EMAIL_NUM)) {
- GList *v = e_vcard_attribute_param_get_values (param);
- email_num = v ? atoi (v->data) : -1;
- }
- else if (!g_ascii_strcasecmp (param_name,
- EVC_X_DEST_HTML_MAIL)) {
- GList *v = e_vcard_attribute_param_get_values (param);
- html_pref = v ? !g_ascii_strcasecmp (v->data, "true") : FALSE;
+ hash_table = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free, NULL);
+
+ g_hash_table_insert (hash_table, g_strdup ("0"), dest);
+
+ e_destination_set_name (dest,
+ e_contact_get_const (dest->priv->contact, E_CONTACT_FILE_AS));
+
+ attrs = g_list_copy (e_vcard_get_attributes (E_VCARD (dest->priv->contact)));
+ list_length = g_list_length (attrs);
+
+ attr = attrs;
+ while (list_length) {
+ EDestination *parent_dest;
+ gint type;
+ gboolean remove = FALSE; /* Can item be removed from attrs list? */
+
+ GList *params, *param, *value;
+ const gchar *parent_id;
+
+ param = e_vcard_attribute_get_param (attr->data, EVC_PARENT_CL);
+ if (param)
+ parent_id = param->data;
+ else
+ parent_id = "0";
+
+ /* This is so just that we don't have to call g_ascii_strcasecmp more times */
+ if (g_ascii_strcasecmp (EVC_CONTACT_LIST, e_vcard_attribute_get_name (attr->data)) == 0) {
+ lists_count++;
+ type = CONTACT_LIST;
+ } else if (g_ascii_strcasecmp (EVC_EMAIL, e_vcard_attribute_get_name (attr->data)) == 0) {
+ type = CONTACT;
+ } else {
+ type = NONE;
+ remove = TRUE;
+ }
+
+ /* Is parent of current attribute already in the tree? */
+ parent_dest = g_hash_table_lookup (hash_table, parent_id);
+ /* Make sure that when parent with parent_id does not exist the item will be appended to root
+ destination. */
+ if (parent_dest == NULL && lists_count == 0 && list_iterations > 0) {
+ parent_id = "0";
+ parent_dest = dest;
+ }
+ if (type != NONE && parent_dest) {
+ gchar *id = NULL;
+ gint email_num = 0;
+ EDestination *s_dest;
+
+ s_dest = e_destination_new ();
+ s_dest->priv->ignored = FALSE;
+
+ params = e_vcard_attribute_get_params (attr->data);
+ for (param = params; param; param = param->next) {
+ const gchar *param_name = e_vcard_attribute_param_get_name (param->data);
+ if ((g_ascii_strcasecmp (param_name, EVC_CL_UID) == 0) ||
+ (g_ascii_strcasecmp (param_name, EVC_X_DEST_CONTACT_UID) == 0)) {
+ value = e_vcard_attribute_param_get_values (param->data);
+ id = value ? g_strdup (value->data) : NULL;
+ } else if (g_ascii_strcasecmp (param_name, EVC_X_DEST_EMAIL_NUM) == 0) {
+ value = e_vcard_attribute_param_get_values (param->data);
+ email_num = value ? atoi (value->data) : -1;
+ } else if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_HTML_MAIL)) {
+ value = e_vcard_attribute_param_get_values (param->data);
+ e_destination_set_html_mail_pref (s_dest, value ? !g_ascii_strcasecmp (value->data, "true") : FALSE);
}
}
- if (contact_uid) e_destination_set_contact_uid (list_dest, contact_uid, email_num);
- e_destination_set_html_mail_pref (list_dest, html_pref);
- list_dest->priv->ignored = FALSE;
- value = e_vcard_attribute_get_value (attr);
- if (value)
- e_destination_set_raw (list_dest, value);
- g_free (value);
+ if (type == CONTACT) {
+ CamelInternetAddress *addr;
+ const gchar *name, *email;
+ gchar *raw;
+
+ raw = e_vcard_attribute_get_value (attr->data);
+ addr = camel_internet_address_new ();
+ camel_address_unformat (CAMEL_ADDRESS (addr), raw);
+ camel_internet_address_get (addr, 0, &name, &email);
+
+ e_destination_set_name (s_dest, name);
+ e_destination_set_email (s_dest, email);
- dest->priv->list_dests = g_list_append (dest->priv->list_dests, list_dest);
+ dest->priv->list_alldests = g_list_append (dest->priv->list_alldests, s_dest);
+
+ g_object_unref (addr);
+ g_free (raw);
+ } else {
+ gchar *name = e_vcard_attribute_get_value (attr->data);
+ e_destination_set_name (s_dest, name);
+ g_free (name);
+
+ g_hash_table_insert (hash_table, g_strdup (id), s_dest);
+ lists_count--;
+ }
+
+ if (id) {
+ e_destination_set_contact_uid (s_dest, id, email_num);
+ g_free (id);
+ }
+
+ parent_dest->priv->list_dests = g_list_append (parent_dest->priv->list_dests, s_dest);
+
+ remove = TRUE;
}
- g_list_foreach (email, (GFunc) e_vcard_attribute_free, NULL);
- g_list_free (email);
+ /* Go to next attribute */
+ if (attr->next) {
+ attr = attr->next;
+ if (remove) {
+ attrs = g_list_remove_link (attrs, attr->prev);
+ list_length--;
+ }
+ continue;
+ /* Or return to first attribute */
+ } else if (attrs) {
+ if (remove) {
+ attrs = g_list_remove_link (attrs, attr);
+ list_length--;
+ }
+ attr = attrs;
+ list_iterations++;
+ continue;
+ /* When all attribute are processed, leave. */
+ } else {
+ break;
+ }
}
- }
- else {
+
+ g_hash_table_unref (hash_table);
+ g_list_free (attrs);
+
+ } else {
/* handle the normal contact case */
/* is there anything to do here? */
}
@@ -428,11 +526,10 @@ e_destination_set_contact (EDestination *dest, EContact *contact, gint email_num
g_signal_emit (dest, signals[CHANGED], 0);
} else if (dest->priv->email_num != email_num) {
/* Splitting here would help the contact lists not rebuiding, so that it remembers ignored values */
- g_object_ref (contact);
e_destination_clear (dest);
- dest->priv->contact = contact;
+ dest->priv->contact = e_contact_duplicate (contact);
dest->priv->contact_uid = e_contact_get (dest->priv->contact, E_CONTACT_UID);
@@ -440,7 +537,6 @@ e_destination_set_contact (EDestination *dest, EContact *contact, gint email_num
g_signal_emit (dest, signals[CHANGED], 0);
}
-
}
#ifndef E_BOOK_DISABLE_DEPRECATED
@@ -873,6 +969,38 @@ e_destination_get_email (const EDestination *dest)
return priv->email;
}
+
+/* Helper function to e_destination_get_address capable of recursively
+ * iterating through structured destinations list */
+static void
+destination_get_address (const EDestination *dest,
+ CamelInternetAddress *addr)
+{
+ const GList *iter;
+
+ if (e_destination_is_evolution_list (dest)) {
+
+ for (iter = dest->priv->list_dests; iter; iter = iter->next) {
+ EDestination *list_dest = E_DESTINATION (iter->data);
+
+ destination_get_address (list_dest, addr);
+ }
+
+ } else {
+ const gchar *name, *email;
+ name = e_destination_get_name (dest);
+ email = e_destination_get_email (dest);
+
+ if (nonempty (name) && nonempty (email))
+ camel_internet_address_add (addr, name, email);
+ else if (nonempty (email))
+ camel_address_decode (CAMEL_ADDRESS (addr), email);
+ else /* this case loses i suppose, but there's
+ nothing we can do here */
+ camel_address_decode (CAMEL_ADDRESS (addr), name);
+ }
+}
+
/**
* e_destination_get_address:
* @dest: an #EDestination
@@ -894,46 +1022,22 @@ e_destination_get_address (const EDestination *dest)
priv = (struct _EDestinationPrivate *) dest->priv; /* cast out const */
- if (e_destination_is_evolution_list (dest)) {
- GList *iter = dest->priv->list_dests;
-
- while (iter) {
- EDestination *list_dest = E_DESTINATION (iter->data);
+ if (priv->addr) {
+ g_free (priv->addr);
+ priv->addr = NULL;
+ }
- if (!e_destination_empty (list_dest) && !list_dest->priv->ignored) {
- const gchar *name, *email;
- name = e_destination_get_name (list_dest);
- email = e_destination_get_email (list_dest);
-
- if (nonempty (name) && nonempty (email))
- camel_internet_address_add (addr, name, email);
- else if (nonempty (email))
- camel_address_decode (CAMEL_ADDRESS (addr), email);
- else /* this case loses i suppose, but there's
- nothing we can do here */
- camel_address_decode (CAMEL_ADDRESS (addr), name);
- }
- iter = g_list_next (iter);
- }
+ if (e_destination_is_evolution_list (dest)) {
+ destination_get_address (dest, addr);
priv->addr = camel_address_encode (CAMEL_ADDRESS (addr));
} else if (priv->raw) {
if (camel_address_unformat (CAMEL_ADDRESS (addr), priv->raw))
priv->addr = camel_address_encode (CAMEL_ADDRESS (addr));
} else {
- const gchar *name, *email;
- name = e_destination_get_name (dest);
- email = e_destination_get_email (dest);
-
- if (nonempty (name) && nonempty (email))
- camel_internet_address_add (addr, name, email);
- else if (nonempty (email))
- camel_address_decode (CAMEL_ADDRESS (addr), email);
- else /* this case loses i suppose, but there's
- nothing we can do here */
- camel_address_decode (CAMEL_ADDRESS (addr), name);
-
+ destination_get_address (dest, addr);
priv->addr = camel_address_encode (CAMEL_ADDRESS (addr));
}
+
g_object_unref (addr);
return priv->addr;
@@ -1044,16 +1148,17 @@ e_destination_list_show_addresses (const EDestination *dest)
}
/**
- * e_destination_list_get_dests:
+ * e_destination_list_get_root_dests:
* @dest: an #EDestination
*
- * If @dest is a list, gets the list of destinations. The list
- * and its elements belong to @dest, and should not be freed.
+ * If @dest is a list, gets the list of EDestinations assigned directly
+ * to @dest.
+ * The list and its elements belong to @dest, and should not be freed.
*
* Returns: A list of elements of type #EDestination, or %NULL.
**/
const GList *
-e_destination_list_get_dests (const EDestination *dest)
+e_destination_list_get_root_dests (const EDestination *dest)
{
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
@@ -1064,6 +1169,41 @@ e_destination_list_get_dests (const EDestination *dest)
}
/**
+ * e_destination_list_get_dests:
+ * @dest: an #EDestination
+ *
+ * If @dest is a list, gets recursively list of all destinations.
+ * Everything returned from this function belongs to @dest and
+ * thus should not be freed.
+ *
+ * Returns: A list of elements of type #EDestination, or %NULL.
+ *
+ * Since: 3.2
+ **/
+const GList *
+e_destination_list_get_dests (const EDestination *dest)
+{
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
+
+ if (!e_destination_is_evolution_list (dest))
+ return NULL;
+
+ if (!dest->priv->list_alldests) {
+ GList *iter;
+ for (iter = dest->priv->list_dests; iter; iter = iter->next) {
+ if (e_destination_is_evolution_list (iter->data)) {
+ GList *l = g_list_copy ((GList*)e_destination_list_get_dests (iter->data));
+ dest->priv->list_alldests = g_list_concat (dest->priv->list_alldests, l);
+ } else {
+ dest->priv->list_alldests = g_list_append (dest->priv->list_alldests, iter->data);
+ }
+ }
+ }
+
+ return dest->priv->list_alldests;
+}
+
+/**
* e_destination_get_html_mail_pref:
* @dest: an #EDestination
*
diff --git a/addressbook/libebook/e-destination.h b/addressbook/libebook/e-destination.h
index 6ac4e13..2d12e01 100644
--- a/addressbook/libebook/e-destination.h
+++ b/addressbook/libebook/e-destination.h
@@ -97,6 +97,7 @@ const gchar *e_destination_get_address (const EDestination *dest); /*
gboolean e_destination_is_evolution_list (const EDestination *dest);
gboolean e_destination_list_show_addresses (const EDestination *dest);
const GList *e_destination_list_get_dests (const EDestination *dest);
+const GList *e_destination_list_get_root_dests (const EDestination *dest);
gboolean e_destination_is_ignored (const EDestination *dest);
void e_destination_set_ignored (EDestination *dest, gboolean ignored);
diff --git a/addressbook/libebook/e-vcard.h b/addressbook/libebook/e-vcard.h
index 544dff4..4424e20 100644
--- a/addressbook/libebook/e-vcard.h
+++ b/addressbook/libebook/e-vcard.h
@@ -85,9 +85,15 @@ G_BEGIN_DECLS
#define EVC_X_JABBER "X-JABBER"
#define EVC_X_LIST_SHOW_ADDRESSES "X-EVOLUTION-LIST-SHOW-ADDRESSES"
#define EVC_X_LIST "X-EVOLUTION-LIST"
-#define EVC_X_MANAGER "X-EVOLUTION-MANAGER"
+#define EVC_X_LIST_NAME "X-EVOLUTION-LIST-NAME"
+#define EVC_X_MANAGER "X-EVOLUTION-MANAGER"
#define EVC_X_MSN "X-MSN"
+/* Constants for Evo contact lists only */
+#define EVC_CONTACT_LIST "X-EVOLUTION-CONTACT-LIST-INFO"
+#define EVC_PARENT_CL "X-EVOLUTION-PARENT-UID"
+#define EVC_CL_UID "X-EVOLUTION-CONTACT-LIST-UID"
+
/**
* EVC_X_SKYPE:
*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]