/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/***************************************************************************
 *            kolab-util-kconv.c
 *
 *  Mon Apr 11 11:02:25 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 <glib.h>

#include "kolab-util-kconv.h"

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

void
kolab_util_kconv_kconvmail_gdestroy (gpointer data)
{
	Kolab_conv_mail *kconvmail = NULL;

	kconvmail = (Kolab_conv_mail *)data;

	kolabconv_free_kmail (kconvmail);
}

Kolab_conv_mail*
kolab_util_kconv_kconvmail_clone (const Kolab_conv_mail *kconvmail)
{
	Kolab_conv_mail *newkcmail = NULL;
	guint ii = 0;

	if (kconvmail == NULL)
		return NULL;

	newkcmail = g_new0 (Kolab_conv_mail, 1);
	newkcmail->length = kconvmail->length;
	newkcmail->mail_parts = NULL;

	if (newkcmail->length > 0)
		newkcmail->mail_parts = g_new0 (Kolab_conv_mail_part,
		                                newkcmail->length);
	for (ii = 0; ii < newkcmail->length; ii++) {
		Kolab_conv_mail_part *kcmpart = NULL;
		Kolab_conv_mail_part *newpart = NULL;

		kcmpart = &(kconvmail->mail_parts[ii]);
		newpart = &(newkcmail->mail_parts[ii]);

		newpart->name = g_strdup (kcmpart->name);
		newpart->mime_type = g_strdup (kcmpart->mime_type);
		newpart->length = kcmpart->length;
		newpart->data = g_memdup (kcmpart->data,
		                          newpart->length);
	}

	return newkcmail;
}

/*----------------------------------------------------------------------------*/
/* Kolab_conv_mail <en|de>coding, checksumming */

GList*
kolab_util_kconv_kconvmail_data_base64_encode (const Kolab_conv_mail *kconvmail)
{
	GList *kconvbase64 = NULL;
	guint ii = 0;

	g_assert (kconvmail != NULL);
	g_assert (kconvmail->length > 0);
	g_assert (kconvmail->mail_parts != NULL);

	/* iterate over kconvmail parts */
	for (ii = 0; ii < kconvmail->length; ii++) {
		Kolab_conv_mail_part *kconvmailpart = NULL;
		gchar *base64str = NULL;

		kconvmailpart = &(kconvmail->mail_parts[ii]);

		g_assert (kconvmailpart != NULL);
		g_assert (kconvmailpart->data != NULL);
		g_assert (kconvmailpart->length > 0);

		base64str = g_base64_encode ((guchar *) kconvmailpart->data,
		                             (gsize) kconvmailpart->length);
		kconvbase64 = g_list_append (kconvbase64, base64str);
	}

	return kconvbase64;
}

Kolab_conv_mail*
kolab_util_kconv_kconvmail_data_base64_decode (GList *kconvbase64)
{
	Kolab_conv_mail *kconvmail = NULL;
	GList *kconvbase64_ptr = NULL;
	guint kconvbase64_len = 0;
	guint ii = 0;

	kconvbase64_len = g_list_length (kconvbase64);

	if (kconvbase64_len == 0)
		return NULL;

	/* create new Kolab_conv_mail structure */
	kconvmail = g_new0 (Kolab_conv_mail, 1);
	kconvmail->length = kconvbase64_len;
	kconvmail->mail_parts = g_new0 (Kolab_conv_mail_part, kconvbase64_len);

	kconvbase64_ptr = kconvbase64;
	for (ii = 0; ii < kconvmail->length; ii++) {
		Kolab_conv_mail_part *kconvmailpart = NULL;
		gchar *base64_data = NULL;
		guchar *part_data = NULL;
		gsize part_len = 0;

		kconvmailpart = &(kconvmail->mail_parts[ii]);
		base64_data = kconvbase64_ptr->data;

		g_assert (kconvmailpart != NULL);
		g_assert (base64_data != NULL);

		/* the following values need to be set later on,
		 * they are stored in InfoDb with each attachment
		 * part (including the Kolab XML part)
		 */
		kconvmailpart->name = NULL;
		kconvmailpart->mime_type = NULL;

		/* decode and set */
		part_data = g_base64_decode (base64_data, &part_len);

		g_assert (part_data != NULL);
		g_assert (part_len > 0);

		kconvmailpart->data = (gchar *) part_data;
		kconvmailpart->length = (guint) part_len;

		kconvbase64_ptr = g_list_next (kconvbase64_ptr);
	}

	return kconvmail;
}

gchar*
kolab_util_kconv_kconvmail_checksum (const Kolab_conv_mail *kconvmail)
{
	GChecksum *checksum = NULL;
	gchar *checksum_str = NULL;
	guint ii = 0;

	/* we need to do checksumming over all members of the
	 * Kolab_conv_mail_parts, which includes the part
	 * name and mimetype (we do need to catch changes in
	 * these parts since it also means "changed data set,
	 * even if the actual payload data did not change)
	 */

	g_assert (kconvmail != NULL);
	g_assert (kconvmail->length > 0);
	g_assert (kconvmail->mail_parts != NULL);

	/* We can use the simplest checksumming algorithm available
	 * here, since we do not need the checksum for crypto purposes
	 * but just for telling whether or not a data blob has changed
	 */

	checksum = g_checksum_new (G_CHECKSUM_SHA1);

	for (ii = 0; ii < kconvmail->length; ii++) {
		Kolab_conv_mail_part *kconvmailpart = NULL;

		kconvmailpart = &(kconvmail->mail_parts[ii]);

		/* mime part (file)name */
		g_checksum_update (checksum,
		                   (const guchar *) kconvmailpart->name,
		                   (gssize) strlen (kconvmailpart->name));
		/* mime part type */
		g_checksum_update (checksum,
		                   (const guchar *) kconvmailpart->mime_type,
		                   (gssize) strlen (kconvmailpart->mime_type));
		/*mime part payload data */
		g_checksum_update (checksum,
		                   (const guchar *) kconvmailpart->data,
		                   (gssize) kconvmailpart->length);
	}

	checksum_str = g_strdup (g_checksum_get_string (checksum));

	g_checksum_free (checksum);

	return checksum_str;
}

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