/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* mail-local.c: Local mailbox support. */

/* 
 * Authors: 
 *  Michael Zucchi <NotZed@helixcode.com>
 *  Peter Williams <peterw@helixcode.com>
 *  Ettore Perazzoli <ettore@helixcode.com>
 *  Dan Winship <danw@helixcode.com>
 *
 * Copyright 2000 Helix Code, Inc. (http://www.helixcode.com)
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <bonobo.h>
#include <libgnomeui/gnome-dialog.h>
#include <glade/glade.h>
#include <gnome-xml/xmlmemory.h>

#include "Evolution.h"
#include "evolution-storage.h"
#include "evolution-shell-component.h"
#include "evolution-storage-listener.h"

#include "camel/camel.h"

#include "filter/vfolder-context.h"
#include "filter/vfolder-rule.h"
#include "filter/vfolder-editor.h"

#include "mail.h"
#include "mail-local.h"
#include "mail-tools.h"
#include "mail-threads.h"
#include "folder-browser.h"

#define d(x)


/* Local folder metainfo */

struct _local_meta {
	char *path;		/* path of metainfo file */

	char *format;		/* format of mailbox */
	char *name;		/* name of mbox itself */
	int indexed;		/* do we index the body? */
};

static struct _local_meta *
load_metainfo(const char *path)
{
	xmlDocPtr doc;
	xmlNodePtr node;
	struct _local_meta *meta;

	meta = g_malloc0(sizeof(*meta));
	meta->path = g_strdup(path);

	d(printf("Loading folder metainfo from : %s\n", meta->path));

	doc = xmlParseFile(meta->path);
	if (doc == NULL) {
		goto dodefault;
	}
	node = doc->root;
	if (strcmp(node->name, "folderinfo")) {
		goto dodefault;
	}
	node = node->childs;
	while (node) {
		if (!strcmp(node->name, "folder")) {
			char *index;
			meta->format = xmlGetProp(node, "type");
			meta->name = xmlGetProp(node, "name");
			index = xmlGetProp(node, "index");
			if (index) {
				meta->indexed = atoi(index);
				xmlFree(index);
			} else
				meta->indexed = TRUE;
			
		}
		node = node->next;
	}
	xmlFreeDoc(doc);
	return meta;

dodefault:
	meta->format = g_strdup("mbox"); /* defaults */
	meta->name = g_strdup("mbox");
	meta->indexed = TRUE;
	if (doc)
		xmlFreeDoc(doc);
	return meta;
}

static void
free_metainfo(struct _local_meta *meta)
{
	g_free(meta->path);
	g_free(meta->format);
	g_free(meta->name);
	g_free(meta);
}

static int
save_metainfo(struct _local_meta *meta)
{
	xmlDocPtr doc;
	xmlNodePtr root, node;
	int ret;

	d(printf("Saving folder metainfo to : %s\n", meta->path));

	doc = xmlNewDoc("1.0");
	root = xmlNewDocNode(doc, NULL, "folderinfo", NULL);
	xmlDocSetRootElement(doc, root);

	node  = xmlNewChild(root, NULL, "folder", NULL);
	xmlSetProp(node, "type", meta->format);
	xmlSetProp(node, "name", meta->name);
	xmlSetProp(node, "index", meta->indexed?"1":"0");

	ret = xmlSaveFile(meta->path, doc);
	xmlFreeDoc(doc);
	return ret;
}


/* Local folder reconfiguration stuff */

/*
   open new
   copy old->new
   close old
   rename old oldsave
   rename new old
   open oldsave
   delete oldsave

   close old
   rename oldtmp
   open new
   open oldtmp
   copy oldtmp new
   close oldtmp
   close oldnew

*/

static void update_progress(char *fmt, float percent)
{
	if (fmt)
		mail_op_set_message ("%s", fmt);
	/*mail_op_set_percentage (percent);*/
}

/* ******************** */

typedef struct reconfigure_folder_input_s {
	FolderBrowser *fb;
	gchar *newtype;
	GtkWidget *frame;
	GtkWidget *apply;
	GtkWidget *cancel;
	GtkOptionMenu *optionlist;
} reconfigure_folder_input_t;

static gchar *
describe_reconfigure_folder (gpointer in_data, gboolean gerund)
{
	reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data;

	if (gerund)
		return g_strdup_printf (_("Changing folder \"%s\" to \"%s\" format"),
					input->fb->uri,
					input->newtype);
	else
		return g_strdup_printf (_("Change folder \"%s\" to \"%s\" format"),
					input->fb->uri,
					input->newtype);
}

static void
setup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex)
{
	reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data;

	if (!IS_FOLDER_BROWSER (input->fb)) {
		camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM,
				     "Input has a bad FolderBrowser in reconfigure_folder");
		return;
	}

	if (!input->newtype) {
		camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM,
				     "No new folder type in reconfigure_folder");
		return;
	}

	gtk_object_ref (GTK_OBJECT (input->fb));
}

static void
do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex)
{
	reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data;

	CamelStore *fromstore = NULL, *tostore = NULL;
	char *fromurl = NULL, *tourl = NULL;
	CamelFolder *fromfolder = NULL, *tofolder = NULL;

	char *metapath;
	char *tmpname;
	char *uri;
	CamelURL *url = NULL;
	struct _local_meta *meta;
	guint32 flags;

	d(printf("reconfiguring folder: %s to type %s\n", input->fb->uri, input->newtype));

	/* get the actual location of the mailbox */
	url = camel_url_new(input->fb->uri, ex);
	if (camel_exception_is_set(ex)) {
		g_warning("%s is not a workable url!", input->fb->uri);
		goto cleanup;
	}

	metapath = g_strdup_printf("%s/local-metadata.xml", url->path);
	meta = load_metainfo(metapath);
	g_free(metapath);

	/* first, 'close' the old folder */
	if (input->fb->folder != NULL) {
		update_progress(_("Closing current folder"), 0.0);

		mail_tool_camel_lock_up ();
		camel_folder_sync(input->fb->folder, FALSE, ex);
		mail_tool_camel_lock_down ();
		camel_object_unref (CAMEL_OBJECT (input->fb->folder));
		input->fb->folder = NULL;
	}

	camel_url_set_protocol (url, meta->format);
	fromurl = camel_url_to_string (url, FALSE);
	camel_url_set_protocol (url, input->newtype);
	tourl = camel_url_to_string (url, FALSE);

	d(printf("opening stores %s and %s\n", fromurl, tourl));

	mail_tool_camel_lock_up ();
	fromstore = camel_session_get_store(session, fromurl, ex);
	mail_tool_camel_lock_down ();

	if (camel_exception_is_set(ex))
		goto cleanup;

	mail_tool_camel_lock_up ();
	tostore = camel_session_get_store(session, tourl, ex);
	mail_tool_camel_lock_down ();
	if (camel_exception_is_set(ex))
		goto cleanup;

	/* rename the old mbox and open it again, without indexing */
	tmpname = g_strdup_printf("%s_reconfig", meta->name);
	d(printf("renaming %s to %s, and opening it\n", meta->name, tmpname));
	update_progress(_("Renaming old folder and opening"), 0.0);

	mail_tool_camel_lock_up ();
	camel_store_rename_folder(fromstore, meta->name, tmpname, ex);
	if (camel_exception_is_set(ex)) {
		mail_tool_camel_lock_down ();
		goto cleanup;
	}
	
	/* we dont need to set the create flag ... or need an index if it has one */
	fromfolder = camel_store_get_folder(fromstore, tmpname, 0, ex);
	if (fromfolder == NULL || camel_exception_is_set(ex)) {
		/* try and recover ... */
		camel_exception_clear (ex);
		camel_store_rename_folder(fromstore, tmpname, meta->name, ex);
		mail_tool_camel_lock_down ();
		goto cleanup;
	}

	/* create a new mbox */
	d(printf("Creating the destination mbox\n"));
	update_progress(_("Creating new folder"), 0.0);

	flags = CAMEL_STORE_FOLDER_CREATE;
	if (meta->indexed)
		flags |= CAMEL_STORE_FOLDER_BODY_INDEX;
	tofolder = camel_store_get_folder(tostore, meta->name, flags, ex);
	if (tofolder == NULL || camel_exception_is_set(ex)) {
		d(printf("cannot open destination folder\n"));
		/* try and recover ... */
		camel_exception_clear (ex);
		camel_store_rename_folder(fromstore, tmpname, meta->name, ex);
		mail_tool_camel_lock_down ();
		goto cleanup;
	}

	update_progress(_("Copying messages"), 0.0);
	mail_tool_move_folder_contents (fromfolder, tofolder, FALSE, ex);

	d(printf("delete old mbox ...\n"));
	camel_store_delete_folder(fromstore, tmpname, ex);
	mail_tool_camel_lock_down ();

	/* switch format */
	g_free(meta->format);
	meta->format = g_strdup(input->newtype);
	if (save_metainfo(meta) == -1) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
				      _("Cannot save folder metainfo; "
					"you'll probably find you can't\n"
					"open this folder anymore: %s"),
				      tourl);
	}
	free_metainfo(meta);

	/* force a reload of the newly formatted folder */
	d(printf("opening new source\n"));
	uri = g_strdup(input->fb->uri);
	folder_browser_set_uri(input->fb, uri);
	g_free(uri);

	/* and unref our copy of the new folder ... */
 cleanup:
	if (tofolder)
		camel_object_unref (CAMEL_OBJECT (tofolder));
	if (fromfolder)
		camel_object_unref (CAMEL_OBJECT (fromfolder));
	if (fromstore)
		camel_object_unref (CAMEL_OBJECT (fromstore));
	if (tostore)
		camel_object_unref (CAMEL_OBJECT (tostore));
	g_free(fromurl);
	g_free(tourl);
	if (url)
		camel_url_free (url);
}

static void
cleanup_reconfigure_folder  (gpointer in_data, gpointer op_data, CamelException *ex)
{
	reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data;

	if (camel_exception_is_set(ex)) {
		GtkWidget *win = gtk_widget_get_ancestor((GtkWidget *)input->frame, GTK_TYPE_WINDOW);
		gnome_error_dialog_parented (_("If you can no longer open this mailbox, then\n"
					       "you may need to repair it manually."), GTK_WINDOW (win));
	}

	gtk_object_unref (GTK_OBJECT (input->fb));
	g_free (input->newtype);
}

static const mail_operation_spec op_reconfigure_folder =
{
	describe_reconfigure_folder,
	0,
	setup_reconfigure_folder,
	do_reconfigure_folder,
	cleanup_reconfigure_folder
};

static void
reconfigure_clicked(GnomeDialog *d, int button, reconfigure_folder_input_t *data)
{
	if (button == 0) {
		GtkMenu *menu;
		int type;
		char *types[] = { "mh", "mbox" };

		menu = (GtkMenu *)gtk_option_menu_get_menu(data->optionlist);
		type = g_list_index(GTK_MENU_SHELL(menu)->children, gtk_menu_get_active(menu));
		if (type < 0 || type > 1)
			type = 1;

		gtk_widget_set_sensitive(data->frame, FALSE);
		gtk_widget_set_sensitive(data->apply, FALSE);
		gtk_widget_set_sensitive(data->cancel, FALSE);

		data->newtype = g_strdup (types[type]);
		mail_operation_queue (&op_reconfigure_folder, data, TRUE);
	}

	if (button != -1)
		gnome_dialog_close(d);
}

void
local_reconfigure_folder(FolderBrowser *fb)
{
	CamelStore *store;
	GladeXML *gui;
	GnomeDialog *gd;
	reconfigure_folder_input_t *data;

	if (fb->folder == NULL) {
		g_warning("Trying to reconfigure nonexistant folder");
		return;
	}

	data = g_new (reconfigure_folder_input_t, 1);

	store = camel_folder_get_parent_store(fb->folder);

	gui = glade_xml_new(EVOLUTION_GLADEDIR "/local-config.glade", "dialog_format");
	gd = (GnomeDialog *)glade_xml_get_widget (gui, "dialog_format");

	data->frame = glade_xml_get_widget (gui, "frame_format");
	data->apply = glade_xml_get_widget (gui, "apply_format");
	data->cancel = glade_xml_get_widget (gui, "cancel_format");
	data->optionlist = (GtkOptionMenu *)glade_xml_get_widget (gui, "option_format");
	data->newtype = NULL;
	data->fb = fb;

	gtk_label_set_text((GtkLabel *)glade_xml_get_widget (gui, "label_format"),
			   ((CamelService *)store)->url->protocol);

	gtk_signal_connect((GtkObject *)gd, "clicked", reconfigure_clicked, data);
	gtk_object_unref((GtkObject *)gui);

	gnome_dialog_run_and_close (GNOME_DIALOG (gd));
}



/* MailLocalStore implementation */

#define MAIL_LOCAL_STORE_TYPE     (mail_local_store_get_type ())
#define MAIL_LOCAL_STORE(obj)     (CAMEL_CHECK_CAST((obj), MAIL_LOCAL_STORE_TYPE, MailLocalStore))
#define MAIL_LOCAL_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_LOCAL_STORE_TYPE, MailLocalStoreClass))
#define MAIL_IS_LOCAL_STORE(o)    (CAMEL_CHECK_TYPE((o), MAIL_LOCAL_STORE_TYPE))

typedef struct {
	CamelStore parent_object;	

	GNOME_Evolution_LocalStorage corba_local_storage;
	EvolutionStorageListener *local_storage_listener;

	char *local_path;
	int local_pathlen;
	GHashTable *folders, *unread;
} MailLocalStore;

typedef struct {
	CamelStoreClass parent_class;
} MailLocalStoreClass;

typedef struct {
	CamelFolder *folder;
	MailLocalStore *local_store;
	char *path, *name;
	int last_unread;
} MailLocalFolder;

CamelType mail_local_store_get_type (void);

static char *get_name (CamelService *service, gboolean brief);
static CamelFolder *get_folder (CamelStore *store, const char *folder_name,
				guint32 flags, CamelException *ex);
static void delete_folder (CamelStore *store, const char *folder_name,
			   CamelException *ex);
static void rename_folder (CamelStore *store, const char *old_name,
			   const char *new_name, CamelException *ex);
static char *get_folder_name (CamelStore *store, const char *folder_name,
			      CamelException *ex);

static void
mail_local_store_class_init (MailLocalStoreClass *mail_local_store_class)
{
	CamelStoreClass *camel_store_class =
		CAMEL_STORE_CLASS (mail_local_store_class);
	CamelServiceClass *camel_service_class =
		CAMEL_SERVICE_CLASS (mail_local_store_class);

	/* virtual method overload */
	camel_service_class->get_name = get_name;

	camel_store_class->get_folder = get_folder;
	camel_store_class->delete_folder = delete_folder;
	camel_store_class->rename_folder = rename_folder;
	camel_store_class->get_folder_name = get_folder_name;
}

static void
mail_local_store_init (gpointer object, gpointer klass)
{
	MailLocalStore *local_store = MAIL_LOCAL_STORE (object);

	local_store->corba_local_storage = CORBA_OBJECT_NIL;
}

static void
free_folder (gpointer key, gpointer data, gpointer user_data)
{
	MailLocalFolder *lf = data;

	g_free (key);
	camel_object_unref (CAMEL_OBJECT (lf->folder));
	g_free (lf->path);
}

static void
mail_local_store_finalize (gpointer object)
{
	MailLocalStore *local_store = MAIL_LOCAL_STORE (object);
	CORBA_Environment ev;

	CORBA_exception_init (&ev);
	if (!CORBA_Object_is_nil (local_store->corba_local_storage, &ev)) {
		Bonobo_Unknown_unref (local_store->corba_local_storage, &ev);
		CORBA_Object_release (local_store->corba_local_storage, &ev);
	}
	CORBA_exception_free (&ev);

	if (local_store->local_storage_listener)
		gtk_object_unref (GTK_OBJECT (local_store->local_storage_listener));

	g_hash_table_foreach (local_store->folders, free_folder, NULL);
	g_hash_table_destroy (local_store->folders);

	g_free (local_store->local_path);
}

CamelType
mail_local_store_get_type (void)
{
	static CamelType mail_local_store_type = CAMEL_INVALID_TYPE;

	if (mail_local_store_type == CAMEL_INVALID_TYPE) {
		mail_local_store_type = camel_type_register (
			CAMEL_STORE_TYPE, "MailLocalStore",
			sizeof (MailLocalStore),
			sizeof (MailLocalStoreClass),
			(CamelObjectClassInitFunc) mail_local_store_class_init,
			NULL,
			(CamelObjectInitFunc) mail_local_store_init,
			(CamelObjectFinalizeFunc) mail_local_store_finalize);
	}

	return mail_local_store_type;
}

static CamelFolder *
get_folder (CamelStore *store, const char *folder_name,
	    guint32 flags, CamelException *ex)
{
	MailLocalStore *local_store = (MailLocalStore *)store;
	CamelFolder *folder;

	folder = g_hash_table_lookup (local_store->folders, folder_name);
	if (folder)
		camel_object_ref (CAMEL_OBJECT (folder));
	else {
		camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
				      "No such folder %s", folder_name);
	}
	return folder;
}

static void
delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
{
	/* No-op. The shell local storage deals with this. */
}

static void
rename_folder (CamelStore *store, const char *old, const char *new,
	       CamelException *ex)
{
	/* Probable no-op... */
}

static char *
get_folder_name (CamelStore *store, const char *folder_name,
		 CamelException *ex)
{
	return g_strdup (folder_name);
}

static char *
get_name (CamelService *service, gboolean brief)
{
	return g_strdup ("Local mail folders");
}


/* Callbacks for the EvolutionStorageListner signals.  */

static void
local_storage_destroyed_cb (EvolutionStorageListener *storage_listener,
			    void *data)
{
	/* FIXME: Dunno how to handle this yet.  */
	g_warning ("%s -- The LocalStorage has gone?!", __FILE__);
}


static void
local_folder_changed (CamelObject *object, gpointer event_data,
		      gpointer user_data)
{
	MailLocalFolder *local_folder = user_data;
	int unread = GPOINTER_TO_INT (event_data);
	char *display;

	if (unread != local_folder->last_unread) {
		CORBA_Environment ev;

		CORBA_exception_init (&ev);
		if (unread > 0) {
			display = g_strdup_printf ("%s (%d)",
						   local_folder->name, unread);
			GNOME_Evolution_LocalStorage_updateFolder (
				local_folder->local_store->corba_local_storage,
				local_folder->path, display, TRUE, &ev);
			g_free (display);
		} else {
			GNOME_Evolution_LocalStorage_updateFolder (
				local_folder->local_store->corba_local_storage,
				local_folder->path, local_folder->name,
				FALSE, &ev);
		}
		CORBA_exception_free (&ev);

		local_folder->last_unread = unread;
	}
}

static void
local_folder_changed_proxy (CamelObject *folder, gpointer event_data,
			    gpointer user_data)
{
	int unread;

	unread = camel_folder_get_unread_message_count (CAMEL_FOLDER (folder));
	mail_op_forward_event (local_folder_changed, folder,
			       GINT_TO_POINTER (unread), user_data);
}

static char *
describe_register_folder (gpointer in_data, gboolean gerund)
{
	if (gerund)
		return g_strdup (_("Registering local folder"));
	else
		return g_strdup (_("Register local folder"));
}

static void
do_register_folder (gpointer in_data, gpointer op_data, CamelException *ex)
{
	MailLocalFolder *local_folder = in_data;
	char *name;
	struct _local_meta *meta;
	CamelStore *store;
	guint32 flags;

	name = g_strdup_printf ("/%s/local-metadata.xml", local_folder->name);
	meta = load_metainfo (name);
	g_free (name);

	name = g_strdup_printf ("%s:/%s", meta->format, local_folder->name);
	store = camel_session_get_store (session, name, ex);
	g_free (name);
	if (!store) {
		free_metainfo (meta);
		return;
	}

	flags = CAMEL_STORE_FOLDER_CREATE;
	if (meta->indexed)
		flags |= CAMEL_STORE_FOLDER_BODY_INDEX;
	local_folder->folder = camel_store_get_folder (store, meta->name, flags, ex);
	local_folder->last_unread = camel_folder_get_unread_message_count (
		local_folder->folder);
	camel_object_unref (CAMEL_OBJECT (store));
	free_metainfo (meta);
}

static void
cleanup_register_folder (gpointer in_data, gpointer op_data,
			 CamelException *ex)
{
	MailLocalFolder *local_folder = in_data;
	int unread;

	if (!local_folder->folder) {
		g_free (local_folder);
		return;
	}

	g_hash_table_insert (local_folder->local_store->folders,
			     local_folder->name, local_folder->folder);
	local_folder->name = strrchr (local_folder->path, '/') + 1;

	camel_object_hook_event (CAMEL_OBJECT (local_folder->folder),
				 "folder_changed", local_folder_changed_proxy,
				 local_folder);
	camel_object_hook_event (CAMEL_OBJECT (local_folder->folder),
				 "message_changed", local_folder_changed_proxy,
				 local_folder);
	unread = local_folder->last_unread;
	local_folder->last_unread = 0;
	local_folder_changed (CAMEL_OBJECT (local_folder->folder),
			      GINT_TO_POINTER (unread), local_folder);
}

static const mail_operation_spec op_register_folder =
{
	describe_register_folder,
	0,
	NULL,
	do_register_folder,
	cleanup_register_folder
};

static void
local_storage_new_folder_cb (EvolutionStorageListener *storage_listener,
			     const char *path,
			     const GNOME_Evolution_Folder *folder,
			     void *data)
{
	MailLocalStore *local_store = data;
	MailLocalFolder *local_folder;

	if (strcmp (folder->type, "mail") != 0 ||
	    strncmp (folder->physical_uri, "file://", 7) != 0 ||
	    strncmp (folder->physical_uri + 7, local_store->local_path,
		     local_store->local_pathlen) != 0)
		return;

	local_folder = g_new0 (MailLocalFolder, 1);
	local_folder->name = g_strdup (folder->physical_uri + 8);
	local_folder->path = g_strdup (path);
	local_folder->local_store = local_store;
	mail_operation_queue (&op_register_folder, local_folder, FALSE);
}

static void
local_storage_removed_folder_cb (EvolutionStorageListener *storage_listener,
				 const char *path,
				 void *data)
{
	MailLocalStore *local_store = data;
	CamelFolder *folder;

	if (strncmp (path, "file://", 7) != 0 ||
	    strncmp (path + 7, local_store->local_path,
		     local_store->local_pathlen) != 0)
		return;

	path += 7 + local_store->local_pathlen;

	folder = g_hash_table_lookup (local_store->folders, path);
	if (folder) {
		camel_object_unref (CAMEL_OBJECT (folder));
		g_hash_table_remove (local_store->folders, path);
	}
}

static CamelProvider local_provider = {
	"file", "Local mail", NULL, "mail",
	CAMEL_PROVIDER_IS_STORAGE, CAMEL_URL_NEED_PATH,
	{ 0, 0 }, NULL
};

/* There's only one "file:" store. */
static guint
non_hash (gconstpointer key)
{
	return 0;
}

static gint
non_equal (gconstpointer a, gconstpointer b)
{
	return TRUE;
}

void
mail_local_storage_startup (EvolutionShellClient *shellclient,
			    const char *evolution_path)
{
	MailLocalStore *local_store;
	GNOME_Evolution_StorageListener corba_local_storage_listener;
	CORBA_Environment ev;

	/* Register with Camel to handle file: URLs */
	local_provider.object_types[CAMEL_PROVIDER_STORE] =
		mail_local_store_get_type();

	local_provider.service_cache = g_hash_table_new (non_hash, non_equal);
	camel_session_register_provider (session, &local_provider);


	/* Now build the storage. */
	local_store = (MailLocalStore *)camel_session_get_service (
		session, "file:/", CAMEL_PROVIDER_STORE, NULL);
	if (!local_store) {
		g_warning ("No local store!");
		return;
	}
	local_store->corba_local_storage =
		evolution_shell_client_get_local_storage (shellclient);
	if (local_store->corba_local_storage == CORBA_OBJECT_NIL) {
		g_warning ("No local storage!");
		camel_object_unref (CAMEL_OBJECT (local_store));
		return;
	}

	local_store->local_storage_listener =
		evolution_storage_listener_new ();
	corba_local_storage_listener =
		evolution_storage_listener_corba_objref (
			local_store->local_storage_listener);

	gtk_signal_connect (GTK_OBJECT (local_store->local_storage_listener),
			    "destroyed",
			    GTK_SIGNAL_FUNC (local_storage_destroyed_cb),
			    local_store);
	gtk_signal_connect (GTK_OBJECT (local_store->local_storage_listener),
			    "new_folder",
			    GTK_SIGNAL_FUNC (local_storage_new_folder_cb),
			    local_store);
	gtk_signal_connect (GTK_OBJECT (local_store->local_storage_listener),
			    "removed_folder",
			    GTK_SIGNAL_FUNC (local_storage_removed_folder_cb),
			    local_store);

	local_store->local_path = g_strdup_printf ("%s/local",
						   evolution_path);
	local_store->local_pathlen = strlen (local_store->local_path);

	local_store->folders = g_hash_table_new (g_str_hash, g_str_equal);

	CORBA_exception_init (&ev);
	GNOME_Evolution_Storage_addListener (local_store->corba_local_storage,
					corba_local_storage_listener, &ev);
	if (ev._major != CORBA_NO_EXCEPTION) {
		g_warning ("Cannot add a listener to the Local Storage.");
		camel_object_unref (CAMEL_OBJECT (local_store));
		CORBA_exception_free (&ev);
		return;
	}
	CORBA_exception_free (&ev);
}