/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/***************************************************************************
 *            test-kolab-mail-access.c
 *
 *  Mon Jan 10 15:06:45 2011
 *  Copyright  2010  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
 */

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

#define _GNU_SOURCE
#include <string.h>

#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <glib.h>
#include <stdlib.h>

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

#include <libekolab/kolab-settings-handler.h>
#include <libekolab/kolab-mail-handle.h>
#include <libekolab/kolab-mail-access.h>
#include <libekolab/kolab-util-backend.h>
#include <libekolab/kolab-types.h>

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

#define TESTCASE "test-kolab-mail-access"
#define AUTH "auth"
#define SECURITY "security"

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

static gboolean
kolab_itest_koma_ksettings_envset (KolabSettingsHandler *ksettings,
                                   GError **err)
{
	GKeyFile *key_file = NULL;
	gchar *config = NULL;
	gboolean ok = FALSE;
	GError *tmp_err = NULL;

	gchar *servername = NULL;
	gint   imapport = -1;
	gchar *username = NULL;
	gchar *userpass = NULL;
	gchar *pkcs11pin = NULL;
	gint   tls_variant = -1;

	g_assert (KOLAB_IS_SETTINGS_HANDLER (ksettings));
	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);

	key_file = g_key_file_new ();

	config = g_strdup (TESTCASE ".conf");
	g_return_val_if_fail (g_key_file_load_from_file (key_file, config, G_KEY_FILE_NONE, NULL), FALSE);
	g_free (config);

	servername = g_key_file_get_string (key_file, TESTCASE, "servername", NULL);
	imapport = g_key_file_get_integer (key_file, TESTCASE, "imapport", NULL);
	username = g_key_file_get_string (key_file, AUTH, "username", NULL);
	userpass = g_key_file_get_string (key_file, AUTH, "password", NULL);
	pkcs11pin = g_key_file_get_string (key_file, SECURITY, "pkcs11pin", NULL);
	tls_variant = g_key_file_get_integer (key_file, SECURITY, "tls_variant", NULL);

	g_key_file_free (key_file);

	g_assert (servername != NULL);
	g_assert (imapport > 0);
	g_assert (username != NULL);
	g_assert (userpass != NULL);
	g_assert (pkcs11pin != NULL);
	g_assert ((tls_variant >= KOLAB_TLS_VARIANT_NONE) &&
	          (tls_variant <  KOLAB_TLS_LAST_VARIANT));

	ok = kolab_settings_handler_set_char_field (ksettings,
	                                            KOLAB_SETTINGS_HANDLER_CHAR_FIELD_KOLAB_SERVER_NAME,
	                                            servername,
	                                            &tmp_err);
	if (! ok) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	ok = kolab_settings_handler_set_int_field (ksettings,
	                                           KOLAB_SETTINGS_HANDLER_INT_FIELD_KOLAB_SERVER_IMAP_PORT,
	                                           imapport,
	                                           &tmp_err);
	if (! ok) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	ok = kolab_settings_handler_set_char_field (ksettings,
	                                            KOLAB_SETTINGS_HANDLER_CHAR_FIELD_KOLAB_USER_NAME,
	                                            username,
	                                            &tmp_err);
	if (! ok) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	ok = kolab_settings_handler_set_char_field (ksettings,
	                                            KOLAB_SETTINGS_HANDLER_CHAR_FIELD_KOLAB_USER_PASSWORD,
	                                            userpass,
	                                            &tmp_err);
	if (! ok) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	ok = kolab_settings_handler_set_char_field (ksettings,
	                                            KOLAB_SETTINGS_HANDLER_CHAR_FIELD_PKCS11_USER_PIN,
	                                            pkcs11pin,
	                                            &tmp_err);
	if (! ok) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	ok = kolab_settings_handler_set_uint_field (ksettings,
	                                            KOLAB_SETTINGS_HANDLER_UINT_FIELD_TLS_VARIANT,
	                                            (guint)tls_variant,
	                                            &tmp_err);
	if (! ok) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	return TRUE;
}

static gboolean
test_kolab_mail_access_retrieve_store (KolabMailAccess *kmailaccess,
                                       KolabFolderContextID context,
                                       GError **err)
{
	GList *sources_lst = NULL;
	GList *sources_lst_ptr = NULL;
	GError *tmp_err = NULL;

	sources_lst = kolab_mail_access_query_sources (kmailaccess,
	                                               &tmp_err);
	if (tmp_err != NULL) {
		g_propagate_error (err, tmp_err);
		return FALSE;
	}

	sources_lst_ptr = sources_lst;
	while (sources_lst_ptr != NULL) {
		GList *uids_lst = NULL;
		GList *uids_lst_ptr = NULL;
		gchar *sourcename = (gchar*) sources_lst_ptr->data;

		uids_lst = kolab_mail_access_query_uids (kmailaccess,
		                                         sourcename,
		                                         NULL,
		                                         &tmp_err);
		if (tmp_err != NULL) {
			g_propagate_error (err, tmp_err);
			return FALSE;
		}

		uids_lst_ptr = uids_lst;
		while (uids_lst_ptr != NULL) {
			const KolabMailHandle *kmh = NULL;
			ECalComponent *ecalcomp = NULL;
			ECalComponent *timezone = NULL;
			EContact *econtact = NULL;
			KolabMailHandle *kmh_s = NULL;
			gchar *uid = (gchar *) uids_lst_ptr->data;
			gboolean r_ok = TRUE;
			gboolean s_ok = TRUE;

			kmh = kolab_mail_access_get_handle (kmailaccess,
			                                    uid,
			                                    sourcename,
			                                    NULL,
			                                    &tmp_err);
			if (tmp_err != NULL) {
				g_warning ("%s: %s",
				           __func__, tmp_err->message);
				g_error_free (tmp_err);
				tmp_err = NULL;
				goto skip;
			}

			r_ok = kolab_mail_access_retrieve_handle (kmailaccess,
			                                          kmh,
			                                          TRUE, /* bulk operation */
			                                          NULL,
			                                          &tmp_err);
			if (! r_ok) {
				g_warning ("%s: %s",
				           __func__, tmp_err->message);
				g_error_free (tmp_err);
				tmp_err = NULL;
				goto skip;
			}

			switch (context) {
			case KOLAB_FOLDER_CONTEXT_CALENDAR:
				ecalcomp = kolab_mail_handle_get_ecalcomponent (kmh);
				timezone = kolab_mail_handle_get_timezone (kmh);
				kmh_s = kolab_mail_handle_new_from_ecalcomponent (ecalcomp,
				                                                  timezone);
				g_object_unref (ecalcomp);
				if (timezone != NULL)
					g_object_unref (timezone);
				break;
			case KOLAB_FOLDER_CONTEXT_CONTACT:
				econtact = kolab_mail_handle_get_econtact (kmh);
				kmh_s = kolab_mail_handle_new_from_econtact (econtact);
				g_object_unref (econtact);
				break;
			default:
				g_assert_not_reached();
			}

			s_ok = kolab_mail_access_store_handle (kmailaccess,
			                                       kmh_s,
			                                       sourcename,
			                                       NULL,
			                                       &tmp_err);
			if (! s_ok) {
				g_warning ("%s: %s",
				           __func__, tmp_err->message);
				g_error_free (tmp_err);
				tmp_err = NULL;
			}

		skip:
			uids_lst_ptr = g_list_next (uids_lst_ptr);
		}

		kolab_util_glib_glist_free (uids_lst);
		sources_lst_ptr = g_list_next (sources_lst_ptr);
	}

	kolab_util_glib_glist_free (sources_lst);
	return TRUE;
}

static gboolean
test_kolab_mail_access (KolabFolderContextID context)
{
	KolabMailAccess *kmailaccess = NULL;
	KolabSettingsHandler *ksettings = NULL;
	gboolean ok = FALSE;
	gboolean rval = TRUE;
	GError *tmp_err = NULL;

	/* init camel */
	ok = kolab_util_camel_init (&tmp_err);
	if (! ok)
		goto test_part_cleanup;

	/* create settings handler object */
	ksettings = KOLAB_SETTINGS_HANDLER (g_object_new (KOLAB_TYPE_SETTINGS_HANDLER, NULL));

	/* configure settings */
	ok = kolab_settings_handler_configure (ksettings,
	                                       context,
	                                       &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	ok = kolab_settings_handler_bringup (ksettings, &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	ok = kolab_itest_koma_ksettings_envset (ksettings, &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	/* create mail access subsystem object */
	kmailaccess = KOLAB_MAIL_ACCESS (g_object_new (KOLAB_TYPE_MAIL_ACCESS, NULL));

	/* configure mail access subsystem */
	ok = kolab_mail_access_configure (kmailaccess, ksettings, &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	/* test operational mode switching configured->offline */
	ok = kolab_mail_access_bringup (kmailaccess,
	                                NULL,
	                                &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	/* test operational mode switching offline->online */
	ok = kolab_mail_access_set_opmode (kmailaccess,
	                                   KOLAB_MAIL_ACCESS_OPMODE_ONLINE,
	                                   NULL,
	                                   &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	/* access folders according to context (retrieve/store of PIM objects) */
	ok = test_kolab_mail_access_retrieve_store (kmailaccess,
	                                            context,
	                                            &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	/* test operational mode switching online->offline */
	ok = kolab_mail_access_set_opmode (kmailaccess,
	                                   KOLAB_MAIL_ACCESS_OPMODE_OFFLINE,
	                                   NULL,
	                                   &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	/* shutdown subsystems */
	ok = kolab_mail_access_shutdown (kmailaccess,
	                                 NULL,
	                                 &tmp_err);
	if (! ok)
		goto test_part_cleanup;

	ok = kolab_settings_handler_shutdown (ksettings, &tmp_err);

 test_part_cleanup:

	if (kmailaccess != NULL)
		g_object_unref (kmailaccess);
	if (ksettings != NULL)
		g_object_unref (ksettings);

	if (tmp_err != NULL) {
		g_warning ("%s: %s", __func__, tmp_err->message);
		g_error_free (tmp_err);
		tmp_err = NULL;
		rval = FALSE;
	}

	/* shut down camel */
	ok = kolab_util_camel_shutdown (&tmp_err);
	if (! ok) {
		g_warning ("%s: %s", __func__, tmp_err->message);
		g_error_free (tmp_err);
		rval = FALSE;
	}

	return rval;
}

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

gint
main (gint argc, gchar **argv)
{
	gboolean ok = FALSE;
	pid_t pid = 0;
	int status = 0;
	int chldexit = 0;

	(void)argc;
	(void)argv;

	/* init glib */
	kolab_util_glib_init ();

	pid = fork();
	if (pid == -1) {
		g_warning ("%s: could not fork()", __func__);
		return EXIT_FAILURE;
	}

	if (pid == 0) {
		ok = test_kolab_mail_access (KOLAB_FOLDER_CONTEXT_CALENDAR);
	} else {
		waitpid (pid, &status, 0); /* wait for child (serialize testcase) */
		if (WIFEXITED (status)) {
			chldexit = WEXITSTATUS (status);
			if (chldexit != EXIT_SUCCESS) {
				g_warning ("%s: child process exited unsuccessfully (code %i)",
				           __func__, chldexit);
				return EXIT_FAILURE;
			}
		}
		ok = test_kolab_mail_access (KOLAB_FOLDER_CONTEXT_CONTACT);
	}

	if (! ok) {
		g_debug ("%s: KolabMailAccess test FAILURE", __func__);
		return EXIT_FAILURE;
	}

	g_debug ("%s: KolabMailAccess test SUCCESS", __func__);

	/* shut down glib */
	kolab_util_glib_shutdown ();

	return EXIT_SUCCESS;
}

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