/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/***************************************************************************
 *            kolab-mail-handle.c
 *
 *  Fri Jan 14 15:15:54 2011
 *  Copyright  2011  Christian Hilberg
 *  <hilberg@kernelconcepts.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
 */

/*----------------------------------------------------------------------------*/

#include <config.h>

#include <glib/gi18n-lib.h>

#include <libekolabutil/kolab-util-folder.h>
#include <libekolabutil/kolab-util-kconv.h>

#include "kolab-util-backend.h"

#include "kolab-mail-handle.h"
#include "kolab-mail-handle-friend.h"

/*----------------------------------------------------------------------------*/

typedef struct _KolabMailHandlePrivate KolabMailHandlePrivate;
struct _KolabMailHandlePrivate
{
	gchar *kolab_uid;
	gchar *foldername;
	ECalComponent *ecalcomp;
	ECalComponent *timezone;
	EContact *econtact;
	KolabMailSummary *summary;
	Kolab_conv_mail *kconvmail;
};

#define KOLAB_MAIL_HANDLE_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KOLAB_TYPE_MAIL_HANDLE, KolabMailHandlePrivate))

G_DEFINE_TYPE (KolabMailHandle, kolab_mail_handle, G_TYPE_OBJECT)

/*----------------------------------------------------------------------------*/
/* object/class init */

static void
kolab_mail_handle_init (KolabMailHandle *object)
{
	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (object));

	self = object;
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	priv->kolab_uid = NULL;
	priv->foldername = NULL;
	priv->ecalcomp = NULL;
	priv->timezone = NULL;
	priv->econtact = NULL;
	priv->summary = NULL;
	priv->kconvmail = NULL;
}

static void
kolab_mail_handle_dispose (GObject *object)
{
	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;

	self = KOLAB_MAIL_HANDLE (object);
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->ecalcomp != NULL) {
		g_object_unref (priv->ecalcomp);
		priv->ecalcomp = NULL;
	}

	if (priv->timezone != NULL) {
		g_object_unref (priv->timezone);
		priv->timezone = NULL;
	}

	if (priv->econtact != NULL) {
		g_object_unref (priv->econtact);
		priv->econtact = NULL;
	}

	if (priv->summary != NULL) {
		kolab_mail_summary_free (priv->summary);
		priv->summary = NULL;
	}

	if (priv->kconvmail != NULL) {
		kolabconv_free_kmail (priv->kconvmail);
		priv->kconvmail = NULL;
	}

	G_OBJECT_CLASS (kolab_mail_handle_parent_class)->dispose (object);
}

static void
kolab_mail_handle_finalize (GObject *object)
{
	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;

	self = KOLAB_MAIL_HANDLE (object);
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->kolab_uid != NULL)
		g_free (priv->kolab_uid);
	if (priv->foldername != NULL)
		g_free (priv->foldername);

	G_OBJECT_CLASS (kolab_mail_handle_parent_class)->finalize (object);
}

static void
kolab_mail_handle_class_init (KolabMailHandleClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	/* GObjectClass *parent_class = G_OBJECT_CLASS (klass); */

	g_type_class_add_private (klass, sizeof (KolabMailHandlePrivate));

	object_class->dispose = kolab_mail_handle_dispose;
	object_class->finalize = kolab_mail_handle_finalize;
}

/*----------------------------------------------------------------------------*/
/* private util functions */


static gboolean
kolab_mail_handle_check_complete (const KolabMailHandle *self,
                                  KolabFolderContextID context,
                                  const gchar *function_name,
                                  GError **err)
{
	KolabMailHandlePrivate *priv = NULL;
	guint folder_context = 0;
	gboolean complete = FALSE;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	g_assert (priv->kolab_uid != NULL);
	g_assert (priv->foldername != NULL);

	if (priv->summary == NULL) {
		g_warning ("%s: UID (%s) Folder (%s) without summary",
		           function_name, priv->kolab_uid, priv->foldername);
		return FALSE;
	}

	if (! kolab_mail_summary_check (priv->summary)) {
		g_set_error (err,
		             KOLAB_BACKEND_ERROR,
		             KOLAB_BACKEND_ERROR_DATATYPE_INTERNAL,
		             _("Internal inconsistency detected: PIM Object handle has inconsistent summary information, UID '%s', Folder '%s'"),
		             priv->kolab_uid, priv->foldername);
		return FALSE;
	}

	folder_context = kolab_mail_summary_get_uint_field (priv->summary,
	                                                    KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_CONTEXT);
	if (folder_context != context) {
		g_set_error (err,
		             KOLAB_BACKEND_ERROR,
		             KOLAB_BACKEND_ERROR_CONTEXT_MISUSE,
		             _("Internal inconsistency detected: PIM Object handle has inconsistent folder context information (expected %i, got %i), UID '%s', Folder '%s'"),
		             context, folder_context, priv->kolab_uid, priv->foldername);
		return FALSE;
	}

	complete = kolab_mail_summary_get_bool_field (priv->summary,
	                                              KOLAB_MAIL_SUMMARY_BOOL_FIELD_COMPLETE);
	if (! complete) {
		g_set_error (err,
		             KOLAB_BACKEND_ERROR,
		             KOLAB_BACKEND_ERROR_HANDLE_INCOMPLETE,
		             _("Internal inconsistency detected: PIM Object handle is incomplete, UID '%s', Folder '%s'"),
		             priv->kolab_uid, priv->foldername);
		return FALSE;
	}

	return TRUE;
}


/*----------------------------------------------------------------------------*/
/* friend functions -
 * resulting objects may be incomplete, special care to be taken
 */

KolabMailHandle*
kolab_mail_handle_new_shallow (const gchar *uid,
                               const gchar *foldername)
{

	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;

	g_assert (uid != NULL);
	/* foldername may be NULL */

	/* instantiate kolab mail handle */
	self = KOLAB_MAIL_HANDLE (g_object_new (KOLAB_TYPE_MAIL_HANDLE, NULL));
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	priv->kolab_uid = g_strdup (uid);
	priv->foldername = g_strdup (foldername);
	priv->ecalcomp = NULL;
	priv->timezone = NULL;
	priv->econtact = NULL;
	priv->summary = NULL;
	priv->kconvmail = NULL;

	return self;
}

KolabMailHandle*
kolab_mail_handle_new_from_kconvmail (Kolab_conv_mail *kconvmail,
                                      const gchar *uid,
                                      const gchar *foldername,
                                      KolabFolderTypeID folder_type)
{
	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;
	KolabFolderContextID context = KOLAB_FOLDER_CONTEXT_INVAL;

	g_assert (kconvmail != NULL);
	g_assert (uid != NULL);
	g_assert (foldername != NULL);

	context = kolab_util_folder_type_map_to_context_id (folder_type);
	g_assert ((context >= KOLAB_FOLDER_CONTEXT_EMAIL) &&
	          (context < KOLAB_FOLDER_LAST_CONTEXT));

	/* create handle object */
	self = kolab_mail_handle_new_shallow (uid, foldername);
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	priv->kconvmail = kconvmail;

	/* contains a mostly-empty summary, this needs to be
	 * synced with InfoDb data (the summary created here
	 * is used mostly to carry the cache location bits
	 * when a handle is created inside ImapClient or
	 * SideCache)
	 */

	priv->summary = kolab_mail_summary_new ();
	kolab_mail_summary_set_char_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_CHAR_FIELD_KOLAB_UID,
	                                   g_strdup (uid));
	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_CONTEXT,
	                                   context);
	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_TYPE,
	                                   folder_type);

	return self;
}

KolabMailHandle*
kolab_mail_handle_new_from_handle (const KolabMailHandle *kmailhandle)
{
	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;
	const gchar *uid = NULL;
	const gchar *foldername = NULL;
	const KolabMailSummary *summary = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (kmailhandle));

	/* get kmailhandle details */
	uid = kolab_mail_handle_get_uid (kmailhandle);
	foldername = kolab_mail_handle_get_foldername (kmailhandle);
	summary = kolab_mail_handle_get_summary (kmailhandle);

	/* create new handle object */
	self = kolab_mail_handle_new_shallow (uid, foldername);
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	/* set summary */
	priv->summary = kolab_mail_summary_clone (summary);

	/* eds data types and kconvmail remain NULL */

	return self;
}

KolabMailHandle*
kolab_mail_handle_new_from_handle_with_kconvmail (const KolabMailHandle *kmailhandle)
{
	KolabMailHandle *self = NULL;
	const Kolab_conv_mail *kconvmail = NULL;
	Kolab_conv_mail *kconvmail_loc = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (kmailhandle));

	self = kolab_mail_handle_new_from_handle (kmailhandle);

	kconvmail = kolab_mail_handle_get_kconvmail (kmailhandle);
	if (kconvmail != NULL) {
		kconvmail_loc = kolab_util_kconv_kconvmail_clone (kconvmail);
		kolab_mail_handle_set_kconvmail (self, kconvmail_loc);
	}

	return self;
}

gboolean
kolab_mail_handle_convert_eds_to_kconvmail (KolabMailHandle *self,
                                            GError **err)
{
	KolabMailHandlePrivate *priv = NULL;
	Kolab_conv_mail *kconvmail = NULL;
	ECalComponentWithTZ *calcomptz = NULL;
	KolabFolderTypeID folder_type = KOLAB_FOLDER_TYPE_INVAL;
	KolabFolderContextID context = KOLAB_FOLDER_CONTEXT_INVAL;
	gboolean ok = FALSE;
	GError *tmp_err = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	folder_type = kolab_mail_summary_get_uint_field (priv->summary,
	                                                 KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_TYPE);
	context = kolab_mail_summary_get_uint_field (priv->summary,
	                                             KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_CONTEXT);
	ok = kolab_mail_handle_check_complete (self,
	                                       context,
	                                       __func__,
	                                       &tmp_err);
	if (! ok) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	g_debug ("%s: UID (%s) Folder (%s) converting to Kolab, folder type/context (%i)/(%i)",
	         __func__, priv->kolab_uid, priv->foldername, folder_type, context);

	calcomptz = g_new0 (ECalComponentWithTZ, 1);
	calcomptz->maincomp = priv->ecalcomp;
	calcomptz->timezone = priv->timezone;

	switch (folder_type) {
	case KOLAB_FOLDER_TYPE_EVENT_DEFAULT:
	case KOLAB_FOLDER_TYPE_EVENT: /* E_CAL_COMPONENT_EVENT */
		g_debug ("%s: UID (%s) Folder (%s) converting type EVENT",
		         __func__, priv->kolab_uid, priv->foldername);
		kconvmail = kolabconv_eevent_to_kevent (calcomptz, &tmp_err);
		break;
	case KOLAB_FOLDER_TYPE_TASK_DEFAULT:
	case KOLAB_FOLDER_TYPE_TASK:  /* E_CAL_COMPONENT_TODO */
		g_debug ("%s: UID (%s) Folder (%s) converting type TASK",
		         __func__, priv->kolab_uid, priv->foldername);
		kconvmail = kolabconv_etask_to_ktask (calcomptz, &tmp_err);
		break;
	case KOLAB_FOLDER_TYPE_NOTE_DEFAULT:
	case KOLAB_FOLDER_TYPE_NOTE:  /* E_CAL_COMPONENT_JOURNAL */
		g_debug ("%s: UID (%s) Folder (%s) converting type NOTE",
		         __func__, priv->kolab_uid, priv->foldername);
		kconvmail = kolabconv_enote_to_knote (calcomptz, &tmp_err);
		break;
	case KOLAB_FOLDER_TYPE_CONTACT_DEFAULT:
	case KOLAB_FOLDER_TYPE_CONTACT:
		g_debug ("%s: UID (%s) Folder (%s) converting type CONTACT",
		         __func__, priv->kolab_uid, priv->foldername);
		kconvmail = kolabconv_econtact_to_kcontact (priv->econtact, &tmp_err);
		break;
		/* FIXME take care of JOURNAL type which we don't support */
	default:
		g_assert_not_reached ();
	}

	calcomptz->maincomp = NULL;
	calcomptz->timezone = NULL;
	g_free (calcomptz);

	if (tmp_err != NULL) {
		if (kconvmail != NULL)
			kolabconv_free_kmail (kconvmail);
		g_propagate_error (err, tmp_err);
		return FALSE;
	}
	if (kconvmail == NULL) {
		g_set_error (err,
		             KOLAB_BACKEND_ERROR,
		             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
		             _("Data conversion to Kolab format failed for PIM Object, UID '%s', Folder '%s'"),
		             priv->kolab_uid, priv->foldername);
		return FALSE;
	}

	/* if kconvmail exists, replace. kconvmail gets ripped out (resected)
	 * later on when the handle is passed to ImapClient for store operation.
	 * Passing the handle to SideCache for store will resect only in
	 * offline operational mode (when online, ImapClient needs kconvmail
	 * as well, so SideCache must not resect it)
	 */
	if (priv->kconvmail != NULL)
		kolabconv_free_kmail (priv->kconvmail);
	priv->kconvmail = kconvmail;

	return TRUE;
}

gboolean
kolab_mail_handle_convert_kconvmail_to_eds (KolabMailHandle *self,
                                            GError **err)
{
	KolabMailHandlePrivate *priv = NULL;
	ECalComponentWithTZ *calcomptz = NULL;
	EContact *econtact = NULL;
	KolabMailSummary *summary = NULL;
	KolabFolderTypeID folder_type = KOLAB_FOLDER_TYPE_INVAL;
	KolabFolderContextID context = KOLAB_FOLDER_CONTEXT_INVAL;
	const gchar *component_uid = NULL;
	gchar *contact_uid = NULL;
	GError *tmp_err = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	g_assert (priv->kconvmail != NULL);

	folder_type = kolab_mail_summary_get_uint_field (priv->summary,
	                                                 KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_TYPE);
	context = kolab_mail_summary_get_uint_field (priv->summary,
	                                             KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_CONTEXT);

	g_debug ("%s: UID (%s) Folder (%s) converting from Kolab, folder type/context (%i)/(%i)",
	         __func__, priv->kolab_uid, priv->foldername, folder_type, context);

	/* do Kolab->EDS data conversion */
	switch (folder_type) {
	case KOLAB_FOLDER_TYPE_EVENT_DEFAULT:
	case KOLAB_FOLDER_TYPE_EVENT: /* E_CAL_COMPONENT_EVENT */
		g_debug ("%s: UID (%s) Folder (%s) converting from type EVENT",
		         __func__, priv->kolab_uid, priv->foldername);
		calcomptz = kolabconv_kevent_to_eevent (priv->kconvmail,
		                                        &tmp_err);
		break;
	case KOLAB_FOLDER_TYPE_TASK_DEFAULT:
	case KOLAB_FOLDER_TYPE_TASK:  /* E_CAL_COMPONENT_TODO */
		g_debug ("%s: UID (%s) Folder (%s) converting from type TASK",
		         __func__, priv->kolab_uid, priv->foldername);
		calcomptz = kolabconv_ktask_to_etask (priv->kconvmail,
		                                      &tmp_err);
		break;
	case KOLAB_FOLDER_TYPE_NOTE_DEFAULT:
	case KOLAB_FOLDER_TYPE_NOTE:  /* E_CAL_COMPONENT_JOURNAL */
		g_debug ("%s: UID (%s) Folder (%s) converting from type NOTE",
		         __func__, priv->kolab_uid, priv->foldername);
		calcomptz = kolabconv_knote_to_enote (priv->kconvmail,
		                                      &tmp_err);
		break;
	case KOLAB_FOLDER_TYPE_CONTACT_DEFAULT:
	case KOLAB_FOLDER_TYPE_CONTACT:
		g_debug ("%s: UID (%s) Folder (%s) converting from type CONTACT",
		         __func__, priv->kolab_uid, priv->foldername);
		econtact = kolabconv_kcontact_to_econtact (priv->kconvmail,
		                                           &tmp_err);
		break;
	case KOLAB_FOLDER_TYPE_JOURNAL_DEFAULT:
	case KOLAB_FOLDER_TYPE_JOURNAL:
		g_set_error (err,
		             KOLAB_BACKEND_ERROR,
		             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
		             _("JOURNAL data type not supported for PIM Object, UID '%s', Folder '%s'"),
		             priv->kolab_uid, priv->foldername);
		return FALSE;
	default:
		g_set_error (err,
		             KOLAB_BACKEND_ERROR,
		             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
		             _("Unknown data type for PIM Object, UID '%s', Folder '%s'"),
		             priv->kolab_uid, priv->foldername);
		return FALSE;
	}

	/* enforce GError conformance */
	if (tmp_err != NULL) {
		if (calcomptz != NULL) {
			kolabconv_free_ecalendar (calcomptz);
			calcomptz = NULL;
			g_warning ("%s: UID (%s) Folder (%s) GError set but ECalComponentWithTZ* not NULL",
			           __func__, priv->kolab_uid, priv->foldername);
		}
		if (econtact != NULL) {
			kolabconv_free_econtact (econtact);
			econtact = NULL;
			g_warning ("%s: UID (%s) Folder (%s) GError set but EContact* not NULL",
			           __func__, priv->kolab_uid, priv->foldername);
		}
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	/* sanity checking */
	switch (context) {
	case KOLAB_FOLDER_CONTEXT_CALENDAR:
		/* ECalComponentWithTZ sanity checks */
		if (calcomptz == NULL) {
			g_set_error (err,
			             KOLAB_BACKEND_ERROR,
			             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
			             _("Conversion from Kolab calendar type to Evolution failed for PIM Object, UID '%s', Folder '%s'"),
			             priv->kolab_uid, priv->foldername);
			return FALSE;
		}
		if (calcomptz->maincomp == NULL) {
			g_set_error (err,
			             KOLAB_BACKEND_ERROR,
			             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
			             _("Internal inconsistency detected: Corrupt timezone object for PIM Object, UID '%s', Folder '%s'"),
			             priv->kolab_uid, priv->foldername);
			return FALSE;
		}
		e_cal_component_get_uid (calcomptz->maincomp, &component_uid);
		if (g_strcmp0 (priv->kolab_uid, component_uid) != 0) {
			g_debug ("%s: Kolab UID (subject/xml): (%s)/(%s)",
			         __func__, priv->kolab_uid, component_uid);
			kolabconv_free_ecalendar (calcomptz);
			g_set_error (err,
			             KOLAB_BACKEND_ERROR,
			             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
			             _("Invalid Kolab mail object (UID in subject does not match UID in data part), UID '%s', Folder '%s'"),
			             priv->kolab_uid, priv->foldername);
			return FALSE;
		}
		/* KolabMailSummary */
		summary = kolab_mail_summary_new_from_ecalcomponent (calcomptz->maincomp);
		break;
	case KOLAB_FOLDER_CONTEXT_CONTACT:
		/* EContact sanity checks */
		if (econtact == NULL) {
			g_set_error (err,
			             KOLAB_BACKEND_ERROR,
			             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
			             "Conversion from Kolab contact type to Evolution failed for PIM Object, UID '%s', Folder '%s'",
			             priv->kolab_uid, priv->foldername);
			return FALSE;
		}
		contact_uid = e_contact_get (econtact, E_CONTACT_UID);
		if (g_strcmp0 (priv->kolab_uid, contact_uid) != 0) {
			g_debug ("%s: Kolab UID (subject/xml): (%s)/(%s)",
			         __func__, priv->kolab_uid, contact_uid);
			g_free (contact_uid);
			kolabconv_free_econtact (econtact);
			g_set_error (err,
			             KOLAB_BACKEND_ERROR,
			             KOLAB_BACKEND_ERROR_DATATYPE_KOLAB,
			             _("Invalid Kolab mail object (UID in subject does not match UID in data part), UID '%s', Folder '%s'"),
			             priv->kolab_uid, priv->foldername);
			return FALSE;
		}
		g_free (contact_uid);
		/* KolabMailSummary */
		summary = kolab_mail_summary_new_from_econtact (econtact);
		break;
	default:
		g_assert_not_reached ();
	}

	/* set the summary bits we know here */
	kolab_mail_summary_update_eds_data (priv->summary, summary);
	kolab_mail_summary_free (summary);

	/* KolabMailSummary check */
	if (! kolab_mail_summary_check (priv->summary)) {
		if (calcomptz != NULL)
			kolabconv_free_ecalendar (calcomptz);
		if (econtact != NULL)
			kolabconv_free_econtact (econtact);
		g_set_error (err,
		             KOLAB_BACKEND_ERROR,
		             KOLAB_BACKEND_ERROR_DATATYPE_INTERNAL,
		             _("Internal inconsistency detected: Invalid summary information for PIM Object, UID '%s', Folder '%s'"),
		             priv->kolab_uid, priv->foldername);
		return FALSE;
	}

	/* attach handle data */
	switch (context) {
	case KOLAB_FOLDER_CONTEXT_CALENDAR:
		if (priv->ecalcomp != NULL)
			g_object_unref (priv->ecalcomp);
		if (priv->timezone != NULL)
			g_object_unref (priv->timezone);
		priv->ecalcomp = calcomptz->maincomp;
		priv->timezone = calcomptz->timezone;
		calcomptz->maincomp = NULL;
		calcomptz->timezone = NULL;
		g_free (calcomptz); /* free struct only */
		break;
	case KOLAB_FOLDER_CONTEXT_CONTACT:
		if (priv->econtact)
			g_object_unref (priv->econtact);
		priv->econtact = econtact;
		break;
	default:
		g_assert_not_reached ();
	}

	/* once the conversion is completed, we only keep EDS payload data */
	kolabconv_free_kmail (priv->kconvmail);
	priv->kconvmail = NULL;

	return TRUE;
}

Kolab_conv_mail*
kolab_mail_handle_resect_kconvmail (KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;
	Kolab_conv_mail *kconvmail = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->kconvmail == NULL)
		return NULL;

	kconvmail = priv->kconvmail;
	priv->kconvmail = NULL;
	return kconvmail;
}

const Kolab_conv_mail*
kolab_mail_handle_get_kconvmail (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	return priv->kconvmail;
}

void
kolab_mail_handle_set_kconvmail (KolabMailHandle *self,
                                 Kolab_conv_mail *kconvmail)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->kconvmail != NULL)
		kolabconv_free_kmail (priv->kconvmail);

	priv->kconvmail = kconvmail;
}

void
kolab_mail_handle_drop_kconvmail (KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->kconvmail != NULL) {
		kolabconv_free_kmail (priv->kconvmail);
		priv->kconvmail = NULL;
	}
}

gboolean
kolab_mail_handle_has_kconvmail (KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->kconvmail == NULL)
		return FALSE;

	return TRUE;
}

gboolean
kolab_mail_handle_kconvmail_is_equal (KolabMailHandle *self,
                                      KolabMailHandle *other)
{
	const Kolab_conv_mail *s_kconvmail = NULL;
	const Kolab_conv_mail *o_kconvmail = NULL;
	gchar *s_checksum = NULL;
	gchar *o_checksum = NULL;
	gboolean is_eq = TRUE;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_assert (KOLAB_IS_MAIL_HANDLE (other));

	s_kconvmail = kolab_mail_handle_get_kconvmail (self);
	o_kconvmail = kolab_mail_handle_get_kconvmail (other);

	if ((s_kconvmail == NULL) && (o_kconvmail == NULL))
		return TRUE;

	if (((s_kconvmail == NULL) && (o_kconvmail != NULL)) ||
	    ((s_kconvmail != NULL) && (o_kconvmail == NULL)))
		return FALSE;

	s_checksum = kolab_util_kconv_kconvmail_checksum (s_kconvmail);
	o_checksum = kolab_util_kconv_kconvmail_checksum (o_kconvmail);

	if (! g_strcmp0 (s_checksum, o_checksum))
		is_eq = FALSE;

	g_free (s_checksum);
	g_free (o_checksum);

	return is_eq;
}

void
kolab_mail_handle_set_uid (KolabMailHandle *self,
                           const gchar *uid)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_assert (uid != NULL);

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->kolab_uid != NULL)
		g_free (priv->kolab_uid);
	priv->kolab_uid = g_strdup (uid);

	if (priv->summary)
		/* overwrites existing! */
		kolab_mail_summary_set_char_field (priv->summary,
		                                   KOLAB_MAIL_SUMMARY_CHAR_FIELD_KOLAB_UID,
		                                   g_strdup (uid));
}

gboolean
kolab_mail_handle_set_uid_full (KolabMailHandle *self,
                                const gchar *uid,
                                GError **err)
{
	KolabMailHandlePrivate *priv = NULL;
	KolabFolderContextID context = KOLAB_FOLDER_CONTEXT_INVAL;
	gboolean ok = FALSE;
	GError *tmp_err = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_assert (uid != NULL);

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	context = kolab_mail_summary_get_uint_field (priv->summary,
	                                             KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_CONTEXT);
	switch (context) {
	case KOLAB_FOLDER_CONTEXT_CALENDAR:
		if ((priv->ecalcomp == NULL) && (priv->kconvmail != NULL)) {
			ok = kolab_mail_handle_convert_kconvmail_to_eds (self,
			                                                 &tmp_err);
			if (! ok) {
				g_propagate_error (err, tmp_err);
				return FALSE;
			}
		}
		if (priv->ecalcomp != NULL)
			e_cal_component_set_uid (priv->ecalcomp, uid);
		break;
	case KOLAB_FOLDER_CONTEXT_CONTACT:
		if ((priv->econtact == NULL) && (priv->kconvmail != NULL)) {
			ok = kolab_mail_handle_convert_kconvmail_to_eds (self,
			                                                 &tmp_err);
			if (! ok) {
				g_propagate_error (err, tmp_err);
				return FALSE;
			}
		}
		if (priv->econtact != NULL)
			e_contact_set (priv->econtact, E_CONTACT_UID, uid);
		break;
	default:
		{ /* nop */ }
	}

	kolab_mail_handle_set_uid (self, uid);
	return TRUE;
}

void
kolab_mail_handle_set_foldername (KolabMailHandle *self,
                                  const gchar *foldername)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_assert (foldername != NULL);

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->foldername != NULL)
		g_free (priv->foldername);
	priv->foldername = g_strdup (foldername);
}

const KolabMailSummary*
kolab_mail_handle_get_summary (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	return priv->summary;
}

KolabMailSummary*
kolab_mail_handle_get_summary_nonconst (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	return priv->summary;
}

gboolean
kolab_mail_handle_set_summary (KolabMailHandle *self,
                               KolabMailSummary *summary,
                               GError **err)
{
	/* we take ownership of *summary here */

	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	/* summary may be NULL */
	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (summary != NULL) {
		if (! kolab_mail_summary_check (summary)) {
			g_set_error (err,
			             KOLAB_BACKEND_ERROR,
			             KOLAB_BACKEND_ERROR_INTERNAL,
			             _("Internal inconsistency detected: Invalid summary information for PIM Object, UID '%s', Folder '%s'"),
			             priv->kolab_uid, priv->foldername);
			return FALSE;
		}
	}

	if (priv->summary)
		kolab_mail_summary_free (priv->summary);

	priv->summary = summary;
	return TRUE;
}

/*----------------------------------------------------------------------------*/
/* create new object from Evo/EDS data types */

/**
 * kolab_mail_handle_new_from_ecalcomponent:
 * @ecalcomp: the #ECalComponent to create the handle from
 * @timezone: the timezone information to attach to the calendar component (or NULL)
 *
 * Creates a new #KolabMailHandle from @ecalcomp. The @ecalcomp data is checked
 * and attached to the #KolabMailHandle, and so is the timezone
 * data (if supplied). The @timezone may be NULL if none is to be set explicitly.
 * The newly created handle should be handed over to #KolabMailAccess as soon as
 * possible by a call to kolab_mail_access_store_handle().
 *
 * The refcount of each #ECalComponent passed in gets incremented. g_object_unref()
 * any passed-in #ECalComponent if no longer needed outside the #KolabMailHandle.
 *
 * This sets the %KOLAB_FOLDER_CONTEXT_CALENDAR context on the handle, which means
 * that it can be passed to a #KolabMailAccess only if the latter is configured
 * with the same context.
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: none</listitem>
 *   <listitem>Handle postcondition: complete, %KOLAB_FOLDER_CONTEXT_CALENDAR</listitem>
 * </itemizedlist>
 *
 * Returns: a #KolabMailHandle instance
 */
KolabMailHandle*
kolab_mail_handle_new_from_ecalcomponent (ECalComponent *ecalcomp,
                                          ECalComponent *timezone)
{
	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;
	ECalComponentVType vtype = E_CAL_COMPONENT_NO_TYPE;
	KolabFolderTypeID folder_type = KOLAB_FOLDER_TYPE_INVAL;
	KolabFolderContextID context = KOLAB_FOLDER_CONTEXT_INVAL;
	const gchar *ecalcomp_uid = NULL;

	g_assert (E_IS_CAL_COMPONENT (ecalcomp));

	vtype = e_cal_component_get_vtype (ecalcomp);
	switch (vtype) {
	case E_CAL_COMPONENT_EVENT:
		folder_type = KOLAB_FOLDER_TYPE_EVENT;
		break;
	case E_CAL_COMPONENT_TODO:
		folder_type = KOLAB_FOLDER_TYPE_TASK;
		break;
	case E_CAL_COMPONENT_JOURNAL:
		folder_type = KOLAB_FOLDER_TYPE_NOTE;
		break;
	default:
		g_assert_not_reached ();
	}
	context = kolab_util_folder_type_map_to_context_id (folder_type);
	g_assert (context != KOLAB_FOLDER_CONTEXT_INVAL);

	if (timezone != NULL) {
		g_assert (E_IS_CAL_COMPONENT (timezone));
		g_assert (e_cal_component_get_vtype (timezone) == E_CAL_COMPONENT_TIMEZONE);
	}

	/* get Kolab UID */
	e_cal_component_get_uid (ecalcomp, &ecalcomp_uid);
	g_assert (ecalcomp_uid != NULL);

	/* instantiate kolab mail handle */
	self = kolab_mail_handle_new_shallow (ecalcomp_uid, NULL);
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	/* set local members */
	g_object_ref (ecalcomp);
	priv->ecalcomp = ecalcomp;
	if (timezone != NULL) {
		g_object_ref (timezone);
		priv->timezone = timezone;
	}

	/* kolab mail handle summary */
	priv->summary = kolab_mail_summary_new_from_ecalcomponent (ecalcomp);
	kolab_mail_summary_set_char_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_CHAR_FIELD_KOLAB_UID,
	                                   g_strdup (priv->kolab_uid));
	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_TYPE,
	                                   folder_type);
	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_CONTEXT,
	                                   KOLAB_FOLDER_CONTEXT_CALENDAR);
	kolab_mail_summary_set_bool_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_BOOL_FIELD_COMPLETE,
	                                   TRUE);
	return self;
}

/**
 * kolab_mail_handle_new_from_econtact:
 * @econtact: the #EContact to create the handle from
 *
 * Creates a new #KolabMailHandle from @econtact. The @econtact data is checked
 * and attached to the #KolabMailHandle.
 * The newly created handle should be handed over to #KolabMailAccess as soon as
 * possible by a call to kolab_mail_access_store_handle().
 *
 * The refcount of the #EContact passed in gets incremented. g_object_unref()
 * the passed-in #EContact if no longer needed outside the #KolabMailHandle.
 *
 * This sets the %KOLAB_FOLDER_CONTEXT_CONTACT context on the handle, which means
 * that it can be passed to a #KolabMailAccess only if the latter is configured
 * with the same context.
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: none</listitem>
 *   <listitem>Handle postcondition: complete, %KOLAB_FOLDER_CONTEXT_CONTACT</listitem>
 * </itemizedlist>
 *
 * Returns: a #KolabMailHandle instance
 */
KolabMailHandle*
kolab_mail_handle_new_from_econtact (EContact *econtact)
{
	KolabMailHandle *self = NULL;
	KolabMailHandlePrivate *priv = NULL;
	gchar *econtact_uid = NULL;

	g_assert (E_IS_CONTACT (econtact));

	/* get Kolab UID */
	econtact_uid = e_contact_get (econtact, E_CONTACT_UID);
	g_assert (econtact_uid != NULL);

	/* instantiate kolab mail handle */
	self = kolab_mail_handle_new_shallow (econtact_uid, NULL);
	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);
	g_free (econtact_uid); /* in contrast to ECalComponent, need to free() this */

	/* set local members */
	g_object_ref (econtact);
	priv->econtact = econtact;

	/* kolab mail handle summary */
	priv->summary = kolab_mail_summary_new_from_econtact (econtact);
	kolab_mail_summary_set_char_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_CHAR_FIELD_KOLAB_UID,
	                                   g_strdup (priv->kolab_uid));
	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_TYPE,
	                                   KOLAB_FOLDER_TYPE_CONTACT);
	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_FOLDER_CONTEXT,
	                                   KOLAB_FOLDER_CONTEXT_CONTACT);
	kolab_mail_summary_set_bool_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_BOOL_FIELD_COMPLETE,
	                                   TRUE);
	return self;
}

/*----------------------------------------------------------------------------*/
/* GLib special destruction functions */

void
kolab_mail_handle_gdestroy (gpointer object)
{
	KolabMailHandle *self = KOLAB_MAIL_HANDLE (object);
	g_object_unref (self);
}

/*----------------------------------------------------------------------------*/
/* getters working on complete as well as on incomplete KolabMailHandles */

/**
 * kolab_mail_handle_is_complete:
 * @self: a #KolabMailHandle instance
 *
 * Checks whether or not a #KolabMailHandle instance is complete.
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: none</listitem>
 *   <listitem>Handle postcondition: none</listitem>
 * </itemizedlist>
 *
 * Returns: TRUE if @self is complete,
 *	    FALSE otherwise
 */
gboolean
kolab_mail_handle_is_complete (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;
	gboolean complete = FALSE;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->summary == NULL)
		return FALSE;

	complete = kolab_mail_summary_get_bool_field (priv->summary,
	                                              KOLAB_MAIL_SUMMARY_BOOL_FIELD_COMPLETE);
	return complete;
}

/**
 * kolab_mail_handle_get_uid:
 * @self: a #KolabMailHandle instance
 *
 * Gets the UID string from a #KolabMailHandle instance. It is an error if
 * there is no UID associated with a #KolabMailHandle instance.
 *
 * TODO check whether this function should throw a critical error in case
 *      of a NULL UID instead of a warning only
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: none</listitem>
 *   <listitem>Handle postcondition: none</listitem>
 * </itemizedlist>
 *
 * Returns: the UID string for this #KolabMailHandle instance
 */
const gchar*
kolab_mail_handle_get_uid (const KolabMailHandle *self)
{
	/* may return NULL (this is an error condition) */

	KolabMailHandlePrivate *priv = NULL;
	const gchar *s_uid = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	/* if priv->summary is still NULL, all we can do is return
	 * the priv->kolab_uid (which, if NULL, signals an error condition)
	 */

	if (priv->summary != NULL) {
		s_uid = kolab_mail_summary_get_char_field (priv->summary,
		                                           KOLAB_MAIL_SUMMARY_CHAR_FIELD_KOLAB_UID);
		if (priv->kolab_uid != NULL) {
			/* consistency check
			 * Since the Kolab UID is our primary key, we shouldn't
			 * try to avoid double/triple/...-checking. Litte work,
			 * much gain
			 */
			if (g_strcmp0 (s_uid, priv->kolab_uid) != 0) {
				/* TODO
				 * - should we fail with an error instead of giving a warning?
				 * - should we invalidate the mail handle?
				 * - keep the invalidated mail handle so we can skip it
				 *   (without further processing it)?
				 */
				g_warning ("%s: invalid Kolab mail (UID [%s] in subject does not match UID [%s] in data part)",
				           __func__, priv->kolab_uid, s_uid);
				return NULL;
			}
		} else {
			/* TODO issue warning ? */
			priv->kolab_uid = g_strdup (s_uid);
		}
	}

	return priv->kolab_uid;
}

/**
 * kolab_mail_handle_get_foldername:
 * @self: a #KolabMailHandle instance
 *
 * Gets the IMAP folder name this #KolabMailHandle instance is stored in.
 * If the mail handle has not yet been stored within #KolabMailAccess by
 * a call to kolab_mail_access_store_handle(), the folder name returned
 * is NULL.
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: none</listitem>
 *   <listitem>Handle postcondition: none</listitem>
 * </itemizedlist>
 *
 * Returns: the IMAP folder name string for this
 *          #KolabMailHandle instance (may be NULL)
 */
const gchar*
kolab_mail_handle_get_foldername (const KolabMailHandle *self)
{
	/* may return NULL */

	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	return priv->foldername;
}

KolabObjectCacheLocation
kolab_mail_handle_get_cache_location (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;
	KolabObjectCacheLocation location = KOLAB_OBJECT_CACHE_LOCATION_INVAL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->summary == NULL) {
		g_warning ("%s: UID [%s] without summary",
		           __func__, priv->kolab_uid);
		return KOLAB_OBJECT_CACHE_LOCATION_INVAL;
	}

	location = kolab_mail_summary_get_uint_field (priv->summary,
	                                              KOLAB_MAIL_SUMMARY_UINT_FIELD_CACHE_LOCATION);
	return location;
}

gboolean
kolab_mail_handle_set_cache_location (KolabMailHandle *self,
                                      KolabObjectCacheLocation location)
{
	KolabMailHandlePrivate *priv = NULL;
	KolabObjectCacheLocation cl = KOLAB_OBJECT_CACHE_LOCATION_NONE;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_assert (location < KOLAB_OBJECT_CACHE_LOCATION_INVAL);

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->summary == NULL) {
		g_warning ("%s: UID [%s] without summary",
		           __func__, priv->kolab_uid);
		return FALSE;
	}

	if (location > KOLAB_OBJECT_CACHE_LOCATION_NONE) {
		cl = kolab_mail_summary_get_uint_field (priv->summary,
		                                        KOLAB_MAIL_SUMMARY_UINT_FIELD_CACHE_LOCATION);
		cl = cl | location;
	}

	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_CACHE_LOCATION,
	                                   cl);

	return TRUE;
}

gboolean
kolab_mail_handle_unset_cache_location (KolabMailHandle *self,
                                        KolabObjectCacheLocation location)
{
	KolabMailHandlePrivate *priv = NULL;
	KolabObjectCacheLocation cl = KOLAB_OBJECT_CACHE_LOCATION_NONE;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));
	g_assert ((location > KOLAB_OBJECT_CACHE_LOCATION_NONE) &&
	          (location < KOLAB_OBJECT_CACHE_LOCATION_INVAL));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->summary == NULL) {
		g_warning ("%s: UID [%s] without summary",
		           __func__, priv->kolab_uid);
		return FALSE;
	}

	cl = kolab_mail_summary_get_uint_field (priv->summary,
	                                        KOLAB_MAIL_SUMMARY_UINT_FIELD_CACHE_LOCATION);
	cl = cl & (~location);

	kolab_mail_summary_set_uint_field (priv->summary,
	                                   KOLAB_MAIL_SUMMARY_UINT_FIELD_CACHE_LOCATION,
	                                   cl);

	return TRUE;
}


/*----------------------------------------------------------------------------*/
/* getters working on completed KolabMailHandles ONLY.
 *
 * If the KolabMailHandle supplied is shallow and does contain summary info only
 * (i.e. is incomplete), it needs to be retrieve()d by KolabMailAccess first.
 *
 * This situation can occur both in offline and online operation, especially
 * in conjuction with queries for KolabMailHandles when only summary information
 * is read but no actual email data is processed (whether cached or resulting from
 * online operation).
 *
 * If any of these getters is called on an incomplete KolabMailHandle, the return
 * value will be NULL.
 */

/**
 * kolab_mail_handle_get_ecalcomponent:
 * @self: a #KolabMailHandle instance
 *
 * Returns the #ECalComponent instance associated with the handle with it's
 * refcount incremented by 1. Unref the #ECalComponent if it is no longer
 * needed outside the handle. If there is timezone information attached to
 * the #ECalComponent, it can be queried for with a subsequent call to
 * kolab_mail_handle_get_timezone(). The @timezone may be NULL if none was set
 * on the PIM data object.
 *
 * This requires the %KOLAB_FOLDER_CONTEXT_CALENDAR context be set on the handle.
 * The handle must be complete in order to retrieve an #ECalComponent from it.
 * If the handle is incomplete, the function returns NULL.
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: complete, %KOLAB_FOLDER_CONTEXT_CALENDAR</listitem>
 *   <listitem>Handle postcondition: none</listitem>
 * </itemizedlist>
 *
 * Returns: a ref'd #ECalComponent instance, or NULL
 */
ECalComponent*
kolab_mail_handle_get_ecalcomponent (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->ecalcomp == NULL)
		return NULL;

	g_object_ref (priv->ecalcomp);
	return priv->ecalcomp;
}

/**
 * kolab_mail_handle_get_timezone:
 * @self: a #KolabMailHandle instance
 *
 * Gets the timezone information as an #ECalComponent from this
 * #KolabMailHandle instance. The return value is NULL if there is no timezone
 * information. This function is useful only in %KOLAB_FOLDER_CONTEXT_CALENDAR
 * context. The refcount on the #ECalComponent returned is incremented by one,
 * if the component is not NULL
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: none</listitem>
 *   <listitem>Handle postcondition: none</listitem>
 * </itemizedlist>
 *
 * Returns: the timezone #ECalComponent, or NULL
 */
ECalComponent*
kolab_mail_handle_get_timezone (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->timezone == NULL)
		return NULL;

	g_object_ref (priv->timezone);
	return priv->timezone;
}

/**
 * kolab_mail_handle_get_econtact:
 * @self: a #KolabMailHandle instance
 *
 * Returns the #EContact instance associated with the handle with it's
 * refcount incremented by 1. Unref the #EContact if it is no longer
 * needed outside the handle.
 *
 * This requires the %KOLAB_FOLDER_CONTEXT_CONTACT context be set on the handle.
 * The handle must be complete in order to retrieve an #EContact from it.
 * If the handle is incomplete, the function returns NULL.
 *
 * <itemizedlist>
 *   <listitem>Handle precondition: complete, %KOLAB_FOLDER_CONTEXT_CONTACT</listitem>
 *   <listitem>Handle postcondition: none</listitem>
 * </itemizedlist>
 *
 * Returns: a new #EContact instance, or NULL
 */
EContact*
kolab_mail_handle_get_econtact (const KolabMailHandle *self)
{
	KolabMailHandlePrivate *priv = NULL;

	g_assert (KOLAB_IS_MAIL_HANDLE (self));

	priv = KOLAB_MAIL_HANDLE_PRIVATE (self);

	if (priv->econtact == NULL)
		return NULL;

	g_object_ref (priv->econtact);
	return priv->econtact;
}

/*----------------------------------------------------------------------------*/
