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

/* 
 * Authors: 
 *  Michael Zucchi <NotZed@ximian.com>
 *  Peter Williams <peterw@ximian.com>
 *  Ettore Perazzoli <ettore@ximian.com>
 *  Dan Winship <danw@ximian.com>
 *
 * Copyright 2000 Ximian, Inc. (www.ximian.com)
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of version 2 of the GNU General Public 
 * License as published by the Free Software Foundation.
 *
 * 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 <unistd.h>
#include <errno.h>

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

#include "gal/widgets/e-gui-utils.h"
#include "e-util/e-path.h"
#include "gal/util/e-unicode-i18n.h"

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

#include "camel/camel.h"
#include "camel/camel-vtrash-folder.h"

#include "mail.h"
#include "mail-local.h"
#include "mail-tools.h"
#include "folder-browser.h"
#include "mail-mt.h"
#include "mail-folder-cache.h"
#include "mail-vfolder.h"
#include "mail-ops.h"

#define d(x) 

/* sigh, required for passing around to some functions */
static GNOME_Evolution_Storage local_corba_storage = CORBA_OBJECT_NIL;

/* ** MailLocalStore ** (protos) ************************************************** */

#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;

	/* stores CamelFolderInfo's of the folders we're supposed to know about, by uri */
	GHashTable *folder_infos;
	GMutex *folder_info_lock;

} MailLocalStore;

typedef struct {
	CamelStoreClass parent_class;
} MailLocalStoreClass;

static CamelType mail_local_store_get_type (void);

static MailLocalStore *global_local_store;

/* ** MailLocalFolder ** (protos) ************************************************* */

#define MAIL_LOCAL_FOLDER_TYPE     (mail_local_folder_get_type ())
#define MAIL_LOCAL_FOLDER(obj)     (CAMEL_CHECK_CAST((obj), MAIL_LOCAL_FOLDER_TYPE, MailLocalFolder))
#define MAIL_LOCAL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_LOCAL_FOLDER_TYPE, MailLocalFolderClass))
#define MAIL_IS_LOCAL_FOLDER(o)    (CAMEL_CHECK_TYPE((o), MAIL_LOCAL_FOLDER_TYPE))

#define LOCAL_STORE_LOCK(folder)   (g_mutex_lock   (((MailLocalStore *)folder)->folder_info_lock))
#define LOCAL_STORE_UNLOCK(folder) (g_mutex_unlock (((MailLocalStore *)folder)->folder_info_lock))

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

	char *format;		/* format of mailbox */
	char *name;		/* name of actual mbox */
	int indexed;		/* is body indexed? */
};

typedef struct {
	CamelFolder parent_object;

	CamelFolder *real_folder;
	CamelStore *real_store;

	char *real_path;

	struct _local_meta *meta;

	GMutex *real_folder_lock; /* no way to use the CamelFolder's lock, so... */
} MailLocalFolder;

typedef struct {
	CamelFolderClass parent_class;
} MailLocalFolderClass;

static CamelType mail_local_folder_get_type (void);

#ifdef ENABLE_THREADS
#define LOCAL_FOLDER_LOCK(folder)   (g_mutex_lock   (((MailLocalFolder *)folder)->real_folder_lock))
#define LOCAL_FOLDER_UNLOCK(folder) (g_mutex_unlock (((MailLocalFolder *)folder)->real_folder_lock))
#else
#define LOCAL_FOLDER_LOCK(folder)
#define LOCAL_FOLDER_UNLOCK(folder)
#endif

/* ** MailLocalFolder ************************************************************* */

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

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

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

	doc = xmlParseFile(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, *txt;
			
			txt = xmlGetProp(node, "type");
			meta->format = g_strdup(txt?txt:"mbox");
			xmlFree(txt);
			
			txt = xmlGetProp(node, "name");
			meta->name = g_strdup(txt?txt:"mbox");
			xmlFree(txt);
			
			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;
	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 gboolean
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;
}

static CamelFolderClass *mlf_parent_class = NULL;

/* forward a bunch of functions to the real folder. This pretty
 * much sucks but I haven't found a better way of doing it.
 */

/* We need to do it without having locked our folder, otherwise
   we can get sync hangs with vfolders/trash */
static void
mlf_refresh_info(CamelFolder *folder, CamelException *ex)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_refresh_info(f, ex);
	camel_object_unref((CamelObject *)f);
}

static void
mlf_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_sync(f, expunge, ex);
	camel_object_unref((CamelObject *)f);
}

static void
mlf_expunge(CamelFolder *folder, CamelException *ex)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_expunge(f, ex);
	camel_object_unref((CamelObject *)f);
}

static void
mlf_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, CamelException *ex)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_append_message(f, message, info, ex);
	camel_object_unref((CamelObject *)f);
}

static CamelMimeMessage *
mlf_get_message(CamelFolder *folder, const char *uid, CamelException *ex)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelMimeMessage *ret;
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	ret = camel_folder_get_message(f, uid, ex);
	camel_object_unref((CamelObject *)f);

	return ret;
}

static GPtrArray *
mlf_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (folder);
	GPtrArray *ret;
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	ret = camel_folder_search_by_expression(f, expression, ex);
	camel_object_unref((CamelObject *)f);

	return ret;
}

static GPtrArray *
mlf_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (folder);
	GPtrArray *ret;
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	ret = camel_folder_search_by_uids(f, expression, uids, ex);
	camel_object_unref((CamelObject *)f);

	return ret;
}

static void
mlf_search_free(CamelFolder *folder, GPtrArray *result)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_search_free(f, result);
	camel_object_unref((CamelObject *)f);
}

static void
mlf_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_set_message_flags(mlf->real_folder, uid, flags, set);
	camel_object_unref((CamelObject *)f);
}

static void
mlf_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_set_message_user_flag(mlf->real_folder, uid, name, value);
	camel_object_unref((CamelObject *)f);
}

static void
mlf_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder);
	CamelFolder *f;

	LOCAL_FOLDER_LOCK(mlf);
	f = mlf->real_folder;
	camel_object_ref((CamelObject *)f);
	LOCAL_FOLDER_UNLOCK(mlf);

	camel_folder_set_message_user_tag(mlf->real_folder, uid, name, value);
	camel_object_unref((CamelObject *)f);
}

/* Internal store-rename call, update our strings */
static void
mlf_rename(CamelFolder *folder, const char *new)
{
	MailLocalFolder *mlf = (MailLocalFolder *)folder;

	/* first, proxy it down */
	if (mlf->real_folder) {
		char *mbox = g_strdup_printf("%s/%s", new, mlf->meta->name);

		d(printf("renaming real folder to %s\n", mbox));

		camel_folder_rename(mlf->real_folder, mbox);
		g_free(mbox);
	}

	/* Then do our stuff */
	g_free(mlf->real_path);
	mlf->real_path = g_strdup(new);

	g_free(mlf->meta->path);
	mlf->meta->path = g_strdup_printf("%s/%s/local-metadata.xml", ((CamelService *)folder->parent_store)->url->path, new);

	/* Then pass it up */
	((CamelFolderClass *)mlf_parent_class)->rename(folder, new);
}

/* and, conversely, forward the real folder's signals. */

static void
mlf_proxy_message_changed(CamelObject *real_folder, gpointer event_data, gpointer user_data)
{
	camel_object_trigger_event((CamelObject *)user_data, "message_changed", event_data);
}

static void
mlf_proxy_folder_changed(CamelObject *real_folder, gpointer event_data, gpointer user_data)
{
	camel_object_trigger_event((CamelObject *)user_data, "folder_changed", event_data);
}

static void
mlf_unset_folder (MailLocalFolder *mlf)
{
	CamelFolder *folder = (CamelFolder *)mlf;

	g_assert(mlf->real_folder);

	camel_object_unhook_event(CAMEL_OBJECT(mlf->real_folder),
				  "message_changed",
				  mlf_proxy_message_changed,
				  mlf);
	camel_object_unhook_event(CAMEL_OBJECT(mlf->real_folder),
				  "folder_changed",
				  mlf_proxy_folder_changed,
				  mlf);

	camel_object_unref((CamelObject *)folder->summary);
	folder->summary = NULL;
	camel_object_unref((CamelObject *)mlf->real_folder);
	mlf->real_folder = NULL;
	camel_object_unref((CamelObject *)mlf->real_store);
	mlf->real_store = NULL;

	folder->permanent_flags = 0;
	folder->folder_flags = 0;
}

static gboolean
mlf_set_folder(MailLocalFolder *mlf, guint32 flags, CamelException *ex)
{
	CamelFolder *folder = (CamelFolder *)mlf;
	char *uri, *mbox;

	g_assert(mlf->real_folder == NULL);

	uri = g_strdup_printf("%s:%s", mlf->meta->format, ((CamelService *)folder->parent_store)->url->path);

	d(printf("opening real store: %s\n", uri));
	mlf->real_store = camel_session_get_store(session, uri, ex);
	g_free(uri);
	if (mlf->real_store == NULL)
		return FALSE;

	if (mlf->meta->indexed)
		flags |= CAMEL_STORE_FOLDER_BODY_INDEX;

	/* mlf->real_folder = camel_store_get_folder(mlf->real_store, mlf->meta->name, flags, ex); */
	mbox = g_strdup_printf("%s/%s", mlf->real_path, mlf->meta->name);
	d(printf("Opening mbox on real path: %s\n", mbox));
	mlf->real_folder = camel_store_get_folder(mlf->real_store, mbox, flags, ex);
	g_free(mbox);
	if (mlf->real_folder == NULL)
		return FALSE;

	if (mlf->real_folder->folder_flags & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY) {
		folder->summary = mlf->real_folder->summary;
		camel_object_ref((CamelObject *)mlf->real_folder->summary);
	}

	folder->permanent_flags = mlf->real_folder->permanent_flags;
	folder->folder_flags = mlf->real_folder->folder_flags;

	camel_object_hook_event((CamelObject *)mlf->real_folder, "message_changed", mlf_proxy_message_changed, mlf);
	camel_object_hook_event((CamelObject *)mlf->real_folder, "folder_changed", mlf_proxy_folder_changed, mlf);

	return TRUE;
}

static void 
mlf_class_init (CamelObjectClass *camel_object_class)
{
	CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_object_class);

	/* override all the functions subclassed in providers/local/ */

	camel_folder_class->refresh_info = mlf_refresh_info;
	camel_folder_class->sync = mlf_sync;
	camel_folder_class->expunge = mlf_expunge;
	camel_folder_class->append_message = mlf_append_message;
	camel_folder_class->get_message = mlf_get_message;
	camel_folder_class->search_free = mlf_search_free;

	camel_folder_class->search_by_expression = mlf_search_by_expression;
	camel_folder_class->search_by_uids = mlf_search_by_uids;
	camel_folder_class->set_message_flags = mlf_set_message_flags;
	camel_folder_class->set_message_user_flag = mlf_set_message_user_flag;
	camel_folder_class->set_message_user_tag = mlf_set_message_user_tag;

	camel_folder_class->rename = mlf_rename;
}

static void
mlf_init (CamelObject *obj)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (obj);

#ifdef ENABLE_THREADS
	mlf->real_folder_lock = g_mutex_new();
#endif
}

static void
mlf_finalize (CamelObject *obj)
{
	MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (obj);

	if (mlf->real_folder)
		mlf_unset_folder(mlf);

	free_metainfo(mlf->meta);
	
#ifdef ENABLE_THREADS
	g_mutex_free (mlf->real_folder_lock);
#endif
}

static CamelType
mail_local_folder_get_type (void)
{
	static CamelType mail_local_folder_type = CAMEL_INVALID_TYPE;

	if (mail_local_folder_type == CAMEL_INVALID_TYPE) {
		mail_local_folder_type = camel_type_register(CAMEL_FOLDER_TYPE,
							     "MailLocalFolder",
							     sizeof (MailLocalFolder),
							     sizeof (MailLocalFolderClass),
							     mlf_class_init,
							     NULL,
							     mlf_init,
							     mlf_finalize);
		mlf_parent_class = (CamelFolderClass *)camel_type_get_global_classfuncs (CAMEL_FOLDER_TYPE);
	}

	return mail_local_folder_type;
}

static MailLocalFolder *
mail_local_folder_construct(MailLocalFolder *mlf, MailLocalStore  *parent_store, const char *full_name, CamelException *ex)
{
	const char *name;
	char *metapath;

	name = strrchr(full_name, '/');
	if (name == NULL)
		name = full_name;
	name = name + 1;

	d(printf("constructing local folder: full = %s, name = %s\n", full_name, name));

	camel_folder_construct(CAMEL_FOLDER (mlf), CAMEL_STORE(parent_store), full_name, name);

	mlf->real_path = g_strdup(((CamelFolder *)mlf)->full_name);

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

	return mlf;
}

static gboolean
mail_local_folder_reconfigure (MailLocalFolder *mlf, const char *new_format, int index_body, CamelException *ex)
{
	CamelStore *fromstore = NULL;
	CamelFolder *fromfolder = NULL;
	char *oldformat = NULL;
	char *store_uri;
	GPtrArray *uids;
	int real_folder_frozen = FALSE;
	int format_change, index_changed;
	char *tmpname = NULL;
	char *mbox = NULL;

	format_change = strcmp(mlf->meta->format, new_format) != 0;
	index_changed = mlf->meta->indexed != index_body;

	if (format_change == FALSE && index_changed == FALSE)
		return TRUE;

	camel_operation_start(NULL, _("Reconfiguring folder"));

	/* first things first */
	g_assert (ex);
	LOCAL_FOLDER_LOCK (mlf);

	/* first, 'close' the old folder */
	if (mlf->real_folder) {
		camel_folder_sync(mlf->real_folder, FALSE, ex);
		if (camel_exception_is_set (ex))
			goto cleanup;
		mlf_unset_folder(mlf);
	}

	/* only indexed change, just re-open with new flags */
	if (!format_change) {
		mlf->meta->indexed = index_body;
		mlf_set_folder(mlf, CAMEL_STORE_FOLDER_CREATE, ex);
		save_metainfo(mlf->meta);
		goto cleanup;
	}

	store_uri = g_strdup_printf("%s:%s", mlf->meta->format, ((CamelService *)((CamelFolder *)mlf)->parent_store)->url->path);
	fromstore = camel_session_get_store(session, store_uri, ex);
	g_free(store_uri);
	if (fromstore == NULL)
		goto cleanup;

	oldformat = mlf->meta->format;
	mlf->meta->format = g_strdup(new_format);

	/* rename the old mbox and open it again, without indexing */
	tmpname = g_strdup_printf ("%s/%s_reconfig", mlf->real_path, mlf->meta->name);
	mbox = g_strdup_printf("%s/%s", mlf->real_path, mlf->meta->name);
	d(printf("renaming %s to %s, and opening it\n", mbox, tmpname));
	
	camel_store_rename_folder(fromstore, mbox, tmpname, ex);
	if (camel_exception_is_set(ex))
		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, mbox, ex);
		goto cleanup;
	}
	
	/* create a new mbox */
	d(printf("Creating the destination mbox\n"));

	if (!mlf_set_folder(mlf, CAMEL_STORE_FOLDER_CREATE, ex)) {
		d(printf("cannot open destination folder\n"));
		/* try and recover ... */
		camel_exception_clear(ex);
		camel_store_rename_folder(fromstore, tmpname, mbox, ex);
		goto cleanup;
	}

	real_folder_frozen = TRUE;
	camel_folder_freeze(mlf->real_folder);

	uids = camel_folder_get_uids(fromfolder);
	camel_folder_move_messages_to(fromfolder, uids, mlf->real_folder, ex);
	camel_folder_free_uids(fromfolder, uids);
	if (camel_exception_is_set(ex))
		goto cleanup;
	
	camel_folder_expunge(fromfolder, ex);
	
	d(printf("delete old mbox ...\n"));
	camel_object_unref(CAMEL_OBJECT(fromfolder));
	fromfolder = NULL;
	camel_store_delete_folder(fromstore, tmpname, ex);
	
	/* switch format */
	g_free(oldformat);
	oldformat = NULL;
	if (save_metainfo(mlf->meta) == FALSE) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
				      _("Cannot save folder metainfo; "
					"you'll probably find you can't\n"
					"open this folder anymore: %s: %s"),
				      mlf->meta->path, strerror(errno));
	}
	
 cleanup:
	if (oldformat) {
		g_free(mlf->meta->format);
		mlf->meta->format = oldformat;
	}
	if (mlf->real_folder == NULL)
		mlf_set_folder (mlf, CAMEL_STORE_FOLDER_CREATE, ex);
	if (fromfolder)
		camel_object_unref((CamelObject *)fromfolder);
	if (fromstore)
		camel_object_unref((CamelObject *)fromstore);

	g_free(tmpname);
	g_free(mbox);

	LOCAL_FOLDER_UNLOCK (mlf);

	if (real_folder_frozen)
		camel_folder_thaw(mlf->real_folder);

	camel_operation_end(NULL);

	return !camel_exception_is_set(ex);
}
		
/* ******************************************************************************** */

static CamelObjectClass *local_store_parent_class = NULL;

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

	d(printf("--LOCAL-- get_folder: %s\n", folder_name));

	folder = (MailLocalFolder *)camel_object_new(MAIL_LOCAL_FOLDER_TYPE);
	folder = mail_local_folder_construct(folder, local_store, folder_name, ex);
	if (folder == NULL)
		return NULL;

	if (!mlf_set_folder(folder, flags, ex)) {
		camel_object_unref(CAMEL_OBJECT(folder));
		return NULL;
	}

	if (flags & CAMEL_STORE_FOLDER_CREATE) {
		if (save_metainfo(folder->meta) == -1) {
			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
					      _("Cannot save folder metainfo to %s: %s"),
					      folder->meta->path, strerror(errno));
			camel_object_unref(CAMEL_OBJECT (folder));
			return NULL;
		}
	}

	return (CamelFolder *)folder;
}

static void
mls_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex)
{
	CamelStore *real_store;
	char *metapath, *uri, *mbox;
	CamelException local_ex;
	struct _local_meta *meta;

	d(printf("Deleting folder: %s %s\n", ((CamelService *)store)->url->path, folder_name));

	camel_exception_init(&local_ex);

	/* find the real store for this folder, and proxy the call */
	metapath = g_strdup_printf("%s%s/local-metadata.xml", ((CamelService *)store)->url->path, folder_name);
	meta = load_metainfo(metapath);
	uri = g_strdup_printf("%s:%s", meta->format, ((CamelService *)store)->url->path);
	real_store = (CamelStore *)camel_session_get_service(session, uri, CAMEL_PROVIDER_STORE, ex);
	g_free(uri);
	if (real_store == NULL) {
		g_free(metapath);
		free_metainfo(meta);
		camel_object_unref((CamelObject *)real_store);
		return;
	}

	mbox = g_strdup_printf("%s/%s", folder_name, meta->name);
	camel_store_delete_folder(real_store, mbox, &local_ex);
	g_free(mbox);
	if (camel_exception_is_set(&local_ex)) {
		camel_exception_xfer(ex, &local_ex);
		g_free(metapath);
		free_metainfo(meta);
		camel_object_unref((CamelObject *)real_store);
		return;
	}

	camel_object_unref((CamelObject *)real_store);

	free_metainfo(meta);

	if (unlink(metapath) == -1) {
		camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
				     _("Cannot delete folder metadata %s: %s"),
				     metapath, strerror(errno));
	}

	g_free(metapath);
}

static void
mls_rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex)
{
	CamelStore *real_store;
	/*MailLocalStore *mls = (MailLocalStore *)store;*/
	char *uri;
	/*CamelException local_ex;*/
	struct _local_meta *meta;
	char *oldname, *newname;
	char *oldmeta, *newmeta;
	struct stat st;

	/* folder:rename() updates all our in-memory data to match */

	/* FIXME: Need to lock the subfolder that matches this if its open
	   Then rename it and unlock it when done */

	d(printf("Renaming folder from '%s' to '%s'\n", old_name, new_name));

	oldmeta = g_strdup_printf("%s%s/local-metadata.xml", ((CamelService *)store)->url->path, old_name);
	newmeta = g_strdup_printf("%s%s/local-metadata.xml", ((CamelService *)store)->url->path, new_name);

	meta = load_metainfo(oldmeta);
	uri = g_strdup_printf("%s:%s", meta->format, ((CamelService *)store)->url->path);
	real_store = (CamelStore *)camel_session_get_service(session, uri, CAMEL_PROVIDER_STORE, ex);
	g_free(uri);
	if (real_store == NULL) {
		g_free(newmeta);
		g_free(oldmeta);
		free_metainfo(meta);
		return;
	}

	oldname = g_strdup_printf("%s/%s", old_name, meta->name);
	newname = g_strdup_printf("%s/%s", new_name, meta->name);

	camel_store_rename_folder(real_store, oldname, newname, ex);
	if (!camel_exception_is_set(ex)) {
		/* If this fails?  Well, doesn't really matter but 'fail' anyway */
		if (stat(oldmeta, &st) == 0
		    && rename(oldmeta, newmeta) == -1) {
			camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
					     _("Could not rename folder %s to %s: %s"),
					     old_name, new_name, strerror(errno));
		} else {
			/* So .. .the shell does a remove/add now the rename worked, so we dont
			   have to do this.  However totally broken that idea might be */
#if 0
			CamelFolderInfo *info;
			const char *tmp;
			char *olduri, *newuri;

			olduri = g_strdup_printf("%s:%s%s", ((CamelService *)store)->url->protocol, ((CamelService *)store)->url->path, old_name);
			newuri = g_strdup_printf("%s:%s%s", ((CamelService *)store)->url->protocol, ((CamelService *)store)->url->path, new_name);
			info = g_hash_table_lookup(mls->folder_infos, olduri);
			if (info) {
				CamelRenameInfo reninfo;

				g_free(info->url);
				g_free(info->full_name);
				g_free(info->name);
				g_free(info->path);
				info->url = newuri;
				info->full_name = g_strdup(new_name);
				info->path = g_strdup_printf("/%s", new_name);
				tmp = strchr(new_name, '/');
				if (tmp == NULL)
					tmp = new_name;
				info->name = g_strdup(tmp);
				g_hash_table_insert(mls->folder_infos, info->url, info);

				reninfo.new = info;
				reninfo.old_base = (char *)old_name;
				
				camel_object_trigger_event((CamelObject *)store, "folder_renamed", &reninfo);
			} else {
				g_free(newuri);
				g_warning("Cannot find existing folder '%s' in table?\n", olduri);
			}

			g_free(olduri);
#endif
		}
	}

	g_free(newname);
	g_free(oldname);

	camel_object_unref((CamelObject *)real_store);

	free_metainfo(meta);

	g_free(newmeta);
	g_free(oldmeta);
}

static char *
mls_get_name (CamelService *service, gboolean brief)
{
	if (brief)
		return g_strdup("local");

	return g_strdup("Local mail folders");
}

static void
mls_init (MailLocalStore *mls, MailLocalStoreClass *mlsclass)
{
	mls->folder_infos = g_hash_table_new(g_str_hash, g_str_equal);
	mls->folder_info_lock = g_mutex_new();
}

static void
free_info(void *key, void *value, void *data)
{
	CamelFolderInfo *info = value;

	camel_folder_info_free (info);
}

static void
mls_finalise(MailLocalStore *mls)
{
	g_hash_table_foreach(mls->folder_infos, (GHFunc)free_info, NULL);
	g_hash_table_destroy(mls->folder_infos);
	g_mutex_free(mls->folder_info_lock);
}

static void
mls_class_init (CamelObjectClass *camel_object_class)
{
	CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_object_class);
	CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_object_class);
	
	/* virtual method overload -- the bare minimum */
	camel_service_class->get_name    = mls_get_name;
	camel_store_class->get_folder    = mls_get_folder;
	camel_store_class->delete_folder = mls_delete_folder;
	camel_store_class->rename_folder = mls_rename_folder;

	local_store_parent_class = camel_type_get_global_classfuncs (CAMEL_STORE_TYPE);
}

static 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) mls_class_init,
			NULL,
			(CamelObjectInitFunc) mls_init,
			(CamelObjectFinalizeFunc) mls_finalise);
	}

	return mail_local_store_type;
}

static void mail_local_store_add_folder(MailLocalStore *mls, const char *uri, const char *path, const char *name)
{
	CamelFolderInfo *info = NULL;
	CamelURL *url;

	d(printf("Shell adding folder: '%s' path = '%s'\n", uri, path));

	url = camel_url_new(uri, NULL);
	if (url == NULL) {
		g_warning("Shell trying to add invalid folder url: %s", uri);
		return;
	}
	if (url->path == NULL || url->path[0] == 0) {
		g_warning("Shell trying to add invalid folder url: %s", uri);
		camel_url_free(url);
		return;
	}

	LOCAL_STORE_LOCK(mls);

	if (g_hash_table_lookup(mls->folder_infos, uri)) {
		g_warning("Shell trying to add a folder I already have!");
	} else {
		info = g_malloc0(sizeof(*info));
		info->url = g_strdup(uri);
		info->full_name = g_strdup(url->path+1);
		info->name = g_strdup(name);
		info->unread_message_count = -1;
		info->path = g_strdup (path);
		g_hash_table_insert(mls->folder_infos, info->url, info);
	}

	LOCAL_STORE_UNLOCK(mls);

	camel_url_free(url);

	if (info) {
		/* FIXME: should copy info, so we dont get a removed while we're using it? */
		camel_object_trigger_event((CamelObject *)mls, "folder_created", info);

		/* this is just so the folder is opened at least once to setup the folder
		   counts etc in the display.  Joy eh?   The result is discarded. */
		mail_get_folder (uri, CAMEL_STORE_FOLDER_CREATE, NULL, NULL, mail_thread_queued_slow);
	}
}

struct _search_info {
	const char *path;
	CamelFolderInfo *info;
};

static void
remove_find_path(char *uri, CamelFolderInfo *info, struct _search_info *data)
{
	if (!strcmp(info->path, data->path))
		data->info = info;
}

static void mail_local_store_remove_folder(MailLocalStore *mls, const char *path)
{
	struct _search_info data = { path, NULL };

	d(printf("shell removing folder? '%s'\n", path));

	/* we're keyed on uri, not path, so have to search for it manually */

	LOCAL_STORE_LOCK(mls);
	g_hash_table_foreach(mls->folder_infos, (GHFunc)remove_find_path, &data);
	if (data.info)
		g_hash_table_remove(mls->folder_infos, data.info->url);
	LOCAL_STORE_UNLOCK(mls);

	if (data.info) {
		camel_object_trigger_event((CamelObject *)mls, "folder_deleted", data.info);

		g_free(data.info->url);
		g_free(data.info->full_name);
		g_free(data.info->name);
		g_free(data.info);
	}
}

/* ** Local Provider ************************************************************** */

static CamelProvider local_provider = {
	"file", "Local mail", NULL, "mail",
	CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_EXTERNAL,
	CAMEL_URL_NEED_PATH,
	/* ... */
};

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

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

static void
mail_local_provider_init (void)
{
	/* Register with Camel to handle file: URLs */
	local_provider.object_types[CAMEL_PROVIDER_STORE] = MAIL_LOCAL_STORE_TYPE;

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

/* ** Local Storage Listener ****************************************************** */

static void
local_storage_destroyed_cb (EvolutionStorageListener *storage_listener,
			    void *data)
{
	CORBA_Environment ev;

	CORBA_exception_init (&ev);
	bonobo_object_release_unref (data, &ev);
	CORBA_exception_free (&ev);
}


static void
local_storage_new_folder_cb (EvolutionStorageListener *storage_listener,
			     const char *path,
			     const GNOME_Evolution_Folder *folder,
			     void *data)
{
	d(printf("Local folder new:\n"));
	d(printf(" path = '%s'\n uri = '%s'\n display = '%s'\n",
		 path, folder->physicalUri, folder->displayName));

	/* We dont actually add the trash to our local folders list, get_trash is handled
	   outside our internal folder list */

	if (strcmp(folder->type, "mail") == 0) {
		mail_local_store_add_folder(global_local_store, folder->physicalUri, path, folder->displayName);
	} else if (strcmp(folder->type, "vtrash") == 0) {
		CamelFolderInfo info;
		CamelURL *url;

		url = camel_url_new(folder->physicalUri, NULL);
		if (url == NULL) {
			g_warning("Shell trying to add invalid folder url: %s", folder->physicalUri);
			return;
		}
		if (url->path == NULL || url->path[0] == 0) {
			g_warning("Shell trying to add invalid folder url: %s", folder->physicalUri);
			camel_url_free(url);
			return;
		}

		memset(&info, 0, sizeof(info));
		info.full_name = CAMEL_VTRASH_NAME;
		info.name = folder->displayName;
		info.url = g_strdup_printf("vtrash:%s", folder->physicalUri);
		info.unread_message_count = 0;
		info.path = (char *)path;

		camel_object_trigger_event((CamelObject *)global_local_store, "folder_created", &info);
		g_free(info.url);
		camel_url_free(url);
	}
}


static void
local_storage_removed_folder_cb (EvolutionStorageListener *storage_listener,
				 const char *path,
				 void *data)
{
	d(printf("Local folder remove:\n"));
	d(printf(" path = '%s'\n", path));

	mail_local_store_remove_folder(global_local_store, path);
}

static void
storage_listener_startup (EvolutionShellClient *shellclient)
{
	EvolutionStorageListener *local_storage_listener;
	GNOME_Evolution_StorageListener corba_local_storage_listener;
	GNOME_Evolution_Storage corba_storage;
	CORBA_Environment ev;

	d(printf("---- CALLING STORAGE LISTENER STARTUP ---\n"));

	local_corba_storage = corba_storage = evolution_shell_client_get_local_storage (shellclient);
	if (corba_storage == CORBA_OBJECT_NIL) {
		g_warning ("No local storage available from shell client!");
		return;
	}

	/* setup to record this store's changes */
	mail_note_store((CamelStore *)global_local_store, NULL, local_corba_storage, NULL, NULL);

	local_storage_listener = evolution_storage_listener_new ();
	corba_local_storage_listener = evolution_storage_listener_corba_objref (
		local_storage_listener);

	gtk_signal_connect (GTK_OBJECT (local_storage_listener),
			    "destroyed",
			    GTK_SIGNAL_FUNC (local_storage_destroyed_cb),
			    corba_storage);
	gtk_signal_connect (GTK_OBJECT (local_storage_listener),
			    "new_folder",
			    GTK_SIGNAL_FUNC (local_storage_new_folder_cb),
			    corba_storage);
	gtk_signal_connect (GTK_OBJECT (local_storage_listener),
			    "removed_folder",
	 		    GTK_SIGNAL_FUNC (local_storage_removed_folder_cb),
			    corba_storage);

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

/* ** The rest ******************************************************************** */

void
mail_local_storage_startup (EvolutionShellClient *shellclient, const char *evolution_path)
{
	mail_local_provider_init ();

	global_local_store = MAIL_LOCAL_STORE(camel_session_get_service (session, "file:/", CAMEL_PROVIDER_STORE, NULL));

	if (!global_local_store) {
		g_warning ("No local store!");
		return;
	}

	storage_listener_startup (shellclient);
}


/*----------------------------------------------------------------------
 * 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

*/

/* we should have our own progress bar for this */

struct _reconfigure_msg {
	struct _mail_msg msg;

	FolderBrowser *fb;
	char *newtype;
	unsigned int index_body:1;
	GtkWidget *frame;
	GtkWidget *apply;
	GtkWidget *cancel;
	GtkWidget *check_index_body;
	GtkOptionMenu *optionlist;
	CamelFolder *folder_out;
};

/* hash table of folders that the user has a reconfig-folder dialog for */
static GHashTable *reconfigure_folder_hash = NULL;

static char *
reconfigure_folder_describe (struct _mail_msg *mm, int done)
{
	struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm;
	
	return g_strdup_printf (_("Changing folder \"%s\" to \"%s\" format"),
				m->fb->uri,
				m->newtype);
}

static void
reconfigure_folder_reconfigure (struct _mail_msg *mm)
{
	struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm;
	CamelFolder *local_folder = NULL;

	d(printf("reconfiguring folder: %s to type %s\n", m->fb->uri, m->newtype));
	
	if (strncmp (m->fb->uri, "file:", 5)) {
		camel_exception_setv (&mm->ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
				      _("%s may not be reconfigured because it is not a local folder"), 
				      m->fb->uri);
		return;
	}

	local_folder = mail_tool_uri_to_folder (m->fb->uri, 0, &mm->ex);
	if (camel_exception_is_set (&mm->ex)) {
		g_warning ("Can't resolve URI \"%s\" for reconfiguration!", m->fb->uri);
		return;
	}

	mail_local_folder_reconfigure (MAIL_LOCAL_FOLDER (local_folder), m->newtype, m->index_body, &mm->ex);
	m->folder_out = local_folder;
}

static void
reconfigure_folder_reconfigured (struct _mail_msg *mm)
{
	struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm;
	/*char *uri;*/
	
	if (camel_exception_is_set (&mm->ex)) {
		gnome_error_dialog (_("If you can no longer open this mailbox, then\n"
				      "you may need to repair it manually."));
	}

	message_list_set_folder (m->fb->message_list, m->folder_out, FALSE);
}

static void
reconfigure_folder_free (struct _mail_msg *mm)
{
	struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm;

	/* remove this folder from our hash since we are done with it */
	g_hash_table_remove (reconfigure_folder_hash, m->fb->folder);
	if (g_hash_table_size (reconfigure_folder_hash) == 0) {
		/* additional cleanup */
		g_hash_table_destroy (reconfigure_folder_hash);
		reconfigure_folder_hash = NULL;
	}

	if (m->folder_out)
		camel_object_unref (CAMEL_OBJECT (m->folder_out));
	gtk_object_unref (GTK_OBJECT (m->fb));
	g_free (m->newtype);
}

static struct _mail_msg_op reconfigure_folder_op = {
	reconfigure_folder_describe,
	reconfigure_folder_reconfigure,
	reconfigure_folder_reconfigured,
	reconfigure_folder_free,
};

static void
reconfigure_clicked (GnomeDialog *dialog, int button, struct _reconfigure_msg *m)
{
	if (button == 0) {
		GtkWidget *menu, *item;
		
		/* hack to clear the message list during update */
		/* we need to do this because the message list caches
		 * CamelMessageInfos from the old folder. */
		message_list_set_folder(m->fb->message_list, NULL, FALSE);
		
		menu = gtk_option_menu_get_menu(m->optionlist);
		item = gtk_menu_get_active(GTK_MENU(menu));
		m->newtype = g_strdup(gtk_object_get_data((GtkObject *)item, "type"));
		m->index_body = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m->check_index_body));

		gtk_widget_set_sensitive (m->frame, FALSE);
		gtk_widget_set_sensitive (m->apply, FALSE);
		gtk_widget_set_sensitive (m->cancel, FALSE);
		
		e_thread_put (mail_thread_queued, (EMsg *)m);
	} else
		mail_msg_free ((struct _mail_msg *)m);
	
	if (button != -1)
		gnome_dialog_close (dialog);
}

void
mail_local_reconfigure_folder (FolderBrowser *fb)
{
	GladeXML *gui;
	GnomeDialog *gd;
	struct _reconfigure_msg *m;
	char *title;
	GList *p;
	GtkWidget *menu;
	char *currentformat;
	int index=0, history=0;

	if (fb->folder == NULL) {
		g_warning ("Trying to reconfigure nonexistant folder");
		return;
	}
	
	if (!reconfigure_folder_hash)
		reconfigure_folder_hash = g_hash_table_new (NULL, NULL);
	
	if ((gd = g_hash_table_lookup (reconfigure_folder_hash, fb->folder))) {
		gdk_window_raise (GTK_WIDGET (gd)->window);
		return;
	}
	
	/* check if we can work on this folder */
	if (!MAIL_IS_LOCAL_FOLDER (fb->folder)) {
		e_notice (NULL, GNOME_MESSAGE_BOX_WARNING,
			  _("You cannot change the format of a non-local folder."));
		return;
	}
	
	m = mail_msg_new (&reconfigure_folder_op, NULL, sizeof (*m));
	
	gui = glade_xml_new (EVOLUTION_GLADEDIR "/local-config.glade", "dialog_format");
	gd = (GnomeDialog *)glade_xml_get_widget (gui, "dialog_format");
	
	title = g_strdup_printf (_("Reconfigure /%s"),
				 camel_folder_get_full_name (fb->folder));
	gtk_window_set_title (GTK_WINDOW (gd), title);
	g_free (title);
	
	m->frame = glade_xml_get_widget (gui, "frame_format");
	m->apply = glade_xml_get_widget (gui, "apply_format");
	m->cancel = glade_xml_get_widget (gui, "cancel_format");
	m->optionlist = (GtkOptionMenu *)glade_xml_get_widget (gui, "option_format");
	m->check_index_body = glade_xml_get_widget (gui, "check_index_body");
	m->newtype = NULL;
	m->fb = fb;
	m->folder_out = NULL;
	gtk_object_ref (GTK_OBJECT (fb));

	/* dynamically create the folder type list from camel */
	/* we assume the list is static and never freed */
	currentformat = MAIL_LOCAL_FOLDER (fb->folder)->meta->format;
	p = camel_session_list_providers(session, TRUE);
	menu = gtk_menu_new();
	while (p) {
		CamelProvider *cp = p->data;

		/* we only want local providers */
		if (cp->flags & CAMEL_PROVIDER_IS_LOCAL) {
			GtkWidget *item;
			char *label;

			if (strcmp(cp->protocol, currentformat) == 0)
				history = index;

			label = g_strdup_printf("%s (%s)", cp->protocol, _(cp->name));
			item = gtk_menu_item_new_with_label(label);
			g_free(label);
			gtk_object_set_data((GtkObject *)item, "type", cp->protocol);
			gtk_widget_show(item);
			gtk_menu_append(GTK_MENU(menu), item);
			index++;
		}
		p = p->next;
	}
	gtk_option_menu_remove_menu (GTK_OPTION_MENU(m->optionlist));
	gtk_option_menu_set_menu (GTK_OPTION_MENU(m->optionlist), menu);
	gtk_option_menu_set_history(GTK_OPTION_MENU(m->optionlist), history);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m->check_index_body), MAIL_LOCAL_FOLDER (fb->folder)->meta->indexed);

	gtk_label_set_text ((GtkLabel *)glade_xml_get_widget (gui, "label_format"),
			    MAIL_LOCAL_FOLDER (fb->folder)->meta->format);
	
	gtk_signal_connect (GTK_OBJECT (gd), "clicked", reconfigure_clicked, m);
	gtk_object_unref (GTK_OBJECT (gui));
	
	g_hash_table_insert (reconfigure_folder_hash, (gpointer) fb->folder, (gpointer) gd);
	
	gnome_dialog_run (GNOME_DIALOG (gd));
}
ommitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=bf509e48d25c5c29386eccf1bdb0022cfb8ae708'>Remove no-longer-needed e_unicode_init.</a></td><td>Dan Winship</td><td><span title='2000-11-30 04:41:28 +0800'>2000-11-30</span></td><td>2</td><td><span class='deletions'>-2</span>/<span class='insertions'>+2</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=292dd96540823a9e7969701c95341eada2ce16f6'>Fix the allocation here (again) and put a comment explaining it. (Fixes a</a></td><td>Dan Winship</td><td><span title='2000-11-30 04:02:09 +0800'>2000-11-30</span></td><td>2</td><td><span class='deletions'>-1</span>/<span class='insertions'>+14</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=3ca789bf0f8844be4718d2b9b1b9416b334d0424'>Wait until after setting up the local storage to find the</a></td><td>Dan Winship</td><td><span title='2000-11-29 06:59:00 +0800'>2000-11-29</span></td><td>3</td><td><span class='deletions'>-11</span>/<span class='insertions'>+16</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=f22ac8e3a051c76a48206a7a717c21a180148b58'>Added the SaveAs bonobo menu verb thingy.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-29 04:37:43 +0800'>2000-11-29</span></td><td>6</td><td><span class='deletions'>-38</span>/<span class='insertions'>+94</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=dfc6c01cf945c1d3b12a16f151a693d778892b7f'>Fix the initial unread counts after the last patch.</a></td><td>Dan Winship</td><td><span title='2000-11-29 02:04:16 +0800'>2000-11-29</span></td><td>2</td><td><span class='deletions'>-1</span>/<span class='insertions'>+9</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=26fccb498293b89b9bef804fc85436e00a4ee1cd'>This needs to run from the main thread, not the camel thread, so add a</a></td><td>Dan Winship</td><td><span title='2000-11-28 10:10:55 +0800'>2000-11-28</span></td><td>2</td><td><span class='deletions'>-5</span>/<span class='insertions'>+22</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=16ddec870358374df569de984457dc6568fcc862'>Removed some unecessary debugging printf's</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-28 04:42:44 +0800'>2000-11-28</span></td><td>2</td><td><span class='deletions'>-2</span>/<span class='insertions'>+4</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=54f0a66dc33f62ce0ce6b3f2274915995e3871d3'>Revert the new druid for now, until the corresponding code is done, so</a></td><td>Dan Winship</td><td><span title='2000-11-28 02:33:53 +0800'>2000-11-28</span></td><td>3</td><td><span class='deletions'>-2842</span>/<span class='insertions'>+53</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=f69d5ec14310f4903a8b88224f7c82cfa1de014a'>Big patch. Evolution-services rewrite, services updated for new system,</a></td><td>Iain Holmes</td><td><span title='2000-11-22 08:34:39 +0800'>2000-11-22</span></td><td>8</td><td><span class='deletions'>-34</span>/<span class='insertions'>+103</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=def00f78b1448ed1136236f7eae0009b066f4947'>add GPGME_CFLAGS and GPGME_LIBS</a></td><td>Dan Winship</td><td><span title='2000-11-22 06:56:13 +0800'>2000-11-22</span></td><td>2</td><td><span class='deletions'>-3</span>/<span class='insertions'>+9</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=0fa1b87e9ee6b947b2706a44fc7429730655b3f9'>New function to return if user wants to view message source.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-22 06:09:51 +0800'>2000-11-22</span></td><td>13</td><td><span class='deletions'>-163</span>/<span class='insertions'>+136</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=8d9d1e00dd89221488084e51b4940469e8db4f4e'>IF we dont find a source, clear the exception and ignore it silently. for</a></td><td>Not Zed</td><td><span title='2000-11-21 22:28:06 +0800'>2000-11-21</span></td><td>3</td><td><span class='deletions'>-14</span>/<span class='insertions'>+50</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=c657e20b4c142f72de93fd133e0afeabca872a66'>#include &lt;gtkhtml/gtkhtml-embedded.h&gt;</a></td><td>Radek Doulik</td><td><span title='2000-11-21 19:27:30 +0800'>2000-11-21</span></td><td>2</td><td><span class='deletions'>-0</span>/<span class='insertions'>+5</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=587d706eeac40e84bb7eddf3de2a5c3c5b08b558'>Removed. No longer serves a purpose.</a></td><td>Not Zed</td><td><span title='2000-11-21 12:28:53 +0800'>2000-11-21</span></td><td>5</td><td><span class='deletions'>-794</span>/<span class='insertions'>+25</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=484334eaec8c6bd0c9118c318ceb3a503b7ac824'>Fix IMAP get-mail to work; CORBA calls in the dispatch thread are a no-no.</a></td><td>Peter Williams</td><td><span title='2000-11-21 10:08:37 +0800'>2000-11-21</span></td><td>2</td><td><span class='deletions'>-13</span>/<span class='insertions'>+62</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=7b8057a43c064a5f5a3611eb59d8bd68d1aabe11'>Save out the md5 hash of the messageid as hex, since thats all we have for</a></td><td>Not Zed</td><td><span title='2000-11-21 07:49:53 +0800'>2000-11-21</span></td><td>3</td><td><span class='deletions'>-43</span>/<span class='insertions'>+64</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=768136e12929387977670515f30d87d7a91a7865'>New comparison function that will replace address_compare if/when we ever</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-21 06:59:29 +0800'>2000-11-21</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=ba1dbc4a96583a0b89a2002e620c628c57096fb7'>New comparison function that will replace address_compare if/when we ever</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-21 06:58:39 +0800'>2000-11-21</span></td><td>2</td><td><span class='deletions'>-69</span>/<span class='insertions'>+110</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=b8262fdf8dcffd0a141c14d219f562893476f9ce'>Use the new quote_message function and make it start with "On %s, %s</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-18 06:29:53 +0800'>2000-11-18</span></td><td>5</td><td><span class='deletions'>-105</span>/<span class='insertions'>+123</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=25107cd4d712e05a366ccf772ed0ca40aaaecaa9'>Before we destroy ourselves, unhook ourselves from the folder update</a></td><td>Not Zed</td><td><span title='2000-11-17 14:18:01 +0800'>2000-11-17</span></td><td>2</td><td><span class='deletions'>-1</span>/<span class='insertions'>+15</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=4db080e17f7f6637cf184a84d3e07a97b6e6904a'>Added the MessageViewSource bonobo menu verb.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-17 07:05:32 +0800'>2000-11-17</span></td><td>5</td><td><span class='deletions'>-0</span>/<span class='insertions'>+134</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=64f95feb7da6e02faf8395f14a1329a133e367cd'>Added a new Forward as Attachment bonobo menu item verb.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-16 08:36:07 +0800'>2000-11-16</span></td><td>8</td><td><span class='deletions'>-76</span>/<span class='insertions'>+343</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=ca58532ff1e6b163206946027bed37d5666d32d4'>#!/usr/bin/perl -pi.bak</a></td><td>Michael Meeks</td><td><span title='2000-11-16 00:46:18 +0800'>2000-11-16</span></td><td>3</td><td><span class='deletions'>-6</span>/<span class='insertions'>+6</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=4bc4ee63bea0b2eaa1215be0df33f454a2918f37'>Take a 'subscribe' argument so that this can function as a subscribe AND</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-14 07:18:11 +0800'>2000-11-14</span></td><td>2</td><td><span class='deletions'>-132</span>/<span class='insertions'>+64</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=a53ac3867bb028e0b318aa9fcfda00657b1cfd7d'>Update the gal reqiurement version.</a></td><td>Christopher James Lahey</td><td><span title='2000-11-14 03:33:47 +0800'>2000-11-14</span></td><td>2</td><td><span class='deletions'>-3</span>/<span class='insertions'>+10</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=6e4eb7b99e5a210720cb7c686c9278c1df01345c'>Do this the normal way rather than calling mail_operation_wait_for_finish.</a></td><td>Dan Winship</td><td><span title='2000-11-13 08:57:43 +0800'>2000-11-13</span></td><td>2</td><td><span class='deletions'>-27</span>/<span class='insertions'>+36</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=f95b414ea30553ac44b3c74d3f1d1cd5adebc32d'>Sync the source folder.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-13 05:50:27 +0800'>2000-11-13</span></td><td>3</td><td><span class='deletions'>-1</span>/<span class='insertions'>+8</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=ddae78720c0cdc7984cc50e41a0db99368244e3d'>Clear the rdate and exrule lists from the component if we are setting a</a></td><td>Federico Mena Quintero</td><td><span title='2000-11-13 02:53:08 +0800'>2000-11-13</span></td><td>2</td><td><span class='deletions'>-28</span>/<span class='insertions'>+82</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=4441d197dcd3ebd6f901778e0d9098e4e4d96f6e'>Update the remaining "IDL:Evolution*" to "IDL:GNOME/Evolution*" to sync up</a></td><td>Matt Bissiri</td><td><span title='2000-11-11 14:27:43 +0800'>2000-11-11</span></td><td>5</td><td><span class='deletions'>-10</span>/<span class='insertions'>+17</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=3d3cfc1137a698a43d6a0137a2924f5933b12f17'>A very, long, very tedious IDL API rename and re-scoping;</a></td><td>Michael Meeks</td><td><span title='2000-11-11 04:41:13 +0800'>2000-11-11</span></td><td>21</td><td><span class='deletions'>-61</span>/<span class='insertions'>+70</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=88d445fac5cc704743da23a2e6099fc5a7a8003a'>New glade file for possibly using to create the subscribe dialog.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-10 06:32:41 +0800'>2000-11-10</span></td><td>3</td><td><span class='deletions'>-0</span>/<span class='insertions'>+316</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=b3a57cc8feb0929e1c5e09e12371b1f9d7ab7e15'>likewise</a></td><td>Radek Doulik</td><td><span title='2000-11-09 01:32:37 +0800'>2000-11-09</span></td><td>3</td><td><span class='deletions'>-7</span>/<span class='insertions'>+14</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=1d895352bc154854bd03aae4f5f4201648230c8d'>Allow rule part to expand when the user resizes the dialog.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-08 07:48:48 +0800'>2000-11-08</span></td><td>2</td><td><span class='deletions'>-38</span>/<span class='insertions'>+46</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=f82d483cd0a88fcbdb1a22561e152e896460dee2'>Don't handle custom searching anymore... we don't want this.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-08 07:32:32 +0800'>2000-11-08</span></td><td>2</td><td><span class='deletions'>-5</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=bda6d263ff41df43a03125fb669e07954ede56e7'>Don't handle custom searching anymore... we don't want this.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-08 06:54:53 +0800'>2000-11-08</span></td><td>2</td><td><span class='deletions'>-27</span>/<span class='insertions'>+18</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=b20396dd8b4146f3577e3629cf8bcb8f9920de52'>when "Show All", clear the entry widget</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-08 06:34:32 +0800'>2000-11-08</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=889ddc56b56ecd0c7d3127f0591b3fbd3d0a11ca'>Updated to use the ESearchBar object rather than the previously used</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-08 06:31:19 +0800'>2000-11-08</span></td><td>4</td><td><span class='deletions'>-277</span>/<span class='insertions'>+263</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=ba58be670e008ff3c4e2f4222fc782bb114f7cba'>	 (on_object_requested): passed the user's default email address</a></td><td>Jesse Pavel</td><td><span title='2000-11-08 06:10:15 +0800'>2000-11-08</span></td><td>2</td><td><span class='deletions'>-1</span>/<span class='insertions'>+11</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=35a8813a4800909bc39ba284e79db08ae1fa2d11'>modified some of the EPopupMenu structures to account for differences in</a></td><td>Jesse Pavel</td><td><span title='2000-11-08 03:03:10 +0800'>2000-11-08</span></td><td>2</td><td><span class='deletions'>-3</span>/<span class='insertions'>+9</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=25ec1b1c821edae387f56a7e5d3199616f15c84c'>Builddir != srcdir is The Way, man.</a></td><td>Ettore Perazzoli</td><td><span title='2000-11-08 02:50:06 +0800'>2000-11-08</span></td><td>2</td><td><span class='deletions'>-1</span>/<span class='insertions'>+7</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=25dcc0b87ac3ab29a4cc35ded91386558b4bc637'>God, I sure wish people would listen when i'm saying i'm changing and API.</a></td><td>Not Zed</td><td><span title='2000-11-07 20:33:01 +0800'>2000-11-07</span></td><td>5</td><td><span class='deletions'>-156</span>/<span class='insertions'>+165</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=3a764dfb814fdd11a2e232d249cb195b70c2b233'>Move filter stuff into a submenu of the popup menu.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-07 07:14:08 +0800'>2000-11-07</span></td><td>2</td><td><span class='deletions'>-38</span>/<span class='insertions'>+47</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=304ec439aef185a16c52ac1e22b9d6e723845ad2'>used Camel to parse the full address before passing the email address to</a></td><td>Jesse Pavel</td><td><span title='2000-11-07 07:07:19 +0800'>2000-11-07</span></td><td>2</td><td><span class='deletions'>-1</span>/<span class='insertions'>+18</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=868b122c9972adeb13d87ced6a554e5505a48340'>Remove mail-local-storage.h include</a></td><td>Dan Winship</td><td><span title='2000-11-07 06:36:12 +0800'>2000-11-07</span></td><td>2</td><td><span class='deletions'>-2</span>/<span class='insertions'>+2</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=dbc4e091133eee525a8b7c0fd449dcca6a5c719f'>	First draft of folder tree unread message indication for /local</a></td><td>Dan Winship</td><td><span title='2000-11-07 06:03:24 +0800'>2000-11-07</span></td><td>8</td><td><span class='deletions'>-378</span>/<span class='insertions'>+491</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=d39b0dfc09e9be5866a078c66ad5903a3b5b1e15'>Fix up #include &lt;config.h&gt; Same here. Here too. Fix indentation of #ifdef</a></td><td>Kjartan Maraas</td><td><span title='2000-11-07 04:49:53 +0800'>2000-11-07</span></td><td>6</td><td><span class='deletions'>-5</span>/<span class='insertions'>+15</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=3ccbffa051d714ce46ee432ccf1c3643c8699d37'>Don't invert the flag. (undelete_msg): Same (when multiple messages are</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-07 04:45:52 +0800'>2000-11-07</span></td><td>2</td><td><span class='deletions'>-8</span>/<span class='insertions'>+9</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=d893466560f87581cb14322a39446d14d9c405f3'>Updated to have the same menu items as the new right-click menu -</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-07 04:05:25 +0800'>2000-11-07</span></td><td>5</td><td><span class='deletions'>-15</span>/<span class='insertions'>+65</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=9ca299b427db9febb37208a33d238463f7a9b3bd'>Added an "Undelete" option to the right-click menu and also set a mask so</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-06 08:53:20 +0800'>2000-11-06</span></td><td>4</td><td><span class='deletions'>-35</span>/<span class='insertions'>+100</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=4f8dfcf38064b5039e23a5965b75cbe8105c4248'>don't free the MessageList search when it's being reused</a></td><td>Dan Winship</td><td><span title='2000-11-04 06:41:03 +0800'>2000-11-04</span></td><td>2</td><td><span class='deletions'>-1</span>/<span class='insertions'>+6</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=7e5a820d0d80e66e1a50b9388351b21781377b1e'>Don't show the passwd in the url string. (mail_tool_local_uri_to_folder):</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-04 05:05:12 +0800'>2000-11-04</span></td><td>2</td><td><span class='deletions'>-6</span>/<span class='insertions'>+13</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=1cb19b5a1b927467589f3b0700c80d74669f8735'>Added new header files.</a></td><td>Jeffrey Stedfast</td><td><span title='2000-11-04 02:55:41 +0800'>2000-11-04</span></td><td>15</td><td><span class='deletions'>-112</span>/<span class='insertions'>+274</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=19983a967556879fb9947c4319dbc9250a304168'>url_flags are now on CamelProvider, not CamelService</a></td><td>Dan Winship</td><td><span title='2000-11-04 02:23:08 +0800'>2000-11-04</span></td><td>5</td><td><span class='deletions'>-12</span>/<span class='insertions'>+28</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=d428113c3aadafa3a23d27ed05954c49c0af84b0'>Clean the idl-generated files properly.</a></td><td>Federico Mena Quintero</td><td><span title='2000-11-04 02:17:50 +0800'>2000-11-04</span></td><td>2</td><td><span class='deletions'>-0</span>/<span class='insertions'>+7</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/gsoc2013-evolution/commit/mail?h=EVOLUTION_2_32_3&amp;id=8952ed2a26a3096c4592bd3dc0d8e47829e3999c'>Added mail-display.h.</a></td><td>Not Zed</td><td><span title='2000-11-03 17:28:00 +0800'>2000-11-03</span></td><td>13</td><td><span class='deletions'>-307</span>/<span class='insertions'>+373</span></td></tr>