/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * contact-e-to-i.c
 *
 *  Created on: 21.12.2010
 *      Author: Umer Kayani <u.kayani@tarent.de>,
 *              Hendrik Helwich <h.helwich@tarent.de>,
 *              Peter Neuhaus <p.neuhaus@tarent.de>,
 *              Andreas Grau <a.grau@tarent.de>
 */

/*
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
 */

#define _XOPEN_SOURCE 500 /* glibc2 needs this */

#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "priv-evolution.h"
#include "evolution.h"
#include "evolution-util.h"
#include "../kolab/kolab-constants.h"
#include "../logging.h"
#include "../util.h"

/*
 * Prototypes for static functions
 */
static void process_contact_e_to_i (I_contact* i_contact, const EContact *e_contact);

static void add_address (const EContact *e_contact, EContactAddress *e_address, I_contact* i_contact,
                         EContactField e_addr_type, GHashTable *k_store_hash);
static void add_email (const EContact *e_contact, EContactField e_field,
                       I_contact* i_contact, gchar * email_str, GHashTable *k_store_hash);
static void add_phone_numbers (const EContact *e_contact, I_contact* i_contact, GHashTable *k_store_hash);
static void add_custom_fields (const EContact *e_contact, I_contact* i_contact, GHashTable *k_store_hash);


static void kolab_store_handle_attachments(const EContact *e_contact, I_common* i_common);
static GHashTable* kolab_store_read_values (const EContact *e_contact, I_contact* i_contact);
static void kolab_store_restore_subnode_xml(I_contact *i_contact, gpointer parent_ptr,
                                            const EContact *e_contact, EContactField e_field, GHashTable *k_store_hash);

static Icontact_address_type address_type_e_to_i(EContactField e_addr_type);
static Icontact_phone_type phone_type_e_to_i(GList *vcard_types);


/**
 * Convert an Evolution EContact to a libekolabconv I_contact.
 */
I_contact*
conv_EContact_to_I_contact (const EContact* e_contact, GError** error)
{
	I_contact *i_contact = NULL;

	g_assert(error != NULL && *error == NULL);
	log_debug ("\nconv_EContact_to_I_contact(): convert EContact to I_contact struct.");

	i_contact = new_i_contact ();

	if (e_contact) {
		process_contact_e_to_i (i_contact, e_contact);
		return i_contact;
	} else {
		log_debug("\nError: Can't generate I_contact from EContact, eContact is NULL\n");
		return NULL;
	}
}


/**
 * Returns true if the given string has a minimal length of one.
 */
static gboolean
is_not_empty(gchar* str)
{
	return str && strlen(str) > 0;
}


/**
 * process all steps of conversion from EContact to I_contact.
 */
static void
process_contact_e_to_i (I_contact* i_contact, const EContact *e_contact)
{
	/* Tested:
	 * - Not needed, works also without duplicate.
	 * - There is not more memory needed with duplicate / everything is freed.
	 * - Common->body has 3 different states in carriage returns and newlines without duplicate.
	 * - Maybe there is more delay for copying.
	 */
	EContact* e_contact_dup = e_contact_duplicate ( (EContact*) e_contact );

	EContactDate *date;
	EContactAddress *address;
	EContactName *name;
	EContactPhoto *e_contact_photo;
	EContactGeo *geo;
	gchar *buffer;

	if (e_contact_dup != NULL) {
		GHashTable *kstore_hash = NULL;
		gchar *nick_name = NULL;
		gchar *full_name = NULL;
		EVCardAttribute *attribute = NULL;
		gchar *value = NULL;

		log_debug("read kolab store information");

		kstore_hash = kolab_store_read_values (e_contact_dup, i_contact);

		log_debug("process birth date");
		/* e_contact_get              (EContact *contact, EContactField field_id); */
		/* *****************************************************************SET BIRTHDAY****************************************** */
		date = e_contact_get (e_contact_dup, E_CONTACT_BIRTH_DATE);
		if (date)
			i_contact->birthday = g_date_new_dmy ((GDateDay)date->day, (GDateMonth)date->month, (GDateYear)date->year);
		e_contact_date_free(date);
		/* *****************************************************************SET ANNIVERSARY*************************************** */
		log_debug("process anniversary");
		date = e_contact_get (e_contact_dup, E_CONTACT_ANNIVERSARY);
		if (date)
			i_contact->anniversary = g_date_new_dmy ((GDateDay)date->day, (GDateMonth)date->month, (GDateYear)date->year);
		e_contact_date_free(date);
		/* *****************************************************************SET ADDRESSES***************************************** */
		log_debug("process addresses");
		address = e_contact_get (e_contact_dup, E_CONTACT_ADDRESS_HOME);
		if (address)
			add_address (e_contact_dup, address, i_contact, E_CONTACT_ADDRESS_HOME, kstore_hash);
		e_contact_address_free(address);
		address = e_contact_get (e_contact_dup, E_CONTACT_ADDRESS_WORK);
		if (address)
			add_address (e_contact_dup, address, i_contact, E_CONTACT_ADDRESS_WORK, kstore_hash);
		e_contact_address_free(address);
		address = e_contact_get (e_contact_dup, E_CONTACT_ADDRESS_OTHER);
		if (address)
			add_address (e_contact_dup, address, i_contact,	E_CONTACT_ADDRESS_OTHER, kstore_hash);
		e_contact_address_free(address);
		/* *****************************************************************GEO ************************************************** */
		log_debug("process GEO");
		geo = e_contact_get (e_contact_dup, E_CONTACT_GEO);
		if (geo) {
			if (geo->latitude >= -90.0 && geo->latitude <= 90.0
			    && geo->longitude >= -180.0 && geo->longitude <= 180.0) {
				i_contact->latitude = geo->latitude;
				i_contact->longitude = geo->longitude;
			}
		}
		e_contact_geo_free(geo);
		/* *****************************************************************SET NAME********************************************** */
		log_debug("process names");
		name = e_contact_get (e_contact_dup, E_CONTACT_NAME);
		if (is_not_empty(name->suffixes))
			i_contact->suffix = g_string_new (name->suffixes);
		if (is_not_empty(name->prefixes))
			i_contact->prefix = g_string_new (name->prefixes);
		if (is_not_empty(name->given))
			i_contact->given_name = g_string_new (name->given);
		if (is_not_empty(name->family))
			i_contact->last_name = g_string_new (name->family);
		if (is_not_empty(name->additional))
			i_contact->middle_names = g_string_new (name->additional);
		if (is_not_empty(name->suffixes))
			i_contact->suffix = g_string_new (name->suffixes);

		e_contact_name_free(name);

		nick_name = e_contact_get (e_contact_dup, E_CONTACT_NICKNAME);
		if (is_not_empty(nick_name))
			i_contact->nick_name = g_string_new (nick_name);
		g_free(nick_name);

		full_name = e_contact_get (e_contact_dup, E_CONTACT_FULL_NAME);
		if (is_not_empty(full_name))
			i_contact->full_name = g_string_new (full_name);
		g_free(full_name);

		/* *****************************************************************SET EMAIL************************************** */
		log_debug("process emails");
		buffer = e_contact_get (e_contact_dup, E_CONTACT_EMAIL_1);
		if (buffer)
			add_email (e_contact_dup, E_CONTACT_EMAIL_1, i_contact, buffer, kstore_hash);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_EMAIL_2);
		if (buffer)
			add_email (e_contact_dup, E_CONTACT_EMAIL_2, i_contact, buffer, kstore_hash);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_EMAIL_3);
		if (buffer)
			add_email (e_contact_dup, E_CONTACT_EMAIL_3, i_contact, buffer, kstore_hash);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_EMAIL_4);
		if (buffer)
			add_email (e_contact_dup, E_CONTACT_EMAIL_4, i_contact, buffer, kstore_hash);
		g_free(buffer);

		/* *****************************************************************SET PHONE************************************** */
		log_debug("process phones");

		/*
		 * set phones:
		 * This is not possible by e_contact_get() like the other attributes,
		 * because multiple numbers of the same type are not supported and previous value will be overwritten in this case.
		 * Phone tags will be processed manually.
		 */

		add_phone_numbers(e_contact_dup, i_contact, kstore_hash);


		/* *****************************************************************SET ORGANIZATIONAL FIELDS********************** */

		log_debug("process organization fields");

		buffer = e_contact_get (e_contact_dup, E_CONTACT_ROLE);
		if (is_not_empty(buffer))
			i_contact->profession = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_TITLE);
		if (is_not_empty(buffer))
			i_contact->job_title = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_ORG);
		if (is_not_empty(buffer))
			i_contact->organization = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_ORG_UNIT);
		if (is_not_empty(buffer))
			i_contact->department = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_MANAGER);
		if (is_not_empty(buffer))
			i_contact->manager_name = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_ASSISTANT);
		if (is_not_empty(buffer))
			i_contact->assistant = g_string_new (buffer);
		g_free(buffer);
		/* *****************************************************************SET WEB FIELDS********************************* */
		log_debug("process web page");
		buffer = e_contact_get (e_contact_dup, E_CONTACT_HOMEPAGE_URL);
		if (is_not_empty(buffer))
			i_contact->web_page = g_string_new (buffer);
		g_free(buffer);
		log_debug("free-busy url");
		buffer = e_contact_get (e_contact_dup, E_CONTACT_FREEBUSY_URL);
		if (is_not_empty(buffer))
			i_contact->free_busy_url = g_string_new (buffer);
		g_free(buffer);
		/* *****************************************************************SET CATEGORY*********************************** */
		log_debug("process categories");
		buffer = e_contact_get (e_contact_dup, E_CONTACT_CATEGORIES);
		if (buffer)
			i_contact->common->categories = g_string_new (buffer);
		g_free(buffer);
		/* *****************************************************************SET MISC FIELDS******************************** */

		log_debug("process misc fields");

		buffer = e_contact_get (e_contact_dup, E_CONTACT_SPOUSE);
		if (is_not_empty(buffer))
			i_contact->spouse_name = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_OFFICE);
		if (buffer)
			i_contact->office_location = g_string_new (buffer);
		g_free(buffer);

		/* *****************************************************************SET COMMON FIELDS****************************** */
		buffer = e_contact_get (e_contact_dup, E_CONTACT_UID);
		if (buffer)
			i_contact->common->uid = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_NOTE);
		if (is_not_empty(buffer))
			i_contact->common->body = g_string_new (buffer);
		g_free(buffer);
		buffer = e_contact_get (e_contact_dup, E_CONTACT_REV);
		if (buffer) {
			struct tm *t = NULL;
			time_t *tt = NULL;

			if (buffer[10] == 'T') /* get rid of 'T' in iso time stamp if neccessary */
				buffer[10] = ' ';

			t = g_new0(struct tm, 1);
			strptime(buffer, "%Y-%m-%d %H:%M:%S", t);
			tt = g_new0(time_t, 1);
			*tt = time_gm(t);
			g_free(t);
			i_contact->common->last_modified_datetime = g_new0(Date_or_datetime, 1);
			i_contact->common->last_modified_datetime->date_time = tt;
			g_free(buffer);
		} else {
			i_contact->common->last_modified_datetime = g_new0(Date_or_datetime, 1);
			i_contact->common->last_modified_datetime->date_time = g_new0(time_t, 1);
			*i_contact->common->last_modified_datetime->date_time = time(0);
		}
		buffer = NULL;
		attribute = e_vcard_get_attribute((EVCard *) e_contact_dup, ICONTACT_KOLAB_CREATED);
		if(attribute)
			value = e_vcard_attribute_get_value (attribute);

		if (attribute && value) {
			struct tm *t2 = NULL;
			time_t *tt2 = NULL;

			if (value[10] == 'T') /* get rid of 'T' in iso time stamp if neccessary */
				value[10] = ' ';

			t2 = g_new0(struct tm, 1);
			strptime (value, "%Y-%m-%d %H:%M:%S", t2);
			tt2 = g_new0(time_t, 1);
			*tt2 = time_gm (t2);
			g_free(t2);
			i_contact->common->creation_datetime = new_date_or_datetime();
			i_contact->common->creation_datetime->date_time = tt2;
		} else {
			i_contact->common->creation_datetime = new_date_or_datetime();
			i_contact->common->creation_datetime->date_time = g_new0(time_t, 1);
			*i_contact->common->creation_datetime->date_time = *i_contact->common->last_modified_datetime->date_time;
		}

		/* g_debug("populateIContactFromEContact: icontact->common->uid == '%s'", icontact->common->uid->str); */

		/* *****************************************************************SET PICTURE FIELDS***************************** */

		log_debug("process picture fields");

		e_contact_photo = e_contact_get (e_contact_dup, E_CONTACT_PHOTO);

		if (e_contact_photo && e_contact_photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
			gchar *d = NULL;

			/* Bin_attachment *photo; */
			/* photo = (Bin_attachment *) malloc ( sizeof(Bin_attachment) ); */
			i_contact->photo = g_new0(Kolab_conv_mail_part, 1);

			i_contact->photo->length = e_contact_photo->data.inlined.length;
			i_contact->photo->data = g_new0(gchar, i_contact->photo->length);

			/* handle mime type */
			d = (gchar*) e_contact_photo->data.inlined.data;

			/* JPEG SOI marker (first two bytes): FF D8 */
			if (memcmp (d, "\xFF\xD8", 2) == 0) {
				i_contact->photo->name = g_strdup("kolab-picture.jpg");
				i_contact->photo->mime_type = g_strdup("image/jpeg");
				/* PNG signature (first eight bytes): 89 50 4E 47 0D 0A 1A 0A */
			} else if (memcmp (d, "\x89PNG\r\n\x1A\n", 8) == 0) {
				i_contact->photo->name = g_strdup("kolab-picture.png");
				i_contact->photo->mime_type = g_strdup("image/png");
			} else {
				i_contact->photo->name = g_strdup("kolab-picture.png");
				i_contact->photo->mime_type = g_strdup(e_contact_photo->data.inlined.mime_type);
			}

			memcpy(i_contact->photo->data, e_contact_photo->data.inlined.data, i_contact->photo->length);
		}

		e_contact_photo_free(e_contact_photo);


		/* *************************************SET X-CUSTOM FIELDS (ALL IM fields, BlogFeed URL and self defined fields)*** */

		log_debug("process X-CUSTOMER fields");

		add_custom_fields(e_contact_dup, i_contact, kstore_hash);

		/* *************************************SET EVOLUTION HIDDEN FIELDS BACK IN ICONTACT (In KolabStore) ************** */


		kolab_store_handle_attachments(e_contact_dup, i_contact->common);

		/* *************************************SET EVOLUTION SPECIFIC FIELDS INTO EVOLUTIONSTORE IN ICONTACT ************* */

		i_evo_store_add_contact(e_contact_dup, i_contact->common);

		/* TODO: COMPLETE ALL REMAINING FIELDS */
		/* KLBC_CNT_KEY */
		g_hash_table_unref(kstore_hash);

	} else
		log_debug("Error: couldn't generate icontact, eContact is NULL");

	g_object_unref(e_contact_dup);
}

/**
 * add address to I_contact
 */
static void
add_address (const EContact *e_contact, EContactAddress *e_address, I_contact* i_contact,
             EContactField e_addr_type, GHashTable *k_store_hash)
{
	Address *addr = new_address ();

	addr->type = address_type_e_to_i(e_addr_type);
	/* g_debug ("**** e_address_type: %d, addr->type: %d ****", e_addr_type, addr->type); */

	if (e_address->street)
		addr->street = g_string_new (e_address->street);
	if (e_address->po)
		addr->pobox = g_string_new (e_address->po);
	if (e_address->locality)
		addr->locality = g_string_new (e_address->locality);
	if (e_address->region)
		addr->region = g_string_new (e_address->region);
	if (e_address->code)
		addr->postal_code = g_string_new (e_address->code);
	if (e_address->country)
		addr->country = g_string_new (e_address->country);

	i_contact->addresses = g_list_append (i_contact->addresses, addr);
	kolab_store_restore_subnode_xml(i_contact, addr, e_contact, e_addr_type, k_store_hash);
}

/**
 * add email to I_contact
 */
static void
add_email (const EContact *e_contact, EContactField e_field,
           I_contact* i_contact, gchar * email_str, GHashTable *k_store_hash)
{
	Email *structEmail = g_new0(Email, 1);

	if (email_str) {
		structEmail->smtp_address = g_string_new (email_str);

		i_contact->emails = g_list_append (i_contact->emails, (Email *) structEmail);
		kolab_store_restore_subnode_xml(i_contact, structEmail, e_contact, e_field, k_store_hash);
	}
}

/**
 * add all phones to I_contact
 */
static void
add_phone_numbers (const EContact *e_contact, I_contact* i_contact, GHashTable *k_store_hash)
{
	/* read phone tags from vcard manually */
	GList *attrs;
	GList *attr;
	attrs = e_vcard_get_attributes (E_VCARD (e_contact));

	/* for all attributes in vcard object */
	for (attr = attrs; attr;) {
		EVCardAttribute *a = attr->data;

		/* do if it is a phone object */
		if (!strcmp (EVC_TEL, e_vcard_attribute_get_name (a))) {
			gchar* value = NULL;

			GList *params = e_vcard_attribute_get_param (a, EVC_TYPE);
			GList *param;
			GList *type_list = NULL;
			for (param = params; param; param = param->next) {
				EVCardAttributeParam *p = param->data;
				type_list = g_list_append(type_list, p);
			}

			/* phone number */
			value = e_vcard_attribute_get_value(a);

			if (value != NULL) {
				Phone_number *phone_nr = g_new0(Phone_number, 1);
				phone_nr->number = g_strdup(value);
				phone_nr->type = phone_type_e_to_i(type_list);

				i_contact->phone_numbers = g_list_append (i_contact->phone_numbers, phone_nr);

				g_free(value);

				/*
				 * kolab store:
				 * manual read from kolab store, maybe create a separate function for cases like this, when you have a vcard-attribute instead of e_object
				 */
				if (e_vcard_attribute_get_param(a, ICONTACT_KOLAB_STORE_ID) != NULL) {
					GList *paramlist = e_vcard_attribute_get_param(a, ICONTACT_KOLAB_STORE_ID);
					for (;paramlist != NULL; paramlist = paramlist->next) {
						EVCardAttributeParam *eparam = paramlist->data;

						if (eparam != NULL) {
							GList* xml_str_list = NULL;

							gchar *id_str = (gchar*)eparam;
							gint id = strtol(id_str, (gchar**)0, 10);
							gint *id_ptr = g_new0(gint, 1);
							log_debug("found kolab store id %d", id);
							*id_ptr = id;
							xml_str_list = g_hash_table_lookup(k_store_hash, id_ptr);
							g_free(id_ptr);
							xml_str_list = g_list_last(xml_str_list);
							for (;xml_str_list != NULL; xml_str_list = xml_str_list->prev) {
								gchar *xml_str = (gchar*)xml_str_list->data;
								log_debug("found kolab store item %s", xml_str);
								kolab_store_add_element(i_contact->common, phone_nr, g_strdup(xml_str), FALSE);
							}
						}
					}

				}

			}
			g_list_free(type_list);
			type_list = NULL;
		}
		/* next attribute in vcard */
		attr = attr->next;
	}
}

/**
 * add all custom-fields to I_contact
 */
static void
add_custom_fields (const EContact *e_contact, I_contact* i_contact, GHashTable *k_store_hash)
{
	/* read phone tags from vcard manually */
	GList *attrs;
	GList *attr;
	attrs = e_vcard_get_attributes (E_VCARD (e_contact));

	/* for all attributes in vcard object */
	for (attr = attrs; attr;) {
		EVCardAttribute *a = attr->data;

		Custom *custom_field = g_new0(Custom, 1);

		/* do if it is a blog object */
		if (!strcmp (EVC_X_BLOG_URL, e_vcard_attribute_get_name(a))) {	/* blogfeed */
			custom_field->name = g_string_new(KLBX_CNT_X_CUSTOM_NAME_BLOGFEED);
			custom_field->app = g_string_new("");
		}
		else {
			custom_field->name = g_string_new("All");

			if (!strcmp (EVC_X_AIM, e_vcard_attribute_get_name (a))) 		/* im aim */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_AIM);
			else if (!strcmp (EVC_X_JABBER, e_vcard_attribute_get_name (a))) 	/* im jabber/xmpp */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_XMPP);
			else if (!strcmp (EVC_X_YAHOO, e_vcard_attribute_get_name (a))) 	/* im yahoo */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_YAHOO);
			else if (!strcmp (EVC_X_GADUGADU, e_vcard_attribute_get_name (a))) 	/* im gadu-gadu */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_GADUGADU);
			else if (!strcmp (EVC_X_MSN, e_vcard_attribute_get_name (a))) 		/* im msn */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_MSN);
			else if (!strcmp (EVC_X_ICQ, e_vcard_attribute_get_name (a))) 		/* im icq */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_ICQ);
			else if (!strcmp (EVC_X_GROUPWISE, e_vcard_attribute_get_name (a)))	/* im groupwise */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_GROUPWISE);
			else if (!strcmp (EVC_X_SKYPE, e_vcard_attribute_get_name (a))) 	/* im skype */
				custom_field->app = g_string_new(KLBX_CNT_X_CUSTOM_APP_SKYPE);
		}

		/* test if name and app are set, if not, it is no x custom element and could produce errors due to multiple values etc. */
		if (custom_field->app != NULL && custom_field->name != NULL) {
			gchar *val = e_vcard_attribute_get_value(a);
			if (val != NULL) {
				custom_field->value = g_string_new(val);
				i_contact->custom_list = g_list_append (i_contact->custom_list, custom_field);
			}
		}

		/*
		 * kolab store:
		 * manual read from kolab store, maybe create a separate function for cases like this, when you have a vcard-attribute instead of e_object
		 */
		if (e_vcard_attribute_get_param(a, ICONTACT_KOLAB_STORE_ID) != NULL) {
			GList *paramlist = e_vcard_attribute_get_param(a, ICONTACT_KOLAB_STORE_ID);
			for (;paramlist != NULL; paramlist = paramlist->next) {
				EVCardAttributeParam *eparam = paramlist->data;

				if (eparam != NULL) {
					GList* xml_str_list = NULL;
					gchar *id_str = (gchar*)eparam;
					gint id = strtol(id_str, (gchar**)0, 10);
					gint *id_ptr = g_new0(gint, 1);
					log_debug("found kolab store id %d", id);
					*id_ptr = id;
					xml_str_list = g_hash_table_lookup(k_store_hash, id_ptr);
					g_free(id_ptr);
					xml_str_list = g_list_last(xml_str_list);
					for (;xml_str_list != NULL; xml_str_list = xml_str_list->prev) {
						gchar *xml_str = (gchar*)xml_str_list->data;
						log_debug("found kolab store item %s", xml_str);
						kolab_store_add_element(i_contact->common, custom_field, g_strdup(xml_str), FALSE);
					}
				}
			}

		}
		/* next attribute in vcard */
		attr = attr->next;
	}
	g_list_free(attr);
}

/**
 * Add all hidden kolab mail attachments from the vcard to the kolab store.
 */
static void
kolab_store_handle_attachments(const EContact *e_contact, I_common* icommon)
{
	GList *list = e_vcard_get_attributes ((EVCard *) e_contact);
	for (; list != NULL; list = list->next) {
		EVCardAttribute *attrib = (EVCardAttribute*)list->data;
		if (strcmp(e_vcard_attribute_get_name (attrib), ICONTACT_KOLAB_STORE_ATTACHMENT) == 0) {
			GString *str = NULL;

			Kolab_conv_mail_part *mpart = g_new0(Kolab_conv_mail_part, 1);
			EVCardAttributeParam* param = NULL;
			GList *params = e_vcard_attribute_get_params(attrib);
			for (; params != NULL; params = params->next) {
				if (strcmp(e_vcard_attribute_param_get_name (params->data), ICONTACT_KOLAB_STORE_ATTACHMENT_MTYPE)== 0) {
					GList *vlist = NULL;
					gchar *mime_type = NULL;
					param = (EVCardAttributeParam*)params->data;
					vlist = e_vcard_attribute_param_get_values(param);
					mime_type = g_strdup((gchar*)vlist->data);
					mpart->mime_type = mime_type;
				} else if (strcmp(e_vcard_attribute_param_get_name (params->data), ICONTACT_KOLAB_STORE_ATTACHMENT_NAME)== 0) {
					GList *vlist = NULL;
					gchar *name = NULL;
					param = (EVCardAttributeParam*)params->data;
					vlist = e_vcard_attribute_param_get_values(param);
					name = g_strdup((gchar*)vlist->data);
					mpart->name = name;
				}
			}
			str = e_vcard_attribute_get_value_decoded (attrib);
			mpart->data = str->str;
			mpart->length = str->len;

			icommon->kolab_attachment_store = g_list_prepend(icommon->kolab_attachment_store, mpart);
		}
	}
	g_list_free(list);
}



/**
 * Iterate over all kolab store attributes in the vcard. If they belong below the
 * root xml tag (no id available) they are directly added to the kolab store.
 * All attributes with an id are added to a hash table
 * (key = id; value = xml string) which will be returned by this function.
 * This hash table can be used later if an attribute with an id to the kolab
 * store is found to get all related xml strings which belong to this element.
 */
static GHashTable*
kolab_store_read_values (const EContact *e_contact, I_contact* i_contact)
{
	GHashTable *hash = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL);
	GList *list = e_vcard_get_attributes ((EVCard *) e_contact);
	for (; list != NULL; list = list->next) {
		EVCardAttribute *attrib = (EVCardAttribute*)list->data;
		if (strcmp(e_vcard_attribute_get_name (attrib), ICONTACT_KOLAB_STORE) == 0) {
			EVCardAttributeParam* param = NULL;
			GString *str = NULL;
			GList *params = e_vcard_attribute_get_params(attrib);
			for (; params != NULL; params = params->next)
				if (strcmp(e_vcard_attribute_param_get_name (params->data), ICONTACT_KOLAB_STORE_ID)== 0)
					param = (EVCardAttributeParam*)params->data;
			str = e_vcard_attribute_get_value_decoded (attrib);
			if (param == NULL) {
				kolab_store_add_element(i_contact->common, i_contact->common, strdup(str->str), FALSE);
			} else {
				GList *vlist = e_vcard_attribute_param_get_values(param);
				if (vlist && vlist->data) {
					gchar *id_str = (gchar*)vlist->data;
					gint id = strtol(id_str, (gchar**)0, 10);
					if (id == KOLAB_STORE_PTR_CONTACT_NAME)
						kolab_store_add_element(i_contact->common, (gpointer) KOLAB_STORE_PTR_CONTACT_NAME, strdup(str->str), FALSE);
					else {
						GList *xml_str_list = NULL;
						gint *idptr = g_new0(gint, 1); /* pointer must be different every time */
						*idptr = id;
						xml_str_list = g_hash_table_lookup(hash, idptr);
						xml_str_list = g_list_append(xml_str_list, (gpointer) strdup(str->str));
						g_hash_table_insert(hash, idptr, xml_str_list);
					}
				}
			}
			g_string_free (str, TRUE);
		}
	}
	g_list_free(list);
	return hash;
}


/**
 * If the given EContact field does have related xml nodes, they are extraced
 * from the EContact via the VCard interface and added to the kolab store.
 *
 * @param  icontact
 *         Holds the kolab store to which the xml nodes are added
 * @param  parent_ptr
 *         A pointer to an element of the given icontact which is related to the
 *         xml nodes. This pointer is used as key for the kolab store.
 * @param  eContact
 *         The EContact (VCard) which is used to access the kolab store id from
 *         the vcard.
 * @param  efield
 *         The EContact field for which related xml nodes are searched
 * @param  k_store_hash
 *         This hash table holds all sub element xml nodes which can be accessed
 *         by kolab store id keys
 */
static void
kolab_store_restore_subnode_xml(I_contact *i_contact, gpointer parent_ptr,
                                const EContact *e_contact, EContactField e_field, GHashTable *k_store_hash)
{
	gchar *e_value = NULL;
	GList *e_attr_list = NULL;

	log_debug("get vcard attributes for econtact field");

	e_value = e_contact_get ((EContact*) e_contact, e_field); /* params cannot be accessed here */
	e_attr_list = e_contact_get_attributes ((EContact*)e_contact, e_field); /* params can be accessed here but attribute set is bigger than before => use evalue to reduce attribute set. */
	for (; e_attr_list != NULL; e_attr_list = e_attr_list->next) {
		GList *eparams = NULL;
		EVCardAttribute *eattr = (EVCardAttribute*) e_attr_list->data;
		if (e_vcard_attribute_is_single_valued(eattr)) {
			gchar *avalue = e_vcard_attribute_get_value (eattr);
			if (strcmp(avalue, e_value) != 0)
				continue;
		} else {
			/* log_warn("could not read kolab store id from multivalued vcard field"); */
			break;
		}
		/* log_debug("get vcard parameters for attribute %s", ((GString*)e_vcard_attribute_get_values_decoded(eattr)->data)->str); */
		/* gchar *aname = e_vcard_attribute_get_name(eattr); no new string is created here */
		eparams = e_vcard_attribute_get_params (eattr);
		for (;eparams != NULL; eparams = eparams->next) {
			if (strcmp(e_vcard_attribute_param_get_name (eparams->data), ICONTACT_KOLAB_STORE_ID) == 0) {
				EVCardAttributeParam *eparam = eparams->data;
				GList *epvlist = e_vcard_attribute_param_get_values(eparam);
				if (epvlist != NULL) {
					gchar *id_str = epvlist->data;
					GList* xml_str_list = NULL;

					gint id = strtol (id_str, (gchar**)0, 10);
					gint *id_ptr = g_new0(gint, 1);
					log_debug("found kolab store id %d", id);
					*id_ptr = id;
					xml_str_list = g_hash_table_lookup(k_store_hash, id_ptr);
					g_free(id_ptr);
					xml_str_list = g_list_last(xml_str_list);
					for (;xml_str_list != NULL; xml_str_list = xml_str_list->prev) {
						gchar *xml_str = (gchar*)xml_str_list->data;
						log_debug("found kolab store item %s", xml_str);
						kolab_store_add_element(i_contact->common, parent_ptr, g_strdup(xml_str), FALSE);
					}
					g_list_free(xml_str_list);
				}
				g_list_free(epvlist);
			}
		}
		g_list_free(eparams);
	}
	g_list_free(e_attr_list);
	g_free(e_value);
}

/**
 * convert address type from evolution to libekolabconv
 */
static Icontact_address_type
address_type_e_to_i(EContactField e_addr_type)
{
	switch (e_addr_type) {
	case E_CONTACT_ADDRESS_HOME:
		return ICONTACT_ADDR_TYPE_HOME;
	case E_CONTACT_ADDRESS_WORK:
		return ICONTACT_ADDR_TYPE_BUSINESS;
	case E_CONTACT_ADDRESS_LABEL_OTHER:
	default:
		return ICONTACT_ADDR_TYPE_OTHER;
	}
}


/**
 * map vcard phone type to icontact phone type
 */
static Icontact_phone_type
phone_type_e_to_i(GList *vcard_types)
{
	/* set default phone type: */
	const Icontact_phone_type DEFAULT_TYPE = ICONTACT_PHONE_PRIMARY;

	if (g_list_length(vcard_types) == 1) {
		if (strcmp(vcard_types->data, "PREF") == 0)
			return ICONTACT_PHONE_PRIMARY;
		else if (strcmp(vcard_types->data, EVC_X_ASSISTANT) == 0)
			return ICONTACT_PHONE_ASSISTANT;
		else if (strcmp(vcard_types->data, EVC_X_CALLBACK) == 0)
			return ICONTACT_PHONE_CALLBACK;
		else if (strcmp(vcard_types->data, "CAR") == 0)
			return ICONTACT_PHONE_CAR;
		else if (strcmp(vcard_types->data, "X-EVOLUTION-COMPANY") == 0)
			return ICONTACT_PHONE_COMPANY;
		else if (strcmp(vcard_types->data, "ISDN") == 0)
			return ICONTACT_PHONE_ISDN;
		else if (strcmp(vcard_types->data, "CELL") == 0)
			return ICONTACT_PHONE_MOBILE;
		else if (strcmp(vcard_types->data, "PAGER") == 0)
			return ICONTACT_PHONE_PAGER;
		else if (strcmp(vcard_types->data, EVC_X_RADIO) == 0)
			return ICONTACT_PHONE_RADIO;
		else if (strcmp(vcard_types->data, EVC_X_TELEX) == 0)
			return ICONTACT_PHONE_TELEX;
		else if (strcmp(vcard_types->data, EVC_X_TTYTDD) == 0)
			return ICONTACT_PHONE_TTYTDD;
		else if (strcmp(vcard_types->data, "VOICE") == 0)
			return ICONTACT_PHONE_OTHER;
		else if (strcmp(vcard_types->data, "FAX") == 0)		/* OTHER_FAX */
			return ICONTACT_PHONE_BUSINESS_FAX;
		else
			return DEFAULT_TYPE;
	} else {
		/* combinated types */
		if (g_list_find_custom(vcard_types, "WORK", (GCompareFunc)strcmp) != NULL) {
			if (g_list_find_custom(vcard_types, "VOICE", (GCompareFunc)strcmp) != NULL) {
				return ICONTACT_PHONE_BUSINESS_1;	/* TYPE=WORK,VOICE */
			} else if (g_list_find_custom(vcard_types, "FAX", (GCompareFunc)strcmp) != NULL) {
				return ICONTACT_PHONE_BUSINESS_FAX;	/* TYPE=WORK,FAX */
			} else {
				return DEFAULT_TYPE;
			}
		} else if (g_list_find_custom(vcard_types, "HOME", (GCompareFunc)strcmp) != NULL) {
			if (g_list_find_custom(vcard_types, "VOICE", (GCompareFunc)strcmp) != NULL) {
				return ICONTACT_PHONE_HOME_1;		/* TYPE=HOME,VOICE */
			} else if (g_list_find_custom(vcard_types, "FAX", (GCompareFunc)strcmp) != NULL) {
				return ICONTACT_PHONE_HOME_FAX;		/* TYPE=HOME,FAX */
			} else {
				return DEFAULT_TYPE;
			}
		} else {
			return DEFAULT_TYPE;
		}
	}
}
