diff --git a/Makefile.am b/Makefile.am
index 28036bf..31f991e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,8 +1,10 @@
 SUBDIRS = \
-	camel mail \
-	addressbook calendar \
-	storage \
-	po docs
+	tools \
+	camel \
+	addressbook \
+	calendar \
+	po \
+	docs
 
 DISTCLEANFILES = \
 	intltool-extract \
diff --git a/camel/Makefile.am b/camel/Makefile.am
index 0195f84..a10e9cc 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -21,8 +21,8 @@ libcamelexchange_la_SOURCES =  \
 	camel-exchange-store.c \
 	camel-exchange-summary.c \
 	camel-exchange-transport.c \
-	camel-stub-marshal.c \
-	camel-stub.c
+	camel-exchange-utils.c \
+	mail-utils.c
 
 noinst_HEADERS = \
 	camel-exchange-folder.h \
@@ -31,17 +31,17 @@ noinst_HEADERS = \
 	camel-exchange-store.h \
 	camel-exchange-summary.h \
 	camel-exchange-transport.h \
-	camel-stub-constants.h \
-	camel-stub-marshal.h \
-	camel-stub.h
+	camel-exchange-utils.h \
+	mail-utils.h
 
 libcamelexchange_la_LDFLAGS = -avoid-version -module $(NO_UNDEFINED)
 
-libcamelexchange_la_LIBADD =  \
-	$(LDAP_LIBS) \
-	$(LIBEXCHANGE_LIBS) \
-	$(EXCHANGE_STORAGE_LIBS) \
-	$(SOCKET_LIBS) \
+libcamelexchange_la_LIBADD =		\
+	$(top_builddir)/tools/libevolution-exchange-shared.la \
+	$(LDAP_LIBS)			\
+	$(LIBEXCHANGE_LIBS)		\
+	$(EXCHANGE_STORAGE_LIBS)	\
+	$(SOCKET_LIBS)			\
 	$(PTHREAD_LIB)
 
 EXTRA_DIST = libcamelexchange.urls
diff --git a/camel/camel-exchange-folder.c b/camel/camel-exchange-folder.c
index 54b8c1c..74ea777 100644
--- a/camel/camel-exchange-folder.c
+++ b/camel/camel-exchange-folder.c
@@ -30,12 +30,6 @@
 #include <glib/gi18n-lib.h>
 #include <libedataserver/e-data-server-util.h>
 
-#include "camel-exchange-folder.h"
-#include "camel-exchange-search.h"
-#include "camel-exchange-store.h"
-#include "camel-exchange-summary.h"
-#include "camel-exchange-journal.h"
-
 #include <camel/camel-data-wrapper.h>
 #include <camel/camel-exception.h>
 #include <camel/camel-file-utils.h>
@@ -48,6 +42,13 @@
 #include <camel/camel-folder-summary.h>
 #include <camel/camel-string-utils.h>
 
+#include "camel-exchange-folder.h"
+#include "camel-exchange-search.h"
+#include "camel-exchange-store.h"
+#include "camel-exchange-summary.h"
+#include "camel-exchange-journal.h"
+#include "camel-exchange-utils.h"
+
 static CamelOfflineFolderClass *parent_class = NULL;
 
 /* Returns the class for a CamelFolder */
@@ -178,18 +179,11 @@ refresh_info (CamelFolder *folder, CamelException *ex)
 	if (camel_exchange_store_connected (store, ex)) {
 		camel_offline_journal_replay (exch->journal, NULL);
 
-		camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_REFRESH_FOLDER,
-				 CAMEL_STUB_ARG_FOLDER, folder->full_name,
-				 CAMEL_STUB_ARG_END);
+		camel_exchange_utils_refresh_folder (CAMEL_SERVICE (folder->parent_store), folder->full_name, ex);
 	}
 
 	/* sync up the counts now */
-	if (!camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_SYNC_COUNT,
-				 CAMEL_STUB_ARG_FOLDER, folder->full_name,
-				 CAMEL_STUB_ARG_RETURN,
-				 CAMEL_STUB_ARG_UINT32, &unread_count,
-				 CAMEL_STUB_ARG_UINT32, &visible_count,
-				 CAMEL_STUB_ARG_END)) {
+	if (!camel_exchange_utils_sync_count (CAMEL_SERVICE (folder->parent_store), folder->full_name, &unread_count, &visible_count, ex)) {
 		g_print("\n Error syncing up the counts");
 	}
 
@@ -200,7 +194,6 @@ refresh_info (CamelFolder *folder, CamelException *ex)
 static void
 exchange_expunge (CamelFolder *folder, CamelException *ex)
 {
-	CamelExchangeFolder *exch = CAMEL_EXCHANGE_FOLDER (folder);
 	CamelFolder *trash;
 	GPtrArray *uids;
 	CamelExchangeStore *store = CAMEL_EXCHANGE_STORE (folder->parent_store);
@@ -218,10 +211,7 @@ exchange_expunge (CamelFolder *folder, CamelException *ex)
 	}
 
 	uids = camel_folder_get_uids (trash);
-	camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_EXPUNGE_UIDS,
-			 CAMEL_STUB_ARG_FOLDER, trash->full_name,
-			 CAMEL_STUB_ARG_STRINGARRAY, uids,
-			 CAMEL_STUB_ARG_END);
+	camel_exchange_utils_expunge_uids (CAMEL_SERVICE (trash->parent_store), trash->full_name, uids, ex);
 	camel_folder_free_uids (trash, uids);
 	camel_object_unref (CAMEL_OBJECT (trash));
 }
@@ -240,14 +230,13 @@ append_message_data (CamelFolder *folder, GByteArray *message,
 	if (!subject)
 		subject = _("No Subject");
 
-	if (camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_APPEND_MESSAGE,
-			     CAMEL_STUB_ARG_FOLDER, folder->full_name,
-			     CAMEL_STUB_ARG_UINT32, info? camel_message_info_flags(info): 0,
-			     CAMEL_STUB_ARG_STRING, subject,
-			     CAMEL_STUB_ARG_BYTEARRAY, message,
-			     CAMEL_STUB_ARG_RETURN,
-			     CAMEL_STUB_ARG_STRING, &new_uid,
-			     CAMEL_STUB_ARG_END)) {
+	if (camel_exchange_utils_append_message (CAMEL_SERVICE (folder->parent_store),
+				folder->full_name,
+				info ? camel_message_info_flags (info) : 0,
+				subject,
+				message,
+				&new_uid,
+				ex)) {
 		stream_cache = camel_data_cache_add (exch->cache,
 						     "cache", new_uid, NULL);
 		if (stream_cache) {
@@ -405,12 +394,7 @@ get_message_data (CamelFolder *folder, const gchar *uid, CamelException *ex)
 		return NULL;
 	}
 
-	if (!camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_GET_MESSAGE,
-			      CAMEL_STUB_ARG_FOLDER, folder->full_name,
-			      CAMEL_STUB_ARG_STRING, uid,
-			      CAMEL_STUB_ARG_RETURN,
-			      CAMEL_STUB_ARG_BYTEARRAY, &ba,
-			      CAMEL_STUB_ARG_END))
+	if (!camel_exchange_utils_get_message (CAMEL_SERVICE (folder->parent_store), folder->full_name, uid, &ba, ex))
 		return NULL;
 
 	stream = camel_data_cache_add (exch->cache, "cache", uid, ex);
@@ -544,7 +528,6 @@ transfer_messages_the_hard_way (CamelFolder *source, GPtrArray *uids,
 				GPtrArray **transferred_uids,
 				gboolean delete_originals, CamelException *ex)
 {
-	CamelExchangeFolder *exch_source = CAMEL_EXCHANGE_FOLDER (source);
 	CamelException local_ex;
 	CamelMessageInfo *info;
 	GByteArray *ba;
@@ -585,16 +568,12 @@ transfer_messages_the_hard_way (CamelFolder *source, GPtrArray *uids,
 	}
 
 	if (delete_originals) {
-		camel_stub_send (exch_source->stub, ex,
-				 CAMEL_STUB_CMD_EXPUNGE_UIDS,
-				 CAMEL_STUB_ARG_FOLDER, source->full_name,
-				 CAMEL_STUB_ARG_STRINGARRAY, uids,
-				 CAMEL_STUB_ARG_END);
+		camel_exchange_utils_expunge_uids (CAMEL_SERVICE (source->parent_store), source->full_name, uids, ex);
 	}
 }
 
 static void
-cache_xfer (CamelExchangeFolder *stub_source, CamelExchangeFolder *stub_dest,
+cache_xfer (CamelExchangeFolder *folder_source, CamelExchangeFolder *folder_dest,
 	    GPtrArray *src_uids, GPtrArray *dest_uids, gboolean delete)
 {
 	CamelStream *src, *dest;
@@ -604,12 +583,12 @@ cache_xfer (CamelExchangeFolder *stub_source, CamelExchangeFolder *stub_dest,
 		if (!*(gchar *)dest_uids->pdata[i])
 			continue;
 
-		src = camel_data_cache_get (stub_source->cache, "cache",
+		src = camel_data_cache_get (folder_source->cache, "cache",
 					    src_uids->pdata[i], NULL);
 		if (!src)
 			continue;
 
-		dest = camel_data_cache_add (stub_dest->cache, "cache",
+		dest = camel_data_cache_add (folder_dest->cache, "cache",
 					     dest_uids->pdata[i], NULL);
 		if (dest) {
 			camel_stream_write_to_stream (src, dest);
@@ -618,7 +597,7 @@ cache_xfer (CamelExchangeFolder *stub_source, CamelExchangeFolder *stub_dest,
 		camel_object_unref (CAMEL_OBJECT (src));
 
 		if (delete) {
-			camel_data_cache_remove (stub_source->cache, "cache",
+			camel_data_cache_remove (folder_source->cache, "cache",
 						 src_uids->pdata[i], NULL);
 		}
 	}
@@ -684,25 +663,20 @@ transfer_messages_to (CamelFolder *source, GPtrArray *uids,
 		return;
 	}
 
-	if (camel_stub_send (exch_source->stub, ex,
-			     CAMEL_STUB_CMD_TRANSFER_MESSAGES,
-			     CAMEL_STUB_ARG_FOLDER, source->full_name,
-			     CAMEL_STUB_ARG_FOLDER, dest->full_name,
-			     CAMEL_STUB_ARG_STRINGARRAY, uids,
-			     CAMEL_STUB_ARG_UINT32, (guint32)delete_originals,
-			     CAMEL_STUB_ARG_RETURN,
-			     CAMEL_STUB_ARG_STRINGARRAY, &ret_uids,
-			     CAMEL_STUB_ARG_END)) {
+	if (camel_exchange_utils_transfer_messages (CAMEL_SERVICE (store),
+				source->full_name,
+				dest->full_name,
+				uids,
+				delete_originals,
+				&ret_uids,
+				ex)) {
 		if (ret_uids->len != 0)
 			cache_xfer (exch_source, exch_dest, uids, ret_uids, FALSE);
 
 		if (transferred_uids)
 			*transferred_uids = ret_uids;
 		else {
-			gint i;
-
-			for (i = 0; i < ret_uids->len; i++)
-				g_free (ret_uids->pdata[i]);
+			g_ptr_array_foreach (ret_uids, (GFunc) g_free, NULL);
 			g_ptr_array_free (ret_uids, TRUE);
 		}
 	} else if (transferred_uids)
@@ -995,19 +969,15 @@ camel_exchange_folder_update_message_tag (CamelExchangeFolder *exch,
  * @camel_flags: the folder flags passed to camel_store_get_folder().
  * @folder_dir: local directory this folder can cache data into
  * @offline_state : offline status
- * @stub: the #CamelStub.
  * @ex: a #CamelException
  *
- * Constructs @folder by requesting the necessary data from the server
- * via @stub.
- *
  * Return value: success or failure.
  **/
 gboolean
 camel_exchange_folder_construct (CamelFolder *folder, CamelStore *parent,
 				 const gchar *name, guint32 camel_flags,
 				 const gchar *folder_dir, gint offline_state,
-				 CamelStub *stub, CamelException *ex)
+				 CamelException *ex)
 {
 	CamelExchangeFolder *exch = (CamelExchangeFolder *)folder;
 	const gchar *short_name;
@@ -1081,10 +1051,8 @@ camel_exchange_folder_construct (CamelFolder *folder, CamelStore *parent,
 		camel_message_info_free(info);
 	}
 
-	if (stub) {
-		gboolean ok, create = camel_flags & CAMEL_STORE_FOLDER_CREATE;
-
-		exch->stub = stub;
+	if (parent) {
+		gboolean ok, create = camel_flags & CAMEL_STORE_FOLDER_CREATE, readonly = FALSE;
 
 		summary = camel_folder_get_summary (folder);
 		uids = g_ptr_array_new ();
@@ -1106,17 +1074,9 @@ camel_exchange_folder_construct (CamelFolder *folder, CamelStore *parent,
 		}
 
 		camel_operation_start (NULL, _("Scanning for changed messages"));
-		ok = camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_GET_FOLDER,
-				      CAMEL_STUB_ARG_FOLDER, name,
-				      CAMEL_STUB_ARG_UINT32, create,
-				      CAMEL_STUB_ARG_STRINGARRAY, uids,
-				      CAMEL_STUB_ARG_BYTEARRAY, flags,
-				      CAMEL_STUB_ARG_STRINGARRAY, hrefs,
-				      CAMEL_STUB_ARG_UINT32, CAMEL_EXCHANGE_SUMMARY(folder->summary)->high_article_num,
-				      CAMEL_STUB_ARG_RETURN,
-				      CAMEL_STUB_ARG_UINT32, &folder_flags,
-				      CAMEL_STUB_ARG_STRING, &exch->source,
-				      CAMEL_STUB_ARG_END);
+		ok = camel_exchange_utils_get_folder (CAMEL_SERVICE (parent),
+				      name, create, uids, flags, hrefs, CAMEL_EXCHANGE_SUMMARY (folder->summary)->high_article_num,
+				      &folder_flags, &exch->source, &readonly, ex);
 		camel_operation_end (NULL);
 		g_ptr_array_free (uids, TRUE);
 		g_byte_array_free (flags, TRUE);
@@ -1125,25 +1085,23 @@ camel_exchange_folder_construct (CamelFolder *folder, CamelStore *parent,
 		if (!ok)
 			return FALSE;
 
-		if (folder_flags & CAMEL_STUB_FOLDER_FILTER)
+		if (folder_flags & CAMEL_FOLDER_FILTER_RECENT)
 			folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
-		if (folder_flags & CAMEL_STUB_FOLDER_FILTER_EXPUNGE)
+		if (folder_flags & CAMEL_FOLDER_FILTER_EXPUNGE)
 			folder->folder_flags |= CAMEL_FOLDER_FILTER_EXPUNGE;	
-		if (folder_flags & CAMEL_STUB_FOLDER_FILTER_JUNK)
+		if (folder_flags & CAMEL_FOLDER_FILTER_JUNK)
 			folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
 
-		camel_exchange_summary_set_readonly (folder->summary, folder_flags & CAMEL_STUB_FOLDER_READONLY);
+		camel_exchange_summary_set_readonly (folder->summary, readonly);
 
-		if (offline_state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL )
+		if (offline_state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 			return TRUE;
 
 		if (len)
 			return TRUE;
 
 		camel_operation_start (NULL, _("Fetching summary information for new messages"));
-		ok = camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_REFRESH_FOLDER,
-				      CAMEL_STUB_ARG_FOLDER, folder->full_name,
-				      CAMEL_STUB_ARG_END);
+		ok = camel_exchange_utils_refresh_folder (CAMEL_SERVICE (parent), folder->full_name, ex);
 		camel_operation_end (NULL);
 		if (!ok)
 			return FALSE;
diff --git a/camel/camel-exchange-folder.h b/camel/camel-exchange-folder.h
index ed06d17..590355f 100644
--- a/camel/camel-exchange-folder.h
+++ b/camel/camel-exchange-folder.h
@@ -13,7 +13,6 @@ G_BEGIN_DECLS
 #include <camel/camel-data-cache.h>
 #include <camel/camel-offline-folder.h>
 #include <camel/camel-offline-journal.h>
-#include "camel-stub.h"
 
 #define CAMEL_EXCHANGE_FOLDER_TYPE     (camel_exchange_folder_get_type ())
 #define CAMEL_EXCHANGE_FOLDER(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_EXCHANGE_FOLDER_TYPE, CamelExchangeFolder))
@@ -23,7 +22,6 @@ G_BEGIN_DECLS
 typedef struct {
 	CamelOfflineFolder parent_object;
 
-	CamelStub *stub;
 	CamelDataCache *cache;
 	CamelOfflineJournal *journal;
 	gchar *source;
@@ -45,7 +43,6 @@ gboolean camel_exchange_folder_construct            (CamelFolder *folder,
 						     guint32 camel_flags,
 						     const gchar *folder_dir,
 						     gint offline_state,
-						     CamelStub *stub,
 						     CamelException *ex);
 
 void     camel_exchange_folder_add_message          (CamelExchangeFolder *exch,
diff --git a/camel/camel-exchange-journal.c b/camel/camel-exchange-journal.c
index d8b2a9d..fe19e50 100644
--- a/camel/camel-exchange-journal.c
+++ b/camel/camel-exchange-journal.c
@@ -42,6 +42,7 @@
 #include "camel-exchange-journal.h"
 #include "camel-exchange-store.h"
 #include "camel-exchange-summary.h"
+#include "camel-exchange-utils.h"
 
 #define d(x)
 
@@ -231,20 +232,14 @@ exchange_message_info_dup_to (CamelMessageInfoBase *dest, CamelMessageInfoBase *
 static gint
 exchange_entry_play_delete (CamelOfflineJournal *journal, CamelExchangeJournalEntry *entry, CamelException *ex)
 {
-	CamelExchangeFolder *exchange_folder = (CamelExchangeFolder *) journal->folder;
-
-	camel_stub_send_oneway (exchange_folder->stub,
-				CAMEL_STUB_CMD_SET_MESSAGE_FLAGS,
-				CAMEL_STUB_ARG_FOLDER,
-				((CamelFolder *)exchange_folder)->full_name,
-				CAMEL_STUB_ARG_STRING,
-				entry->uid,
-				CAMEL_STUB_ARG_UINT32,
-				entry->set,
-				CAMEL_STUB_ARG_UINT32,
-				entry->flags,
-				CAMEL_STUB_ARG_END);
+	CamelFolder *folder = (CamelFolder *) journal->folder;
 
+	camel_exchange_utils_set_message_flags (CAMEL_SERVICE (folder->parent_store),
+					folder->full_name,
+					entry->uid,
+					entry->set,
+					entry->flags,
+					ex);
 	return 0;
 }
 
diff --git a/camel/camel-exchange-search.c b/camel/camel-exchange-search.c
index 2bdf1b9..a662cf7 100644
--- a/camel/camel-exchange-search.c
+++ b/camel/camel-exchange-search.c
@@ -30,6 +30,7 @@
 
 #include "camel-exchange-search.h"
 #include "camel-exchange-folder.h"
+#include "camel-exchange-utils.h"
 
 static ESExpResult *
 exchange_body_contains (struct _ESExp *f, gint argc, struct _ESExpResult **argv,
@@ -71,7 +72,6 @@ static ESExpResult *
 exchange_body_contains (struct _ESExp *f, gint argc, struct _ESExpResult **argv,
 			CamelFolderSearch *s)
 {
-	CamelExchangeFolder *folder = CAMEL_EXCHANGE_FOLDER (s->folder);
 	gchar *value = argv[0]->value.string, *real_uid;
 	const gchar *uid;
 	ESExpResult *r;
@@ -105,13 +105,7 @@ exchange_body_contains (struct _ESExp *f, gint argc, struct _ESExpResult **argv,
 	}
 
 	/* FIXME: what if we have multiple string args? */
-	if (!camel_stub_send (folder->stub, NULL,
-			      CAMEL_STUB_CMD_SEARCH_FOLDER,
-			      CAMEL_STUB_ARG_FOLDER, s->folder->full_name,
-			      CAMEL_STUB_ARG_STRING, value,
-			      CAMEL_STUB_ARG_RETURN,
-			      CAMEL_STUB_ARG_STRINGARRAY, &found_uids,
-			      CAMEL_STUB_ARG_END))
+	if (!camel_exchange_utils_search (CAMEL_SERVICE (s->folder->parent_store), s->folder->full_name, value, &found_uids, NULL))
 		return r;
 
 	if (!found_uids->len) {
diff --git a/camel/camel-exchange-store.c b/camel/camel-exchange-store.c
index 66fe9bd..0d7a7fb 100644
--- a/camel/camel-exchange-store.c
+++ b/camel/camel-exchange-store.c
@@ -34,6 +34,7 @@
 #include "camel-exchange-store.h"
 #include "camel-exchange-folder.h"
 #include "camel-exchange-summary.h"
+#include "camel-exchange-utils.h"
 
 #define SUBFOLDER_DIR_NAME     "subfolders"
 #define SUBFOLDER_DIR_NAME_LEN 10
@@ -84,8 +85,6 @@ static void		exchange_unsubscribe_folder (CamelStore *store,
 						CamelException *ex);
 static gboolean exchange_can_refresh_folder (CamelStore *store, CamelFolderInfo *info, CamelException *ex);
 
-static void stub_notification (CamelObject *object, gpointer event_data, gpointer user_data);
-
 static void
 class_init (CamelExchangeStoreClass *camel_exchange_store_class)
 {
@@ -137,11 +136,6 @@ init (CamelExchangeStore *exch, CamelExchangeStoreClass *klass)
 static void
 finalize (CamelExchangeStore *exch)
 {
-	if (exch->stub) {
-		camel_object_unref (CAMEL_OBJECT (exch->stub));
-		exch->stub = NULL;
-	}
-
 	g_free (exch->trash_name);
 
 	if (exch->folders_lock)
@@ -292,8 +286,6 @@ construct (CamelService *service, CamelSession *session,
 
 	if (!(exch->storage_path = camel_session_get_storage_path (session, service, ex)))
 		return;
-
-	exch->stub = NULL;
 }
 
 extern CamelServiceAuthType camel_exchange_password_authtype;
@@ -354,66 +346,28 @@ camel_exchange_forget_password (CamelService *service, CamelException *ex)
 	}
 }
 
-static void
-update_camel_stub (gpointer folder_name, gpointer folder, gpointer user_data)
-{
-	CamelExchangeFolder *exch_folder = CAMEL_EXCHANGE_FOLDER (folder);
-	if (exch_folder)
-		exch_folder->stub = (CamelStub *)user_data;
-}
-
 static gboolean
 exchange_connect (CamelService *service, CamelException *ex)
 {
 	CamelExchangeStore *exch = CAMEL_EXCHANGE_STORE (service);
-	gchar *real_user, *socket_path, *dot_exchange_username, *user_at_host;
 	gchar *password = NULL;
 	guint32 connect_status;
 	gboolean online_mode = FALSE;
 
 	/* This lock is only needed for offline operation. exchange_connect
-	   is called many times in offline to ensure we are connected atleast
-	   to the mail stub. Think twice before changing anything here.*/
+	   is called many times in offline. */
 
 	g_mutex_lock (exch->connect_lock);
 
 	online_mode = camel_session_is_online (service->session);
-
-	if (exch->stub == NULL) {
-		real_user = strpbrk (service->url->user, "\\/");
-		if (real_user)
-			real_user++;
-		else
-			real_user = service->url->user;
-		dot_exchange_username = g_strdup_printf (".exchange-%s", g_get_user_name ());
-		user_at_host = g_strdup_printf ("%s@%s", real_user, service->url->host);
-		e_filename_make_safe (user_at_host);
-		socket_path = g_build_filename (g_get_tmp_dir (),
-						dot_exchange_username,
-						user_at_host,
-						NULL);
-		g_free (dot_exchange_username);
-		g_free (user_at_host);
-
-		exch->stub = camel_stub_new (socket_path, _("Evolution Exchange backend process"), ex);
-		g_free (socket_path);
-		if (!exch->stub) {
-			g_mutex_unlock (exch->connect_lock);
-			return FALSE;
-		}
-
-		camel_object_hook_event (CAMEL_OBJECT (exch->stub), "notification",
-					 stub_notification, exch);
-	} else if (!online_mode && exch->stub_connected) {
+/*	if (!online_mode) {
 		g_mutex_unlock (exch->connect_lock);
 		return TRUE;
 	}
-
+*/
 	if (online_mode) {
 		camel_exchange_get_password (service, ex);
 		if (camel_exception_is_set (ex)) {
-			camel_object_unref (exch->stub);
-			exch->stub = NULL;
 			g_mutex_unlock (exch->connect_lock);
 			return FALSE;
 		}
@@ -421,16 +375,10 @@ exchange_connect (CamelService *service, CamelException *ex)
 	}
 
 	/* Initialize the stub connection */
-	if (!camel_stub_send (exch->stub, NULL, CAMEL_STUB_CMD_CONNECT,
-			      CAMEL_STUB_ARG_STRING, password,
-			      CAMEL_STUB_ARG_RETURN,
-			      CAMEL_STUB_ARG_UINT32, &connect_status,
-			      CAMEL_STUB_ARG_END)) {
+	if (!camel_exchange_utils_connect (service, password, &connect_status, ex)) {
 		/* The user cancelled the connection attempt. */
-		camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
-				     "Cancelled");
-		camel_object_unref (exch->stub);
-		exch->stub = NULL;
+		if (!camel_exception_is_set (ex))
+			camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, "Cancelled");
 		g_mutex_unlock (exch->connect_lock);
 		return FALSE;
 	}
@@ -440,16 +388,10 @@ exchange_connect (CamelService *service, CamelException *ex)
 		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
 				     _("Could not authenticate to server. "
 				       "(Password incorrect?)\n\n"));
-		camel_object_unref (exch->stub);
-		exch->stub = NULL;
 		g_mutex_unlock (exch->connect_lock);
 		return FALSE;
-	} else {
-		exch->stub_connected = TRUE;
 	}
 
-	g_hash_table_foreach (exch->folders, update_camel_stub, exch->stub);
-
 	g_mutex_unlock (exch->connect_lock);
 
 	return TRUE;
@@ -458,13 +400,8 @@ exchange_connect (CamelService *service, CamelException *ex)
 static gboolean
 exchange_disconnect (CamelService *service, gboolean clean, CamelException *ex)
 {
-
-	CamelExchangeStore *exch = CAMEL_EXCHANGE_STORE (service);
-
-	if (exch->stub) {
-		exch->stub = NULL;
-	}
-
+	/* CamelExchangeStore *exch = CAMEL_EXCHANGE_STORE (service); */
+	/* keep account connect as it can be used for other parts like cal, gal or addressbook? */
 	return TRUE;
 }
 
@@ -514,7 +451,7 @@ exchange_get_folder (CamelStore *store, const gchar *folder_name,
 
 	if (!camel_exchange_folder_construct (folder, store, folder_name,
 					      flags, folder_dir, ((CamelOfflineStore *) store)->state,
-					      exch->stub, ex)) {
+					      ex)) {
 		gchar *key;
 		g_mutex_lock (exch->folders_lock);
 		if (g_hash_table_lookup_extended (exch->folders, folder_name,
@@ -541,23 +478,18 @@ exchange_get_folder (CamelStore *store, const gchar *folder_name,
 static gboolean
 exchange_folder_subscribed (CamelStore *store, const gchar *folder_name)
 {
-	CamelExchangeStore *exch = CAMEL_EXCHANGE_STORE (store);
-	guint32 is_subscribed;
+	gboolean is_subscribed = FALSE;
 
 	d(printf ("is subscribed folder : %s\n", folder_name));
 	if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
 		return FALSE;
 	}
 
-	if (!camel_stub_send (exch->stub, NULL, CAMEL_STUB_CMD_IS_SUBSCRIBED_FOLDER,
-			      CAMEL_STUB_ARG_FOLDER, folder_name,
-			      CAMEL_STUB_ARG_RETURN,
-			      CAMEL_STUB_ARG_UINT32, &is_subscribed,
-			      CAMEL_STUB_ARG_END)) {
+	if (!camel_exchange_utils_is_subscribed_folder (CAMEL_SERVICE (store), folder_name, &is_subscribed, NULL)) {
 		return FALSE;
 	}
 
-	return is_subscribed ? TRUE : FALSE;
+	return is_subscribed;
 }
 
 static void
@@ -572,9 +504,7 @@ exchange_subscribe_folder (CamelStore *store, const gchar *folder_name,
 		return;
 	}
 
-	camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_SUBSCRIBE_FOLDER,
-			      CAMEL_STUB_ARG_FOLDER, folder_name,
-			      CAMEL_STUB_ARG_END);
+	camel_exchange_utils_subscribe_folder (CAMEL_SERVICE (store), folder_name, ex);
 }
 
 static void
@@ -589,9 +519,7 @@ exchange_unsubscribe_folder (CamelStore *store, const gchar *folder_name,
 		return;
 	}
 
-	camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_UNSUBSCRIBE_FOLDER,
-			      CAMEL_STUB_ARG_FOLDER, folder_name,
-			      CAMEL_STUB_ARG_END);
+	camel_exchange_utils_unsubscribe_folder (CAMEL_SERVICE (store), folder_name, ex);
 }
 
 static CamelFolder *
@@ -602,10 +530,7 @@ get_trash (CamelStore *store, CamelException *ex)
 	RETURN_VAL_IF_NOT_CONNECTED (exch, ex, NULL);
 
 	if (!exch->trash_name) {
-		if (!camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_GET_TRASH_NAME,
-				      CAMEL_STUB_ARG_RETURN,
-				      CAMEL_STUB_ARG_STRING, &exch->trash_name,
-				      CAMEL_STUB_ARG_END))
+		if (!camel_exchange_utils_get_trash_name (CAMEL_SERVICE (store), &exch->trash_name, ex))
 			return NULL;
 	}
 
@@ -614,7 +539,7 @@ get_trash (CamelStore *store, CamelException *ex)
 
 /* Note: steals @name and @uri */
 static CamelFolderInfo *
-make_folder_info (CamelExchangeStore *exch, gchar *name, gchar *uri,
+make_folder_info (CamelExchangeStore *exch, gchar *name, const gchar *uri,
 		  gint unread_count, gint flags)
 {
 	CamelFolderInfo *info;
@@ -657,27 +582,27 @@ make_folder_info (CamelExchangeStore *exch, gchar *name, gchar *uri,
 	}
 	info->unread = unread_count;
 
-	if (flags & CAMEL_STUB_FOLDER_NOSELECT)
+	if (flags & CAMEL_FOLDER_NOSELECT)
 		info->flags = CAMEL_FOLDER_NOSELECT;
 
-	if (flags & CAMEL_STUB_FOLDER_SYSTEM)
+	if (flags & CAMEL_FOLDER_SYSTEM)
 		info->flags |= CAMEL_FOLDER_SYSTEM;
 
-	if (flags & CAMEL_STUB_FOLDER_TYPE_INBOX)
+	if ((flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
 		info->flags |= CAMEL_FOLDER_TYPE_INBOX;
 
-	if (flags & CAMEL_STUB_FOLDER_TYPE_TRASH)
+	if ((flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_TRASH)
 		info->flags |= CAMEL_FOLDER_TYPE_TRASH;
 
-	if (flags & CAMEL_STUB_FOLDER_TYPE_SENT)
+	if ((flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_SENT)
 		info->flags |= CAMEL_FOLDER_TYPE_SENT;
 
-	if (flags & CAMEL_STUB_FOLDER_SUBSCRIBED) {
+	if (flags & CAMEL_FOLDER_SUBSCRIBED) {
 		info->flags |= CAMEL_FOLDER_SUBSCRIBED;
 		d(printf ("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMmark as subscribed\n"));
 	}
 
-	if (flags & CAMEL_STUB_FOLDER_NOCHILDREN)
+	if (flags & CAMEL_FOLDER_NOCHILDREN)
 		info->flags |= CAMEL_FOLDER_NOCHILDREN;
 	return info;
 }
@@ -713,9 +638,9 @@ static CamelFolderInfo *
 exchange_get_folder_info (CamelStore *store, const gchar *top, guint32 flags, CamelException *ex)
 {
 	CamelExchangeStore *exch = CAMEL_EXCHANGE_STORE (store);
-	GPtrArray *folders, *folder_names, *folder_uris;
-	GArray *unread_counts;
-	GArray *folder_flags;
+	GPtrArray *folders, *folder_names = NULL, *folder_uris = NULL;
+	GArray *unread_counts = NULL;
+	GArray *folder_flags = NULL;
 	CamelFolderInfo *info;
 	guint32 store_flags = 0;
 	gint i;
@@ -741,25 +666,14 @@ exchange_get_folder_info (CamelStore *store, const gchar *top, guint32 flags, Ca
 		return NULL;
 	}
 
-	if (camel_stub_marshal_eof (exch->stub->cmd))
-		return NULL;
-
 	if (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
-		store_flags |= CAMEL_STUB_STORE_FOLDER_INFO_RECURSIVE;
+		store_flags |= CAMEL_STORE_FOLDER_INFO_RECURSIVE;
 	if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)
-		store_flags |= CAMEL_STUB_STORE_FOLDER_INFO_SUBSCRIBED;
+		store_flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 	if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST)
-		store_flags |= CAMEL_STUB_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
-
-	if (!camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_GET_FOLDER_INFO,
-			      CAMEL_STUB_ARG_STRING, top,
-			      CAMEL_STUB_ARG_UINT32, store_flags,
-			      CAMEL_STUB_ARG_RETURN,
-			      CAMEL_STUB_ARG_STRINGARRAY, &folder_names,
-			      CAMEL_STUB_ARG_STRINGARRAY, &folder_uris,
-			      CAMEL_STUB_ARG_UINT32ARRAY, &unread_counts,
-			      CAMEL_STUB_ARG_UINT32ARRAY, &folder_flags,
-			      CAMEL_STUB_ARG_END)) {
+		store_flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
+
+	if (!camel_exchange_utils_get_folder_info (CAMEL_SERVICE (store), top, store_flags, &folder_names, &folder_uris, &unread_counts, &folder_flags, ex)) {
 		return NULL;
 	}
 	if (!folder_names) {
@@ -774,12 +688,13 @@ exchange_get_folder_info (CamelStore *store, const gchar *top, guint32 flags, Ca
 	for (i = 0; i < folder_names->len; i++) {
 		info = make_folder_info (exch, folder_names->pdata[i],
 					 folder_uris->pdata[i],
-					 g_array_index (unread_counts, int, i),
-					 g_array_index (folder_flags, int, i));
+					 g_array_index (unread_counts, gint, i),
+					 g_array_index (folder_flags, gint, i));
 		if (info)
 			g_ptr_array_add (folders, info);
 	}
 	g_ptr_array_free (folder_names, TRUE);
+	g_ptr_array_foreach (folder_uris, (GFunc) g_free, NULL);
 	g_ptr_array_free (folder_uris, TRUE);
 	g_array_free (unread_counts, TRUE);
 	g_array_free (folder_flags, TRUE);
@@ -807,19 +722,15 @@ exchange_create_folder (CamelStore *store, const gchar *parent_name,
 		return NULL;
 	}
 
-	if (!camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_CREATE_FOLDER,
-			      CAMEL_STUB_ARG_FOLDER, parent_name,
-			      CAMEL_STUB_ARG_STRING, folder_name,
-			      CAMEL_STUB_ARG_RETURN,
-			      CAMEL_STUB_ARG_STRING, &folder_uri,
-			      CAMEL_STUB_ARG_UINT32, &unread_count,
-			      CAMEL_STUB_ARG_UINT32, &flags,
-			      CAMEL_STUB_ARG_END))
+	if (!camel_exchange_utils_create_folder (CAMEL_SERVICE (store), parent_name, folder_name, &folder_uri, &unread_count, &flags, ex))
 		return NULL;
 
 	info = make_folder_info (exch, g_strdup (folder_name),
 				 folder_uri, unread_count, flags);
 	info->flags |= CAMEL_FOLDER_NOCHILDREN;
+
+	g_free (folder_uri);
+
 	return info;
 }
 
@@ -834,9 +745,7 @@ exchange_delete_folder (CamelStore *store, const gchar *folder_name,
 		return;
 	}
 
-	camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_DELETE_FOLDER,
-			 CAMEL_STUB_ARG_FOLDER, folder_name,
-			 CAMEL_STUB_ARG_END);
+	camel_exchange_utils_delete_folder (CAMEL_SERVICE (store), folder_name, ex);
 }
 
 static void
@@ -857,15 +766,7 @@ exchange_rename_folder (CamelStore *store, const gchar *old_name,
 		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot rename folder in offline mode."));
 		return;
 	}
-	if (!camel_stub_send (exch->stub, ex, CAMEL_STUB_CMD_RENAME_FOLDER,
-			      CAMEL_STUB_ARG_STRING, old_name,
-			      CAMEL_STUB_ARG_STRING, new_name,
-			      CAMEL_STUB_ARG_RETURN,
-			      CAMEL_STUB_ARG_STRINGARRAY, &folder_names,
-			      CAMEL_STUB_ARG_STRINGARRAY, &folder_uris,
-			      CAMEL_STUB_ARG_UINT32ARRAY, &unread_counts,
-			      CAMEL_STUB_ARG_UINT32ARRAY, &folder_flags,
-			      CAMEL_STUB_ARG_END)) {
+	if (!camel_exchange_utils_rename_folder (CAMEL_SERVICE (store), old_name, new_name, &folder_names, &folder_uris, &unread_counts, &folder_flags, ex)) {
 		return;
 	}
 
@@ -887,6 +788,7 @@ exchange_rename_folder (CamelStore *store, const gchar *old_name,
 			g_ptr_array_add (folders, info);
 	}
 	g_ptr_array_free (folder_names, TRUE);
+	g_ptr_array_foreach (folder_uris, (GFunc) g_free, NULL);
 	g_ptr_array_free (folder_uris, TRUE);
 	g_array_free (unread_counts, TRUE);
 	g_array_free (folder_flags, TRUE);
@@ -914,291 +816,53 @@ exchange_rename_folder (CamelStore *store, const gchar *old_name,
 
 }
 
-static void
-stub_notification (CamelObject *object, gpointer event_data, gpointer user_data)
+static gboolean
+exchange_can_refresh_folder (CamelStore *store, CamelFolderInfo *info, CamelException *ex)
 {
-	CamelStub *stub = CAMEL_STUB (object);
-	CamelExchangeStore *exch = CAMEL_EXCHANGE_STORE (user_data);
-	guint32 retval = GPOINTER_TO_UINT (event_data);
-
-	switch (retval) {
-	case CAMEL_STUB_RETVAL_NEW_MESSAGE:
-	{
-		CamelExchangeFolder *folder;
-		gchar *folder_name, *uid, *headers, *href;
-		guint32 flags, size;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uid) == -1 ||
-		    camel_stub_marshal_decode_uint32 (stub->status, &flags) == -1 ||
-		    camel_stub_marshal_decode_uint32 (stub->status, &size) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &headers) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &href) == -1)
-			return;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder) {
-			camel_exchange_folder_add_message (folder, uid, flags,
-							   size, headers, href);
-		}
-
-		g_free (folder_name);
-		g_free (uid);
-		g_free (headers);
-		g_free (href);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_REMOVED_MESSAGE:
-	{
-		CamelExchangeFolder *folder;
-		gchar *folder_name, *uid;
-		CamelMessageInfo *info;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uid) == -1)
-			return;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder && (info = camel_folder_summary_uid (((CamelFolder *)folder)->summary, uid))) {
-			camel_message_info_free (info);
-			camel_exchange_folder_remove_message (folder, uid);
-		}
-
-		g_free (folder_name);
-		g_free (uid);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_CHANGED_MESSAGE:
-	{
-		CamelExchangeFolder *folder;
-		gchar *folder_name, *uid;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uid) == -1)
-			break;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder)
-			camel_exchange_folder_uncache_message (folder, uid);
-
-		g_free (folder_name);
-		g_free (uid);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_CHANGED_FLAGS:
-	{
-		CamelExchangeFolder *folder;
-		gchar *folder_name, *uid;
-		guint32 flags;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uid) == -1 ||
-		    camel_stub_marshal_decode_uint32 (stub->status, &flags) == -1)
-			break;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder)
-			camel_exchange_folder_update_message_flags (folder, uid, flags);
-
-		g_free (folder_name);
-		g_free (uid);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_CHANGED_FLAGS_EX:
-	{
-		CamelExchangeFolder *folder;
-		gchar *folder_name, *uid;
-		guint32 flags;
-		guint32 mask;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uid) == -1 ||
-		    camel_stub_marshal_decode_uint32 (stub->status, &flags) == -1 ||
-		    camel_stub_marshal_decode_uint32 (stub->status, &mask) == -1)
-			break;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder)
-			camel_exchange_folder_update_message_flags_ex (folder, uid,
-								       flags, mask);
-
-		g_free (folder_name);
-		g_free (uid);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_CHANGED_TAG:
-	{
-		CamelExchangeFolder *folder;
-		gchar *folder_name, *uid, *name, *value;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uid) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &value) == -1)
-			break;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder)
-			camel_exchange_folder_update_message_tag (folder, uid, name, value);
-
-		g_free (folder_name);
-		g_free (uid);
-		g_free (name);
-		g_free (value);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_FREEZE_FOLDER:
-	{
-		CamelFolder *folder;
-		gchar *folder_name;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1)
-			break;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder)
-			camel_folder_freeze (folder);
-
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_THAW_FOLDER:
-	{
-		CamelFolder *folder;
-		gchar *folder_name;
-
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1)
-			break;
-
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder)
-			camel_folder_thaw (folder);
-
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_FOLDER_CREATED:
-	{
-		CamelFolderInfo *info;
-		gchar *name, *uri;
-
-		if (camel_stub_marshal_decode_string (stub->status, &name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uri) == -1)
-			break;
-
-		info = make_folder_info (exch, name, uri, -1, 0);
-		info->flags |= CAMEL_FOLDER_NOCHILDREN;
-		camel_object_trigger_event (CAMEL_OBJECT (exch),
-					    "folder_subscribed", info);
-		camel_folder_info_free (info);
-		break;
-	}
-
-	case CAMEL_STUB_RETVAL_FOLDER_DELETED:
-	{
-		CamelFolderInfo *info;
-		CamelFolder *folder;
-		gchar *name, *uri;
-
-		if (camel_stub_marshal_decode_string (stub->status, &name) == -1 ||
-		    camel_stub_marshal_decode_string (stub->status, &uri) == -1)
-			break;
-
-		info = make_folder_info (exch, name, uri, -1, 0);
+	gboolean res;
 
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, info->full_name);
-		if (folder) {
-			g_hash_table_remove (exch->folders, info->full_name);
-			camel_object_unref (CAMEL_OBJECT (folder));
-		}
-		g_mutex_unlock (exch->folders_lock);
+	res = CAMEL_STORE_CLASS(parent_class)->can_refresh_folder (store, info, ex) ||
+	      (camel_url_get_param (((CamelService *)store)->url, "check_all") != NULL);
 
-		camel_object_trigger_event (CAMEL_OBJECT (exch),
-					    "folder_unsubscribed", info);
-		camel_folder_info_free (info);
-		break;
-	}
+	return res;
+}
 
-	case CAMEL_STUB_RETVAL_FOLDER_SET_READONLY:
-	{
-		CamelFolder *folder;
-		gchar *folder_name;
-		guint32 readonly;
+void
+camel_exchange_store_folder_created (CamelExchangeStore *estore, const gchar *name, const gchar *uri)
+{
+	CamelFolderInfo *info;
 
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_uint32 (stub->status, &readonly) == -1)
-			break;
+	g_return_if_fail (estore != NULL);
+	g_return_if_fail (CAMEL_IS_EXCHANGE_STORE (estore));
 
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder) {
-			camel_exchange_summary_set_readonly (folder->summary, readonly ? TRUE : FALSE);
-		}
+	info = make_folder_info (estore, g_strdup (name), uri, -1, 0);
+	info->flags |= CAMEL_FOLDER_NOCHILDREN;
 
-		g_free (folder_name);
-		break;
-	}
+	camel_object_trigger_event (CAMEL_OBJECT (estore), "folder_subscribed", info);
 
-	case CAMEL_STUB_RETVAL_FOLDER_SET_ARTICLE_NUM:
-	{
-		CamelFolder *folder;
-		gchar *folder_name;
-		guint32 high_article_num;
+	camel_folder_info_free (info);
+}
 
-		if (camel_stub_marshal_decode_folder (stub->status, &folder_name) == -1 ||
-		    camel_stub_marshal_decode_uint32 (stub->status, &high_article_num) == -1)
-			break;
+void
+camel_exchange_store_folder_deleted (CamelExchangeStore *estore, const gchar *name, const gchar *uri)
+{
+	CamelFolderInfo *info;
+	CamelFolder *folder;
 
-		g_mutex_lock (exch->folders_lock);
-		folder = g_hash_table_lookup (exch->folders, folder_name);
-		g_mutex_unlock (exch->folders_lock);
-		if (folder) {
-			camel_exchange_summary_set_article_num (folder->summary, high_article_num);
-		}
+	g_return_if_fail (estore != NULL);
+	g_return_if_fail (CAMEL_IS_EXCHANGE_STORE (estore));
 
-		g_free (folder_name);
-		break;
-	}
+	info = make_folder_info (estore, g_strdup (name), uri, -1, 0);
 
-	default:
-		g_critical ("%s: Uncaught case (%d)", G_STRLOC, retval);
-		break;
+	g_mutex_lock (estore->folders_lock);
+	folder = g_hash_table_lookup (estore->folders, info->full_name);
+	if (folder) {
+		g_hash_table_remove (estore->folders, info->full_name);
+		camel_object_unref (CAMEL_OBJECT (folder));
 	}
-}
+	g_mutex_unlock (estore->folders_lock);
 
-static gboolean
-exchange_can_refresh_folder (CamelStore *store, CamelFolderInfo *info, CamelException *ex)
-{
-	gboolean res;
-
-	res = CAMEL_STORE_CLASS(parent_class)->can_refresh_folder (store, info, ex) ||
-	      (camel_url_get_param (((CamelService *)store)->url, "check_all") != NULL);
+	camel_object_trigger_event (CAMEL_OBJECT (estore), "folder_unsubscribed", info);
 
-	return res;
+	camel_folder_info_free (info);
 }
diff --git a/camel/camel-exchange-store.h b/camel/camel-exchange-store.h
index 5aeae45..d634fb0 100644
--- a/camel/camel-exchange-store.h
+++ b/camel/camel-exchange-store.h
@@ -10,7 +10,6 @@ G_BEGIN_DECLS
 
 #include <camel/camel-store.h>
 #include <camel/camel-offline-store.h>
-#include "camel-stub.h"
 
 #define CAMEL_EXCHANGE_STORE_TYPE     (camel_exchange_store_get_type ())
 #define CAMEL_EXCHANGE_STORE(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_EXCHANGE_STORE_TYPE, CamelExchangeStore))
@@ -20,13 +19,11 @@ G_BEGIN_DECLS
 typedef struct {
 	CamelOfflineStore parent_object;
 
-	CamelStub *stub;
 	gchar *storage_path, *base_url;
 	gchar *trash_name;
 	GHashTable *folders;
 	GMutex *folders_lock;
 
-	gboolean stub_connected;
 	GMutex *connect_lock;
 
 } CamelExchangeStore;
@@ -41,6 +38,9 @@ CamelType camel_exchange_store_get_type (void);
 
 gboolean camel_exchange_store_connected (CamelExchangeStore *store, CamelException *ex);
 
+void camel_exchange_store_folder_created (CamelExchangeStore *estore, const gchar *name, const gchar *uri);
+void camel_exchange_store_folder_deleted (CamelExchangeStore *estore, const gchar *name, const gchar *uri);
+
 G_END_DECLS
 
 #endif /* CAMEL_EXCHANGE_STORE_H */
diff --git a/camel/camel-exchange-summary.c b/camel/camel-exchange-summary.c
index 0924e29..0e91dde 100644
--- a/camel/camel-exchange-summary.c
+++ b/camel/camel-exchange-summary.c
@@ -32,10 +32,10 @@
 #include <camel/camel-offline-store.h>
 #include <camel/camel-string-utils.h>
 
-#include "camel-stub.h"
 #include "camel-exchange-folder.h"
 #include "camel-exchange-journal.h"
 #include "camel-exchange-summary.h"
+#include "camel-exchange-utils.h"
 
 #define CAMEL_EXCHANGE_SUMMARY_VERSION (2)
 
@@ -389,7 +389,6 @@ check_for_trash (CamelFolder *folder)
 static gboolean
 expunge_mail (CamelFolder *folder, CamelMessageInfo *info)
 {
-	CamelExchangeFolder *exchange_folder = (CamelExchangeFolder *) folder;
 	GPtrArray *uids = g_ptr_array_new ();
 	gchar *uid = g_strdup (info->uid);
 	CamelException lex;
@@ -397,11 +396,7 @@ expunge_mail (CamelFolder *folder, CamelMessageInfo *info)
 	g_ptr_array_add (uids, uid);
 
 	camel_exception_init (&lex);
-	camel_stub_send (exchange_folder->stub, &lex,
-			 CAMEL_STUB_CMD_EXPUNGE_UIDS,
-			 CAMEL_STUB_ARG_FOLDER, folder->full_name,
-			 CAMEL_STUB_ARG_STRINGARRAY, uids,
-			 CAMEL_STUB_ARG_END);
+	camel_exchange_utils_expunge_uids (CAMEL_SERVICE (folder->parent_store), folder->full_name, uids, &lex);
 
 	g_ptr_array_free (uids, TRUE);
 	return camel_exception_is_set (&lex);
@@ -422,13 +417,7 @@ info_set_flags(CamelMessageInfo *info, guint32 flags, guint32 set)
 			    check_for_trash (folder)) {
 				return expunge_mail (folder, info);
 			} else {
-				camel_stub_send_oneway (((CamelExchangeFolder *)folder)->stub,
-							CAMEL_STUB_CMD_SET_MESSAGE_FLAGS,
-							CAMEL_STUB_ARG_FOLDER, folder->full_name,
-							CAMEL_STUB_ARG_STRING, info->uid,
-							CAMEL_STUB_ARG_UINT32, set,
-							CAMEL_STUB_ARG_UINT32, flags,
-							CAMEL_STUB_ARG_END);
+				camel_exchange_utils_set_message_flags (CAMEL_SERVICE (folder->parent_store), folder->full_name, info->uid, set, flags, NULL);
 				return CAMEL_FOLDER_SUMMARY_CLASS (parent_class)->info_set_flags(info, flags, set);
 			}
 		}
@@ -459,13 +448,8 @@ info_set_user_tag(CamelMessageInfo *info, const gchar *name, const gchar *value)
 
 	res = CAMEL_FOLDER_SUMMARY_CLASS (parent_class)->info_set_user_tag(info, name, value);
 	if (res && info->summary->folder && info->uid) {
-		camel_stub_send_oneway (((CamelExchangeFolder *)info->summary->folder)->stub,
-					CAMEL_STUB_CMD_SET_MESSAGE_TAG,
-					CAMEL_STUB_ARG_FOLDER, info->summary->folder->full_name,
-					CAMEL_STUB_ARG_STRING, info->uid,
-					CAMEL_STUB_ARG_STRING, name,
-					CAMEL_STUB_ARG_STRING, value,
-					CAMEL_STUB_ARG_END);
+		CamelFolder *folder = info->summary->folder;
+		camel_exchange_utils_set_message_tag (CAMEL_SERVICE (folder->parent_store), folder->full_name, info->uid, name, value, NULL);
 	}
 
 	return res;
diff --git a/camel/camel-exchange-transport.c b/camel/camel-exchange-transport.c
index cf33bba..2403b7e 100644
--- a/camel/camel-exchange-transport.c
+++ b/camel/camel-exchange-transport.c
@@ -26,7 +26,7 @@
 #include <glib/gi18n-lib.h>
 
 #include "camel-exchange-transport.h"
-#include "camel-stub.h"
+#include "camel-exchange-utils.h"
 
 #include <camel/camel-data-wrapper.h>
 #include <camel/camel-exception.h>
@@ -38,8 +38,6 @@
 
 #include <string.h>
 
-extern CamelStub *das_global_camel_stub;
-
 static gboolean exchange_send_to (CamelTransport *transport,
 				  CamelMimeMessage *message,
 				  CamelAddress *from,
@@ -111,6 +109,8 @@ exchange_send_to (CamelTransport *transport, CamelMimeMessage *message,
 		return FALSE;
 	}
 
+	g_free (url_string);
+
 	recipients_array = g_ptr_array_new ();
 	len = camel_address_length (recipients);
 	cia = CAMEL_INTERNET_ADDRESS (recipients);
@@ -119,7 +119,6 @@ exchange_send_to (CamelTransport *transport, CamelMimeMessage *message,
 			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
 					     _("Cannot send message: one or more invalid recipients"));
 			g_ptr_array_free (recipients_array, TRUE);
-			g_free (url_string);
 			return FALSE;
 		}
 		g_ptr_array_add (recipients_array, (gchar *)addr);
@@ -129,21 +128,9 @@ exchange_send_to (CamelTransport *transport, CamelMimeMessage *message,
 		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 				     _("Could not find 'From' address in message"));
 		g_ptr_array_free (recipients_array, TRUE);
-		g_free (url_string);
 		return FALSE;
 	}
 
-	if (!das_global_camel_stub) {
-		store = camel_session_get_store (service->session, url_string, ex);
-		if (!store) {
-			g_ptr_array_free (recipients_array, TRUE);
-			g_free (url_string);
-			return FALSE;
-		}
-		g_return_val_if_fail (das_global_camel_stub, FALSE);
-	}
-	g_free (url_string);
-
 	stream = camel_stream_mem_new ();
 	crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
 	filtered_stream = camel_stream_filter_new_with_stream (stream);
@@ -177,12 +164,7 @@ exchange_send_to (CamelTransport *transport, CamelMimeMessage *message,
 		g_slist_free (bcc);
 	}
 
-	success = camel_stub_send (das_global_camel_stub, ex,
-				   CAMEL_STUB_CMD_SEND_MESSAGE,
-				   CAMEL_STUB_ARG_STRING, addr,
-				   CAMEL_STUB_ARG_STRINGARRAY, recipients_array,
-				   CAMEL_STUB_ARG_BYTEARRAY, CAMEL_STREAM_MEM (stream)->buffer,
-				   CAMEL_STUB_ARG_END);
+	success = camel_exchange_utils_send_message (CAMEL_SERVICE (transport), addr, recipients_array, CAMEL_STREAM_MEM (stream)->buffer, ex);
 
 	g_ptr_array_free (recipients_array, TRUE);
 	camel_object_unref (CAMEL_OBJECT (stream));
diff --git a/camel/camel-exchange-utils.c b/camel/camel-exchange-utils.c
new file mode 100644
index 0000000..b0501c4
--- /dev/null
+++ b/camel/camel-exchange-utils.c
@@ -0,0 +1,3437 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2001-2004 Novell, Inc.
+ *
+ * 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.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <exchange-constants.h>
+#include <exchange-account.h>
+#include <e-folder-exchange.h>
+#include <e2k-propnames.h>
+#include <e2k-restriction.h>
+#include <e2k-uri.h>
+#include <e2k-utils.h>
+#include <exchange-hierarchy.h>
+#include <mapi.h>
+
+#include <camel/camel-folder.h>
+#include <camel/camel-service.h>
+#include <camel/camel-session.h>
+#include <camel/camel-store.h>
+
+#include "camel-exchange-folder.h"
+#include "camel-exchange-store.h"
+#include "camel-exchange-summary.h"
+#include "camel-exchange-utils.h"
+#include "mail-utils.h"
+
+#include "tools/exchange-share-config-listener.h"
+
+#define d(x)
+
+typedef struct {
+	/* the first two are set immediately, the rest after connect */
+	CamelExchangeStore *estore;
+	ExchangeAccount *account;
+	GHashTable *folders_by_name;
+
+	E2kContext *ctx;
+	const gchar *mail_submission_uri;
+	EFolder *inbox, *deleted_items, *sent_items;
+
+	GStaticRecMutex changed_msgs_mutex;
+
+	guint new_folder_id, removed_folder_id;
+	const gchar *ignore_new_folder, *ignore_removed_folder;
+} ExchangeData;
+
+typedef struct {
+	gchar *uid, *href;
+	guint32 seq, flags;
+	guint32 change_flags, change_mask;
+	GData *tag_updates;
+} ExchangeMessage;
+
+typedef enum {
+	EXCHANGE_FOLDER_REAL,
+	EXCHANGE_FOLDER_POST,
+	EXCHANGE_FOLDER_NOTES,
+	EXCHANGE_FOLDER_OTHER
+} ExchangeFolderType;
+
+typedef struct {
+	ExchangeData *ed;
+
+	EFolder *folder;
+	const gchar *name;
+	ExchangeFolderType type;
+	guint32 access;
+
+	GPtrArray *messages;
+	GHashTable *messages_by_uid, *messages_by_href;
+	guint32 seq, high_article_num, deleted_count;
+
+	guint32 unread_count;
+	gboolean scanned;
+
+	GPtrArray *changed_messages;
+	guint flag_timeout, pending_delete_ops;
+
+	time_t last_activity;
+	guint sync_deletion_timeout;
+} ExchangeFolder;
+
+static const gchar *mapi_message_props[] = {
+	E2K_PR_MAILHEADER_SUBJECT,
+	E2K_PR_MAILHEADER_FROM,
+	E2K_PR_MAILHEADER_TO,
+	E2K_PR_MAILHEADER_CC,
+	E2K_PR_MAILHEADER_DATE,
+	E2K_PR_MAILHEADER_RECEIVED,
+	E2K_PR_MAILHEADER_MESSAGE_ID,
+	E2K_PR_MAILHEADER_IN_REPLY_TO,
+	E2K_PR_MAILHEADER_REFERENCES,
+	E2K_PR_MAILHEADER_THREAD_INDEX,
+	E2K_PR_DAV_CONTENT_TYPE
+};
+
+static gboolean
+is_same_ed (CamelExchangeStore *estore, ExchangeAccount *eaccount, CamelService *service)
+{
+	g_return_val_if_fail (eaccount != NULL, FALSE);
+	g_return_val_if_fail (service != NULL, FALSE);
+	g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
+
+	if (CAMEL_IS_EXCHANGE_STORE (service) && estore && estore == CAMEL_EXCHANGE_STORE (service))
+		return TRUE;
+
+	if (service->url) {
+		if (estore && camel_url_equal (CAMEL_SERVICE (estore)->url, service->url))
+			return TRUE;
+
+		if (eaccount) {
+			EAccount *account = exchange_account_fetch (eaccount);
+
+			/* source url and transport url are same for exchange */
+			if (account && e_account_get_string (account, E_ACCOUNT_SOURCE_URL)) {
+				CamelURL *url = camel_url_new (e_account_get_string (account, E_ACCOUNT_SOURCE_URL), NULL);
+
+				if (url) {
+					CamelProvider *provider = camel_service_get_provider (service);
+
+					if ((provider && provider->url_equal && provider->url_equal (url, service->url))
+					    || camel_url_equal (url, service->url)) {
+						camel_url_free (url);
+						return TRUE;
+					}
+
+					camel_url_free (url);
+				}
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+static void free_folder (gpointer value);
+
+static ExchangeData *
+get_data_for_service (CamelService *service)
+{
+	static GSList *edies = NULL;
+	G_LOCK_DEFINE_STATIC (edies);
+
+	GSList *p, *accounts;
+	ExchangeData *res = NULL;
+
+	g_return_val_if_fail (service != NULL, NULL);
+	g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
+
+	G_LOCK (edies);
+	for (p = edies; p; p = p->next) {
+		ExchangeData *ed = p->data;
+
+		if (ed && is_same_ed (ed->estore, ed->account, service)) {
+			G_UNLOCK (edies);
+			return ed;
+		}
+	}
+
+	accounts = exchange_share_config_listener_get_accounts (exchange_share_config_listener_get_global ());
+	for (p = accounts; p; p = p->next) {
+		ExchangeAccount *a = p->data;
+
+		if (a && is_same_ed (NULL, a, service)) {
+			res = g_new0 (ExchangeData, 1);
+			res->account = a;
+			if (CAMEL_IS_EXCHANGE_STORE (service))
+				res->estore = CAMEL_EXCHANGE_STORE (service);
+			res->folders_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_folder);
+			g_static_rec_mutex_init (&res->changed_msgs_mutex);
+
+			edies = g_slist_prepend (edies, res);
+			break;
+		}
+	}
+
+	g_slist_free (accounts);
+
+	G_UNLOCK (edies);
+
+	return res;
+}
+
+static gint
+is_online (ExchangeData *ed)
+{
+	CamelSession *session;
+
+	g_return_val_if_fail (ed != NULL, OFFLINE_MODE);
+	g_return_val_if_fail (ed->estore != NULL, OFFLINE_MODE);
+
+	session = camel_service_get_session (CAMEL_SERVICE (ed->estore));
+	g_return_val_if_fail (session != NULL, OFFLINE_MODE);
+
+	return camel_session_is_online (session) ? ONLINE_MODE : OFFLINE_MODE;
+}
+
+static void
+set_exception (CamelException *ex, const gchar *err)
+{
+	g_return_if_fail (err != NULL);
+
+	if (ex && !camel_exception_is_set (ex))
+		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, err);
+}
+
+static CamelFolder *
+get_camel_folder (ExchangeFolder *mfld)
+{
+	CamelFolder *folder;
+
+	g_return_val_if_fail (mfld != NULL, NULL);
+	g_return_val_if_fail (mfld->name != NULL, NULL);
+	g_return_val_if_fail (mfld->ed != NULL, NULL);
+	g_return_val_if_fail (mfld->ed->estore != NULL, NULL);
+	g_return_val_if_fail (mfld->ed->estore->folders != NULL, NULL);
+
+	g_mutex_lock (mfld->ed->estore->folders_lock);
+	folder = g_hash_table_lookup (mfld->ed->estore->folders, mfld->name);
+	g_mutex_unlock (mfld->ed->estore->folders_lock);
+
+	return folder;
+}
+
+static void
+folder_changed (ExchangeFolder *mfld)
+{
+	e_folder_set_unread_count (mfld->folder, mfld->unread_count);
+}
+
+static gint
+find_message_index (ExchangeFolder *mfld, gint seq)
+{
+	ExchangeMessage *mmsg;
+	gint low, high, mid;
+
+	low = 0;
+	high = mfld->messages->len - 1;
+
+	while (low <= high) {
+		mid = (low + high) / 2;
+		mmsg = mfld->messages->pdata[mid];
+		if (seq == mmsg->seq)
+			return mid;
+		else if (seq < mmsg->seq)
+			high = mid - 1;
+		else
+			low = mid + 1;
+	}
+
+	return -1;
+}
+
+static inline ExchangeMessage *
+find_message (ExchangeFolder *mfld, const gchar *uid)
+{
+	return g_hash_table_lookup (mfld->messages_by_uid, uid);
+}
+
+static inline ExchangeMessage *
+find_message_by_href (ExchangeFolder *mfld, const gchar *href)
+{
+	return g_hash_table_lookup (mfld->messages_by_href, href);
+}
+
+static ExchangeMessage *
+new_message (const gchar *uid, const gchar *uri, guint32 seq, guint32 flags)
+{
+	ExchangeMessage *mmsg;
+
+	mmsg = g_new0 (ExchangeMessage, 1);
+	mmsg->uid = g_strdup (uid);
+	mmsg->href = g_strdup (uri);
+	mmsg->seq = seq;
+	mmsg->flags = flags;
+
+	return mmsg;
+}
+
+static void
+message_remove_at_index (ExchangeFolder *mfld, CamelFolder *folder, gint index)
+{
+	ExchangeMessage *mmsg;
+	CamelMessageInfo *info;
+
+	mmsg = mfld->messages->pdata[index];
+	d(printf("Deleting mmsg %p\n", mmsg));
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+	g_ptr_array_remove_index (mfld->messages, index);
+	g_hash_table_remove (mfld->messages_by_uid, mmsg->uid);
+	if (mmsg->href)
+		g_hash_table_remove (mfld->messages_by_href, mmsg->href);
+	if (!(mmsg->flags & CAMEL_MESSAGE_SEEN)) {
+		mfld->unread_count--;
+		folder_changed (mfld);
+	}
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+
+	if (mmsg->change_mask || mmsg->tag_updates) {
+		gint i;
+
+		g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+
+		for (i = 0; i < mfld->changed_messages->len; i++) {
+			if (mfld->changed_messages->pdata[i] == (gpointer)mmsg) {
+				g_ptr_array_remove_index_fast (mfld->changed_messages, i);
+				break;
+			}
+		}
+		g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+
+		g_datalist_clear (&mmsg->tag_updates);
+	}
+
+	if (folder && (info = camel_folder_summary_uid (folder->summary, mmsg->uid))) {
+		camel_message_info_free (info);
+		camel_exchange_folder_remove_message (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid);
+	}
+
+	g_free (mmsg->uid);
+	g_free (mmsg->href);
+	g_free (mmsg);
+}
+
+static void
+message_removed (ExchangeFolder *mfld, CamelFolder *folder, const gchar *href)
+{
+	ExchangeMessage *mmsg;
+	guint index;
+
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+	mmsg = g_hash_table_lookup (mfld->messages_by_href, href);
+	if (!mmsg) {
+		g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+		return;
+	}
+	index = find_message_index (mfld, mmsg->seq);
+	g_return_if_fail (index != -1);
+
+	message_remove_at_index (mfld, folder, index);
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+}
+
+static const gchar *
+uidstrip (const gchar *repl_uid)
+{
+	/* The first two cases are just to prevent crashes in the face
+	 * of extreme lossage. They shouldn't ever happen, and the
+	 * rest of the code probably won't work right if they do.
+	 */
+	if (strncmp (repl_uid, "rid:", 4))
+		return repl_uid;
+	else if (strlen (repl_uid) < 36)
+		return repl_uid;
+	else
+		return repl_uid + 36;
+}
+
+struct refresh_message {
+	gchar *uid, *href, *headers, *fff, *reply_by, *completed;
+	guint32 flags, size, article_num;
+};
+
+static gint
+refresh_message_compar (gconstpointer a, gconstpointer b)
+{
+	const struct refresh_message *rma = a, *rmb = b;
+
+	return strcmp (rma->uid, rmb->uid);
+}
+
+static void
+change_flags (ExchangeFolder *mfld, CamelFolder *folder, ExchangeMessage *mmsg, guint32 new_flags)
+{
+	if ((mmsg->flags ^ new_flags) & CAMEL_MESSAGE_SEEN) {
+		if (mmsg->flags & CAMEL_MESSAGE_SEEN)
+			mfld->unread_count++;
+		else
+			mfld->unread_count--;
+		folder_changed (mfld);
+	}
+	mmsg->flags = new_flags;
+
+	if (folder)
+		camel_exchange_folder_update_message_flags (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, mmsg->flags);
+}
+
+static void
+refresh_folder_internal (ExchangeFolder *mfld, CamelException *ex)
+{
+	static const gchar *new_message_props[] = {
+		E2K_PR_REPL_UID,
+		PR_INTERNET_ARTICLE_NUMBER,
+		PR_TRANSPORT_MESSAGE_HEADERS,
+		E2K_PR_HTTPMAIL_READ,
+		E2K_PR_HTTPMAIL_HAS_ATTACHMENT,
+		PR_ACTION_FLAG,
+		PR_IMPORTANCE,
+		PR_DELEGATED_BY_RULE,
+		E2K_PR_HTTPMAIL_MESSAGE_FLAG,
+		E2K_PR_MAILHEADER_REPLY_BY,
+		E2K_PR_MAILHEADER_COMPLETED,
+		E2K_PR_DAV_CONTENT_LENGTH
+	};
+
+	E2kRestriction *rn;
+	GArray *messages;
+	GHashTable *mapi_message_hash;
+	GPtrArray *mapi_hrefs;
+	gboolean has_read_flag = (mfld->access & MAPI_ACCESS_READ);
+	E2kResultIter *iter;
+	E2kResult *result;
+	gchar *prop, *uid, *href;
+	struct refresh_message rm, *rmp;
+	E2kHTTPStatus status;
+	gint got, total, i, n;
+	gpointer key, value;
+	ExchangeMessage *mmsg;
+	CamelFolder *folder;
+
+	if (is_online (mfld->ed) != ONLINE_MODE) {
+		return;
+	}
+
+	messages = g_array_new (FALSE, FALSE, sizeof (struct refresh_message));
+	mapi_message_hash = g_hash_table_new (g_str_hash, g_str_equal);
+	mapi_hrefs = g_ptr_array_new ();
+
+	/*
+	 * STEP 1: Fetch information about new messages, including SMTP
+	 * headers when available.
+	 */
+
+	rn = e2k_restriction_andv (
+		e2k_restriction_prop_bool (E2K_PR_DAV_IS_COLLECTION,
+					   E2K_RELOP_EQ, FALSE),
+		e2k_restriction_prop_bool (E2K_PR_DAV_IS_HIDDEN,
+					   E2K_RELOP_EQ, FALSE),
+		e2k_restriction_prop_int (PR_INTERNET_ARTICLE_NUMBER,
+					  E2K_RELOP_GT,
+					  mfld->high_article_num),
+		NULL);
+	iter = e_folder_exchange_search_start (mfld->folder, NULL,
+					       new_message_props,
+					       G_N_ELEMENTS (new_message_props),
+					       rn, NULL, TRUE);
+	e2k_restriction_unref (rn);
+
+	got = 0;
+	total = e2k_result_iter_get_total (iter);
+	while ((result = e2k_result_iter_next (iter))) {
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (result->status)) {
+			g_message ("%s: got unsuccessful at %s (%s)", G_STRFUNC, mfld->name, result->href ? result->href : "[null]");
+			continue;
+		}
+
+		uid = e2k_properties_get_prop (result->props, E2K_PR_REPL_UID);
+		if (!uid)
+			continue;
+		prop = e2k_properties_get_prop (result->props,
+						PR_INTERNET_ARTICLE_NUMBER);
+		if (!prop)
+			continue;
+
+		rm.uid = g_strdup (uidstrip (uid));
+		rm.href = g_strdup (result->href);
+		rm.article_num = strtoul (prop, NULL, 10);
+
+		rm.flags = mail_util_props_to_camel_flags (result->props,
+							   has_read_flag);
+
+		prop = e2k_properties_get_prop (result->props,
+						E2K_PR_HTTPMAIL_MESSAGE_FLAG);
+		if (prop)
+			rm.fff = g_strdup (prop);
+		else
+			rm.fff = NULL;
+		prop = e2k_properties_get_prop (result->props,
+						E2K_PR_MAILHEADER_REPLY_BY);
+		if (prop)
+			rm.reply_by = g_strdup (prop);
+		else
+			rm.reply_by = NULL;
+		prop = e2k_properties_get_prop (result->props,
+						E2K_PR_MAILHEADER_COMPLETED);
+		if (prop)
+			rm.completed = g_strdup (prop);
+		else
+			rm.completed = NULL;
+
+		prop = e2k_properties_get_prop (result->props,
+						E2K_PR_DAV_CONTENT_LENGTH);
+		rm.size = prop ? strtoul (prop, NULL, 10) : 0;
+
+		rm.headers = mail_util_extract_transport_headers (result->props);
+
+		g_array_append_val (messages, rm);
+
+		if (rm.headers) {
+			got++;
+			camel_operation_progress (NULL, (got * 100) / total);
+		} else {
+			href = strrchr (rm.href, '/');
+			if (!href++)
+				href = rm.href;
+
+			g_hash_table_insert (mapi_message_hash, href,
+					     GINT_TO_POINTER (messages->len - 1));
+			g_ptr_array_add (mapi_hrefs, href);
+		}
+	}
+	status = e2k_result_iter_free (iter);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		g_warning ("got_new_smtp_messages: %d", status);
+		set_exception (ex, _("Could not get new messages"));
+		goto done;
+	}
+
+	if (mapi_hrefs->len == 0)
+		goto return_data;
+
+	/*
+	 * STEP 2: Fetch MAPI property data for non-SMTP messages.
+	 */
+
+	iter = e_folder_exchange_bpropfind_start (mfld->folder, NULL,
+						  (const gchar **)mapi_hrefs->pdata,
+						  mapi_hrefs->len,
+						  mapi_message_props,
+						  G_N_ELEMENTS (mapi_message_props));
+	while ((result = e2k_result_iter_next (iter))) {
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (result->status))
+			continue;
+
+		href = strrchr (result->href, '/');
+		if (!href++)
+			href = result->href;
+
+		if (!g_hash_table_lookup_extended (mapi_message_hash, href,
+						   &key, &value))
+			continue;
+		n = GPOINTER_TO_INT (value);
+
+		rmp = &((struct refresh_message *)messages->data)[n];
+		rmp->headers = mail_util_mapi_to_smtp_headers (result->props);
+
+		got++;
+		camel_operation_progress (NULL, (got * 100) / total);
+	}
+	status = e2k_result_iter_free (iter);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		g_warning ("got_new_mapi_messages: %d", status);
+		set_exception (ex, _("Could not get new messages"));
+		goto done;
+	}
+
+	/*
+	 * STEP 3: Organize the data, update our records and Camel's
+	 */
+
+ return_data:
+	camel_operation_progress (NULL, 100);
+	folder = get_camel_folder (mfld);
+	if (folder)
+		camel_folder_freeze (folder);
+
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+	qsort (messages->data, messages->len,
+	       sizeof (rm), refresh_message_compar);
+	for (i = 0; i < messages->len; i++) {
+		rm = g_array_index (messages, struct refresh_message, i);
+
+		/* If we already have a message with this UID, then
+		 * that means it's not a new message, it's just that
+		 * the article number changed.
+		 */
+		mmsg = find_message (mfld, rm.uid);
+		if (mmsg) {
+			if (rm.flags != mmsg->flags)
+				change_flags (mfld, folder, mmsg, rm.flags);
+		} else {
+			if (g_hash_table_lookup (mfld->messages_by_href, rm.href)) {
+				mfld->deleted_count++;
+				message_removed (mfld, folder, rm.href);
+			}
+
+			mmsg = new_message (rm.uid, rm.href, mfld->seq++, rm.flags);
+			g_ptr_array_add (mfld->messages, mmsg);
+			g_hash_table_insert (mfld->messages_by_uid, mmsg->uid, mmsg);
+			g_hash_table_insert (mfld->messages_by_href, mmsg->href, mmsg);
+
+			if (!(mmsg->flags & CAMEL_MESSAGE_SEEN))
+				mfld->unread_count++;
+
+			if (folder)
+				camel_exchange_folder_add_message (CAMEL_EXCHANGE_FOLDER (folder), rm.uid, rm.flags, rm.size, rm.headers, rm.href);
+		}
+
+		if (rm.article_num > mfld->high_article_num) {
+			mfld->high_article_num = rm.article_num;
+			if (folder)
+				camel_exchange_summary_set_article_num (folder->summary, mfld->high_article_num);
+		}
+
+		if (rm.fff && folder)
+			camel_exchange_folder_update_message_tag (CAMEL_EXCHANGE_FOLDER (folder), rm.uid, "follow-up", rm.fff);
+		if (rm.reply_by && folder)
+			camel_exchange_folder_update_message_tag (CAMEL_EXCHANGE_FOLDER (folder), rm.uid, "due-by", rm.reply_by);
+		if (rm.completed && folder)
+			camel_exchange_folder_update_message_tag (CAMEL_EXCHANGE_FOLDER (folder), rm.uid, "completed-on", rm.completed);
+	}
+
+	if (folder)
+		camel_folder_thaw (folder);
+
+	mfld->scanned = TRUE;
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+	folder_changed (mfld);
+
+ done:
+	/*
+	 * CLEANUP
+	 */
+	rmp = (struct refresh_message *)messages->data;
+	for (i = 0; i < messages->len; i++) {
+		g_free (rmp[i].uid);
+		g_free (rmp[i].href);
+		g_free (rmp[i].headers);
+		g_free (rmp[i].fff);
+		g_free (rmp[i].reply_by);
+		g_free (rmp[i].completed);
+	}
+	g_array_free (messages, TRUE);
+
+	g_hash_table_destroy (mapi_message_hash);
+	g_ptr_array_free (mapi_hrefs, TRUE);
+}
+
+static void
+sync_deletions (ExchangeFolder *mfld)
+{
+	static const gchar *sync_deleted_props[] = {
+		PR_DELETED_COUNT_TOTAL,
+		E2K_PR_DAV_VISIBLE_COUNT
+	};
+
+	E2kHTTPStatus status;
+	E2kResult *results;
+	gint nresults = 0;
+	const gchar *prop;
+	gint deleted_count = -1, visible_count = -1;
+	E2kRestriction *rn;
+	E2kResultIter *iter;
+	E2kResult *result;
+	gint my_i, read;
+	ExchangeMessage *mmsg;
+	GHashTable *known_messages;
+	CamelFolder *folder;
+
+	g_return_if_fail (mfld != NULL);
+	g_return_if_fail (mfld->ed != NULL);
+
+	if (is_online (mfld->ed) != ONLINE_MODE)
+		return;
+
+	status = e_folder_exchange_propfind (mfld->folder, NULL,
+					     sync_deleted_props,
+					     G_N_ELEMENTS (sync_deleted_props),
+					     &results, &nresults);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status) || !nresults) {
+		g_warning ("got_sync_deleted_props: %d", status);
+		return;
+	}
+
+	prop = e2k_properties_get_prop (results[0].props,
+					PR_DELETED_COUNT_TOTAL);
+	if (prop)
+		deleted_count = atoi (prop);
+
+	prop = e2k_properties_get_prop (results[0].props,
+					E2K_PR_DAV_VISIBLE_COUNT);
+	if (prop)
+		visible_count = atoi (prop);
+
+	e2k_results_free (results, nresults);
+
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+	if (visible_count >= mfld->messages->len) {
+		if (mfld->deleted_count == deleted_count) {
+			g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+			return;
+		}
+
+		if (mfld->deleted_count == 0) {
+			mfld->deleted_count = deleted_count;
+			g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+			return;
+		}
+	}
+
+	prop = E2K_PR_HTTPMAIL_READ;
+	rn = e2k_restriction_andv (
+		e2k_restriction_prop_bool (E2K_PR_DAV_IS_COLLECTION,
+					   E2K_RELOP_EQ, FALSE),
+		e2k_restriction_prop_bool (E2K_PR_DAV_IS_HIDDEN,
+					   E2K_RELOP_EQ, FALSE),
+		NULL);
+
+	iter = e_folder_exchange_search_start (mfld->folder, NULL,
+					       &prop, 1, rn,
+					       E2K_PR_DAV_CREATION_DATE,
+					       FALSE);
+	e2k_restriction_unref (rn);
+
+	known_messages = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	folder = get_camel_folder (mfld);
+
+	my_i = mfld->messages->len - 1;
+	while ((result = e2k_result_iter_next (iter))) {
+		mmsg = find_message_by_href (mfld, result->href);
+		if (!mmsg) {
+			/* oops, message from the server not found in our list;
+			   return failure to possibly do full resync again? */
+			g_message ("%s: Oops, message %s not found in %s", G_STRFUNC, result->href, mfld->name);
+			continue;
+		}
+
+		g_hash_table_insert (known_messages, mmsg, mmsg);
+
+		/* See if its read flag changed while we weren't watching */
+		prop = e2k_properties_get_prop (result->props,
+						E2K_PR_HTTPMAIL_READ);
+		read = (prop && atoi (prop)) ? CAMEL_MESSAGE_SEEN : 0;
+		if ((mmsg->flags & CAMEL_MESSAGE_SEEN) != read) {
+			change_flags (mfld, folder, mmsg, mmsg->flags ^ CAMEL_MESSAGE_SEEN);
+		}
+
+	}
+	status = e2k_result_iter_free (iter);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+		g_warning ("synced_deleted: %d", status);
+
+	/* Clear out removed messages from mfld */
+	for (my_i = mfld->messages->len - 1; my_i >= 0; my_i --) {
+		mmsg = mfld->messages->pdata[my_i];
+		if (!g_hash_table_lookup (known_messages, mmsg)) {
+			mfld->deleted_count++;
+			message_remove_at_index (mfld, folder, my_i);
+		}
+	}
+
+	g_hash_table_destroy (known_messages);
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+}
+
+static void
+storage_folder_changed (EFolder *folder, gpointer user_data)
+{
+	ExchangeFolder *mfld = user_data;
+
+	if (e_folder_get_unread_count (folder) > mfld->unread_count)
+		refresh_folder_internal (mfld, NULL);
+}
+
+static void
+free_message (ExchangeMessage *mmsg)
+{
+	g_datalist_clear (&mmsg->tag_updates);
+	g_free (mmsg->uid);
+	g_free (mmsg->href);
+	g_free (mmsg);
+}
+
+static void
+free_folder (gpointer value)
+{
+	ExchangeFolder *mfld = value;
+	gint i;
+
+	d(g_print ("%s:%s:%d: freeing mfld: name=[%s]\n", __FILE__, __PRETTY_FUNCTION__, __LINE__,
+		   mfld->name));
+
+	e_folder_exchange_unsubscribe (mfld->folder);
+	g_signal_handlers_disconnect_by_func (mfld->folder, storage_folder_changed, mfld);
+	g_object_unref (mfld->folder);
+	mfld->folder = NULL;
+
+	for (i = 0; i < mfld->messages->len; i++)
+		free_message (mfld->messages->pdata[i]);
+	g_ptr_array_free (mfld->messages, TRUE);
+	g_hash_table_destroy (mfld->messages_by_uid);
+	g_hash_table_destroy (mfld->messages_by_href);
+
+	g_ptr_array_free (mfld->changed_messages, TRUE);
+	if (mfld->flag_timeout) {
+		g_warning ("unreffing mfld with unsynced flags");
+		g_source_remove (mfld->flag_timeout);
+	}
+	if (mfld->sync_deletion_timeout)
+		g_source_remove (mfld->sync_deletion_timeout);
+	g_free (mfld);
+}
+
+static void
+got_folder_error (ExchangeFolder *mfld, CamelException *ex, const gchar *err)
+{
+	set_exception (ex, err);
+
+	free_folder (mfld);
+}
+
+static void
+mfld_get_folder_online_sync_updates (gpointer key, gpointer value, gpointer user_data)
+{
+	guint index, seq, i;
+	ExchangeFolder *mfld = (ExchangeFolder *) user_data;
+	ExchangeMessage *mmsg = NULL;
+
+	index = GPOINTER_TO_UINT (key);
+	seq = GPOINTER_TO_UINT (value);
+
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+
+	/* Camel DB Summary changes are not fetching all the messages at start-up.
+	   Use this else it would crash badly.
+	*/
+	if (index >= mfld->messages->len) {
+		g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+		return;
+	}
+
+	mmsg = mfld->messages->pdata[index];
+	if (mmsg->seq != seq) {
+		for (i = 0; i < mfld->messages->len; i++) {
+			mmsg = mfld->messages->pdata[i];
+			if (mmsg->seq == seq)
+				break;
+		}
+		seq = i;
+	}
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+
+	/* FIXME FIXME FIXME: Some miscalculation happens here,though,
+	not a serious one
+	*/
+	/* message_remove_at_index already handles lock/unlock */
+	/*message_remove_at_index (stub, mfld, seq);*/
+
+}
+
+static gboolean
+get_folder_contents_online (ExchangeFolder *mfld, CamelException *ex)
+{
+	static const gchar *open_folder_sync_props[] = {
+		E2K_PR_REPL_UID,
+		PR_INTERNET_ARTICLE_NUMBER,
+		PR_ACTION_FLAG,
+		PR_IMPORTANCE,
+		PR_DELEGATED_BY_RULE,
+		E2K_PR_HTTPMAIL_READ,
+		E2K_PR_HTTPMAIL_MESSAGE_FLAG,
+		E2K_PR_MAILHEADER_REPLY_BY,
+		E2K_PR_MAILHEADER_COMPLETED
+	};
+
+	ExchangeMessage *mmsg, *mmsg_cpy;
+	E2kHTTPStatus status;
+	gboolean readonly = FALSE;
+	E2kRestriction *rn;
+	E2kResultIter *iter;
+	E2kResult *result;
+	const gchar *prop, *uid;
+	guint32 article_num, camel_flags, high_article_num;
+	gint i, total = -1;
+	guint m;
+	CamelFolder *folder;
+
+	GPtrArray *msgs_copy = NULL;
+	GHashTable *rm_idx_uid = NULL;
+
+	/* Make a copy of the mfld->messages array for our processing */
+	msgs_copy = g_ptr_array_new ();
+
+	/* Store the index/seq of the messages to be removed from mfld->messages */
+	rm_idx_uid = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+	for (i = 0; i < mfld->messages->len; i++) {
+		mmsg = mfld->messages->pdata[i];
+		mmsg_cpy = new_message (mmsg->uid, mmsg->href, mmsg->seq, mmsg->flags);
+		g_ptr_array_add (msgs_copy, mmsg_cpy);
+	}
+	high_article_num = 0;
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+
+	rn = e2k_restriction_andv (
+		e2k_restriction_prop_bool (E2K_PR_DAV_IS_COLLECTION,
+					   E2K_RELOP_EQ, FALSE),
+		e2k_restriction_prop_bool (E2K_PR_DAV_IS_HIDDEN,
+					   E2K_RELOP_EQ, FALSE),
+		NULL);
+
+	iter = e_folder_exchange_search_start (mfld->folder, NULL,
+					       open_folder_sync_props,
+					       G_N_ELEMENTS (open_folder_sync_props),
+					       rn, E2K_PR_DAV_CREATION_DATE,
+					       TRUE);
+	e2k_restriction_unref (rn);
+
+	folder = get_camel_folder (mfld);
+
+	m = 0;
+	total = e2k_result_iter_get_total (iter);
+	while (m < msgs_copy->len && (result = e2k_result_iter_next (iter))) {
+		prop = e2k_properties_get_prop (result->props,
+						PR_INTERNET_ARTICLE_NUMBER);
+		if (!prop)
+			continue;
+		article_num = strtoul (prop, NULL, 10);
+
+		prop = e2k_properties_get_prop (result->props,
+						E2K_PR_REPL_UID);
+		if (!prop)
+			continue;
+		uid = uidstrip (prop);
+
+		camel_flags = mail_util_props_to_camel_flags (result->props,
+							      !readonly);
+
+		mmsg_cpy = msgs_copy->pdata[m];
+		while (strcmp (uid, mmsg_cpy->uid)) {
+			/* Remove mmsg from our msgs_copy array */
+			g_ptr_array_remove_index (msgs_copy, m);
+
+			/* Put the index/uid as key/value in the rm_idx_uid hashtable.
+			   This hashtable will be used to sync with mfld->messages.
+			 */
+			g_hash_table_insert (rm_idx_uid, GUINT_TO_POINTER(m),
+					     GUINT_TO_POINTER(mmsg_cpy->seq));
+			g_free (mmsg_cpy->uid);
+			g_free (mmsg_cpy->href);
+			g_free (mmsg_cpy);
+
+			if (m == msgs_copy->len) {
+				mmsg_cpy = NULL;
+				if (article_num < high_article_num)
+					high_article_num = article_num - 1;
+				break;
+			}
+			mmsg_cpy = msgs_copy->pdata[m];
+		}
+		if (!mmsg_cpy)
+			break;
+
+		if (article_num > high_article_num)
+			high_article_num = article_num;
+
+		g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+		mmsg = mfld->messages->pdata[m];
+
+		/* Validate mmsg == mmsg_cpy - this may fail if user has deleted some messages,
+		   while we were updating in a separate thread.
+		*/
+		if (mmsg->seq != mmsg_cpy->seq) {
+			/* We don't want to scan all of mfld->messages, as some new messages
+			   would have got added to the array and hence restrict to the original
+			   array of messages that we loaded from summary.
+			*/
+			for (i = 0; i < msgs_copy->len; i++) {
+				mmsg = mfld->messages->pdata[i];
+				if (mmsg->seq == mmsg_cpy->seq)
+					break;
+			}
+		}
+
+		if (!mmsg->href) {
+			mmsg->href = g_strdup (result->href);
+			if (mmsg_cpy->href)
+				g_free (mmsg_cpy->href);
+			mmsg_cpy->href = g_strdup (result->href);
+			/* Do not allow duplicates */
+			if (!g_hash_table_lookup (mfld->messages_by_href, mmsg->href))
+				g_hash_table_insert (mfld->messages_by_href, mmsg->href, mmsg);
+		}
+
+		if (mmsg->flags != camel_flags)
+			change_flags (mfld, folder, mmsg, camel_flags);
+
+		g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+
+		if (article_num > high_article_num)
+			high_article_num = article_num;
+
+		prop = e2k_properties_get_prop (result->props, E2K_PR_HTTPMAIL_MESSAGE_FLAG);
+		if (prop && folder)
+			camel_exchange_folder_update_message_tag (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, "follow-up", prop);
+		prop = e2k_properties_get_prop (result->props, E2K_PR_MAILHEADER_REPLY_BY);
+		if (prop && folder)
+			camel_exchange_folder_update_message_tag (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, "due-by", prop);
+		prop = e2k_properties_get_prop (result->props, E2K_PR_MAILHEADER_COMPLETED);
+		if (prop && folder)
+			camel_exchange_folder_update_message_tag (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, "completed-on", prop);
+
+		m++;
+#if 0
+		if (ex) {
+			camel_operation_progress (NULL, (m * 100) / total);
+		}
+#endif
+	}
+
+	/* If there are further messages beyond mfld->messages->len,
+	 * then that means camel doesn't know about them yet, and so
+	 * we need to ignore them for a while. But if any of them have
+	 * an article number lower than the highest article number
+	 * we've seen, bump high_article_num down so that that message
+	 * gets caught by refresh_info later too.
+	 */
+	while ((result = e2k_result_iter_next (iter))) {
+		prop = e2k_properties_get_prop (result->props,
+						PR_INTERNET_ARTICLE_NUMBER);
+		if (prop) {
+			article_num = strtoul (prop, NULL, 10);
+			if (article_num <= high_article_num)
+				high_article_num = article_num - 1;
+		}
+
+		m++;
+#if 0
+		if (ex) {
+			camel_operation_progress (NULL, (m * 100) / total);
+		}
+#endif
+	}
+	status = e2k_result_iter_free (iter);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		g_warning ("got_folder: %d", status);
+		got_folder_error (mfld, ex, _("Could not open folder"));
+		return FALSE;
+	}
+
+	/* Discard remaining messages that no longer exist.
+	   Do not increment 'i', because the remove_index is decrementing array length. */
+	for (i = 0; i < msgs_copy->len;) {
+		mmsg_cpy = msgs_copy->pdata[i];
+		if (!mmsg_cpy->href) {
+			/* Put the index/uid as key/value in the rm_idx_uid hashtable.
+			   This hashtable will be used to sync with mfld->messages.
+			 */
+			g_hash_table_insert (rm_idx_uid, GUINT_TO_POINTER(m),
+					     GUINT_TO_POINTER(mmsg_cpy->seq));
+		}
+
+		/* Remove mmsg from our msgs_copy array */
+		g_ptr_array_remove_index (msgs_copy, i);
+
+		g_free (mmsg_cpy->uid);
+		g_free (mmsg_cpy->href);
+		g_free (mmsg_cpy);
+	}
+
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+	mfld->high_article_num = high_article_num;
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+
+	if (folder)
+		camel_exchange_summary_set_article_num (folder->summary, mfld->high_article_num);
+
+	g_hash_table_foreach (rm_idx_uid, mfld_get_folder_online_sync_updates, mfld);
+
+	g_ptr_array_free (msgs_copy, TRUE);
+	g_hash_table_destroy (rm_idx_uid);
+
+	return TRUE;
+}
+
+static gpointer
+get_folder_contents_online_func (gpointer data)
+{
+	ExchangeFolder *mfld = data;
+
+	if (!mfld)
+		return NULL;
+
+	get_folder_contents_online (mfld, NULL);
+
+	return NULL;
+}
+
+#define FIVE_SECONDS (5)
+#define  ONE_MINUTE  (60)
+#define FIVE_MINUTES (60*5)
+
+static gboolean
+timeout_sync_deletions (gpointer user_data)
+{
+	ExchangeFolder *mfld = user_data;
+
+	sync_deletions (mfld);
+	return FALSE;
+}
+
+static void
+notify_cb (E2kContext *ctx, const gchar *uri, E2kContextChangeType type, gpointer user_data)
+{
+	ExchangeFolder *mfld = user_data;
+	time_t now;
+
+	if (type == E2K_CONTEXT_OBJECT_ADDED)
+		refresh_folder_internal (mfld, NULL);
+	else {
+		now = time (NULL);
+
+		/* If the user did something in Evolution in the
+		 * last 5 seconds, assume that this notification is
+		 * a result of that and ignore it.
+		 */
+		if (now < mfld->last_activity + FIVE_SECONDS)
+			return;
+
+		/* sync_deletions() is somewhat server-intensive, so
+		 * we don't want to run it unnecessarily. In
+		 * particular, if the user leaves Evolution running,
+		 * goes home for the night, and then reads mail from
+		 * home, we don't want to run sync_deletions() every
+		 * time the user deletes a message; we just need to
+		 * make sure we do it by the time the user gets back
+		 * in the morning. On the other hand, if the user just
+		 * switches to Outlook for just a moment and then
+		 * comes back, we'd like to update fairly quickly.
+		 *
+		 * So, if the user has been idle for less than a
+		 * minute, we update right away. Otherwise, we set a
+		 * timer, and keep resetting it with each new
+		 * notification, meaning we (hopefully) only sync
+		 * after the user stops changing things.
+		 *
+		 * If the user returns to Evolution while we have a
+		 * timer set, then folder_from_name() will immediately
+		 * call sync_deletions.
+		 */
+
+		if (mfld->sync_deletion_timeout) {
+			g_source_remove (mfld->sync_deletion_timeout);
+			mfld->sync_deletion_timeout = 0;
+		}
+
+		if (now < mfld->last_activity + ONE_MINUTE)
+			sync_deletions (mfld);
+		else if (now < mfld->last_activity + FIVE_MINUTES) {
+			mfld->sync_deletion_timeout =
+				g_timeout_add (ONE_MINUTE * 1000,
+					       timeout_sync_deletions,
+					       mfld);
+		} else {
+			mfld->sync_deletion_timeout =
+				g_timeout_add (FIVE_MINUTES * 1000,
+					       timeout_sync_deletions,
+					       mfld);
+		}
+	}
+}
+
+static gboolean
+get_folder_online (ExchangeFolder *mfld, CamelException *ex)
+{
+	static const gchar *open_folder_props[] = {
+		PR_ACCESS,
+		PR_DELETED_COUNT_TOTAL
+	};
+
+	E2kHTTPStatus status;
+	E2kResult *results;
+	gint nresults = 0;
+	gboolean readonly;
+	const gchar *prop;
+
+	mfld->changed_messages = g_ptr_array_new ();
+
+	status = e_folder_exchange_propfind (mfld->folder, NULL,
+					     open_folder_props,
+					     G_N_ELEMENTS (open_folder_props),
+					     &results, &nresults);
+	if (status == E2K_HTTP_UNAUTHORIZED) {
+		got_folder_error (mfld, ex, _("Could not open folder: Permission denied"));
+		return FALSE;
+	} else if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		g_warning ("got_folder_props: %d", status);
+		got_folder_error (mfld, ex, _("Could not open folder"));
+		return FALSE;
+	}
+
+	if (nresults) {
+		prop = e2k_properties_get_prop (results[0].props, PR_ACCESS);
+		if (prop)
+			mfld->access = atoi (prop);
+		else
+			mfld->access = ~0;
+	} else
+		mfld->access = ~0;
+
+	if (!(mfld->access & MAPI_ACCESS_READ)) {
+		got_folder_error (mfld, ex, _("Could not open folder: Permission denied"));
+		if (nresults)
+			e2k_results_free (results, nresults);
+		return FALSE;
+	}
+	readonly = (mfld->access & (MAPI_ACCESS_MODIFY | MAPI_ACCESS_CREATE_CONTENTS)) == 0;
+
+	prop = e2k_properties_get_prop (results[0].props, PR_DELETED_COUNT_TOTAL);
+	if (prop)
+		mfld->deleted_count = atoi (prop);
+
+	/*
+	   TODO: Varadhan - June 16, 2007 - Compare deleted_count with
+	   that of CamelFolder and appropriately sync mfld->messages.
+	   Also, sync flags and camel_flags of all messages - No reliable
+	   way to fetch only changed messages as Read/UnRead flags do not
+	   change the PR_LAST_MODIFICATION_TIME property of a message.
+	*/
+	if (g_hash_table_size (mfld->messages_by_href) < 1) {
+		if (!get_folder_contents_online (mfld, ex))
+			return FALSE;
+	} else {
+		/* FIXME: Pass a GError and handle the error */
+		g_thread_create (get_folder_contents_online_func,
+				 mfld, FALSE, NULL);
+	}
+
+	e_folder_exchange_subscribe (mfld->folder,
+				     E2K_CONTEXT_OBJECT_ADDED, 30,
+				     notify_cb, mfld);
+	e_folder_exchange_subscribe (mfld->folder,
+				     E2K_CONTEXT_OBJECT_REMOVED, 30,
+				     notify_cb, mfld);
+	e_folder_exchange_subscribe (mfld->folder,
+				     E2K_CONTEXT_OBJECT_MOVED, 30,
+				     notify_cb, mfld);
+	if (nresults)
+		e2k_results_free (results, nresults);
+
+	return TRUE;
+}
+
+static ExchangeFolder *
+folder_from_name (ExchangeData *ed, const gchar *folder_name, guint32 perms, CamelException *ex)
+{
+	ExchangeFolder *mfld;
+
+	mfld = g_hash_table_lookup (ed->folders_by_name, folder_name);
+	if (!mfld) {
+		set_exception (ex, _("No such folder"));
+		return NULL;
+	}
+
+	/* If sync_deletion_timeout is set, that means the user has been
+	 * idle in Evolution for longer than a minute, during which
+	 * time he has deleted messages using another email client,
+	 * which we haven't bothered to sync up with yet. Do that now.
+	 */
+	if (mfld->sync_deletion_timeout) {
+		g_source_remove (mfld->sync_deletion_timeout);
+		mfld->sync_deletion_timeout = 0;
+		sync_deletions (mfld);
+	}
+
+	if ((perms == MAPI_ACCESS_MODIFY || perms == MAPI_ACCESS_DELETE) &&
+	    !(mfld->access & perms)) {
+		/* try with MAPI_ACCESS_CREATE_CONTENTS */
+		perms = MAPI_ACCESS_CREATE_CONTENTS;
+	}
+
+	if (perms && !(mfld->access & perms)) {
+		set_exception (ex, _("Permission denied"));
+		return NULL;
+	}
+
+	mfld->last_activity = time (NULL);
+	return mfld;
+}
+
+static void
+mark_one_read (E2kContext *ctx, const gchar *uri, gboolean read)
+{
+	E2kProperties *props;
+	E2kHTTPStatus status;
+
+	props = e2k_properties_new ();
+	e2k_properties_set_bool (props, E2K_PR_HTTPMAIL_READ, read);
+
+	status = e2k_context_proppatch (ctx, NULL, uri, props, FALSE, NULL);
+	e2k_properties_free (props);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+		g_warning ("mark_one_read: %d", status);
+}
+
+static void
+mark_read (EFolder *folder, GPtrArray *hrefs, gboolean read)
+{
+	E2kProperties *props;
+	E2kResultIter *iter;
+	E2kHTTPStatus status;
+
+	props = e2k_properties_new ();
+	e2k_properties_set_bool (props, E2K_PR_HTTPMAIL_READ, read);
+
+	iter = e_folder_exchange_bproppatch_start (folder, NULL,
+						   (const gchar **)hrefs->pdata,
+						   hrefs->len, props, FALSE);
+	e2k_properties_free (props);
+
+	while (e2k_result_iter_next (iter))
+		;
+	status = e2k_result_iter_free (iter);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+		g_warning ("mark_read: %d", status);
+}
+
+static gboolean
+process_flags (gpointer user_data)
+{
+	ExchangeFolder *mfld = user_data;
+	ExchangeData *ed = mfld->ed;
+	ExchangeMessage *mmsg;
+	GPtrArray *seen = NULL, *unseen = NULL, *deleted = NULL;
+	gint i;
+	guint32 hier_type = e_folder_exchange_get_hierarchy (mfld->folder)->type;
+
+	g_static_rec_mutex_lock (&ed->changed_msgs_mutex);
+
+	for (i = 0; i < mfld->changed_messages->len; i++) {
+		mmsg = mfld->changed_messages->pdata[i];
+		d(printf("Process flags %p\n", mmsg));
+		if (!mmsg->href) {
+			d(g_print ("%s:%s:%d: mfld = [%s], type=[%d]\n", __FILE__, __GNUC_PRETTY_FUNCTION__,
+				   __LINE__, mfld->name, mfld->type));
+		}
+
+		if (mmsg->change_mask & CAMEL_MESSAGE_SEEN) {
+			if (mmsg->change_flags & CAMEL_MESSAGE_SEEN) {
+				if (!seen)
+					seen = g_ptr_array_new ();
+				g_ptr_array_add (seen, g_strdup (strrchr (mmsg->href, '/') + 1));
+				mmsg->flags |= CAMEL_MESSAGE_SEEN;
+			} else {
+				if (!unseen)
+					unseen = g_ptr_array_new ();
+				g_ptr_array_add (unseen, g_strdup (strrchr (mmsg->href, '/') + 1));
+				mmsg->flags &= ~CAMEL_MESSAGE_SEEN;
+			}
+			mmsg->change_mask &= ~CAMEL_MESSAGE_SEEN;
+		}
+
+		if (mmsg->change_mask & CAMEL_MESSAGE_ANSWERED) {
+			E2kProperties *props;
+			E2kHTTPStatus status;
+
+			props = e2k_properties_new ();
+
+			if (mmsg->change_flags & CAMEL_MESSAGE_ANSWERED) {
+				e2k_properties_set_int (props, PR_ACTION, MAPI_ACTION_REPLIED);
+				e2k_properties_set_int (props, PR_ACTION_FLAG, (mmsg->change_flags & CAMEL_MESSAGE_ANSWERED_ALL) ?
+							MAPI_ACTION_FLAG_REPLIED_TO_ALL :
+							MAPI_ACTION_FLAG_REPLIED_TO_SENDER);
+				e2k_properties_set_date (props, PR_ACTION_DATE,
+							e2k_make_timestamp (time (NULL)));
+			} else {
+				e2k_properties_remove (props, PR_ACTION);
+				e2k_properties_remove (props, PR_ACTION_FLAG);
+				e2k_properties_remove (props, PR_ACTION_DATE);
+			}
+
+			status = e2k_context_proppatch (ed->ctx, NULL, mmsg->href, props, FALSE, NULL);
+
+			e2k_properties_free (props);
+
+			if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+				g_warning ("set_replied_flags: %d", status);
+
+			mmsg->change_mask &= ~(CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_ANSWERED_ALL);
+		}
+
+		if (mmsg->change_mask & CAMEL_MESSAGE_FLAGGED) {
+			E2kProperties *props;
+			E2kHTTPStatus status;
+
+			props = e2k_properties_new ();
+
+			if (mmsg->change_flags & CAMEL_MESSAGE_FLAGGED) {
+				e2k_properties_set_int (props, PR_IMPORTANCE, MAPI_IMPORTANCE_HIGH);
+			} else {
+				e2k_properties_set_int (props, PR_IMPORTANCE, MAPI_IMPORTANCE_NORMAL);
+			}
+
+			status = e2k_context_proppatch (ed->ctx, NULL, mmsg->href, props, FALSE, NULL);
+
+			e2k_properties_free (props);
+
+			if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+				g_warning ("set_important_flag: %d", status);
+
+			mmsg->change_mask &= ~CAMEL_MESSAGE_FLAGGED;
+		}
+
+		if (mmsg->tag_updates) {
+			E2kProperties *props;
+			const gchar *value;
+			gint flag_status;
+			E2kHTTPStatus status;
+
+			flag_status = MAPI_FOLLOWUP_UNFLAGGED;
+			props = e2k_properties_new ();
+
+			value = g_datalist_get_data (&mmsg->tag_updates, "follow-up");
+			if (value) {
+				if (*value) {
+					e2k_properties_set_string (props, E2K_PR_HTTPMAIL_MESSAGE_FLAG, g_strdup (value));
+					flag_status = MAPI_FOLLOWUP_FLAGGED;
+				} else {
+					e2k_properties_remove (props, E2K_PR_HTTPMAIL_MESSAGE_FLAG);
+				}
+			}
+
+			value = g_datalist_get_data (&mmsg->tag_updates, "due-by");
+			if (value) {
+				if (*value) {
+					e2k_properties_set_string (props, E2K_PR_MAILHEADER_REPLY_BY, g_strdup (value));
+				} else {
+					e2k_properties_remove (props, E2K_PR_MAILHEADER_REPLY_BY);
+				}
+			}
+
+			value = g_datalist_get_data (&mmsg->tag_updates, "completed-on");
+			if (value) {
+				if (*value) {
+					e2k_properties_set_string (props, E2K_PR_MAILHEADER_COMPLETED, g_strdup (value));
+					flag_status = MAPI_FOLLOWUP_COMPLETED;
+				} else {
+					e2k_properties_remove (props, E2K_PR_MAILHEADER_COMPLETED);
+				}
+			}
+			g_datalist_clear (&mmsg->tag_updates);
+
+			e2k_properties_set_int (props, PR_FLAG_STATUS, flag_status);
+
+			status = e2k_context_proppatch (ed->ctx, NULL, mmsg->href, props, FALSE, NULL);
+
+			e2k_properties_free (props);
+
+			if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+				g_warning ("update_tags: %d", status);
+		}
+
+		if (!mmsg->change_mask)
+			g_ptr_array_remove_index_fast (mfld->changed_messages, i--);
+	}
+
+	g_static_rec_mutex_unlock (&ed->changed_msgs_mutex);
+
+	if (seen || unseen) {
+		if (seen) {
+			mark_read (mfld->folder, seen, TRUE);
+			g_ptr_array_foreach (seen, (GFunc)g_free, NULL);
+			g_ptr_array_free (seen, TRUE);
+		}
+		if (unseen) {
+			mark_read (mfld->folder, unseen, FALSE);
+			g_ptr_array_foreach (unseen, (GFunc)g_free, NULL);
+			g_ptr_array_free (unseen, TRUE);
+		}
+
+		if (mfld->changed_messages->len == 0) {
+			mfld->flag_timeout = 0;
+			/* change_complete (mfld); */
+			return FALSE;
+		} else
+			return TRUE;
+	}
+
+	g_static_rec_mutex_lock (&ed->changed_msgs_mutex);
+
+	for (i = 0; i < mfld->changed_messages->len; i++) {
+		mmsg = mfld->changed_messages->pdata[i];
+		if (mmsg->change_mask & mmsg->change_flags & CAMEL_MESSAGE_DELETED) {
+			if (!deleted)
+				deleted = g_ptr_array_new ();
+			g_ptr_array_add (deleted, strrchr (mmsg->href, '/') + 1);
+		}
+	}
+	g_static_rec_mutex_unlock (&ed->changed_msgs_mutex);
+
+	if (deleted) {
+		CamelFolder *folder = get_camel_folder (mfld);
+		E2kResultIter *iter;
+		E2kResult *result;
+		E2kHTTPStatus status;
+
+		/* change_pending (mfld); */
+		mfld->pending_delete_ops++;
+		if (folder)
+			camel_folder_freeze (folder);
+
+		if (hier_type == EXCHANGE_HIERARCHY_PERSONAL) {
+			iter = e_folder_exchange_transfer_start (mfld->folder, NULL,
+								 ed->deleted_items,
+								 deleted, TRUE);
+		} else {
+			/* This is for public folder hierarchy. We cannot move
+			   a mail item deleted from a public folder to the
+			   deleted items folder. This code updates the UI to
+			   show the mail folder again if the deletion fails in
+			   such public folder */
+			iter = e_folder_exchange_bdelete_start (mfld->folder, NULL,
+								(const gchar **)deleted->pdata,
+								deleted->len);
+		}
+		g_ptr_array_free (deleted, FALSE);
+		while ((result = e2k_result_iter_next (iter))) {
+			if (hier_type == EXCHANGE_HIERARCHY_PERSONAL) {
+				if (!e2k_properties_get_prop (result->props,
+							      E2K_PR_DAV_LOCATION)) {
+					continue;
+				}
+			} else if (result->status == E2K_HTTP_UNAUTHORIZED) {
+				camel_exchange_folder_update_message_flags_ex (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, 0, CAMEL_MESSAGE_DELETED);
+				continue;
+			}
+
+			message_removed (mfld, folder, result->href);
+			mfld->deleted_count++;
+		}
+		status = e2k_result_iter_free (iter);
+
+		if (folder)
+			camel_folder_thaw (folder);
+
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+			g_warning ("deleted: %d", status);
+
+		mfld->pending_delete_ops--;
+		/* change_complete (mfld); */
+	}
+
+	if (mfld->changed_messages->len) {
+		g_ptr_array_set_size (mfld->changed_messages, 0);
+		/* change_complete (mfld); */
+	}
+
+	mfld->flag_timeout = 0;
+
+	return FALSE;
+}
+
+static E2kHTTPStatus
+get_stickynote (E2kContext *ctx, E2kOperation *op, const gchar *uri, gchar **body, gint *len)
+{
+	static const gchar *stickynote_props[] = {
+		E2K_PR_MAILHEADER_SUBJECT,
+		E2K_PR_DAV_LAST_MODIFIED,
+		E2K_PR_OUTLOOK_STICKYNOTE_COLOR,
+		E2K_PR_OUTLOOK_STICKYNOTE_HEIGHT,
+		E2K_PR_OUTLOOK_STICKYNOTE_WIDTH,
+		E2K_PR_HTTPMAIL_TEXT_DESCRIPTION,
+	};
+
+	E2kHTTPStatus status;
+	E2kResult *results;
+	gint nresults = 0;
+	GString *message;
+
+	status = e2k_context_propfind (ctx, op, uri,
+				       stickynote_props, G_N_ELEMENTS (stickynote_props),
+				       &results, &nresults);
+
+	if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		message = mail_util_stickynote_to_rfc822 (results[0].props);
+		*body = message->str;
+		*len = message->len;
+		g_string_free (message, FALSE);
+		e2k_results_free (results, nresults);
+	}
+
+	return status;
+}
+
+static E2kHTTPStatus
+build_message_from_document (E2kContext *ctx, E2kOperation *op, const gchar *uri, gchar **body, gint *len)
+{
+	E2kHTTPStatus status;
+	E2kResult *results;
+	gint nresults = 0;
+	GString *message;
+	gchar *headers;
+
+	status = e2k_context_propfind (ctx, op, uri, mapi_message_props, G_N_ELEMENTS (mapi_message_props), &results, &nresults);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+		return status;
+	if (!nresults)
+		return E2K_HTTP_MALFORMED;
+
+	headers = mail_util_mapi_to_smtp_headers (results[0].props);
+
+	message = g_string_new (headers);
+	g_string_append_len (message, *body, *len);
+
+	g_free (headers);
+	g_free (*body);
+
+	*len = message->len;
+	*body = g_string_free (message, FALSE);
+
+	e2k_results_free (results, nresults);
+	return status;
+}
+
+static E2kHTTPStatus
+unmangle_delegated_meeting_request (ExchangeData *ed, E2kOperation *op, const gchar *uri, gchar **body, gint *len)
+{
+	const gchar *prop = PR_RCVD_REPRESENTING_EMAIL_ADDRESS;
+	GString *message;
+	gchar *delegator_dn, *delegator_uri, *delegator_folder_physical_uri = NULL;
+	ExchangeAccount *account;
+	E2kGlobalCatalog *gc;
+	E2kGlobalCatalogEntry *entry;
+	E2kGlobalCatalogStatus gcstatus;
+	EFolder *folder = NULL;
+	E2kHTTPStatus status;
+	E2kResult *results;
+	gint nresults = 0;
+	MailUtilDemangleType unmangle_type = MAIL_UTIL_DEMANGLE_DELGATED_MEETING;
+
+	status = e2k_context_propfind (ed->ctx, op, uri, &prop, 1, &results, &nresults);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+		return status;
+	if (!nresults)
+		return E2K_HTTP_MALFORMED;
+
+	delegator_dn = e2k_properties_get_prop (results[0].props, PR_RCVD_REPRESENTING_EMAIL_ADDRESS);
+	if (!delegator_dn) {
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	account = ed->account;
+	gc = exchange_account_get_global_catalog (account);
+	if (!gc) {
+		g_warning ("\nNo GC: could not unmangle meeting request");
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	gcstatus = e2k_global_catalog_lookup (
+		gc, NULL, /* FIXME; cancellable */
+		E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
+		delegator_dn, E2K_GLOBAL_CATALOG_LOOKUP_MAILBOX,
+		&entry);
+	if (gcstatus != E2K_GLOBAL_CATALOG_OK) {
+		g_warning ("\nGC lookup failed: could not unmangle meeting request");
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	delegator_uri = exchange_account_get_foreign_uri (
+		account, entry, E2K_PR_STD_FOLDER_CALENDAR);
+
+	if (delegator_uri) {
+		folder = exchange_account_get_folder (account, delegator_uri);
+		if (folder)
+			delegator_folder_physical_uri = g_strdup (e_folder_get_physical_uri (folder));
+		g_free (delegator_uri);
+	}
+
+	message = g_string_new_len (*body, *len);
+	mail_util_demangle_meeting_related_message (message, entry->display_name,
+						entry->email,
+						delegator_folder_physical_uri,
+						exchange_account_get_email_id (account),
+						unmangle_type);
+	g_free (*body);
+	*body = message->str;
+	*len = message->len;
+	*body = g_string_free (message, FALSE);
+
+	e2k_global_catalog_entry_free (gc, entry);
+	g_free (delegator_folder_physical_uri);
+
+	e2k_results_free (results, nresults);
+	return E2K_HTTP_OK;
+}
+
+static gboolean
+is_foreign_folder (ExchangeData *ed, const gchar *folder_name, gchar **owner_email)
+{
+	EFolder *folder;
+	ExchangeHierarchy *hier;
+	gchar *path;
+
+	path = g_build_filename ("/", folder_name, NULL);
+	folder = exchange_account_get_folder (ed->account, path);
+	if (!folder) {
+		g_free (path);
+		return FALSE;
+	}
+
+	g_free (path);
+	g_object_ref (folder);
+
+	hier = e_folder_exchange_get_hierarchy (folder);
+
+	if (hier->type != EXCHANGE_HIERARCHY_FOREIGN) {
+		g_object_unref (folder);
+		return FALSE;
+	}
+
+	*owner_email = g_strdup (hier->owner_email);
+
+	g_object_unref (folder);
+	return TRUE;
+}
+
+static E2kHTTPStatus
+unmangle_meeting_request_in_subscribed_inbox (ExchangeData *ed, const gchar *delegator_email, gchar **body, gint *len)
+{
+	GString *message;
+	gchar *delegator_uri, *delegator_folder_physical_uri = NULL;
+	ExchangeAccount *account;
+	E2kGlobalCatalog *gc;
+	E2kGlobalCatalogEntry *entry;
+	E2kGlobalCatalogStatus gcstatus;
+	EFolder *folder = NULL;
+	MailUtilDemangleType unmangle_type = MAIL_UTIL_DEMANGLE_MEETING_IN_SUBSCRIBED_INBOX;
+
+	account = ed->account;
+	gc = exchange_account_get_global_catalog (account);
+	if (!gc) {
+		g_warning ("\nNo GC: could not unmangle meeting request in subscribed folder");
+		return E2K_HTTP_OK;
+	}
+
+	gcstatus = e2k_global_catalog_lookup (
+		gc, NULL, /* FIXME; cancellable */
+		E2K_GLOBAL_CATALOG_LOOKUP_BY_EMAIL,
+		delegator_email, E2K_GLOBAL_CATALOG_LOOKUP_MAILBOX,
+		&entry);
+	if (gcstatus != E2K_GLOBAL_CATALOG_OK) {
+		g_warning ("\nGC lookup failed: could not unmangle meeting request in subscribed folder");
+		return E2K_HTTP_OK;
+	}
+
+	delegator_uri = exchange_account_get_foreign_uri (
+		account, entry, E2K_PR_STD_FOLDER_CALENDAR);
+
+	if (delegator_uri) {
+		folder = exchange_account_get_folder (account, delegator_uri);
+		if (folder)
+			delegator_folder_physical_uri = g_strdup (e_folder_get_physical_uri (folder));
+		g_free (delegator_uri);
+	}
+
+	message = g_string_new_len (*body, *len);
+	mail_util_demangle_meeting_related_message (message, entry->display_name,
+						entry->email,
+						delegator_folder_physical_uri,
+						exchange_account_get_email_id (account),
+						unmangle_type);
+	g_free (*body);
+	*body = message->str;
+	*len = message->len;
+	*body = g_string_free (message, FALSE);
+
+	e2k_global_catalog_entry_free (gc, entry);
+	g_free (delegator_folder_physical_uri);
+
+	return E2K_HTTP_OK;
+}
+
+static E2kHTTPStatus
+unmangle_sender_field (ExchangeData *ed, E2kOperation *op, const gchar *uri, gchar **body, gint *len)
+{
+	const gchar *props[] = { PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENDER_EMAIL_ADDRESS };
+	GString *message;
+	gchar *delegator_dn, *sender_dn;
+	ExchangeAccount *account;
+	E2kGlobalCatalog *gc;
+	E2kGlobalCatalogEntry *delegator_entry;
+	E2kGlobalCatalogEntry *sender_entry;
+	E2kGlobalCatalogStatus gcstatus;
+	E2kHTTPStatus status;
+	E2kResult *results;
+	gint nresults = 0;
+	MailUtilDemangleType unmangle_type = MAIL_UTIL_DEMANGLE_SENDER_FIELD;
+
+	status = e2k_context_propfind (ed->ctx, op, uri, props, 2, &results, &nresults);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+		return status;
+	if (!nresults)
+		return E2K_HTTP_MALFORMED;
+
+	delegator_dn = e2k_properties_get_prop (results[0].props, PR_SENT_REPRESENTING_EMAIL_ADDRESS);
+	if (!delegator_dn) {
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	sender_dn = e2k_properties_get_prop (results[0].props, PR_SENDER_EMAIL_ADDRESS);
+	if (!sender_dn) {
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	if (!g_ascii_strcasecmp (delegator_dn, sender_dn)) {
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	account = ed->account;
+	gc = exchange_account_get_global_catalog (account);
+	if (!gc) {
+		g_warning ("\nNo GC: could not unmangle sender field");
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	gcstatus = e2k_global_catalog_lookup (
+		gc, NULL, /* FIXME; cancellable */
+		E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
+		delegator_dn, E2K_GLOBAL_CATALOG_LOOKUP_MAILBOX,
+		&delegator_entry);
+	if (gcstatus != E2K_GLOBAL_CATALOG_OK) {
+		g_warning ("\nGC lookup failed: for delegator_entry - could not unmangle sender field");
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	gcstatus = e2k_global_catalog_lookup (
+		gc, NULL, /* FIXME; cancellable */
+		E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
+		sender_dn, E2K_GLOBAL_CATALOG_LOOKUP_MAILBOX,
+		&sender_entry);
+	if (gcstatus != E2K_GLOBAL_CATALOG_OK) {
+		g_warning ("\nGC lookup failed: for sender_entry - could not unmangle sender field");
+		e2k_results_free (results, nresults);
+		return E2K_HTTP_OK;
+	}
+
+	message = g_string_new_len (*body, *len);
+	mail_util_demangle_meeting_related_message (message, delegator_entry->display_name,
+						delegator_entry->email,
+						NULL,
+						sender_entry->email,
+						unmangle_type);
+	g_free (*body);
+	*body = message->str;
+	*len = message->len;
+	*body = g_string_free (message, FALSE);
+
+	e2k_global_catalog_entry_free (gc, delegator_entry);
+	e2k_global_catalog_entry_free (gc, sender_entry);
+
+	e2k_results_free (results, nresults);
+	return E2K_HTTP_OK;
+}
+
+static void
+get_folder_info_data (ExchangeData *ed, const gchar *top, guint32 store_flags, GPtrArray **names, GPtrArray **uris, GArray **unread, GArray **flags)
+{
+	GPtrArray *folders = NULL;
+	ExchangeHierarchy *hier;
+	EFolder *folder;
+	const gchar *type, *name, *uri, *inbox_uri = NULL, *trash_uri = NULL, *sent_items_uri = NULL;
+	gint unread_count, i, toplen = top ? strlen (top) : 0;
+	guint32 folder_flags = 0;
+	gboolean recursive, subscribed, subscription_list;
+	gint mode = -1;
+	gchar *full_path;
+
+	recursive = (store_flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE);
+	subscribed = (store_flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED);
+	subscription_list = (store_flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST);
+
+	mode = is_online (ed);
+	if (!subscribed && subscription_list) {
+		ExchangeAccountResult result = -1;
+
+		d(g_print ("%s(%d):%s: NOT SUBSCRIBED top = [%s]\n", __FILE__, __LINE__, __GNUC_PRETTY_FUNCTION__, top));
+		if (!toplen)
+			result = exchange_account_open_folder (ed->account, "/public");
+		if (result ==  EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST) {
+			hier = exchange_account_get_hierarchy_by_type (ed->account, EXCHANGE_HIERARCHY_PUBLIC);
+			if (hier)
+				exchange_hierarchy_scan_subtree (hier, hier->toplevel, mode);
+		} else {
+			d(g_print ("%s(%d):%s: NOT SUBSCRIBED - open_folder returned = [%d]\n", __FILE__, __LINE__, __GNUC_PRETTY_FUNCTION__, result));
+		}
+	}
+
+	/* No need to check for recursive flag, as I will always be returning a tree, instead of a single folder info object */
+	if (toplen) {
+		d(g_print ("%s(%d):%s: NOT RECURSIVE and toplen top = [%s]\n", __FILE__, __LINE__, __GNUC_PRETTY_FUNCTION__, top));
+		full_path = g_strdup_printf ("/%s", top);
+		folders = exchange_account_get_folder_tree (ed->account, full_path);
+		g_free (full_path);
+	} else {
+		d(g_print ("%s(%d):%s calling exchange_account_get_folders \n", __FILE__, __LINE__,
+					   __GNUC_PRETTY_FUNCTION__));
+		folders = exchange_account_get_folders (ed->account);
+	}
+
+	*names = g_ptr_array_new ();
+	*uris = g_ptr_array_new ();
+	*unread = g_array_new (FALSE, FALSE, sizeof (gint));
+	*flags = g_array_new (FALSE, FALSE, sizeof (gint));
+	/* Can be NULL if started in offline mode */
+	if (ed->inbox) {
+		inbox_uri = e_folder_get_physical_uri (ed->inbox);
+	}
+
+	if (ed->deleted_items) {
+		trash_uri = e_folder_get_physical_uri (ed->deleted_items);
+	}
+
+	if (ed->sent_items) {
+		sent_items_uri = e_folder_get_physical_uri (ed->sent_items);
+	}
+
+	if (folders) {
+		for (i = 0; i < folders->len; i++) {
+			folder = folders->pdata[i];
+			hier = e_folder_exchange_get_hierarchy (folder);
+			folder_flags = 0;
+
+			if (subscribed) {
+				if (hier->type != EXCHANGE_HIERARCHY_PERSONAL &&
+				    hier->type != EXCHANGE_HIERARCHY_FAVORITES &&
+				    hier->type != EXCHANGE_HIERARCHY_FOREIGN)
+					continue;
+			} else if (subscription_list) {
+				if (hier->type != EXCHANGE_HIERARCHY_PUBLIC)
+					continue;
+			}
+
+			type = e_folder_get_type_string (folder);
+			name = e_folder_get_name (folder);
+			uri = e_folder_get_physical_uri (folder);
+			d(g_print ("Uri: %s\n", uri));
+			d(g_print ("folder type is : %s\n", type));
+
+			if (!strcmp (type, "noselect")) {
+				unread_count = 0;
+				folder_flags = CAMEL_FOLDER_NOSELECT;
+			}
+
+			switch (hier->type) {
+				case EXCHANGE_HIERARCHY_FAVORITES:
+					/* folder_flags will be set only if the type
+					   is noselect and we need to include it */
+					if (strcmp (type, "mail") && !folder_flags)
+						continue;
+					/* selectable */
+					if (!folder_flags)
+						unread_count = e_folder_get_unread_count (folder);
+				case EXCHANGE_HIERARCHY_PUBLIC:
+					if (exchange_account_is_favorite_folder (ed->account, folder)) {
+						folder_flags |= CAMEL_FOLDER_SUBSCRIBED;
+						d(printf ("marked the folder as subscribed\n"));
+					}
+					break;
+				case EXCHANGE_HIERARCHY_FOREIGN:
+					if (folder_flags & CAMEL_FOLDER_NOSELECT && ed->new_folder_id == 0) {
+						/* Rescan the hierarchy - as we don't rescan
+						   foreign hierarchies anywhere for mailer and
+						   only when we are starting up
+						*/
+						exchange_hierarchy_scan_subtree (hier, hier->toplevel, mode);
+					}
+				case EXCHANGE_HIERARCHY_PERSONAL:
+					if (!strcmp (type, "mail")) {
+						unread_count = e_folder_get_unread_count (folder);
+					}
+					else if (!folder_flags) {
+						continue;
+					}
+					break;
+				default:
+					break;
+			}
+
+			if (inbox_uri && !strcmp (uri, inbox_uri))
+				folder_flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
+
+			if (trash_uri && !strcmp (uri, trash_uri))
+				folder_flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_TRASH;
+
+			if (sent_items_uri && !strcmp (uri, sent_items_uri))
+				folder_flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_SENT;
+
+			if (!e_folder_exchange_get_has_subfolders (folder)) {
+				d(printf ("%s:%d:%s - %s has no subfolders", __FILE__, __LINE__, __GNUC_PRETTY_FUNCTION__,
+					  name));
+				folder_flags |= CAMEL_FOLDER_NOCHILDREN;
+			}
+
+			d(g_print ("folder flags is : %d\n", folder_flags));
+
+			g_ptr_array_add (*names, g_strdup (name));
+			g_ptr_array_add (*uris, g_strdup (uri));
+			g_array_append_val (*unread, unread_count);
+			g_array_append_val (*flags, folder_flags);
+		}
+
+		g_ptr_array_free (folders, TRUE);
+	}
+}
+
+struct update_linestatus
+{
+	CamelExchangeStore *estore;
+	gint linestatus;
+	CamelException *ex;
+};
+
+static void
+folder_update_linestatus (gpointer key, gpointer value, gpointer data)
+{
+	ExchangeFolder *mfld = (ExchangeFolder *) value;
+	struct update_linestatus *ul = (struct update_linestatus *) data;
+	guint32 readonly;
+
+	g_return_if_fail (ul != NULL);
+
+	if (ul->linestatus == ONLINE_MODE) {
+		CamelFolder *folder;
+
+		get_folder_online (mfld, ul->ex);
+
+		readonly = (mfld->access & (MAPI_ACCESS_MODIFY | MAPI_ACCESS_CREATE_CONTENTS)) ? 0 : 1;
+
+		folder = get_camel_folder (mfld);
+		if (folder) {
+			camel_exchange_summary_set_readonly (folder->summary, readonly ? TRUE : FALSE);
+		}
+	} else {
+		/* FIXME: need any undo for offline */ ;
+	}
+}
+
+gboolean
+camel_exchange_utils_connect (CamelService *service,
+				const gchar *pwd,
+				guint32 *status, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeAccount *account;
+	ExchangeAccountResult result;
+	E2kContext *ctx;
+	guint32 retval = 1;
+	const gchar *uri;
+	struct update_linestatus ul;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (status != NULL, FALSE);
+
+	ul.linestatus = is_online (ed);
+
+	account = ed->account;
+	if (ul.linestatus == ONLINE_MODE)
+		exchange_account_set_online (account);
+	else if (ul.linestatus == OFFLINE_MODE)
+		exchange_account_set_offline (account);
+
+	ctx = exchange_account_get_context (account);
+	if (!ctx) {
+		ctx = exchange_account_connect (account, pwd, &result);
+	}
+
+	if (!ctx && ul.linestatus == ONLINE_MODE) {
+		retval = 0;
+		goto end;
+	} else if (ul.linestatus == OFFLINE_MODE) {
+		goto end;
+	}
+
+	ed->ctx = g_object_ref (ctx);
+
+	ed->mail_submission_uri = exchange_account_get_standard_uri (account, "sendmsg");
+	uri = exchange_account_get_standard_uri (account, "inbox");
+	ed->inbox = exchange_account_get_folder (account, uri);
+	uri = exchange_account_get_standard_uri (account, "deleteditems");
+	ed->deleted_items = exchange_account_get_folder (account, uri);
+	uri = exchange_account_get_standard_uri (account, "sentitems");
+	ed->sent_items = exchange_account_get_folder (account, uri);
+
+	/* Will be used for offline->online transition to initialize things for
+	   the first time */
+
+	ul.estore = ed->estore;
+	ul.ex = ex;
+	g_hash_table_foreach (ed->folders_by_name,
+			      (GHFunc) folder_update_linestatus,
+			      &ul);
+ end:
+	*status = retval;
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_get_folder (CamelService *service,
+				const gchar *name,
+				gboolean create,
+				GPtrArray *uids,
+				GByteArray *flags,
+				GPtrArray *hrefs,
+				guint32 high_article_num,
+				guint32 *folder_flags, /* out */
+				gchar **folder_uri, /* out */
+				gboolean *readonly, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	ExchangeMessage *mmsg;
+	EFolder *folder;
+	gchar *path;
+	const gchar *outlook_class;
+	guint32 camel_flags;
+	gint i;
+	ExchangeHierarchy *hier;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (folder_flags != NULL, FALSE);
+	g_return_val_if_fail (folder_uri != NULL, FALSE);
+	g_return_val_if_fail (readonly != NULL, FALSE);
+
+	path = g_strdup_printf ("/%s", name);
+	folder = exchange_account_get_folder (ed->account, path);
+	if (!folder && !create) {
+		set_exception (ex, _("No such folder"));
+		g_free (path);
+		return FALSE;
+	} else if (!folder) {
+		ExchangeAccountFolderResult result;
+
+		result = exchange_account_create_folder (ed->account, path, "mail");
+		folder = exchange_account_get_folder (ed->account, path);
+		if (result != EXCHANGE_ACCOUNT_FOLDER_OK || !folder) {
+			set_exception (ex, _("Could not create folder."));
+			g_free (path);
+			return FALSE;
+		}
+	}
+	g_free (path);
+
+	mfld = g_new0 (ExchangeFolder, 1);
+	mfld->ed = ed;
+	mfld->folder = folder;
+	g_object_ref (folder);
+	mfld->name = e_folder_exchange_get_path (folder) + 1;
+
+	if (!strcmp (e_folder_get_type_string (folder), "mail/public"))
+		mfld->type = EXCHANGE_FOLDER_POST;
+	else {
+		outlook_class = e_folder_exchange_get_outlook_class (folder);
+		if (!outlook_class)
+			mfld->type = EXCHANGE_FOLDER_OTHER;
+		else if (!g_ascii_strncasecmp (outlook_class, "IPF.Note", 8))
+			mfld->type = EXCHANGE_FOLDER_REAL;
+		else if (!g_ascii_strncasecmp (outlook_class, "IPF.Post", 8))
+			mfld->type = EXCHANGE_FOLDER_POST;
+		else if (!g_ascii_strncasecmp (outlook_class, "IPF.StickyNote", 14))
+			mfld->type = EXCHANGE_FOLDER_NOTES;
+		else
+			mfld->type = EXCHANGE_FOLDER_OTHER;
+	}
+
+	mfld->messages = g_ptr_array_new ();
+	mfld->messages_by_uid = g_hash_table_new (g_str_hash, g_str_equal);
+	mfld->messages_by_href = g_hash_table_new (g_str_hash, g_str_equal);
+	for (i = 0; i < uids->len; i++) {
+		mmsg = new_message (uids->pdata[i], NULL, mfld->seq++, flags->data[i]);
+		g_ptr_array_add (mfld->messages, mmsg);
+		g_hash_table_insert (mfld->messages_by_uid, mmsg->uid, mmsg);
+
+		if (hrefs->pdata[i] && *((gchar *)hrefs->pdata[i])) {
+			mmsg->href = g_strdup (hrefs->pdata[i]);
+			g_hash_table_insert (mfld->messages_by_href, mmsg->href, mmsg);
+		}
+		if (!(mmsg->flags & CAMEL_MESSAGE_SEEN))
+			mfld->unread_count++;
+	}
+
+	mfld->high_article_num = high_article_num;
+
+	if (is_online (ed) == ONLINE_MODE) {
+		if (!get_folder_online (mfld, ex)) {
+			return FALSE;
+		}
+	}
+	g_signal_connect (mfld->folder, "changed",
+			  G_CALLBACK (storage_folder_changed), mfld);
+
+	g_hash_table_insert (ed->folders_by_name, (gchar *)mfld->name, mfld);
+	folder_changed (mfld);
+
+	*readonly = ((mfld->access & (MAPI_ACCESS_MODIFY | MAPI_ACCESS_CREATE_CONTENTS)) == 0);
+
+	camel_flags = 0;
+	if (ed->account->filter_inbox && (mfld->folder == ed->inbox))
+		camel_flags |= CAMEL_FOLDER_FILTER_RECENT;
+	if (ed->account->filter_junk) {
+		if ((mfld->folder != ed->deleted_items) &&
+		    ((mfld->folder == ed->inbox) ||
+		    !ed->account->filter_junk_inbox_only))
+			camel_flags |= CAMEL_FOLDER_FILTER_JUNK;
+	}
+
+	hier = e_folder_exchange_get_hierarchy (mfld->folder);
+
+	*folder_flags = camel_flags;
+	*folder_uri = g_strdup (hier->source_uri);
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_get_trash_name (CamelService *service,
+				gchar **trash_name, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (trash_name != NULL, FALSE);
+
+	if (!ed->deleted_items) {
+		set_exception (ex, _("Could not open Deleted Items folder"));
+		return FALSE;
+	}
+
+	*trash_name = g_strdup (e_folder_exchange_get_path (ed->deleted_items) + 1);
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_refresh_folder (CamelService *service,
+				const gchar *folder_name,
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+
+	mfld = folder_from_name (ed, folder_name, 0, ex);
+	if (!mfld) {
+		return FALSE;
+	}
+
+	refresh_folder_internal (mfld, ex);
+	sync_deletions (mfld);
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_sync_count (CamelService *service,
+				const gchar *folder_name,
+				guint32 *unread_count, /* out */
+				guint32 *visible_count, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (unread_count != NULL, FALSE);
+	g_return_val_if_fail (visible_count != NULL, FALSE);
+
+	mfld = folder_from_name (ed, folder_name, 0, ex);
+	if (mfld) {
+		*unread_count = mfld->unread_count;
+		*visible_count = mfld->messages->len;
+	} else {
+		*unread_count = 0;
+		*visible_count = 0;
+	}
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_expunge_uids (CamelService *service,
+				const gchar *folder_name,
+				GPtrArray *uids,
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	ExchangeMessage *mmsg;
+	GPtrArray *hrefs;
+	E2kResultIter *iter;
+	E2kResult *result;
+	E2kHTTPStatus status;
+	gint i, ndeleted;
+	gboolean some_error = FALSE;
+	CamelFolder *folder;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+
+	if (!uids->len)
+		return TRUE;
+
+	mfld = folder_from_name (ed, folder_name, MAPI_ACCESS_DELETE, ex);
+	if (!mfld)
+		return FALSE;
+
+	g_static_rec_mutex_lock (&ed->changed_msgs_mutex);
+	hrefs = g_ptr_array_new ();
+	for (i = 0; i < uids->len; i++) {
+		mmsg = find_message (mfld, uids->pdata[i]);
+		if (mmsg)
+			g_ptr_array_add (hrefs, strrchr (mmsg->href, '/') + 1);
+	}
+
+	if (!hrefs->len) {
+		/* Can only happen if there's a bug somewhere else, but we
+		 * don't want to crash.
+		 */
+		g_ptr_array_free (hrefs, TRUE);
+		g_static_rec_mutex_unlock (&ed->changed_msgs_mutex);
+		return TRUE;
+	}
+
+	folder = get_camel_folder (mfld);
+	if (folder)
+		camel_folder_freeze (folder);
+
+	iter = e_folder_exchange_bdelete_start (mfld->folder, NULL,
+						(const gchar **)hrefs->pdata,
+						hrefs->len);
+	ndeleted = 0;
+	while ((result = e2k_result_iter_next (iter))) {
+		if (result->status == E2K_HTTP_UNAUTHORIZED) {
+			some_error = TRUE;
+			continue;
+		}
+		message_removed (mfld, folder, result->href);
+		mfld->deleted_count++;
+		ndeleted++;
+
+		camel_operation_progress (NULL, ndeleted * 100 / hrefs->len);
+	}
+	status = e2k_result_iter_free (iter);
+	g_static_rec_mutex_unlock (&ed->changed_msgs_mutex);
+
+	if (folder)
+		camel_folder_thaw (folder);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		g_warning ("expunged: %d", status);
+		some_error = TRUE;
+		set_exception (ex, _("Could not empty Deleted Items folder"));
+	} else if (some_error) {
+		set_exception (ex, _("Permission denied. Could not delete certain messages."));
+	}
+
+	g_ptr_array_free (hrefs, TRUE);
+
+	return !some_error;
+}
+
+static gboolean
+test_uri (E2kContext *ctx, const gchar *test_name, gpointer messages_by_href)
+{
+	return g_hash_table_lookup (messages_by_href, test_name) == NULL;
+}
+
+gboolean
+camel_exchange_utils_append_message (CamelService *service,
+				const gchar *folder_name,
+				guint32 flags,
+				const gchar *subject,
+				const GByteArray *message,
+				gchar **new_uid, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	E2kHTTPStatus status;
+	gchar *ru_header = NULL, *repl_uid, *location = NULL;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (new_uid != NULL, FALSE);
+	g_return_val_if_fail (message != NULL, FALSE);
+
+	mfld = folder_from_name (ed, folder_name, MAPI_ACCESS_CREATE_CONTENTS, ex);
+	if (!mfld)
+		return FALSE;
+
+	status = e_folder_exchange_put_new (mfld->folder, NULL, subject,
+					    test_uri, mfld->messages_by_href,
+					    "message/rfc822", (const gchar *)message->data, message->len,
+					    &location, &ru_header);
+	if (status != E2K_HTTP_CREATED) {
+		g_warning ("appended_message: %d", status);
+		set_exception (ex, status == E2K_HTTP_INSUFFICIENT_SPACE_ON_RESOURCE ?
+				   _("Could not append message; mailbox is over quota") :
+				   _("Could not append message"));
+		return FALSE;
+	}
+
+	if (location) {
+		if (flags & CAMEL_MESSAGE_SEEN)
+			mark_one_read (ed->ctx, location, TRUE);
+		else
+			mark_one_read (ed->ctx, location, FALSE);
+	}
+
+	if (ru_header && *ru_header == '<' && strlen (ru_header) > 3)
+		repl_uid = g_strndup (ru_header + 1, strlen (ru_header) - 2);
+	else
+		repl_uid = NULL;
+
+	*new_uid = g_strdup (repl_uid ? uidstrip (repl_uid) : "");
+
+	g_free (repl_uid);
+	g_free (ru_header);
+	g_free (location);
+
+	return TRUE;
+}
+
+static void
+change_message (ExchangeFolder *mfld, ExchangeMessage *mmsg)
+{
+	gint i;
+
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
+
+	for (i=0; i<mfld->changed_messages->len; i++)  {
+		if (mfld->changed_messages->pdata[i] == mmsg)
+			break;
+	}
+
+	if (i == mfld->changed_messages->len) {
+		/*change_pending (mfld); !!!TODO!!! */
+		g_ptr_array_add (mfld->changed_messages, mmsg);
+	}
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+
+	if (mfld->flag_timeout)
+		g_source_remove (mfld->flag_timeout);
+	mfld->flag_timeout = g_timeout_add (1000, process_flags, mfld);
+}
+
+gboolean
+camel_exchange_utils_set_message_flags (CamelService *service,
+					const gchar *folder_name,
+					const gchar *uid,
+					guint32 flags,
+					guint32 mask,
+					CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	ExchangeMessage *mmsg;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+
+	mfld = folder_from_name (ed, folder_name, MAPI_ACCESS_MODIFY, ex);
+	if (!mfld)
+		return FALSE;
+
+	mmsg = find_message (mfld, uid);
+	if (!mmsg)
+		return FALSE;
+
+	/* Although we don't actually process the flag change right
+	 * away, we need to update the folder's unread count to match
+	 * what the user now believes it is. (We take advantage of the
+	 * fact that the mailer will never delete a message without
+	 * also marking it read.)
+	 */
+	if (mask & CAMEL_MESSAGE_SEEN) {
+		if (((mmsg->flags ^ flags) & CAMEL_MESSAGE_SEEN) == 0) {
+			/* The user is just setting it to what it
+			 * already is, so ignore it.
+			 */
+			mask &= ~CAMEL_MESSAGE_SEEN;
+		} else {
+			mmsg->flags ^= CAMEL_MESSAGE_SEEN;
+			if (mmsg->flags & CAMEL_MESSAGE_SEEN)
+				mfld->unread_count--;
+			else
+				mfld->unread_count++;
+			folder_changed (mfld);
+		}
+	}
+
+	/* If the user tries to delete a message in a non-person
+	 * hierarchy, we ignore it (which will cause camel to delete
+	 * it the hard way next time it syncs).
+	 */
+
+#if 0
+	/* If we allow camel utils to delete these messages hard way, it may
+	   fail to delete a mail because of permissions, but will append
+	   a mail in deleted items */
+
+	if (mask & flags & CAMEL_MESSAGE_DELETED) {
+		ExchangeHierarchy *hier;
+
+		hier = e_folder_exchange_get_hierarchy (mfld->folder);
+		if (hier->type != EXCHANGE_HIERARCHY_PERSONAL)
+			mask &= ~CAMEL_MESSAGE_DELETED;
+	}
+#endif
+
+	/* If there's nothing left to change, return. */
+	if (!mask)
+		return TRUE;
+
+	mmsg->change_flags |= (flags & mask);
+	mmsg->change_flags &= ~(~flags & mask);
+	mmsg->change_mask |= mask;
+
+	change_message (mfld, mmsg);
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_set_message_tag (CamelService *service,
+				const gchar *folder_name,
+				const gchar *uid,
+				const gchar *name,
+				const gchar *value,
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	ExchangeMessage *mmsg;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+
+	mfld = folder_from_name (ed, folder_name, MAPI_ACCESS_MODIFY, ex);
+	if (!mfld)
+		return FALSE;
+
+	mmsg = find_message (mfld, uid);
+	if (!mmsg)
+		return FALSE;
+
+	g_datalist_set_data_full (&mmsg->tag_updates, name, g_strdup (value), g_free);
+
+	change_message (mfld, mmsg);
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_get_message (CamelService *service,
+				const gchar *folder_name,
+				const gchar *uid,
+				GByteArray **message_bytes, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	ExchangeMessage *mmsg;
+	E2kHTTPStatus status;
+	gchar *body = NULL, *content_type = NULL, *owner_email = NULL;
+	gint len = 0;
+	gboolean res = FALSE;
+	CamelMessageInfo *info;
+	CamelFolder *folder;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (message_bytes != NULL, FALSE);
+
+	mfld = folder_from_name (ed, folder_name, MAPI_ACCESS_READ, ex);
+	if (!mfld)
+		return FALSE;
+
+	folder = get_camel_folder (mfld);
+
+	mmsg = find_message (mfld, uid);
+	if (!mmsg) {
+		if (folder && (info = camel_folder_summary_uid (folder->summary, uid))) {
+			camel_message_info_free (info);
+			camel_exchange_folder_remove_message (CAMEL_EXCHANGE_FOLDER (folder), uid);
+		}
+
+		set_exception (ex, _("No such message"));
+		return FALSE;
+	}
+
+	if (mfld->type == EXCHANGE_FOLDER_NOTES) {
+		status = get_stickynote (ed->ctx, NULL, mmsg->href, &body, &len);
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+			goto error;
+		content_type = g_strdup ("message/rfc822");
+	} else {
+		SoupBuffer *response;
+
+		status = e2k_context_get (ed->ctx, NULL, mmsg->href, &content_type, &response);
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+			goto error;
+
+		len = response->length;
+		body = g_strndup (response->data, response->length);
+		soup_buffer_free (response);
+	}
+
+	/* Public folders especially can contain non-email objects.
+	 * In that case, we fake the headers (which in this case
+	 * should include Content-Type, Content-Disposition, etc,
+	 * courtesy of mp:x67200102.
+	 */
+	if (!content_type || g_ascii_strncasecmp (content_type, "message/", 8)) {
+		status = build_message_from_document (ed->ctx, NULL, mmsg->href, &body, &len);
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+			goto error;
+	}
+
+	/* If this is a delegated meeting request, we need to know who
+	 * delegated it to us.
+	 */
+	if (mmsg->flags & EXMAIL_DELEGATED) {
+		status = unmangle_delegated_meeting_request (ed, NULL, mmsg->href, &body, &len);
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+			goto error;
+	}
+
+	/* If the message is in a subscribed inbox,
+	 * we need to modify the message appropriately.
+	 */
+	if (is_foreign_folder (ed, folder_name, &owner_email)) {
+		status = unmangle_meeting_request_in_subscribed_inbox (ed, owner_email, &body, &len);
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+			goto error;
+	}
+
+	/* If there is a sender field in the meeting request/response,
+	 * we need to know who it is.
+	 */
+	status = unmangle_sender_field (ed, NULL, mmsg->href, &body, &len);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
+		goto error;
+
+	*message_bytes = g_byte_array_sized_new (len);
+	g_byte_array_append (*message_bytes, (const guint8 *)body, len);
+
+	res = TRUE;
+
+	goto cleanup;
+
+ error:
+	g_warning ("get_message: %d", status);
+	if (status == E2K_HTTP_NOT_FOUND) {
+		/* We don't change mfld->deleted_count, because the
+		 * message may actually have gone away before the last
+		 * time we recorded that.
+		 */
+		message_removed (mfld, folder, mmsg->href);
+		set_exception (ex, _("Message has been deleted"));
+	} else
+		set_exception (ex, _("Error retrieving message"));
+
+ cleanup:
+	g_free (body);
+	g_free (content_type);
+	g_free (owner_email);
+
+	return res;
+}
+
+gboolean
+camel_exchange_utils_search (CamelService *service,
+				const gchar *folder_name,
+				const gchar *text,
+				GPtrArray **found_uids, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	E2kRestriction *rn;
+	const gchar *prop, *repl_uid;
+	E2kResultIter *iter;
+	E2kResult *result;
+	E2kHTTPStatus status;
+	GPtrArray *matches;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (found_uids != NULL, FALSE);
+
+	mfld = folder_from_name (ed, folder_name, 0, ex);
+	if (!mfld)
+		return FALSE;
+
+	matches = g_ptr_array_new ();
+
+	prop = E2K_PR_REPL_UID;
+	rn = e2k_restriction_content (PR_BODY, E2K_FL_SUBSTRING, text);
+
+	iter = e_folder_exchange_search_start (mfld->folder, NULL, &prop, 1, rn, NULL, TRUE);
+	e2k_restriction_unref (rn);
+
+	while ((result = e2k_result_iter_next (iter))) {
+		repl_uid = e2k_properties_get_prop (result->props, E2K_PR_REPL_UID);
+		if (repl_uid)
+			g_ptr_array_add (matches, g_strdup (uidstrip (repl_uid)));
+	}
+	status = e2k_result_iter_free (iter);
+
+	if (status == E2K_HTTP_UNPROCESSABLE_ENTITY) {
+		set_exception (ex, _("Mailbox does not support full-text searching"));
+
+		g_ptr_array_foreach (matches, (GFunc) g_free, NULL);
+		g_ptr_array_free (matches, TRUE);
+		matches = NULL;
+	} else {
+		*found_uids = matches;
+	}
+
+	return matches != NULL;
+}
+
+gboolean
+camel_exchange_utils_transfer_messages (CamelService *service,
+					const gchar *source_name,
+					const gchar *dest_name,
+					GPtrArray *uids,
+					gboolean delete_originals,
+					GPtrArray **ret_uids, /* out */
+					CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *source, *dest;
+	ExchangeMessage *mmsg;
+	GPtrArray *hrefs, *new_uids;
+	GHashTable *order;
+	gpointer key, value;
+	E2kResultIter *iter;
+	E2kResult *result;
+	E2kHTTPStatus status;
+	const gchar *uid;
+	gint i, num;
+	CamelFolder *folder;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (ret_uids != NULL, FALSE);
+
+	source = folder_from_name (ed, source_name, delete_originals ? MAPI_ACCESS_DELETE : 0, ex);
+	if (!source)
+		return FALSE;
+	dest = folder_from_name (ed, dest_name, MAPI_ACCESS_CREATE_CONTENTS, ex);
+	if (!dest)
+		return FALSE;
+
+	order = g_hash_table_new (NULL, NULL);
+	hrefs = g_ptr_array_new ();
+	new_uids = g_ptr_array_new ();
+	for (i = 0; i < uids->len; i++) {
+		mmsg = find_message (source, uids->pdata[i]);
+		if (!mmsg)
+			continue;
+
+		if (!mmsg->href || !strrchr (mmsg->href, '/')) {
+			g_warning ("%s: Message '%s' with invalid href '%s'", G_STRFUNC, (gchar *)uids->pdata[i], mmsg->href ? mmsg->href : "NULL");
+			continue;
+		}
+
+		g_hash_table_insert (order, mmsg, GINT_TO_POINTER (i));
+		g_ptr_array_add (hrefs, strrchr (mmsg->href, '/') + 1);
+		g_ptr_array_add (new_uids, g_strdup (""));
+	}
+
+	folder = get_camel_folder (source);
+
+	if (delete_originals && hrefs->len > 1 && folder) {
+		camel_folder_freeze (folder);
+	}
+
+	iter = e_folder_exchange_transfer_start (source->folder, NULL,
+						 dest->folder, hrefs,
+						 delete_originals);
+
+	while ((result = e2k_result_iter_next (iter))) {
+		if (!e2k_properties_get_prop (result->props, E2K_PR_DAV_LOCATION))
+			continue;
+		uid = e2k_properties_get_prop (result->props, E2K_PR_REPL_UID);
+		if (!uid)
+			continue;
+
+		if (delete_originals)
+			source->deleted_count++;
+
+		mmsg = find_message_by_href (source, result->href);
+		if (!mmsg)
+			continue;
+
+		if (!g_hash_table_lookup_extended (order, mmsg, &key, &value))
+			continue;
+		num = GPOINTER_TO_UINT (value);
+		if (num > new_uids->len)
+			continue;
+
+		g_free (new_uids->pdata[num]);
+		new_uids->pdata[num] = g_strdup (uidstrip (uid));
+
+		if (delete_originals)
+			message_removed (source, folder, result->href);
+	}
+	status = e2k_result_iter_free (iter);
+
+	if (delete_originals && hrefs->len > 1 && folder) {
+		camel_folder_thaw (folder);
+	}
+
+	if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		*ret_uids = new_uids;
+	} else {
+		g_warning ("transferred_messages: %d", status);
+		set_exception (ex, _("Unable to move/copy messages"));
+		g_ptr_array_free (new_uids, TRUE);
+		new_uids = NULL;
+	}
+
+	g_ptr_array_free (hrefs, TRUE);
+	g_hash_table_destroy (order);
+
+	return new_uids != NULL;
+}
+
+static void
+account_new_folder (ExchangeAccount *account, EFolder *folder, gpointer user_data)
+{
+	ExchangeData *ed = user_data;
+	ExchangeHierarchy *hier;
+
+	g_return_if_fail (ed != NULL);
+
+	if (strcmp (e_folder_get_type_string (folder), "mail") != 0 &&
+	    strcmp (e_folder_get_type_string (folder), "mail/public") != 0)
+		return;
+
+	if (ed->ignore_new_folder &&
+	    !strcmp (e_folder_exchange_get_path (folder), ed->ignore_new_folder))
+		return;
+
+	hier = e_folder_exchange_get_hierarchy (folder);
+	if (hier->type != EXCHANGE_HIERARCHY_PERSONAL &&
+	    hier->type != EXCHANGE_HIERARCHY_FAVORITES &&
+	    hier->type != EXCHANGE_HIERARCHY_FOREIGN)
+		return;
+
+	camel_exchange_store_folder_created (ed->estore, e_folder_get_name (folder), e_folder_get_physical_uri (folder));
+}
+
+static void
+account_removed_folder (ExchangeAccount *account, EFolder *folder, gpointer user_data)
+{
+	ExchangeData *ed = user_data;
+	ExchangeHierarchy *hier;
+
+	g_return_if_fail (ed != NULL);
+
+	if (strcmp (e_folder_get_type_string (folder), "mail") != 0 &&
+	    strcmp (e_folder_get_type_string (folder), "mail/public") != 0)
+		return;
+
+	if (ed->ignore_removed_folder &&
+	    !strcmp (e_folder_exchange_get_path (folder), ed->ignore_removed_folder))
+		return;
+
+	hier = e_folder_exchange_get_hierarchy (folder);
+	if (hier->type != EXCHANGE_HIERARCHY_PERSONAL &&
+	    hier->type != EXCHANGE_HIERARCHY_FAVORITES &&
+	    hier->type != EXCHANGE_HIERARCHY_FOREIGN)
+		return;
+
+	camel_exchange_store_folder_deleted (ed->estore, e_folder_get_name (folder), e_folder_get_physical_uri (folder));
+}
+
+gboolean
+camel_exchange_utils_get_folder_info (CamelService *service,
+					const gchar *top,
+					guint32 store_flags,
+					GPtrArray **folder_names, /* out */
+					GPtrArray **folder_uris, /* out */
+					GArray **unread_counts, /* out */
+					GArray **folder_flags, /* out */
+					CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (folder_names != NULL, FALSE);
+	g_return_val_if_fail (folder_uris != NULL, FALSE);
+	g_return_val_if_fail (unread_counts != NULL, FALSE);
+	g_return_val_if_fail (folder_flags != NULL, FALSE);
+
+	get_folder_info_data (ed, top, store_flags, folder_names, folder_uris, unread_counts, folder_flags);
+
+	if (ed->new_folder_id == 0) {
+		ed->new_folder_id = g_signal_connect (ed->account, "new_folder", G_CALLBACK (account_new_folder), ed);
+		ed->removed_folder_id = g_signal_connect (ed->account, "removed_folder", G_CALLBACK (account_removed_folder), ed);
+	}
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_send_message (CamelService *service,
+				const gchar *from,
+				GPtrArray *recipients,
+				const GByteArray *message,
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	SoupMessage *msg;
+	E2kHTTPStatus status;
+	gchar *timestamp, *errmsg;
+	GString *data;
+	gint i;
+	gboolean res = FALSE;
+
+	/* This function is called from a transport service, thus it has no idea
+	   about underlying folders and such. The check for estore != NULL is
+	   necessary to be sure the transport service was called after the connect,
+	   because the estore is used in other functions. */
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (ed->estore != NULL, FALSE);
+
+	if (!ed->mail_submission_uri) {
+		set_exception (ex, _("No mail submission URI for this mailbox"));
+		return FALSE;
+	}
+
+	data = g_string_new (NULL);
+	g_string_append_printf (data, "MAIL FROM:<%s>\r\n", from);
+	for (i = 0; i < recipients->len; i++) {
+		g_string_append_printf (data, "RCPT TO:<%s>\r\n", (gchar *)recipients->pdata[i]);
+	}
+	g_string_append (data, "\r\n");
+
+	/* Exchange doesn't add a "Received" header to messages
+	 * received via WebDAV.
+	 */
+	timestamp = e2k_make_timestamp_rfc822 (time (NULL));
+	g_string_append_printf (data, "Received: from %s by %s; %s\r\n",
+				g_get_host_name (), ed->account->exchange_server,
+				timestamp);
+	g_free (timestamp);
+
+	g_string_append_len (data, (const gchar *)message->data, message->len);
+
+	msg = e2k_soup_message_new_full (ed->ctx, ed->mail_submission_uri,
+					 SOUP_METHOD_PUT, "message/rfc821",
+					 SOUP_MEMORY_TAKE,
+					 data->str, data->len);
+	g_string_free (data, FALSE);
+	soup_message_headers_append (msg->request_headers, "Saveinsent", "f");
+
+	status = e2k_context_send_message (ed->ctx, NULL, msg);
+	if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		res = TRUE;
+	} else if (status == E2K_HTTP_NOT_FOUND) {
+		set_exception (ex, _("Server won't accept mail via Exchange transport"));
+	} else if (status == E2K_HTTP_FORBIDDEN) {
+		errmsg = g_strdup_printf (_("Your account does not have permission "
+					    "to use <%s>\nas a From address."),
+					  from);
+		set_exception (ex, errmsg);
+		g_free (errmsg);
+	} else if (status == E2K_HTTP_INSUFFICIENT_SPACE_ON_RESOURCE ||
+		   status == E2K_HTTP_INTERNAL_SERVER_ERROR) {
+		/* (500 is what it actually returns, 507 is what it should
+		 * return, so we handle that too in case the behavior
+		 * changes in the future.)
+		 */
+		E2K_KEEP_PRECEDING_COMMENT_OUT_OF_PO_FILES;
+		set_exception (ex, _("Could not send message.\n"
+				     "This might mean that your account is over quota."));
+	} else {
+		g_warning ("sent_message: %d", status);
+		set_exception (ex, _("Could not send message"));
+	}
+
+	return res;
+}
+
+gboolean
+camel_exchange_utils_create_folder (CamelService *service,
+				const gchar *parent_name,
+				const gchar *folder_name,
+				gchar **folder_uri, /* out */
+				guint32 *unread_count, /* out */
+				guint32 *flags, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeAccountFolderResult result;
+	EFolder *folder;
+	gchar *path;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (folder_uri != NULL, FALSE);
+	g_return_val_if_fail (unread_count != NULL, FALSE);
+	g_return_val_if_fail (flags != NULL, FALSE);
+
+	path = g_build_filename ("/", parent_name, folder_name, NULL);
+	result = exchange_account_create_folder (ed->account, path, "mail");
+	folder = exchange_account_get_folder (ed->account, path);
+	g_free (path);
+
+	switch (result) {
+	case EXCHANGE_ACCOUNT_FOLDER_OK:
+		if (folder)
+			break;
+		/* fall through */
+	default:
+		set_exception (ex, _("Generic error"));
+		return FALSE;
+
+	case EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS:
+		set_exception (ex, _("Folder already exists"));
+		return FALSE;
+
+	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+		set_exception (ex, _("Permission denied"));
+		return FALSE;
+	}
+
+	*folder_uri = g_strdup (e_folder_get_physical_uri (folder));
+	*unread_count = e_folder_get_unread_count (folder);
+	*flags = 0;
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_delete_folder (CamelService *service,
+				const gchar *folder_name,
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeAccountFolderResult result;
+	EFolder *folder;
+	gchar *path;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+
+	path = g_build_filename ("/", folder_name, NULL);
+	folder = exchange_account_get_folder (ed->account, path);
+	if (!folder) {
+		set_exception (ex, _("Folder doesn't exist"));
+		g_free (path);
+		return FALSE;
+	}
+	g_object_ref (folder);
+
+	result = exchange_account_remove_folder (ed->account, path);
+	g_free (path);
+
+	switch (result) {
+	case EXCHANGE_ACCOUNT_FOLDER_OK:
+	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+		g_hash_table_remove (ed->folders_by_name, folder_name);
+		break;
+
+	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED: /* Fall through */
+	case EXCHANGE_ACCOUNT_FOLDER_UNSUPPORTED_OPERATION:
+		set_exception (ex, _("Permission denied"));
+		g_object_unref (folder);
+		return FALSE;
+
+	default:
+		set_exception (ex, _("Generic error"));
+		g_object_unref (folder);
+		return FALSE;
+
+	}
+
+	g_object_unref (folder);
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_rename_folder (CamelService *service,
+				const gchar *old_name,
+				const gchar *new_name,
+				GPtrArray **folder_names, /* out */
+				GPtrArray **folder_uris, /* out */
+				GArray **unread_counts, /* out */
+				GArray **folder_flags, /* out */
+				CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
+	ExchangeAccountFolderResult result;
+	EFolder *folder;
+	gchar *old_path, *new_path;
+	GPtrArray *names, *uris;
+	GArray *unread, *flags;
+	gint i = 0, j = 0;
+	gchar **folder_name;
+	const gchar *uri;
+	gchar *new_name_mod, *old_name_remove, *uri_unescaped, *old_name_mod = NULL;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (folder_names != NULL, FALSE);
+	g_return_val_if_fail (folder_uris != NULL, FALSE);
+	g_return_val_if_fail (unread_counts != NULL, FALSE);
+	g_return_val_if_fail (folder_flags != NULL, FALSE);
+
+	old_path = g_build_filename ("/", old_name, NULL);
+	folder = exchange_account_get_folder (ed->account, old_path);
+	if (!folder) {
+		set_exception (ex, _("Folder doesn't exist"));
+		g_free (old_path);
+		return FALSE;
+	}
+	new_path = g_build_filename ("/", new_name, NULL);
+
+	ed->ignore_removed_folder = old_path;
+	ed->ignore_new_folder = new_path;
+	result = exchange_account_xfer_folder (ed->account, old_path, new_path, TRUE);
+	folder = exchange_account_get_folder (ed->account, new_path);
+	ed->ignore_new_folder = ed->ignore_removed_folder = NULL;
+	g_free (old_path);
+	g_free (new_path);
+
+	switch (result) {
+	case EXCHANGE_ACCOUNT_FOLDER_OK:
+		mfld = g_hash_table_lookup (ed->folders_by_name, old_name);
+		if (!mfld)
+			break;
+
+		g_object_unref (mfld->folder);
+		mfld->folder = g_object_ref (folder);
+		mfld->name = e_folder_exchange_get_path (folder) + 1;
+
+		g_hash_table_steal (ed->folders_by_name, old_name);
+		g_hash_table_insert (ed->folders_by_name, (gchar *)mfld->name, mfld);
+
+		get_folder_info_data (ed, new_name, CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, &names, &uris, &unread, &flags);
+
+		g_hash_table_remove_all (mfld->messages_by_href);
+
+		for (i = 0; i < mfld->messages->len; i++) {
+			ExchangeMessage *mmsg;
+			mmsg = mfld->messages->pdata[i];
+			g_free (mmsg->href);
+			mmsg->href = NULL;
+		}
+
+		if (is_online (ed) == ONLINE_MODE) {
+			if (!get_folder_online (mfld, ex)) {
+				return FALSE;
+			}
+		}
+
+		for (i = 0; i < uris->len; i++) {
+			uri = uris->pdata[i];
+			if (uri == NULL)
+				continue;
+
+			uri_unescaped = g_uri_unescape_string (uri, NULL);
+			new_name_mod = g_strconcat (new_name, "/", NULL);
+			folder_name = g_strsplit (uri_unescaped, new_name_mod, 2);
+
+			if (!folder_name[1]) {
+				g_strfreev (folder_name);
+				old_name_mod = g_strconcat (old_name, "/", NULL);
+				folder_name = g_strsplit (uri_unescaped, old_name_mod, 2);
+				g_free (old_name_mod);
+
+				if (!folder_name[1]) {
+					goto cont_free;
+				}
+			}
+
+			old_name_remove = g_build_filename (old_name, "/", folder_name[1], NULL);
+
+			mfld = g_hash_table_lookup (ed->folders_by_name, old_name_remove);
+
+			/* If the lookup for the ExchangeFolder doesn't succeed then do
+			not modify the corresponding entry in the hash table*/
+			if (!mfld) {
+				g_free (old_name_remove);
+				goto cont_free;
+			}
+
+			new_path = g_build_filename ("/", new_name_mod, folder_name[1], NULL);
+			old_path = g_build_filename ("/", old_name_remove, NULL);
+
+			ed->ignore_removed_folder = old_path;
+			ed->ignore_new_folder = new_path;
+			result = exchange_account_xfer_folder (ed->account, old_path, new_path, TRUE);
+			folder = exchange_account_get_folder (ed->account, new_path);
+			ed->ignore_new_folder = ed->ignore_removed_folder = NULL;
+
+			g_object_unref (mfld->folder);
+			mfld->folder = g_object_ref (folder);
+			mfld->name = e_folder_exchange_get_path (folder) + 1;
+
+			g_hash_table_steal (ed->folders_by_name, old_name_remove);
+			g_hash_table_insert (ed->folders_by_name, (gchar *)mfld->name, mfld);
+
+			g_hash_table_remove_all (mfld->messages_by_href);
+
+			for (j = 0; j < mfld->messages->len; j++) {
+				ExchangeMessage *mmsg;
+				mmsg = mfld->messages->pdata[j];
+				g_free (mmsg->href);
+				mmsg->href = NULL;
+			}
+
+			if (is_online (ed) == ONLINE_MODE) {
+				if (!get_folder_online (mfld, ex)) {
+					return FALSE;
+				}
+			}
+
+			g_free (old_path);
+			g_free (new_path);
+ cont_free:		g_free (new_name_mod);
+			g_free (uri_unescaped);
+			g_strfreev (folder_name);
+		}
+
+		*folder_names = names;
+		*folder_uris = uris;
+		*unread_counts = unread;
+		*folder_flags = flags;
+		break;
+
+	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+		set_exception (ex, _("Folder doesn't exist"));
+		return FALSE;
+
+	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+		set_exception (ex, _("Permission denied"));
+		return FALSE;
+
+	default:
+		set_exception (ex, _("Generic error"));
+		return FALSE;
+
+	}
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_subscribe_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeAccountFolderResult result;
+	EFolder *folder;
+	gchar *path;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+
+	path = g_build_filename ("/", folder_name, NULL);
+	folder = exchange_account_get_folder (ed->account, path);
+	if (!folder) {
+		set_exception (ex, _("Folder doesn't exist"));
+		g_free (path);
+		return FALSE;
+	}
+	g_free (path);
+	g_object_ref (folder);
+
+	if (e_folder_exchange_get_hierarchy (folder)->type != EXCHANGE_HIERARCHY_PUBLIC) {
+		g_object_unref (folder);
+		return TRUE;
+	}
+
+	if (!strcmp (e_folder_get_type_string (folder), "noselect")) {
+		g_object_unref (folder);
+		return TRUE;
+	}
+
+	result = exchange_account_add_favorite (ed->account, folder);
+	g_object_unref (folder);
+
+	switch (result) {
+	case EXCHANGE_ACCOUNT_FOLDER_OK:
+	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+		break;
+
+	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+		set_exception (ex, _("Permission denied"));
+		return FALSE;
+
+	default:
+		set_exception (ex, _("Generic error"));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_unsubscribe_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeAccountFolderResult result;
+	EFolder *folder;
+	gchar *path, *pub_name;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+
+	path = g_build_filename ("/", folder_name, NULL);
+	folder = exchange_account_get_folder (ed->account, path);
+	if (!folder) {
+		set_exception (ex, _("Folder doesn't exist"));
+		g_free (path);
+		return FALSE;
+	}
+	g_free (path);
+	g_object_ref (folder);
+
+	/* if (e_folder_exchange_get_hierarchy (folder)->type != EXCHANGE_HIERARCHY_FAVORITES) {
+	   Should use above check, but the internal uri is the same for both
+	   public and favorite hierarchies and any of them can be used for the check */
+	if (!exchange_account_is_favorite_folder (ed->account, folder)) {
+		g_object_unref (folder);
+		return TRUE;
+	}
+
+	g_object_unref (folder);
+
+	pub_name = strrchr (folder_name, '/');
+	path = g_build_filename ("/favorites", pub_name, NULL);
+	folder = exchange_account_get_folder (ed->account, path);
+	if (!folder) {
+		set_exception (ex, _("Folder doesn't exist"));
+		g_free (path);
+		return FALSE;
+	}
+	g_object_ref (folder);
+
+	result = exchange_account_remove_favorite (ed->account, folder);
+
+	switch (result) {
+	case EXCHANGE_ACCOUNT_FOLDER_OK:
+	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+		g_hash_table_remove (ed->folders_by_name, path + 1);
+		break;
+
+	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+		set_exception (ex, _("Permission denied"));
+		g_object_unref (folder);
+		g_free (path);
+		return FALSE;
+
+	default:
+		set_exception (ex, _("Generic error"));
+		g_object_unref (folder);
+		g_free (path);
+		return FALSE;
+
+	}
+
+	g_object_unref (folder);
+	g_free (path);
+
+	return TRUE;
+}
+
+gboolean
+camel_exchange_utils_is_subscribed_folder (CamelService *service,
+					const gchar *folder_name,
+					gboolean *is_subscribed, /* out */
+					CamelException *ex)
+{
+	ExchangeData *ed = get_data_for_service (service);
+	EFolder *folder;
+	gchar *path;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (is_subscribed != NULL, FALSE);
+
+	*is_subscribed = FALSE;
+
+	path = g_build_filename ("/", folder_name, NULL);
+	folder = exchange_account_get_folder (ed->account, path);
+	if (!folder) {
+		g_free (path);
+		return TRUE;
+	}
+	g_free (path);
+	g_object_ref (folder);
+
+	if (exchange_account_is_favorite_folder (ed->account, folder))
+		*is_subscribed = TRUE;
+
+	g_object_unref (folder);
+
+	return TRUE;
+}
diff --git a/camel/camel-exchange-utils.h b/camel/camel-exchange-utils.h
new file mode 100644
index 0000000..be22166
--- /dev/null
+++ b/camel/camel-exchange-utils.h
@@ -0,0 +1,141 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Copyright (C) 2001-2004 Novell, Inc. */
+
+#ifndef CAMEL_EXCHANGE_UTILS_H
+#define CAMEL_EXCHANGE_UTILS_H
+
+#include <camel/camel-service.h>
+#include <camel/camel-exception.h>
+
+G_BEGIN_DECLS
+
+gboolean camel_exchange_utils_connect (CamelService *service,
+					const gchar *pwd,
+					guint32 *status, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_get_folder (CamelService *service,
+					const gchar *name,
+					gboolean create,
+					GPtrArray *uids,
+					GByteArray *flags,
+					GPtrArray *hrefs,
+					guint32 high_article_num,
+					guint32 *folder_flags, /* out */
+					gchar **folder_uri, /* out */
+					gboolean *readonly, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_get_trash_name (CamelService *service,
+					gchar **trash_name, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_refresh_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_sync_count (CamelService *service,
+					const gchar *folder_name,
+					guint32 *unread_count, /* out */
+					guint32 *visible_count, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_expunge_uids (CamelService *service,
+					const gchar *folder_name,
+					GPtrArray *uids,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_append_message (CamelService *service,
+					const gchar *folder_name,
+					guint32 flags,
+					const gchar *subject,
+					const GByteArray *message,
+					gchar **new_uid, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_set_message_flags (CamelService *service,
+					const gchar *folder_name,
+					const gchar *uid,
+					guint32 flags,
+					guint32 mask,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_set_message_tag (CamelService *service,
+					const gchar *folder_name,
+					const gchar *uid,
+					const gchar *name,
+					const gchar *value,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_get_message (CamelService *service,
+					const gchar *folder_name,
+					const gchar *uid,
+					GByteArray **message_bytes, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_search (CamelService *service,
+					const gchar *folder_name,
+					const gchar *text,
+					GPtrArray **found_uids, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_transfer_messages (CamelService *service,
+					const gchar *source_name,
+					const gchar *dest_name,
+					GPtrArray *uids,
+					gboolean delete_originals,
+					GPtrArray **ret_uids, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_get_folder_info (CamelService *service,
+					const gchar *top,
+					guint32 store_flags,
+					GPtrArray **folder_names, /* out */
+					GPtrArray **folder_uris, /* out */
+					GArray **unread_counts, /* out */
+					GArray **folder_flags, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_send_message (CamelService *service,
+					const gchar *from,
+					GPtrArray *recipients,
+					const GByteArray *message,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_create_folder (CamelService *service,
+					const gchar *parent_name,
+					const gchar *folder_name,
+					gchar **folder_uri, /* out */
+					guint32 *unread_count, /* out */
+					guint32 *flags, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_delete_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_rename_folder (CamelService *service,
+					const gchar *old_name,
+					const gchar *new_name,
+					GPtrArray **folder_names, /* out */
+					GPtrArray **folder_uris, /* out */
+					GArray **unread_counts, /* out */
+					GArray **folder_flags, /* out */
+					CamelException *ex);
+
+gboolean camel_exchange_utils_subscribe_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_unsubscribe_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex);
+
+gboolean camel_exchange_utils_is_subscribed_folder (CamelService *service,
+					const gchar *folder_name,
+					gboolean *is_subscribed, /* out */
+					CamelException *ex);
+
+G_END_DECLS
+
+#endif /* CAMEL_EXCHANGE_UTILS_H */
diff --git a/camel/camel-stub-marshal.c b/camel/camel-stub-marshal.c
deleted file mode 100644
index 5fca078..0000000
--- a/camel/camel-stub-marshal.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2001-2006 Novell, Inc.
- *
- * 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 <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <glib.h>
-
-#ifndef G_OS_WIN32
-#define CLOSESOCKET(s) close (s)
-#else
-#define CLOSESOCKET(s) closesocket (s)
-#include <winsock2.h>
-/* Note: pthread.h from pthreads-win32 also defines ETIMEDOUT (!), as
- * this same value.
- */
-#define ETIMEDOUT WSAETIMEDOUT
-#endif
-
-#include <camel/camel-file-utils.h>
-
-#include "camel-stub-marshal.h"
-
-#if 1
-#define CAMEL_MARSHAL_DEBUG
-static gboolean debug = 0;
-#define DEBUGGING debug
-#else
-#define DEBUGGING 0
-#endif
-
-/**
- * camel_stub_marshal_new:
- * @fd: a socket file descriptor
- *
- * Creates a new #CamelStubMarshal, which handles sending and
- * receiving data between #CamelExchangeStore and #MailStubExchange.
- *
- * Return value: the new #CamelStubMarshal.
- **/
-CamelStubMarshal *
-camel_stub_marshal_new (gint fd)
-{
-	CamelStubMarshal *marshal = g_new0 (CamelStubMarshal, 1);
-
-#ifdef CAMEL_MARSHAL_DEBUG
-	gchar *e2k_debug = getenv ("E2K_DEBUG");
-
-	if (e2k_debug && strchr (e2k_debug, 'm'))
-		debug = TRUE;
-#endif
-
-	marshal->fd = fd;
-	marshal->out = g_byte_array_new ();
-	g_byte_array_set_size (marshal->out, 4);
-	marshal->in = g_byte_array_new ();
-	marshal->inptr = (gchar *)marshal->in->data;
-	return marshal;
-}
-
-/**
- * camel_stub_marshal_free:
- * @marshal: the #CamelStubMarshal
- *
- * Frees @marshal
- **/
-void
-camel_stub_marshal_free (CamelStubMarshal *marshal)
-{
-	CLOSESOCKET (marshal->fd);
-	g_byte_array_free (marshal->out, TRUE);
-	g_byte_array_free (marshal->in, TRUE);
-	g_free (marshal);
-}
-
-static gboolean
-do_read (CamelStubMarshal *marshal, gchar *buf, gsize len)
-{
-	gsize nread = 0;
-	gssize n;
-
-	do {
-		if ((n = camel_read_socket (marshal->fd, buf + nread, len - nread)) <= 0) {
-			if (errno != ETIMEDOUT)
-				break;
-			else
-				n = 0;
-		}
-		nread += n;
-	} while (nread < len);
-
-	if (nread < len) {
-		CLOSESOCKET (marshal->fd);
-		marshal->fd = -1;
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static gint
-marshal_read (CamelStubMarshal *marshal, gchar *buf, gint len)
-{
-	gint avail = marshal->in->len - (marshal->inptr - (gchar *)marshal->in->data);
-	gint nread;
-
-	if (avail == 0) {
-		g_byte_array_set_size (marshal->in, 4);
-		marshal->inptr = (gchar *)marshal->in->data + 4;
-		if (!do_read (marshal, (gchar *)marshal->in->data, 4))
-			return -1;
-		avail =  (gint)marshal->in->data[0]        +
-			((gint)marshal->in->data[1] <<  8) +
-			((gint)marshal->in->data[2] << 16) +
-			((gint)marshal->in->data[3] << 24) - 4;
-		g_byte_array_set_size (marshal->in, avail + 4);
-		marshal->inptr = (gchar *)marshal->in->data + 4;
-		if (!do_read (marshal, ((gchar *)marshal->in->data) + 4, avail)) {
-			g_byte_array_set_size (marshal->in, 4);
-			marshal->inptr = (gchar *)marshal->in->data + 4;
-			return -1;
-		}
-	}
-
-	if (len <= avail)
-		nread = len;
-	else
-		nread = avail;
-	memcpy (buf, marshal->inptr, nread);
-	marshal->inptr += nread;
-
-	if (DEBUGGING) {
-		if (nread < len)
-			printf ("<<< short read: %d of %d\n", nread, len);
-	}
-
-	return nread;
-}
-
-static gint
-marshal_getc (CamelStubMarshal *marshal)
-{
-	gchar buf;
-
-	if (marshal_read (marshal, &buf, 1) == 1)
-		return (guchar)buf;
-	return -1;
-}
-
-static void
-encode_uint32 (CamelStubMarshal *marshal, guint32 value)
-{
-	guchar c;
-	gint i;
-
-	for (i = 28; i > 0; i -= 7) {
-		if (value >= (1 << i)) {
-			c = (value >> i) & 0x7f;
-			g_byte_array_append (marshal->out, &c, 1);
-		}
-	}
-	c = value | 0x80;
-	g_byte_array_append (marshal->out, &c, 1);
-}
-
-static gint
-decode_uint32 (CamelStubMarshal *marshal, guint32 *dest)
-{
-        guint32 value = 0;
-	gint v;
-
-        /* until we get the last byte, keep decoding 7 bits at a time */
-        while ( ((v = marshal_getc (marshal)) & 0x80) == 0 && v!=-1) {
-                value |= v;
-                value <<= 7;
-        }
-	if (v == -1) {
-		*dest = value >> 7;
-		return -1;
-	}
-	*dest = value | (v & 0x7f);
-
-        return 0;
-}
-
-static void
-encode_string (CamelStubMarshal *marshal, const gchar *str)
-{
-	gint len;
-
-	if (!str || !*str) {
-		encode_uint32 (marshal, 1);
-		return;
-	}
-
-	len = strlen (str);
-	encode_uint32 (marshal, len + 1);
-	g_byte_array_append (marshal->out, (guint8 *) str, len);
-}
-
-static gint
-decode_string (CamelStubMarshal *marshal, gchar **str)
-{
-	guint32 len;
-	gchar *ret;
-
-	if (decode_uint32 (marshal, &len) == -1) {
-		*str = NULL;
-		return -1;
-	}
-
-	if (len == 1) {
-		*str = NULL;
-		return 0;
-	}
-
-	ret = g_malloc (len--);
-	if (marshal_read (marshal, ret, len) != len) {
-		g_free (ret);
-		*str = NULL;
-		return -1;
-	}
-
-	ret[len] = 0;
-	*str = ret;
-	return 0;
-}
-
-/**
- * camel_stub_marshal_encode_uint32:
- * @marshal: the #CamelStubMarshal
- * @value: value to send
- *
- * Sends @value across @marshall.
- **/
-void
-camel_stub_marshal_encode_uint32 (CamelStubMarshal *marshal, guint32 value)
-{
-	if (DEBUGGING)
-		printf (">>> %lu\n", (unsigned long)value);
-
-	encode_uint32 (marshal, value);
-}
-
-/**
- * camel_stub_marshal_decode_uint32:
- * @marshal: the #CamelStubMarshal
- * @dest: on successful return, will contain the received value.
- *
- * Receives a uint32 value across @marshal.
- *
- * Return value: 0 on success, -1 on failure.
- **/
-gint
-camel_stub_marshal_decode_uint32 (CamelStubMarshal *marshal, guint32 *dest)
-{
-	if (decode_uint32 (marshal, dest) == -1)
-		return -1;
-
-	if (DEBUGGING)
-		printf ("<<< %lu\n", (unsigned long)*dest);
-	return 0;
-}
-
-/**
- * camel_stub_marshal_encode_string:
- * @marshal: the #CamelStubMarshal
- * @str: string to send
- *
- * Sends @str across @marshall.
- **/
-void
-camel_stub_marshal_encode_string (CamelStubMarshal *marshal, const gchar *str)
-{
-	if (DEBUGGING)
-		printf (">>> \"%s\"\n", str ? str : "");
-
-	encode_string (marshal, str);
-}
-
-/**
- * camel_stub_marshal_decode_string:
- * @marshal: the #CamelStubMarshal
- * @str: on successful return, will contain the received string.
- *
- * Receives a string across @marshal.
- *
- * Return value: 0 on success, -1 on failure.
- **/
-gint
-camel_stub_marshal_decode_string (CamelStubMarshal *marshal, gchar **str)
-{
-	if (decode_string (marshal, str) == -1)
-		return -1;
-	if (!*str)
-		*str = g_malloc0 (1);
-
-	if (DEBUGGING)
-		printf ("<<< \"%s\"\n", *str);
-	return 0;
-}
-
-/**
- * camel_stub_marshal_encode_folder:
- * @marshal: the #CamelStubMarshal
- * @name: folder name to send
- *
- * Sends @name across @marshall. This is an optimization over
- * camel_stub_marshal_encode_string(), because if the same folder name
- * is used in successive calls to camel_stub_marshal_encode_folder()
- * (as will normally be the case when doing many things in the same folder),
- * the folder name only needs to be sent once.
- **/
-void
-camel_stub_marshal_encode_folder (CamelStubMarshal *marshal, const gchar *name)
-{
-	if (marshal->last_folder) {
-		if (!strcmp (name, marshal->last_folder)) {
-			if (DEBUGGING)
-				printf (">>> (%s)\n", name);
-			encode_string (marshal, "");
-			return;
-		}
-
-		g_free (marshal->last_folder);
-	}
-
-	if (DEBUGGING)
-		printf (">>> %s\n", name);
-	encode_string (marshal, name);
-	marshal->last_folder = g_strdup (name);
-}
-
-/**
- * camel_stub_marshal_decode_folder:
- * @marshal: the #CamelStubMarshal
- * @name: on successful return, will contain the received folder name.
- *
- * Receives a folder name across @marshal.
- *
- * Return value: 0 on success, -1 on failure.
- **/
-gint
-camel_stub_marshal_decode_folder (CamelStubMarshal *marshal, gchar **name)
-{
-	if (decode_string (marshal, name) == -1)
-		return -1;
-	if (!*name) {
-		*name = g_strdup (marshal->last_folder);
-		if (DEBUGGING)
-			printf ("<<< (%s)\n", *name);
-	} else {
-		g_free (marshal->last_folder);
-		marshal->last_folder = g_strdup (*name);
-		if (DEBUGGING)
-			printf ("<<< %s\n", *name);
-	}
-
-	return 0;
-}
-
-/**
- * camel_stub_marshal_encode_bytes:
- * @marshal: the #CamelStubMarshal
- * @ba: data to send
- *
- * Sends @ba across @marshall.
- **/
-void
-camel_stub_marshal_encode_bytes (CamelStubMarshal *marshal, GByteArray *ba)
-{
-	if (DEBUGGING)
-		printf (">>> %d bytes\n", ba->len);
-	encode_uint32 (marshal, ba->len);
-	g_byte_array_append (marshal->out, ba->data, ba->len);
-}
-
-/**
- * camel_stub_marshal_decode_bytes:
- * @marshal: the #CamelStubMarshal
- * @ba: on successful return, will contain the received data
- *
- * Receives a byte array across @marshal.
- *
- * Return value: 0 on success, -1 on failure.
- **/
-gint
-camel_stub_marshal_decode_bytes (CamelStubMarshal *marshal, GByteArray **ba)
-{
-	guint32 len;
-
-	if (decode_uint32 (marshal, &len) == -1) {
-		*ba = NULL;
-		return -1;
-	}
-
-	*ba = g_byte_array_new ();
-	g_byte_array_set_size (*ba, len);
-	if (len > 0 && marshal_read (marshal, (gchar *) (*ba)->data, len) != len) {
-		g_byte_array_free (*ba, TRUE);
-		*ba = NULL;
-		return -1;
-	}
-
-	if (DEBUGGING)
-		printf ("<<< %d bytes\n", (*ba)->len);
-	return 0;
-}
-
-/**
- * camel_stub_marshal_flush:
- * @marshal: a #CamelStubMarshal
- *
- * Flushes pending data on @marshal. (No data is actually sent by the
- * "encode" routines until camel_stub_marshal_flush() is called.)
- *
- * Return value: 0 on success, -1 on failure.
- **/
-gint
-camel_stub_marshal_flush (CamelStubMarshal *marshal)
-{
-	gint left;
-
-	if (marshal->out->len == 4)
-		return 0;
-
-	if (marshal->fd == -1) {
-		if (DEBUGGING)
-			printf ("--- flush failed\n");
-		return -1;
-	}
-
-	if (DEBUGGING)
-		printf ("---\n");
-
-	left = marshal->out->len;
-
-	marshal->out->data[0] =  left        & 0xFF;
-	marshal->out->data[1] = (left >>  8) & 0xFF;
-	marshal->out->data[2] = (left >> 16) & 0xFF;
-	marshal->out->data[3] = (left >> 24) & 0xFF;
-
-	if (camel_write_socket (marshal->fd, (gchar *) marshal->out->data, marshal->out->len) == -1) {
-		CLOSESOCKET (marshal->fd);
-		marshal->fd = -1;
-		return -1;
-	}
-
-	g_byte_array_set_size (marshal->out, 4);
-
-	return 0;
-}
-
-/**
- * camel_stub_marshal_eof:
- * @marshal: a #CamelStubMarshal
- *
- * Tests if the other end of @marshal's connection has been closed.
- *
- * Return value: %TRUE or %FALSE.
- **/
-gboolean
-camel_stub_marshal_eof (CamelStubMarshal *marshal)
-{
-	return marshal->fd == -1;
-}
diff --git a/camel/camel-stub-marshal.h b/camel/camel-stub-marshal.h
deleted file mode 100644
index 99c2a3c..0000000
--- a/camel/camel-stub-marshal.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* Copyright (C) 2001-2004 Novell, Inc. */
-
-/* camel-stub-marshal.h: stub marshal/demarshal functions */
-
-#ifndef CAMEL_STUB_MARSHAL_H
-#define CAMEL_STUB_MARSHAL_H 1
-
-G_BEGIN_DECLS
-
-#include <glib.h>
-
-typedef struct {
-	GByteArray *in, *out;
-	gchar *inptr;
-	gint fd;
-
-	gchar *last_folder;
-} CamelStubMarshal;
-
-CamelStubMarshal *camel_stub_marshal_new           (gint fd);
-void              camel_stub_marshal_free          (CamelStubMarshal *marshal);
-
-void              camel_stub_marshal_encode_uint32 (CamelStubMarshal *marshal,
-						    guint32 value);
-gint               camel_stub_marshal_decode_uint32 (CamelStubMarshal *marshal,
-						    guint32 *dest);
-void              camel_stub_marshal_encode_string (CamelStubMarshal *marshal,
-						    const gchar *str);
-gint               camel_stub_marshal_decode_string (CamelStubMarshal *marshal,
-						    gchar **str);
-void              camel_stub_marshal_encode_folder (CamelStubMarshal *marshal,
-						    const gchar *name);
-gint               camel_stub_marshal_decode_folder (CamelStubMarshal *marshal,
-						    gchar **name);
-void              camel_stub_marshal_encode_bytes  (CamelStubMarshal *marshal,
-						    GByteArray *ba);
-gint               camel_stub_marshal_decode_bytes  (CamelStubMarshal *marshal,
-						    GByteArray **ba);
-
-gint               camel_stub_marshal_flush         (CamelStubMarshal *marshal);
-gboolean          camel_stub_marshal_eof           (CamelStubMarshal *marshal);
-
-G_END_DECLS
-
-#endif /* CAMEL_STUB_MARSHAL_H */
-
diff --git a/camel/camel-stub.c b/camel/camel-stub.c
deleted file mode 100644
index a29799e..0000000
--- a/camel/camel-stub.c
+++ /dev/null
@@ -1,635 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2001-2004 Novell, Inc.
- *
- * 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.
- */
-
-/* camel-stub.c: class for a stub to talk to the backend */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib/gi18n-lib.h>
-
-#include "camel-stub.h"
-
-#include <camel/camel-exception.h>
-#include <camel/camel-operation.h>
-
-#include <errno.h>
-#include <string.h>
-
-#ifndef G_OS_WIN32
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#else
-#include <winsock2.h>
-#endif
-
-CamelStub *das_global_camel_stub;
-
-static void
-class_init (CamelObjectClass *stub_class)
-{
-	camel_object_class_add_event (stub_class, "notification", NULL);
-}
-
-static void
-init (CamelStub *stub)
-{
-	stub->read_lock = g_mutex_new ();
-	stub->write_lock = g_mutex_new ();
-	stub->have_status_thread = FALSE;
-}
-
-static void
-finalize (CamelStub *stub)
-{
-	if (stub->cmd)
-		camel_stub_marshal_free (stub->cmd);
-
-	if (stub->have_status_thread) {
-		gpointer unused;
-
-		/* When we close the command channel, the storage will
-		 * close the status channel, which will in turn cause
-		 * the status loop to exit.
-		 *
-		 * Hah... as if. More than likely it'll just get caught in a read() call.
-		 */
-		if (stub->op)
-			camel_operation_cancel (stub->op);
-
-		pthread_join (stub->status_thread, &unused);
-		camel_stub_marshal_free (stub->status);
-
-		if (stub->op) {
-			camel_operation_unref (stub->op);
-			stub->op = NULL;
-		}
-	}
-
-	if (stub->backend_name)
-		g_free (stub->backend_name);
-
-	g_mutex_free (stub->read_lock);
-	g_mutex_free (stub->write_lock);
-
-	if (das_global_camel_stub == stub)
-		das_global_camel_stub = NULL;
-}
-
-CamelType
-camel_stub_get_type (void)
-{
-	static CamelType camel_stub_type = CAMEL_INVALID_TYPE;
-
-	if (!camel_stub_type) {
-		camel_stub_type = camel_type_register (
-			CAMEL_OBJECT_TYPE, "CamelStub",
-			sizeof (CamelStub),
-			sizeof (CamelStubClass),
-			(CamelObjectClassInitFunc) class_init,
-			NULL,
-			(CamelObjectInitFunc) init,
-			(CamelObjectFinalizeFunc) finalize);
-	}
-
-	return camel_stub_type;
-}
-
-static gpointer
-status_main (gpointer data)
-{
-	CamelObject *stub_object = data;
-	CamelStub *stub = data;
-	CamelStubMarshal *status_channel = stub->status;
-	guint32 retval;
-
-	stub->have_status_thread = TRUE;
-
-	stub->op = camel_operation_new (NULL, NULL);
-	camel_operation_register (stub->op);
-
-	while (1) {
-		if (camel_operation_cancel_check (stub->op))
-			break;
-
-		if (camel_stub_marshal_decode_uint32 (status_channel, &retval) == -1)
-			break;
-
-		/* FIXME. If you don't have exactly one thing listening
-		 * to this, it will get out of sync. But I don't want
-		 * CamelStub to have to know the details of the message
-		 * structures. We probably need to make the data more
-		 * self-describing.
-		 */
-		camel_object_trigger_event (stub_object, "notification",
-					    GUINT_TO_POINTER (retval));
-	}
-
-	camel_operation_unregister (stub->op);
-
-	stub->have_status_thread = FALSE;
-
-	return NULL;
-}
-
-#ifndef G_OS_WIN32
-
-static gint
-connect_to_storage (CamelStub *stub, struct sockaddr_un *sa_un,
-		    CamelException *ex)
-{
-	gint fd;
-
-	fd = socket (AF_UNIX, SOCK_STREAM, 0);
-	if (fd == -1) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Could not create socket: %s"),
-				      g_strerror (errno));
-		return -1;
-	}
-	if (connect (fd, (struct sockaddr *)sa_un, sizeof (*sa_un)) == -1) {
-		close (fd);
-		if (errno == ECONNREFUSED) {
-			/* The user has an account configured but the
-			 * backend isn't listening, which probably means that
-			 * he doesn't have a license.
-			 */
-			camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
-					     "Cancelled");
-		} else if (errno == ENOENT) {
-			/* socket_path has changed, mostly because user name has been changed.
-			 * need to restart evolution for changes to take effect.
-			 */
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Could not connect to %s: Please restart Evolution"),
-					      stub->backend_name);
-		}
-		else {
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Could not connect to %s: %s"),
-					      stub->backend_name,
-					      g_strerror (errno));
-		}
-		return -1;
-	}
-	return fd;
-}
-
-#else
-
-static gint
-connect_to_storage (CamelStub *stub, const gchar *socket_path,
-		    CamelException *ex)
-{
-	SOCKET fd;
-	struct sockaddr_in *sa_in;
-	gsize contents_length;
-	GError *error = NULL;
-	gint rc;
-
-	if (!g_file_get_contents (socket_path, (gchar **) &sa_in,
-				  &contents_length, &error)) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Count not read file '%s': %s"),
-				      socket_path, error->message);
-		g_error_free (error);
-		return -1;
-	}
-
-	if (contents_length != sizeof (*sa_in)) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Wrong size file '%s'"),
-				      socket_path);
-		g_free (sa_in);
-		return -1;
-	}
-
-	fd = socket (AF_INET, SOCK_STREAM, 0);
-	if (fd == INVALID_SOCKET) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Could not create socket: %s"),
-				      g_win32_error_message (WSAGetLastError ()));
-		return -1;
-	}
-	rc = connect (fd, (struct sockaddr *)sa_in, sizeof (*sa_in));
-	g_free (sa_in);
-
-	if (rc == SOCKET_ERROR) {
-		closesocket (fd);
-		if (WSAGetLastError () == WSAECONNREFUSED) {
-			/* The user has an account configured but the
-			 * backend isn't listening, which probably means that
-			 * he doesn't have a license.
-			 */
-			camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
-					     "Cancelled");
-		} else {
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Could not connect to %s: %s"),
-					      stub->backend_name,
-					      g_win32_error_message (WSAGetLastError ()));
-		}
-		return -1;
-	}
-	return fd;
-}
-
-#endif
-
-/**
- * camel_stub_new:
- * @socket_path: path to the server's UNIX domain socket
- * @backend_name: human-readably name of the service we are connecting to
- * @ex: a #CamelException
- *
- * Tries to connect to the backend server listening at @socket_path.
- *
- * Return value: on success, a new #CamelStub. On failure, %NULL, in
- * which case @ex will be set.
- **/
-CamelStub *
-camel_stub_new (const gchar *socket_path, const gchar *backend_name,
-		CamelException *ex)
-{
-	CamelStub *stub;
-#ifndef G_OS_WIN32
-	struct sockaddr_un sa_un;
-#endif
-	gint fd;
-
-#ifndef G_OS_WIN32
-	if (strlen (socket_path) > sizeof (sa_un.sun_path) - 1) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Path too long: %s"), socket_path);
-		return NULL;
-	}
-	sa_un.sun_family = AF_UNIX;
-	strcpy (sa_un.sun_path, socket_path);
-#endif
-
-	stub = (CamelStub *)camel_object_new (CAMEL_STUB_TYPE);
-	stub->backend_name = g_strdup (backend_name);
-
-#ifndef G_OS_WIN32
-	fd = connect_to_storage (stub, &sa_un, ex);
-#else
-	fd = connect_to_storage (stub, socket_path, ex);
-#endif
-	if (fd == -1) {
-		camel_object_unref (CAMEL_OBJECT (stub));
-		return NULL;
-	}
-	stub->cmd = camel_stub_marshal_new (fd);
-
-#ifndef G_OS_WIN32
-	fd = connect_to_storage (stub, &sa_un, ex);
-#else
-	fd = connect_to_storage (stub, socket_path, ex);
-#endif
-	if (fd == -1) {
-		camel_object_unref (CAMEL_OBJECT (stub));
-		return NULL;
-	}
-	stub->status = camel_stub_marshal_new (fd);
-
-	/* Spawn status thread */
-	if (pthread_create (&stub->status_thread, NULL, status_main, stub) == -1) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Could not start status thread: %s"),
-				      g_strerror (errno));
-		camel_object_unref (CAMEL_OBJECT (stub));
-		return NULL;
-	}
-
-	das_global_camel_stub = stub;
-	return stub;
-}
-
-static gboolean
-stub_send_internal (CamelStub *stub, CamelException *ex, gboolean oneway,
-		    CamelStubCommand command, va_list ap)
-{
-	CamelStubArgType argtype;
-	gint status = 0;
-	guint32 retval;
-
-	g_return_val_if_fail (stub, FALSE);
-
-	camel_object_ref (CAMEL_OBJECT (stub));
-	if (!oneway)
-		g_mutex_lock (stub->read_lock);
-
-	/* Send command */
-	g_mutex_lock (stub->write_lock);
-	camel_stub_marshal_encode_uint32 (stub->cmd, command);
-	while (1) {
-		argtype = va_arg (ap, gint);
-		switch (argtype) {
-		case CAMEL_STUB_ARG_RETURN:
-		case CAMEL_STUB_ARG_END:
-			goto done_input;
-
-		case CAMEL_STUB_ARG_UINT32:
-		{
-			guint32 val = va_arg (ap, guint32);
-
-			camel_stub_marshal_encode_uint32 (stub->cmd, val);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_STRING:
-		{
-			gchar *string = va_arg (ap, gchar *);
-
-			camel_stub_marshal_encode_string (stub->cmd, string);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_FOLDER:
-		{
-			gchar *name = va_arg (ap, gchar *);
-
-			camel_stub_marshal_encode_folder (stub->cmd, name);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_BYTEARRAY:
-		{
-			GByteArray *ba = va_arg (ap, GByteArray *);
-
-			camel_stub_marshal_encode_bytes (stub->cmd, ba);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_STRINGARRAY:
-		{
-			GPtrArray *arr = va_arg (ap, GPtrArray *);
-			gint i;
-
-			camel_stub_marshal_encode_uint32 (stub->cmd, arr->len);
-			for (i = 0; i < arr->len; i++)
-				camel_stub_marshal_encode_string (stub->cmd, arr->pdata[i]);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_UINT32ARRAY:
-		{
-			GArray *arr = va_arg (ap, GArray *);
-			gint i;
-
-			camel_stub_marshal_encode_uint32 (stub->cmd, arr->len);
-			for (i = 0; i < arr->len; i++)
-				camel_stub_marshal_encode_uint32 (stub->cmd, g_array_index (arr, guint32, i));
-			break;
-		}
-
-		default:
-			g_critical ("%s: Uncaught case (%d)", G_STRLOC, argtype);
-			break;
-		}
-	}
- done_input:
-
-	status = camel_stub_marshal_flush (stub->cmd);
-	g_mutex_unlock (stub->write_lock);
-
-	if (status == -1)
-		goto comm_fail;
-	else if (oneway)
-		goto done;
-
-	/* Read response */
-	do {
-		if (camel_stub_marshal_decode_uint32 (stub->cmd, &retval) == -1)
-			goto comm_fail;
-
-		switch (retval) {
-		case CAMEL_STUB_RETVAL_OK:
-			break;
-
-		case CAMEL_STUB_RETVAL_EXCEPTION:
-		{
-			gchar *desc;
-
-			/* FIXME: exception id? */
-
-			if (camel_stub_marshal_decode_string (stub->cmd, &desc) == -1)
-				goto comm_fail;
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, desc);
-			g_free (desc);
-
-			goto err_out;
-		}
-
-		case CAMEL_STUB_RETVAL_PROGRESS:
-		{
-			guint32 percent;
-
-			if (camel_stub_marshal_decode_uint32 (stub->cmd, &percent) == -1)
-				goto comm_fail;
-			camel_operation_progress (NULL, percent);
-			break;
-		}
-
-		case CAMEL_STUB_RETVAL_RESPONSE:
-		{
-			if (argtype != CAMEL_STUB_ARG_RETURN)
-				goto comm_fail;
-
-			do {
-				argtype = va_arg (ap, gint);
-				switch (argtype) {
-				case CAMEL_STUB_ARG_END:
-					goto done_output;
-
-				case CAMEL_STUB_ARG_UINT32:
-				{
-					guint32 *val = va_arg (ap, guint32 *);
-					guint32 val32;
-
-					status = camel_stub_marshal_decode_uint32 (stub->cmd, &val32);
-					*val = val32;
-					break;
-				}
-
-				case CAMEL_STUB_ARG_STRING:
-				{
-					gchar **string = va_arg (ap, gchar **);
-
-					status = camel_stub_marshal_decode_string (stub->cmd, string);
-					break;
-				}
-
-				case CAMEL_STUB_ARG_FOLDER:
-				{
-					gchar **name = va_arg (ap, gchar **);
-
-					status = camel_stub_marshal_decode_folder (stub->cmd, name);
-					break;
-				}
-
-				case CAMEL_STUB_ARG_BYTEARRAY:
-				{
-					GByteArray **ba = va_arg (ap, GByteArray **);
-
-					status = camel_stub_marshal_decode_bytes (stub->cmd, ba);
-					break;
-				}
-
-				case CAMEL_STUB_ARG_STRINGARRAY:
-				{
-					GPtrArray **arr = va_arg (ap, GPtrArray **);
-					guint32 len;
-					gchar *string;
-					gint i;
-
-					status = camel_stub_marshal_decode_uint32 (stub->cmd, &len);
-					if (status == -1)
-						break;
-					*arr = g_ptr_array_new ();
-					for (i = 0; i < len && status != -1; i++) {
-						status = camel_stub_marshal_decode_string (stub->cmd, &string);
-						if (status != -1)
-							g_ptr_array_add (*arr, string);
-					}
-
-					if (status == -1) {
-						while ((*arr)->len)
-							g_free ((*arr)->pdata[(*arr)->len]);
-						g_ptr_array_free (*arr, TRUE);
-					}
-
-					break;
-				}
-
-				case CAMEL_STUB_ARG_UINT32ARRAY:
-				{
-					GArray **arr = va_arg (ap, GArray **);
-					guint32 i, len, unread_count;
-					status = camel_stub_marshal_decode_uint32 (stub->cmd, &len);
-					if (status == -1)
-						break;
-					*arr = g_array_new (FALSE, FALSE, sizeof (guint32));
-					for (i = 0; i< len && status != -1; i++) {
-						status = camel_stub_marshal_decode_uint32 (stub->cmd, &unread_count);
-						if (status != -1)
-							g_array_append_val (*arr, unread_count);
-					}
-					if (status == -1)
-						g_array_free (*arr, TRUE);
-
-					break;
-				}
-
-				default:
-					g_critical ("%s: Uncaught case (%d)", G_STRLOC, argtype);
-					status = -1;
-					break;
-				}
-			} while (status != -1);
-		done_output:
-			if (status == -1)
-				goto comm_fail;
-
-			break;
-		}
-
-		default:
-			g_critical ("%s: Uncaught case (%d)", G_STRLOC, retval);
-			break;
-		}
-	} while (retval != CAMEL_STUB_RETVAL_OK);
-
- done:
-	if (!oneway)
-		g_mutex_unlock (stub->read_lock);
-	camel_object_unref (CAMEL_OBJECT (stub));
-	return TRUE;
-
- comm_fail:
-	if (camel_stub_marshal_eof (stub->cmd)) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Lost connection to %s"),
-				      stub->backend_name);
-	} else {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Error communicating with %s: %s"),
-				      stub->backend_name, g_strerror (errno));
-	}
-
- err_out:
-	if (!oneway)
-		g_mutex_unlock (stub->read_lock);
-	camel_object_unref (CAMEL_OBJECT (stub));
-	return FALSE;
-}
-
-/**
- * camel_stub_send:
- * @stub: a #CamelStub
- * @ex: a #CamelException
- * @command: the command to send
- * @...: arguments to @command
- *
- * Sends @command to the backend and waits for a response.
- *
- * Return value: %TRUE if command executed successfully, %FALSE
- * if it failed, in which case @ex will be set.
- **/
-gboolean
-camel_stub_send (CamelStub *stub, CamelException *ex,
-		 CamelStubCommand command, ...)
-{
-	va_list ap;
-	gboolean retval;
-
-	va_start (ap, command);
-	retval = stub_send_internal (stub, ex, FALSE, command, ap);
-	va_end (ap);
-
-	return retval;
-}
-
-/**
- * camel_stub_send_oneway:
- * @stub: a #CamelStub
- * @command: the command to send
- * @...: arguments to @command
- *
- * Sends @command to the backend without waiting for a response. (This
- * only works for commands such as %CAMEL_STUB_CMD_SET_MESSAGE_FLAGS
- * which the server does not send a response for.)
- *
- * Return value: %TRUE if command was sent successfull, %FALSE if
- * the command could not be sent.
- **/
-gboolean
-camel_stub_send_oneway (CamelStub *stub, CamelStubCommand command, ...)
-{
-	va_list ap;
-	gboolean retval;
-
-	va_start (ap, command);
-	retval = stub_send_internal (stub, NULL, TRUE, command, ap);
-	va_end (ap);
-
-	return retval;
-}
diff --git a/camel/camel-stub.h b/camel/camel-stub.h
deleted file mode 100644
index 0ffa78b..0000000
--- a/camel/camel-stub.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* Copyright (C) 2001-2004 Novell, Inc. */
-
-/* camel-stub.h: class for a stub to talk to the backend */
-
-#ifndef CAMEL_STUB_H
-#define CAMEL_STUB_H 1
-
-G_BEGIN_DECLS
-
-#include <camel/camel-object.h>
-#include <camel/camel-operation.h>
-
-#include "camel-stub-constants.h"
-#include "camel-stub-marshal.h"
-#include <pthread.h>
-
-#define CAMEL_STUB_TYPE     (camel_stub_get_type ())
-#define CAMEL_STUB(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_STUB_TYPE, CamelStub))
-#define CAMEL_STUB_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_STUB_TYPE, CamelStubClass))
-#define CAMEL_IS_STUB(o)    (CAMEL_CHECK_TYPE((o), CAMEL_STUB_TYPE))
-
-typedef struct {
-	CamelObject parent_object;
-
-	gchar *backend_name;
-
-	GMutex *read_lock, *write_lock;
-	CamelStubMarshal *cmd, *status;
-
-	CamelOperation *op;      /* for cancelling */
-	pthread_t status_thread;
-	gboolean have_status_thread;
-} CamelStub;
-
-typedef struct {
-	CamelObjectClass parent_class;
-
-} CamelStubClass;
-
-/* Standard Camel function */
-CamelType  camel_stub_get_type    (void);
-
-CamelStub *camel_stub_new         (const gchar *socket_path,
-				   const gchar *backend_name,
-				   CamelException *ex);
-
-gboolean   camel_stub_send        (CamelStub *stub, CamelException *ex,
-				   CamelStubCommand command, ...);
-gboolean   camel_stub_send_oneway (CamelStub *stub,
-				   CamelStubCommand command, ...);
-
-G_END_DECLS
-
-#endif /* CAMEL_STUB_H */
-
diff --git a/camel/mail-utils.c b/camel/mail-utils.c
new file mode 100644
index 0000000..4505378
--- /dev/null
+++ b/camel/mail-utils.c
@@ -0,0 +1,448 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2001-2004 Novell, Inc.
+ *
+ * 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 "mail-utils.h"
+#include <e2k-propnames.h>
+#include <e2k-utils.h>
+#include <mapi.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <camel/camel-folder-summary.h>
+#include <libedataserver/e-data-server-util.h>
+#include <e-util/e-html-utils.h>
+#include <e-util/e-util.h>
+#include <libical/ical.h>
+
+/**
+ * mail_util_mapi_to_smtp_headers:
+ * @props: an #E2kProperties containing MAPI header properties.
+ *
+ * Constructs a fake set of RFC822 headers based on the MAPI header
+ * properties in @props.
+ *
+ * Return value: the headers, which must be free when you are done
+ * with them.
+ **/
+gchar *
+mail_util_mapi_to_smtp_headers (E2kProperties *props)
+{
+	GString *headers;
+	gchar *prop, *buf;
+	time_t dt;
+
+	headers = g_string_new (NULL);
+
+#define GET_HEADER(propname,headername) \
+	prop = e2k_properties_get_prop (props, propname); \
+	if (prop && *prop) \
+		g_string_append_printf (headers, headername ": %s\r\n", prop);
+
+	GET_HEADER (E2K_PR_MAILHEADER_RECEIVED, "Received");
+
+	prop = e2k_properties_get_prop (props, E2K_PR_MAILHEADER_DATE);
+	dt = prop ? e2k_parse_timestamp (prop) : 0;
+	buf = e2k_make_timestamp_rfc822 (dt);
+	g_string_append_printf (headers, "Date: %s\r\n", buf);
+	g_free (buf);
+
+	GET_HEADER (E2K_PR_MAILHEADER_SUBJECT, "Subject");
+	GET_HEADER (E2K_PR_MAILHEADER_FROM, "From");
+	GET_HEADER (E2K_PR_MAILHEADER_TO, "To");
+	GET_HEADER (E2K_PR_MAILHEADER_CC, "Cc");
+	GET_HEADER (E2K_PR_MAILHEADER_MESSAGE_ID, "Message-ID");
+	GET_HEADER (E2K_PR_MAILHEADER_IN_REPLY_TO, "In-Reply-To");
+	GET_HEADER (E2K_PR_MAILHEADER_REFERENCES, "References");
+	GET_HEADER (E2K_PR_MAILHEADER_THREAD_INDEX, "Thread-Index");
+
+#undef GET_HEADER
+
+	prop = e2k_properties_get_prop (props, E2K_PR_DAV_CONTENT_TYPE);
+	if (!prop || g_ascii_strncasecmp (prop, "message/", 8) != 0) {
+		g_string_append_printf (headers,
+					"Content-Type: %s\r\n"
+					"Content-Transfer-Encoding: binary\r\n"
+					"Content-Disposition: attachment",
+					prop ? prop : "application/octet-stream");
+		prop = e2k_properties_get_prop (props, E2K_PR_MAILHEADER_SUBJECT);
+		if (prop)
+			g_string_append_printf (headers, "; filename=\"%s\"", prop);
+		g_string_append (headers, "\r\n");
+	}
+
+	g_string_append (headers, "\r\n");
+
+	buf = headers->str;
+	g_string_free (headers, FALSE);
+	return buf;
+}
+
+/**
+ * mail_util_props_to_camel_flags:
+ * @props: an #E2kProperties containing MAPI message properties.
+ * @obey_read_flag: if %FALSE, the %E2K_PR_HTTPMAIL_READ flag in
+ * @props will be ignored.
+ *
+ * Converts the values of the %E2K_PR_HTTPMAIL_READ,
+ * %E2K_PR_HTTPMAIL_HAS_ATTACHMENT, %PR_ACTION_FLAG, and
+ * %PR_DELEGATED_BY_RULE properties to an equivalent set of
+ * Camel message flags.
+ *
+ * Return value: the message flags
+ **/
+guint32
+mail_util_props_to_camel_flags (E2kProperties *props, gboolean obey_read_flag)
+{
+	const gchar *prop;
+	guint32 flags;
+	gint val;
+
+	flags = 0;
+
+	prop = e2k_properties_get_prop (props, E2K_PR_HTTPMAIL_READ);
+	if ((prop && atoi (prop)) || !obey_read_flag)
+		flags |= CAMEL_MESSAGE_SEEN;
+
+	prop = e2k_properties_get_prop (props, E2K_PR_HTTPMAIL_HAS_ATTACHMENT);
+	if (prop && atoi (prop))
+		flags |= CAMEL_MESSAGE_ATTACHMENTS;
+
+	prop = e2k_properties_get_prop (props, PR_ACTION_FLAG);
+	if (prop) {
+		val = atoi (prop);
+		if (val == MAPI_ACTION_FLAG_REPLIED_TO_SENDER)
+			flags |= CAMEL_MESSAGE_ANSWERED;
+		else if (val == MAPI_ACTION_FLAG_REPLIED_TO_ALL) {
+			flags |= (CAMEL_MESSAGE_ANSWERED |
+				  CAMEL_MESSAGE_ANSWERED_ALL);
+		}
+	}
+
+	prop = e2k_properties_get_prop (props, PR_DELEGATED_BY_RULE);
+	if (prop && atoi (prop))
+		flags |= EXMAIL_DELEGATED;
+
+	prop = e2k_properties_get_prop (props, PR_IMPORTANCE);
+	if (prop) {
+		val = atoi (prop);
+		if (val == MAPI_IMPORTANCE_HIGH)
+			flags |= CAMEL_MESSAGE_FLAGGED;
+	}
+
+	return flags;
+}
+
+/**
+ * mail_util_extract_transport_headers:
+ * @props: an #E2kProperties containing mail headers.
+ *
+ * Takes the %PR_TRANSPORT_MESSAGE_HEADERS property from @props and
+ * cleans it up, returning just the RFC822 headers (slightly edited,
+ * as described below).
+ *
+ * Return value: the headers, or %NULL if the property could not be
+ * found or was malformed. You must free the return value when you
+ * are done with it.
+ **/
+gchar *
+mail_util_extract_transport_headers (E2kProperties *props)
+{
+	const gchar *prop, *hstart, *hend, *ctstart, *ctend;
+	gchar *headers;
+
+	prop = e2k_properties_get_prop (props, PR_TRANSPORT_MESSAGE_HEADERS);
+	if (!prop)
+		return NULL;
+
+	/* The format is:
+	 *
+	 *     Microsoft Mail Internet Headers Version 2.0
+	 *     [RFC822 headers here]
+	 *
+	 *     [MIME content boundaries and part headers here]
+	 *
+	 * The RFC822 headers are slightly modified from their original
+	 * form: if there is raw 8-bit data in them, Exchange attempts
+	 * to convert it to UTF8 (based on the charset of the message).
+	 * Also, libxml translates "\r\n" to "\n".
+	 *
+	 * We strip off the MS header at the top and the MIME data
+	 * at the bottom, and change the Content-Type header to claim
+	 * that the body contains UTF-8-encoded plaintext. That way,
+	 * when camel sees it later, it will treat the 8-bit data
+	 * correctly (and it won't emit warnings about the lack of
+	 * boundaries if the original message was multipart).
+	 */
+	hstart = strchr (prop, '\n');
+	if (!hstart++)
+		return NULL;
+	hend = strstr (hstart, "\n\n");
+	if (!hend)
+		hend = hstart + strlen (hstart);
+
+	ctstart = e_util_strstrcase (hstart - 1, "\nContent-Type:");
+	if (ctstart && ctstart < hend) {
+		ctend = strchr (ctstart, '\n');
+
+		headers = g_strdup_printf ("%.*s\nContent-Type: text/plain; charset=\"UTF-8\"%.*s\n\n",
+					   (gint) (ctstart - hstart), hstart,
+					   (gint) (hend - ctend), ctend);
+	} else {
+		headers = g_strdup_printf ("%.*s\nContent-Type: text/plain; charset=\"UTF-8\"\n\n\n",
+					   (gint) (hend - hstart), hstart);
+	}
+
+	return headers;
+}
+
+static const gchar *note_colors[] = {
+	"#CCCCFF", "#CCFFCC", "#FFCCCC", "#FFFFCC", "#FFFFFF"
+};
+static const gint ncolors = sizeof (note_colors) / sizeof (note_colors[0]);
+#define DEFAULT_NOTE_COLOR 3
+
+/**
+ * mail_util_stickynote_to_rfc822:
+ * @props: a set of stickynote properties
+ *
+ * Creates a fake RFC822 message based on the stickynote described by
+ * @props.
+ *
+ * Return value: the fake message, which must be freed with
+ * g_string_free() when you are done with it.
+ **/
+GString *
+mail_util_stickynote_to_rfc822 (E2kProperties *props)
+{
+	const gchar *prop;
+	GString *message;
+	gchar *html, *p;
+	gint color;
+
+	message = g_string_new (NULL);
+	prop = e2k_properties_get_prop (props, E2K_PR_MAILHEADER_SUBJECT);
+	if (prop)
+		g_string_append_printf (message, "Subject: %s\r\n", prop);
+	prop = e2k_properties_get_prop (props, E2K_PR_DAV_LAST_MODIFIED);
+	if (prop) {
+		time_t dt;
+		gchar *buf;
+
+		dt = e2k_parse_timestamp (prop);
+		buf = e2k_make_timestamp_rfc822 (dt);
+		g_string_append_printf (message, "Date: %s\r\n", buf);
+		g_free (buf);
+	}
+	g_string_append (message, "Content-Type: text/html; charset=\"UTF-8\"\r\n\r\n");
+
+	prop = e2k_properties_get_prop (props, E2K_PR_HTTPMAIL_TEXT_DESCRIPTION);
+	if (!prop)
+		return message;
+
+	html = e_text_to_html (prop, (E_TEXT_TO_HTML_CONVERT_NL |
+				      E_TEXT_TO_HTML_CONVERT_SPACES |
+				      E_TEXT_TO_HTML_CONVERT_URLS));
+	for (p = strchr (html, '\r'); p; p = strchr (p, '\r'))
+		*p = ' ';
+
+	g_string_append (message, "<html><body>\r\n");
+
+	prop = e2k_properties_get_prop (props, E2K_PR_OUTLOOK_STICKYNOTE_COLOR);
+	if (prop) {
+		color = atoi (prop);
+		if (color < 0 || color >= ncolors)
+			color = DEFAULT_NOTE_COLOR;
+	} else
+		color = DEFAULT_NOTE_COLOR;
+
+	g_string_append_printf (message, "<table bgcolor=\"%s\"",
+				note_colors[color]);
+	prop = e2k_properties_get_prop (props, E2K_PR_OUTLOOK_STICKYNOTE_WIDTH);
+	if (prop)
+		g_string_append_printf (message, " width=%s", prop);
+	g_string_append (message, " border=1 cellpadding=10>\r\n<tr><td");
+	prop = e2k_properties_get_prop (props, E2K_PR_OUTLOOK_STICKYNOTE_HEIGHT);
+	if (prop)
+		g_string_append_printf (message, " height=%s", prop);
+	g_string_append (message, " valign=top>\r\n");
+	g_string_append (message, html);
+	g_string_append (message, "\r\n</td></tr>\r\n</table></body></html>");
+	g_free (html);
+
+	return message;
+}
+
+/**
+ * mail_util_demangle_meeting_related_message:
+ * @body: the body of the message
+ * @owner_cn: the iCalendar "CN" (common name) of the delegator
+ * @owner_email: the email address of the delegator
+ * @owner_cal_uri: the exchange: URI of the delegator's Calendar
+ * @subscriber_email: the email address of the delegatee
+ *
+ * When delegatees have to respond to meeting-related messages, Exchange
+ * mangles the iCalendar, such that we need to demangle it in order to get the
+ * iTIP control to do the right thing with it. That happens here.
+ *
+ *
+ * Return value: %TRUE if we successfully demangled @body (in place).
+ **/
+gboolean
+mail_util_demangle_meeting_related_message (GString *body,
+				const gchar *owner_cn,
+				const gchar *owner_email,
+				const gchar *owner_cal_uri,
+				const gchar *subscriber_email,
+				MailUtilDemangleType unmangle_type)
+{
+	icalcomponent *vcal_comp, *event_comp;
+	icalproperty *prop = NULL;
+	gchar *vstart, *vend;
+	gchar *ical_str, *str;
+	gint oldlen, newlen;
+	gboolean modify_prop = FALSE;
+
+	vstart = strstr (body->str, "BEGIN:VCALENDAR");
+	if (!vstart)
+		return FALSE;
+	vend = strstr (vstart, "END:VCALENDAR");
+	if (!vend)
+		return FALSE;
+	vend += 13;
+	while (isspace ((guchar)*vend))
+		vend++;
+	oldlen = vend - vstart;
+
+	vcal_comp = icalparser_parse_string (vstart);
+	if (!vcal_comp)
+		return FALSE;
+
+	event_comp = icalcomponent_get_first_component (vcal_comp, ICAL_VEVENT_COMPONENT);
+	if (!event_comp) {
+		icalcomponent_free (vcal_comp);
+		return FALSE;
+	}
+
+	for (prop = icalcomponent_get_first_property (event_comp, ICAL_ATTENDEE_PROPERTY);
+	     prop != NULL;
+	     prop = icalcomponent_get_next_property (event_comp, ICAL_ATTENDEE_PROPERTY)) {
+		const gchar *attendee;
+		gchar *text = NULL;
+
+		attendee = icalproperty_get_value_as_string_r (prop);
+		if (!attendee)
+			continue;
+
+		if (!g_ascii_strncasecmp (attendee, "mailto:", 7))
+			text = g_strdup (attendee+7);
+
+		text = g_strstrip (text);
+		if (text && !g_ascii_strcasecmp (owner_email, text)) {
+			modify_prop = TRUE;
+		/* We do not really need to set the CN parameter. However, setting it might improve usability. */
+			icalproperty_remove_parameter_by_kind (prop, ICAL_CN_PARAMETER);
+			icalproperty_add_parameter (prop, icalparameter_new_cn (g_strdup(owner_cn)));
+			icalproperty_remove_parameter_by_kind (prop, ICAL_SENTBY_PARAMETER);
+			icalproperty_add_parameter (prop,
+				icalparameter_new_sentby (g_strdup_printf("MAILTO:%s", subscriber_email)));
+			g_free (text);
+			break;
+		}
+		g_free (text);
+	}
+
+	prop = icalcomponent_get_first_property (event_comp, ICAL_ORGANIZER_PROPERTY);
+	if (!modify_prop && prop) {
+		const gchar *organizer;
+		gchar *text = NULL;
+
+		organizer = icalproperty_get_value_as_string_r (prop);
+		if (organizer) {
+			if (!g_ascii_strncasecmp (organizer, "mailto:", 7))
+				text = g_strdup (organizer+7);
+
+			text = g_strstrip (text);
+
+			switch (unmangle_type) {
+				case MAIL_UTIL_DEMANGLE_DELGATED_MEETING:
+					if (text && !g_ascii_strcasecmp (subscriber_email, text)) {
+						icalproperty_set_organizer (prop, g_strdup_printf ("MAILTO:%s", owner_email));
+						modify_prop = TRUE;
+					}
+					break;
+				case MAIL_UTIL_DEMANGLE_MEETING_IN_SUBSCRIBED_INBOX:
+				case MAIL_UTIL_DEMANGLE_SENDER_FIELD:
+					if (text && !g_ascii_strcasecmp (owner_email, text))
+						modify_prop = TRUE;
+					break;
+				default: break;
+			}
+			if (modify_prop) {
+			/* We do not really need to set the CN parameter. However, setting it might improve usability. */
+				icalproperty_remove_parameter_by_kind (prop, ICAL_CN_PARAMETER);
+				icalproperty_add_parameter (prop, icalparameter_new_cn (g_strdup(owner_cn)));
+				icalproperty_remove_parameter_by_kind (prop, ICAL_SENTBY_PARAMETER);
+				icalproperty_add_parameter (prop,
+					icalparameter_new_sentby (g_strdup_printf("MAILTO:%s", subscriber_email)));
+			}
+		}
+		g_free (text);
+	}
+
+	switch (unmangle_type) {
+		case MAIL_UTIL_DEMANGLE_DELGATED_MEETING:
+		case MAIL_UTIL_DEMANGLE_MEETING_IN_SUBSCRIBED_INBOX: /* Now add the X-property */
+			if (owner_cal_uri) {
+				prop = icalproperty_new_x (owner_cal_uri);
+				icalproperty_set_x_name (prop, "X-EVOLUTION-DELEGATOR-CALENDAR-URI");
+				icalcomponent_add_property (event_comp, prop);
+			}
+			break;
+		default: break;
+	}
+
+	/* Put the updated ical string back into the body */
+	str = icalcomponent_as_ical_string_r (vcal_comp);
+	ical_str = e2k_lf_to_crlf (str);
+	g_free (str);
+	newlen = strlen (ical_str);
+	if (newlen < oldlen) {
+		memcpy (vstart, ical_str, newlen);
+		memcpy (vstart + newlen, vend, strlen (vend));
+		g_string_set_size (body, body->len + newlen - oldlen);
+	} else {
+		g_string_set_size (body, body->len + newlen - oldlen);
+		memmove (vstart + newlen, vend, strlen (vend));
+		memcpy (vstart, ical_str, newlen);
+	}
+
+	icalcomponent_remove_component (vcal_comp, event_comp);
+	icalcomponent_free (event_comp);
+
+	icalcomponent_free (vcal_comp);
+	g_free (ical_str);
+
+	return TRUE;
+}
diff --git a/camel/mail-utils.h b/camel/mail-utils.h
new file mode 100644
index 0000000..588485f
--- /dev/null
+++ b/camel/mail-utils.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* Copyright (C) 2001-2004 Novell, Inc. */
+
+#ifndef __MAIL_UTILS_H__
+#define __MAIL_UTILS_H__
+
+#include <camel/camel-folder-summary.h>
+
+#include "e2k-properties.h"
+
+#define EXMAIL_DELEGATED CAMEL_MESSAGE_FOLDER_FLAGGED
+
+G_BEGIN_DECLS
+
+typedef enum {
+	MAIL_UTIL_DEMANGLE_DELGATED_MEETING,
+	MAIL_UTIL_DEMANGLE_MEETING_IN_SUBSCRIBED_INBOX,
+	MAIL_UTIL_DEMANGLE_SENDER_FIELD
+} MailUtilDemangleType;
+
+gchar    *mail_util_mapi_to_smtp_headers (E2kProperties *props);
+
+GString *mail_util_stickynote_to_rfc822 (E2kProperties *props);
+
+guint32  mail_util_props_to_camel_flags (E2kProperties *props,
+					 gboolean       obey_read_flag);
+
+gchar *   mail_util_extract_transport_headers (E2kProperties *props);
+
+gboolean
+mail_util_demangle_meeting_related_message (GString *body,
+				const gchar *owner_cn,
+				const gchar *owner_email,
+				const gchar *owner_cal_uri,
+				const gchar *subscriber_email,
+				MailUtilDemangleType unmangle_type);
+
+G_END_DECLS
+
+#endif /* __MAIL_UTILS_H__ */
diff --git a/configure.ac b/configure.ac
index 5d73dff..4f3d1ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ AC_PREREQ(2.52)
 m4_define([eex_version], [2.28.2])
 
 AC_INIT(evolution-exchange, [eex_version], http://bugzilla.gnome.org/enter_bug.cgi?product=Evolution%20Exchange)
-AC_CONFIG_SRCDIR(storage)
+AC_CONFIG_SRCDIR(camel)
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
 # Required Package Versions
@@ -384,10 +384,9 @@ AC_OUTPUT([
 Makefile
 evolution-exchange-zip
 camel/Makefile
-mail/Makefile
 addressbook/Makefile
 calendar/Makefile
-storage/Makefile
+tools/Makefile
 docs/Makefile
 docs/reference/Makefile
 po/Makefile.in
diff --git a/mail/Makefile.am b/mail/Makefile.am
deleted file mode 100644
index 55afa90..0000000
--- a/mail/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-## Process this file with automake to produce Makefile.in
-noinst_LTLIBRARIES = \
-	libexchangemail.la
-
-AM_CPPFLAGS = \
-	-I$(top_srcdir) \
-	-I$(top_srcdir)/camel \
-	-I$(top_srcdir)/storage   \
-	-DG_LOG_DOMAIN=\"exchange-mail\" \
-	$(EXTRA_GNOME_CFLAGS) \
-	$(BONOBO_GNOME_CFLAGS) \
-	$(MAIL_CFLAGS) \
-	$(LIBEXCHANGE_CFLAGS) \
-	$(LDAP_CFLAGS)
-
-libexchangemail_la_SOURCES = \
-	mail-stub.c \
-	mail-stub.h \
-	mail-stub-listener.c \
-	mail-stub-listener.h \
-	mail-stub-exchange.c \
-	mail-stub-exchange.h \
-	mail-utils.c \
-	mail-utils.h
-
--include $(top_srcdir)/git.mk
diff --git a/mail/mail-stub-exchange.h b/mail/mail-stub-exchange.h
deleted file mode 100644
index 0503a49..0000000
--- a/mail/mail-stub-exchange.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* Copyright (C) 2001-2004 Novell, Inc. */
-
-#ifndef __MAIL_STUB_EXCHANGE_H__
-#define __MAIL_STUB_EXCHANGE_H__
-
-#include "mail-stub.h"
-#include <exchange-account.h>
-
-G_BEGIN_DECLS
-
-#define MAIL_TYPE_STUB_EXCHANGE            (mail_stub_exchange_get_type ())
-#define MAIL_STUB_EXCHANGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAIL_TYPE_STUB_EXCHANGE, MailStubExchange))
-#define MAIL_STUB_EXCHANGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MAIL_TYPE_STUB_EXCHANGE, MailStubExchangeClass))
-#define MAIL_STUB_IS_EXCHANGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAIL_TYPE_STUB_EXCHANGE))
-#define MAIL_STUB_IS_EXCHANGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), MAIL_TYPE_STUB_EXCHANGE))
-
-typedef struct _MailStubExchange        MailStubExchange;
-typedef struct _MailStubExchangeClass   MailStubExchangeClass;
-
-struct _MailStubExchange {
-	MailStub parent;
-
-	ExchangeAccount *account;
-	E2kContext *ctx;
-	GHashTable *folders_by_name;
-	const gchar *mail_submission_uri;
-	EFolder *inbox, *deleted_items, *sent_items;
-
-	guint new_folder_id, removed_folder_id;
-	const gchar *ignore_new_folder, *ignore_removed_folder;
-};
-
-struct _MailStubExchangeClass {
-	MailStubClass parent_class;
-
-};
-
-GType             mail_stub_exchange_get_type   (void);
-gboolean          mail_stub_exchange_construct  (MailStubExchange *exchange);
-
-MailStub         *mail_stub_exchange_new        (ExchangeAccount *account,
-						 gint cmd_fd, gint status_fd);
-
-G_END_DECLS
-
-#endif /* __MAIL_STUB_EXCHANGE_H__ */
diff --git a/mail/mail-stub-listener.c b/mail/mail-stub-listener.c
deleted file mode 100644
index ff5d098..0000000
--- a/mail/mail-stub-listener.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2001-2004 Novell, Inc.
- *
- * 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.
- */
-
-/* mail-stub-listener.c: stub connection listener */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#ifndef G_OS_WIN32
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#else
-#include <winsock2.h>
-#endif
-
-#include "mail-stub-listener.h"
-#include <e2k-marshal.h>
-#include <e2k-types.h>
-
-enum {
-	NEW_CONNECTION,
-	LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = { 0 };
-
-#define PARENT_TYPE G_TYPE_OBJECT
-static GObjectClass *parent_class = NULL;
-
-static void finalize (GObject *);
-
-static void
-class_init (GObjectClass *object_class)
-{
-	parent_class = g_type_class_ref (PARENT_TYPE);
-
-	/* virtual method override */
-	object_class->finalize = finalize;
-
-	/* signals */
-	signals[NEW_CONNECTION] =
-		g_signal_new ("new_connection",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (MailStubListenerClass, new_connection),
-			      NULL, NULL,
-			      e2k_marshal_NONE__INT_INT,
-			      G_TYPE_NONE, 2,
-			      G_TYPE_INT, G_TYPE_INT);
-}
-
-static void
-finalize (GObject *object)
-{
-	MailStubListener *listener = MAIL_STUB_LISTENER (object);
-
-	if (listener->channel)
-		g_io_channel_unref (listener->channel);
-	if (listener->socket_path) {
-		g_unlink (listener->socket_path);
-		g_free (listener->socket_path);
-	}
-
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-E2K_MAKE_TYPE (mail_stub_listener, MailStubListener, class_init, NULL, PARENT_TYPE)
-
-static gboolean
-new_connection (GIOChannel *source, GIOCondition condition, gpointer data)
-{
-	MailStubListener *listener = data;
-	gint fd;
-
-	fd = accept (g_io_channel_unix_get_fd (source), NULL, NULL);
-	if (fd == -1)
-		return TRUE;
-
-	if (listener->cmd_fd == -1) {
-		listener->cmd_fd = fd;
-		return TRUE;
-	}
-
-	g_signal_emit (listener, signals[NEW_CONNECTION], 0,
-		       listener->cmd_fd, fd);
-	listener->cmd_fd = -1;
-
-	return TRUE;
-}
-
-gboolean
-mail_stub_listener_construct (MailStubListener *listener, const gchar *socket_path)
-{
-#ifndef G_OS_WIN32
-	struct sockaddr_un sa_un;
-#else
-	struct sockaddr_in sa_in;
-	gint addr_len;
-	GError *error = NULL;
-#endif
-	gint fd;
-
-#ifndef G_OS_WIN32
-	g_return_val_if_fail (strlen (socket_path) < sizeof (sa_un.sun_path), FALSE);
-
-	fd = socket (AF_UNIX, SOCK_STREAM, 0);
-	if (fd == -1)
-		return FALSE;
-
-	unlink (socket_path);
-	listener->socket_path = g_strdup (socket_path);
-	sa_un.sun_family = AF_UNIX;
-	strcpy (sa_un.sun_path, socket_path);
-
-	if (bind (fd, (struct sockaddr *)&sa_un, sizeof (sa_un)) == -1 || listen (fd, 5) == -1) {
-		close (fd);
-		return FALSE;
-	}
-
-	listener->channel = g_io_channel_unix_new (fd);
-#else
-	fd = socket (AF_INET, SOCK_STREAM, 0);
-	if (fd == SOCKET_ERROR)
-		return FALSE;
-	memset (&sa_in, 0, sizeof (sa_in));
-	sa_in.sin_family = AF_INET;
-	sa_in.sin_port = 0;
-	sa_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-
-	if (bind (fd, (struct sockaddr *) &sa_in, sizeof (sa_in)) == SOCKET_ERROR) {
-		g_warning ("bind() failed: %s",
-			   g_win32_error_message (WSAGetLastError ()));
-		closesocket (fd);
-		return FALSE;
-	}
-
-	if (listen (fd, 1) == SOCKET_ERROR) {
-		g_warning ("listen() failed: %s",
-		g_win32_error_message (WSAGetLastError ()));
-		closesocket (fd);
-		return FALSE;
-	}
-
-	addr_len = sizeof (sa_in);
-	if (getsockname (fd, (struct sockaddr *) &sa_in, &addr_len) == SOCKET_ERROR) {
-		g_warning ("getsockname() failed: %s",
-			   g_win32_error_message (WSAGetLastError ()));
-		closesocket (fd);
-		return FALSE;
-	}
-
-	g_unlink (socket_path);
-	listener->socket_path = g_strdup (socket_path);
-
-	printf ("listening on port %d\n", ntohs(sa_in.sin_port));
-
-	if (!g_file_set_contents (socket_path, (gchar *) &sa_in, addr_len, &error)) {
-		g_warning ("Could not save socket address in '%s': %s",
-			   socket_path, error->message);
-		g_error_free (error);
-		closesocket (fd);
-		return FALSE;
-	}
-
-	listener->channel = g_io_channel_win32_new_socket (fd);
-#endif
-	g_io_add_watch (listener->channel, G_IO_IN, new_connection, listener);
-
-	listener->cmd_fd = -1;
-
-	return TRUE;
-}
-
-/**
- * mail_stub_listener_new:
- * @socket_path: path to create a listening socket on
- *
- * Creates a new #MailStubListener listening for connections at
- * @socket_path.
- *
- * Return value: the new #MailStubListener.
- **/
-MailStubListener *
-mail_stub_listener_new (const gchar *socket_path)
-{
-	MailStubListener *listener;
-
-	listener = g_object_new (MAIL_TYPE_STUB_LISTENER, NULL);
-	if (!mail_stub_listener_construct (listener, socket_path)) {
-		g_object_unref (listener);
-		return NULL;
-	}
-	return listener;
-}
diff --git a/mail/mail-stub-listener.h b/mail/mail-stub-listener.h
deleted file mode 100644
index 1d7045b..0000000
--- a/mail/mail-stub-listener.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* Copyright 2001-2004 Novell, Inc. */
-
-#ifndef __MAIL_STUB_LISTENER_H__
-#define __MAIL_STUB_LISTENER_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define MAIL_TYPE_STUB_LISTENER            (mail_stub_listener_get_type ())
-#define MAIL_STUB_LISTENER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAIL_TYPE_STUB_LISTENER, MailStubListener))
-#define MAIL_STUB_LISTENER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MAIL_TYPE_STUB_LISTENER, MailStubListenerClass))
-#define MAIL_STUB_LISTENER_IS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAIL_TYPE_STUB_LISTENER))
-#define MAIL_STUB_LISTENER_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), MAIL_TYPE_STUB_LISTENER))
-
-typedef struct _MailStubListener        MailStubListener;
-typedef struct _MailStubListenerClass   MailStubListenerClass;
-
-struct _MailStubListener {
-	GObject parent;
-
-	gpointer stub;
-	gchar *socket_path;
-	GIOChannel *channel;
-
-	gint cmd_fd;
-};
-
-struct _MailStubListenerClass {
-	GObjectClass parent_class;
-
-	/* signals */
-	void (*new_connection) (MailStubListener *, int, gint);
-};
-
-GType             mail_stub_listener_get_type      (void);
-gboolean          mail_stub_listener_construct     (MailStubListener *stub,
-						    const gchar *socket_path);
-
-MailStubListener *mail_stub_listener_new           (const gchar *socket_path);
-
-G_END_DECLS
-
-#endif /* __MAIL_STUB_LISTENER_H__ */
diff --git a/mail/mail-stub.c b/mail/mail-stub.c
deleted file mode 100644
index 4b5f018..0000000
--- a/mail/mail-stub.c
+++ /dev/null
@@ -1,787 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2001-2004 Novell, Inc.
- *
- * 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.
- */
-
-/* mail-stub.c: the part that talks to the camel stub */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <e2k-uri.h>
-#include <e2k-types.h>
-#include "mail-stub.h"
-#include "camel-stub-constants.h"
-
-#define d(x)
-
-#define PARENT_TYPE G_TYPE_OBJECT
-static MailStubClass *parent_class = NULL;
-
-#define MS_CLASS(stub) (MAIL_STUB_CLASS (G_OBJECT_GET_CLASS (stub)))
-
-static void finalize (GObject *);
-
-static void
-class_init (GObjectClass *object_class)
-{
-	parent_class = g_type_class_ref (PARENT_TYPE);
-
-	/* virtual method override */
-	object_class->finalize = finalize;
-}
-
-static void
-finalize (GObject *object)
-{
-	MailStub *stub = MAIL_STUB (object);
-
-	if (stub->channel)
-		g_io_channel_unref (stub->channel);
-	if (stub->cmd)
-		camel_stub_marshal_free (stub->cmd);
-	if (stub->status)
-		camel_stub_marshal_free (stub->status);
-
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-E2K_MAKE_TYPE (mail_stub, MailStub, class_init, NULL, PARENT_TYPE)
-
-static void
-free_string_array (GPtrArray *strings)
-{
-	gint i;
-
-	for (i = 0; i < strings->len; i++)
-		g_free (strings->pdata[i]);
-	g_ptr_array_free (strings, TRUE);
-}
-
-static gboolean
-connection_handler (GIOChannel *source, GIOCondition condition, gpointer data)
-{
-	MailStub *stub = data;
-	guint32 command;
-
-	if (condition == G_IO_ERR || condition == G_IO_HUP)
-		return FALSE;
-
-	if (camel_stub_marshal_decode_uint32 (stub->cmd, &command) == -1)
-		return FALSE;
-
-	switch (command) {
-	case CAMEL_STUB_CMD_CONNECT:
-	{
-		gchar *pwd
-		d(printf("CONNECT\n"));
-		g_object_ref (stub);
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_STRING, &pwd,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		MS_CLASS (stub)->connect (stub, pwd);
-		g_free (pwd);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_GET_FOLDER:
-	{
-		gchar *folder_name;
-		GPtrArray *uids;
-		GByteArray *flags;
-		GPtrArray *hrefs;
-		guint32 high_article_num;
-		guint32 create;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_UINT32, &create,
-					  CAMEL_STUB_ARG_STRINGARRAY, &uids,
-					  CAMEL_STUB_ARG_BYTEARRAY, &flags,
-					  CAMEL_STUB_ARG_STRINGARRAY, &hrefs,
-					  CAMEL_STUB_ARG_UINT32, &high_article_num,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("GET_FOLDER %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->get_folder (stub, folder_name, create,
-					     uids, flags, hrefs, high_article_num);
-		g_free (folder_name);
-		free_string_array (uids);
-		g_byte_array_free (flags, TRUE);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_GET_TRASH_NAME:
-	{
-		d(printf("GET_TRASH_NAME\n"));
-		g_object_ref (stub);
-		MS_CLASS (stub)->get_trash_name (stub);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_SYNC_FOLDER:
-	{
-		gchar *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("SYNC_FOLDER %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->sync_folder (stub, folder_name);
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_REFRESH_FOLDER:
-	{
-		gchar *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("REFRESH_FOLDER %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->refresh_folder (stub, folder_name);
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_SYNC_COUNT:
-	{
-		gchar *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("SYNC_COUNT %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->sync_count (stub, folder_name);
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_EXPUNGE_UIDS:
-	{
-		gchar *folder_name;
-		GPtrArray *uids;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_STRINGARRAY, &uids,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("EXPUNGE_UIDS %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->expunge_uids (stub, folder_name, uids);
-		g_free (folder_name);
-		free_string_array (uids);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_APPEND_MESSAGE:
-	{
-		gchar *folder_name, *subject;
-		guint32 flags;
-		GByteArray *body;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_UINT32, &flags,
-					  CAMEL_STUB_ARG_STRING, &subject,
-					  CAMEL_STUB_ARG_BYTEARRAY, &body,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("APPEND_MESSAGE %s %lu %s\n", folder_name,
-			 (gulong)flags, subject));
-		g_object_ref (stub);
-		MS_CLASS (stub)->append_message (stub, folder_name, flags, subject, (gchar *) body->data, body->len);
-		g_free (folder_name);
-		g_free (subject);
-		g_byte_array_free (body, TRUE);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_SET_MESSAGE_FLAGS:
-	{
-		gchar *folder_name, *uid;
-		guint32 flags, mask;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_STRING, &uid,
-					  CAMEL_STUB_ARG_UINT32, &flags,
-					  CAMEL_STUB_ARG_UINT32, &mask,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("SET_MESSAGE_FLAGS %s %s %lu %lu\n",
-			 folder_name, uid, (gulong)flags, (gulong)mask));
-		/* Not async, so we don't ref stub */
-		MS_CLASS (stub)->set_message_flags (stub, folder_name, uid, flags, mask);
-		g_free (folder_name);
-		g_free (uid);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_SET_MESSAGE_TAG:
-	{
-		gchar *folder_name, *uid, *name, *value;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_STRING, &uid,
-					  CAMEL_STUB_ARG_STRING, &name,
-					  CAMEL_STUB_ARG_STRING, &value,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("SET_MESSAGE_TAG %s %s %s %s\n",
-			 folder_name, uid, name, value));
-		/* Not async, so we don't ref stub */
-		MS_CLASS (stub)->set_message_tag (stub, folder_name, uid,
-						  name, value);
-		g_free (folder_name);
-		g_free (uid);
-		g_free (name);
-		g_free (value);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_GET_MESSAGE:
-	{
-		gchar *folder_name, *uid;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_STRING, &uid,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("GET_MESSAGE %s %s\n", folder_name, uid));
-		g_object_ref (stub);
-		MS_CLASS (stub)->get_message (stub, folder_name, uid);
-		g_free (folder_name);
-		g_free (uid);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_SEARCH_FOLDER:
-	{
-		gchar *folder_name, *text;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_STRING, &text,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("SEARCH_FOLDER %s %s\n", folder_name, text));
-		g_object_ref (stub);
-		MS_CLASS (stub)->search (stub, folder_name, text);
-		g_free (folder_name);
-		g_free (text);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_TRANSFER_MESSAGES:
-	{
-		gchar *source_name, *dest_name;
-		guint32 delete_originals;
-		GPtrArray *uids;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &source_name,
-					  CAMEL_STUB_ARG_FOLDER, &dest_name,
-					  CAMEL_STUB_ARG_STRINGARRAY, &uids,
-					  CAMEL_STUB_ARG_UINT32, &delete_originals,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("TRANSFER_MESSAGES %s -> %s (%d)\n",
-			 source_name, dest_name, uids->len));
-		g_object_ref (stub);
-		MS_CLASS (stub)->transfer_messages (stub, source_name,
-						    dest_name, uids,
-						    delete_originals);
-		g_free (source_name);
-		g_free (dest_name);
-		free_string_array (uids);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_GET_FOLDER_INFO:
-	{
-		gchar *top;
-		guint32 store_flags;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_STRING, &top,
-					  CAMEL_STUB_ARG_UINT32, &store_flags,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("GET_FOLDER_INFO %s%s\n", top, store_flags ? " (recursive)" : ""));
-		g_object_ref (stub);
-		MS_CLASS (stub)->get_folder_info (stub, top, store_flags);
-		g_free (top);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_SEND_MESSAGE:
-	{
-		gchar *from;
-		GPtrArray *recips;
-		GByteArray *body;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_STRING, &from,
-					  CAMEL_STUB_ARG_STRINGARRAY, &recips,
-					  CAMEL_STUB_ARG_BYTEARRAY, &body,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("SEND_MESSAGE from %s to %d recipients\n",
-			 from, recips->len));
-		g_object_ref (stub);
-		MS_CLASS (stub)->send_message (stub, from, recips,
-					       (gchar *) body->data, body->len);
-		g_free (from);
-		free_string_array (recips);
-		g_byte_array_free (body, TRUE);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_CREATE_FOLDER:
-	{
-		gchar *parent_name, *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &parent_name,
-					  CAMEL_STUB_ARG_STRING, &folder_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("CREATE_FOLDER %s %s\n", parent_name, folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->create_folder (stub, parent_name,
-						folder_name);
-		g_free (parent_name);
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_DELETE_FOLDER:
-	{
-		gchar *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("DELETE_FOLDER %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->delete_folder (stub, folder_name);
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_RENAME_FOLDER:
-	{
-		gchar *old_name, *new_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &old_name,
-					  CAMEL_STUB_ARG_FOLDER, &new_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("RENAME_FOLDER %s %s\n", old_name, new_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->rename_folder (stub, old_name, new_name);
-		g_free (old_name);
-		g_free (new_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_SUBSCRIBE_FOLDER:
-	{
-		gchar *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("SUBSCRIBE_FOLDER %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->subscribe_folder (stub, folder_name);
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_UNSUBSCRIBE_FOLDER:
-	{
-		gchar *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					  CAMEL_STUB_ARG_FOLDER, &folder_name,
-					  CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("UNSUBSCRIBE_FOLDER %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->unsubscribe_folder (stub, folder_name);
-		g_free (folder_name);
-		break;
-	}
-
-	case CAMEL_STUB_CMD_IS_SUBSCRIBED_FOLDER:
-	{
-		gchar *folder_name;
-
-		if (!mail_stub_read_args (stub,
-					CAMEL_STUB_ARG_FOLDER, &folder_name,
-					CAMEL_STUB_ARG_END))
-			goto comm_fail;
-		d(printf("IS_SUBSCRIBED_FOLDER %s\n", folder_name));
-		g_object_ref (stub);
-		MS_CLASS (stub)->is_subscribed_folder (stub, folder_name);
-		g_free (folder_name);
-		break;
-	}
-
-	default:
-		g_critical ("%s: Uncaught case (%d)", G_STRLOC, command);
-		goto comm_fail;
-	}
-
-	return TRUE;
-
- comm_fail:
-	/* Destroy the stub */
-	g_object_unref (stub);
-	return FALSE;
-}
-
-/**
- * mail_stub_read_args:
- * @stub: a #MailStub
- * @...: description of arguments to read
- *
- * Reads arguments as described from @stub's command channel.
- * The varargs list consists of pairs of #CamelStubArgType values
- * followed by pointers to variables of the appropriate type. The
- * list is terminated by %CAMEL_STUB_ARG_END.
- *
- * Return value: success or failure.
- **/
-gboolean
-mail_stub_read_args (MailStub *stub, ...)
-{
-	va_list ap;
-	CamelStubArgType argtype;
-	gint status;
-
-	va_start (ap, stub);
-
-	do {
-		argtype = va_arg (ap, gint);
-		switch (argtype) {
-		case CAMEL_STUB_ARG_END:
-			return TRUE;
-
-		case CAMEL_STUB_ARG_UINT32:
-		{
-			guint32 *val = va_arg (ap, guint32 *);
-			guint32 val32;
-
-			status = camel_stub_marshal_decode_uint32 (stub->cmd, &val32);
-			*val = val32;
-			break;
-		}
-
-		case CAMEL_STUB_ARG_STRING:
-		{
-			gchar **buf = va_arg (ap, gchar **);
-
-			status = camel_stub_marshal_decode_string (stub->cmd, buf);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_FOLDER:
-		{
-			gchar **buf = va_arg (ap, gchar **);
-
-			status = camel_stub_marshal_decode_folder (stub->cmd, buf);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_BYTEARRAY:
-		{
-			GByteArray **ba = va_arg (ap, GByteArray **);
-
-			status = camel_stub_marshal_decode_bytes (stub->cmd, ba);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_STRINGARRAY:
-		{
-			GPtrArray **arr = va_arg (ap, GPtrArray **);
-			guint32 len;
-			gchar *string;
-			gint i;
-
-			status = camel_stub_marshal_decode_uint32 (stub->cmd, &len);
-			if (status == -1)
-				break;
-			*arr = g_ptr_array_new ();
-			for (i = 0; i < len && status != -1; i++) {
-				status = camel_stub_marshal_decode_string (stub->cmd, &string);
-				if (status != -1)
-					g_ptr_array_add (*arr, string);
-			}
-
-			if (status == -1)
-				free_string_array (*arr);
-
-			break;
-		}
-
-		case CAMEL_STUB_ARG_UINT32ARRAY:
-		{
-			GArray **arr = va_arg (ap, GArray **);
-			guint32 i, len, unread_count;
-			status = camel_stub_marshal_decode_uint32 (stub->cmd, &len);
-			if (status == -1)
-				break;
-			*arr = g_array_new (FALSE, FALSE, sizeof (guint32));
-			for (i = 0; i< len && status != -1; i++) {
-				status = camel_stub_marshal_decode_uint32 (stub->cmd, &unread_count);
-				if (status != -1)
-					g_array_append_val (*arr, unread_count);
-			}
-			if (status == -1)
-				g_array_free (*arr, TRUE);
-
-			break;
-		}
-
-		default:
-			g_critical ("%s: Uncaught case (%d)", G_STRLOC, argtype);
-			status = -1;
-			break;
-		}
-	} while (status != -1);
-
-	return FALSE;
-}
-
-/**
- * mail_stub_return_data:
- * @stub: the MailStub
- * @retval: the kind of return data
- * @...: the data
- *
- * Sends substantive data to the CamelStub. If @retval is
- * %CAMEL_STUB_RETVAL_RESPONSE, it is the response data to the
- * last command. Otherwise it is an unsolicited informational
- * message.
- *
- * The data is not actually sent by this call. Response data will be
- * flushed when you call mail_stub_return_ok() or
- * mail_stub_return_error(). For asynchronous notifications, you
- * should be sure to call mail_stub_push_changes().
- **/
-void
-mail_stub_return_data (MailStub *stub, CamelStubRetval retval, ...)
-{
-	va_list ap;
-	CamelStubArgType argtype;
-	CamelStubMarshal *marshal;
-
-	if (retval == CAMEL_STUB_RETVAL_RESPONSE)
-		marshal = stub->cmd;
-	else
-		marshal = stub->status;
-
-	camel_stub_marshal_encode_uint32 (marshal, retval);
-	va_start (ap, retval);
-
-	while (1) {
-		argtype = va_arg (ap, gint);
-		switch (argtype) {
-		case CAMEL_STUB_ARG_END:
-			return;
-
-		case CAMEL_STUB_ARG_UINT32:
-		{
-			guint32 val = va_arg (ap, guint32);
-
-			camel_stub_marshal_encode_uint32 (marshal, val);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_STRING:
-		{
-			gchar *string = va_arg (ap, gchar *);
-
-			camel_stub_marshal_encode_string (marshal, string);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_FOLDER:
-		{
-			gchar *name = va_arg (ap, gchar *);
-
-			camel_stub_marshal_encode_folder (marshal, name);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_BYTEARRAY:
-		{
-			gchar *data = va_arg (ap, gchar *);
-			gint len = va_arg (ap, gint);
-			GByteArray ba;
-
-			ba.data = (guint8 *) data;
-			ba.len = len;
-			camel_stub_marshal_encode_bytes (marshal, &ba);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_STRINGARRAY:
-		{
-			GPtrArray *arr = va_arg (ap, GPtrArray *);
-			gint i;
-
-			camel_stub_marshal_encode_uint32 (marshal, arr->len);
-			for (i = 0; i < arr->len; i++)
-				camel_stub_marshal_encode_string (marshal, arr->pdata[i]);
-			break;
-		}
-
-		case CAMEL_STUB_ARG_UINT32ARRAY:
-		{
-			GArray *arr = va_arg (ap, GArray *);
-			gint i;
-
-			camel_stub_marshal_encode_uint32 (marshal, arr->len);
-			for (i = 0; i < arr->len; i++)
-				camel_stub_marshal_encode_uint32 (marshal, g_array_index (arr, guint32, i));
-			break;
-		}
-
-		default:
-			g_critical ("%s: Uncaught case (%d)", G_STRLOC, argtype);
-			return;
-		}
-	}
-}
-
-/**
- * mail_stub_return_progress:
- * @stub: the MailStub
- * @percent: the percent value to return
- *
- * Sends progress data on the current operation.
- **/
-void
-mail_stub_return_progress (MailStub *stub, gint percent)
-{
-	d(printf("  %d%%", percent));
-	camel_stub_marshal_encode_uint32 (stub->cmd, CAMEL_STUB_RETVAL_PROGRESS);
-	camel_stub_marshal_encode_uint32 (stub->cmd, percent);
-	camel_stub_marshal_flush (stub->cmd);
-}
-
-/**
- * mail_stub_return_ok:
- * @stub: the MailStub
- *
- * Sends a success response to the CamelStub. One of two possible
- * completions to any non-oneway command. This also calls
- * mail_stub_push_changes().
- *
- * Since this unrefs @stub (to balance the ref in connection_handler(),
- * callers should not assume it is still valid after the call.
- **/
-void
-mail_stub_return_ok (MailStub *stub)
-{
-	d(printf("  OK\n"));
-	camel_stub_marshal_flush (stub->status);
-	camel_stub_marshal_encode_uint32 (stub->cmd, CAMEL_STUB_RETVAL_OK);
-	camel_stub_marshal_flush (stub->cmd);
-	g_object_unref (stub);
-}
-
-/**
- * mail_stub_return_error:
- * @stub: the MailStub
- * @message: the error message
- *
- * Sends a failure response to the CamelStub. The other of two
- * possible completions to any non-oneway command. This also calls
- * mail_stub_push_changes ();
- *
- * Since this unrefs @stub (to balance the ref in connection_handler(),
- * callers should not assume it is still valid after the call.
- **/
-void
-mail_stub_return_error (MailStub *stub, const gchar *message)
-{
-	d(printf("  Error: %s\n", message));
-	camel_stub_marshal_flush (stub->status);
-	camel_stub_marshal_encode_uint32 (stub->cmd, CAMEL_STUB_RETVAL_EXCEPTION);
-	camel_stub_marshal_encode_string (stub->cmd, message);
-	camel_stub_marshal_flush (stub->cmd);
-	g_object_unref (stub);
-}
-
-/**
- * mail_stub_push_changes:
- * @stub: the MailStub
- *
- * This flushes the status channel, alerting the CamelStub of
- * new or changed messages.
- **/
-void
-mail_stub_push_changes (MailStub *stub)
-{
-	camel_stub_marshal_flush (stub->status);
-}
-
-/**
- * mail_stub_construct:
- * @stub: the #MailStub
- * @cmd_fd: command socket file descriptor
- * @status_fd: status socket file descriptor
- *
- * Initializes @stub with @cmd_fd and @status_fd.
- **/
-void
-mail_stub_construct (MailStub *stub, gint cmd_fd, gint status_fd)
-{
-#ifndef G_OS_WIN32
-	stub->channel = g_io_channel_unix_new (cmd_fd);
-#else
-	stub->channel = g_io_channel_win32_new_socket (cmd_fd);
-#endif
-	g_io_add_watch (stub->channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
-			connection_handler, stub);
-	stub->cmd = camel_stub_marshal_new (cmd_fd);
-	stub->status = camel_stub_marshal_new (status_fd);
-}
diff --git a/mail/mail-stub.h b/mail/mail-stub.h
deleted file mode 100644
index 6e932b5..0000000
--- a/mail/mail-stub.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* Copyright (C) 2001-2004 Novell, Inc. */
-
-#ifndef __MAIL_STUB_H__
-#define __MAIL_STUB_H__
-
-#include <stdio.h>
-#include <glib-object.h>
-#include "camel-stub-constants.h"
-#include "camel-stub-marshal.h"
-
-G_BEGIN_DECLS
-
-#define MAIL_TYPE_STUB            (mail_stub_get_type ())
-#define MAIL_STUB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAIL_TYPE_STUB, MailStub))
-#define MAIL_STUB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MAIL_TYPE_STUB, MailStubClass))
-#define MAIL_STUB_IS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAIL_TYPE_STUB))
-#define MAIL_STUB_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), MAIL_TYPE_STUB))
-
-typedef struct _MailStub        MailStub;
-typedef struct _MailStubClass   MailStubClass;
-
-struct _MailStub {
-	GObject parent;
-
-	GIOChannel *channel;
-	CamelStubMarshal *cmd, *status;
-};
-
-struct _MailStubClass {
-	GObjectClass parent_class;
-
-	/* methods */
-	void (*connect)            (MailStub *, gchar *pwd);
-	void (*get_folder)         (MailStub *, const gchar *name,
-				    gboolean create, GPtrArray *uids,
-				    GByteArray *flags, GPtrArray *hrefs,
-				    guint32 high_article_num);
-	void (*get_trash_name)     (MailStub *);
-	void (*sync_folder)        (MailStub *, const gchar *folder_name);
-	void (*refresh_folder)     (MailStub *, const gchar *folder_name);
-	void (*sync_count)	   (MailStub *, const gchar *folder_name);
-	void (*expunge_uids)       (MailStub *, const gchar *folder_name,
-				    GPtrArray *uids);
-	void (*append_message)     (MailStub *, const gchar *folder_name,
-				    guint32 flags, const gchar *subject,
-				    const gchar *data, gint length);
-	void (*set_message_flags)  (MailStub *, const gchar *folder_name,
-				    const gchar *uid,
-				    guint32 flags, guint32 mask);
-	void (*set_message_tag)    (MailStub *, const gchar *folder_name,
-				    const gchar *uid,
-				    const gchar *name, const gchar *value);
-	void (*get_message)        (MailStub *, const gchar *folder_name,
-				    const gchar *uid);
-	void (*search)             (MailStub *, const gchar *folder_name,
-				    const gchar *text);
-	void (*transfer_messages)  (MailStub *, const gchar *source_name,
-				    const gchar *dest_name, GPtrArray *uids,
-				    gboolean delete_originals);
-	void (*get_folder_info)    (MailStub *, const gchar *top,
-				    guint32 store_flags);
-	void (*send_message)       (MailStub *, const gchar *from,
-				    GPtrArray *recipients,
-				    const gchar *data, gint length);
-	void (*create_folder)      (MailStub *, const gchar *parent_name,
-				    const gchar *folder_name);
-	void (*delete_folder)      (MailStub *, const gchar *folder_name);
-	void (*rename_folder)      (MailStub *, const gchar *old_name,
-				    const gchar *new_name);
-	void (*subscribe_folder)   (MailStub *, const gchar *folder_name);
-	void (*unsubscribe_folder)   (MailStub *, const gchar *folder_name);
-	void (*is_subscribed_folder)   (MailStub *, const gchar *folder_name);
-};
-
-GType             mail_stub_get_type        (void);
-void              mail_stub_construct       (MailStub        *stub,
-					     gint              cmd_fd,
-					     gint              status_fd);
-
-gboolean          mail_stub_read_args       (MailStub        *stub,
-					     ...);
-
-void              mail_stub_return_data     (MailStub        *stub,
-					     CamelStubRetval  retval,
-					     ...);
-void              mail_stub_return_progress (MailStub        *stub,
-					     gint              percent);
-void              mail_stub_return_ok       (MailStub        *stub);
-void              mail_stub_return_error    (MailStub        *stub,
-					     const gchar      *message);
-
-void              mail_stub_push_changes    (MailStub        *stub);
-
-/* Message flags. This must be kept in sync with camel-folder-summary.h */
-typedef enum {
-	MAIL_STUB_MESSAGE_ANSWERED     = (1 << 0),
-	MAIL_STUB_MESSAGE_DELETED      = (1 << 1),
-	MAIL_STUB_MESSAGE_DRAFT        = (1 << 2),
-	MAIL_STUB_MESSAGE_FLAGGED      = (1 << 3),
-	MAIL_STUB_MESSAGE_SEEN         = (1 << 4),
-	MAIL_STUB_MESSAGE_ATTACHMENTS  = (1 << 5),
-	MAIL_STUB_MESSAGE_ANSWERED_ALL = (1 << 6),
-
-	/* These are our own private ones */
-	MAIL_STUB_MESSAGE_DELEGATED    = (1 << 16)
-} MailStubMessageFlags;
-
-G_END_DECLS
-
-#endif /* __MAIL_STUB_H__ */
diff --git a/mail/mail-utils.h b/mail/mail-utils.h
deleted file mode 100644
index 15fc1b2..0000000
--- a/mail/mail-utils.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* Copyright (C) 2001-2004 Novell, Inc. */
-
-#ifndef __MAIL_UTILS_H__
-#define __MAIL_UTILS_H__
-
-#include "e2k-properties.h"
-
-G_BEGIN_DECLS
-
-typedef enum {
-	MAIL_UTIL_DEMANGLE_DELGATED_MEETING,
-	MAIL_UTIL_DEMANGLE_MEETING_IN_SUBSCRIBED_INBOX,
-	MAIL_UTIL_DEMANGLE_SENDER_FIELD
-} MailUtilDemangleType;
-
-gchar    *mail_util_mapi_to_smtp_headers (E2kProperties *props);
-
-GString *mail_util_stickynote_to_rfc822 (E2kProperties *props);
-
-guint32  mail_util_props_to_camel_flags (E2kProperties *props,
-					 gboolean       obey_read_flag);
-
-gchar *   mail_util_extract_transport_headers (E2kProperties *props);
-
-gboolean
-mail_util_demangle_meeting_related_message (GString *body,
-				const gchar *owner_cn,
-				const gchar *owner_email,
-				const gchar *owner_cal_uri,
-				const gchar *subscriber_email,
-				MailUtilDemangleType unmangle_type);
-
-G_END_DECLS
-
-#endif /* __MAIL_UTILS_H__ */
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index b6f5188..e69de29 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1,5 +0,0 @@
-storage/exchange-delegates-user.c
-storage/exchange-delegates.c
-storage/exchange-permissions-dialog.c
-storage/xc-backend-view.c
-storage/xc-commands.c
diff --git a/storage/exchange-config-listener.c b/storage/exchange-config-listener.c
deleted file mode 100644
index 2c336ac..0000000
--- a/storage/exchange-config-listener.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2001-2004 Novell, Inc.
- *
- * 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.
- */
-
-/* ExchangeConfigListener: a class that listens to the config database
- * and handles creating the ExchangeAccount object and making sure that
- * default folders are updated as needed.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#include <libedataserver/e-source.h>
-#include <libedataserver/e-source-list.h>
-#include <libedataserver/e-source-group.h>
-#include <libedataserver/e-xml-utils.h>
-#include <libedataserver/e-xml-hash-utils.h>
-
-#include <camel/camel-url.h>
-
-#include <e2k-marshal.h>
-#include <e2k-uri.h>
-#include <exchange-account.h>
-#include <e-folder-exchange.h>
-
-#include <e-util/e-dialog-utils.h>
-
-#include "mail-stub-listener.h"
-
-#include "exchange-config-listener.h"
-
-struct _ExchangeConfigListenerPrivate {
-	GConfClient *gconf;
-	guint idle_id;
-
-	gchar *configured_uri, *configured_name;
-	EAccount *configured_account;
-
-	ExchangeAccount *exchange_account;
-};
-
-typedef struct {
-	const gchar *name;
-	const gchar *uri;
-	gint type;
-}FolderInfo;
-
-enum {
-	EXCHANGE_ACCOUNT_CREATED,
-	EXCHANGE_ACCOUNT_REMOVED,
-	LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = { 0 };
-
-#define PARENT_TYPE E_TYPE_ACCOUNT_LIST
-
-#define CONF_KEY_SELECTED_CAL_SOURCES "/apps/evolution/calendar/display/selected_calendars"
-#define CONF_KEY_SELECTED_TASKS_SOURCES "/apps/evolution/calendar/tasks/selected_tasks"
-
-static EAccountListClass *parent_class = NULL;
-
-static void dispose (GObject *object);
-static void finalize (GObject *object);
-
-static void account_added   (EAccountList *account_listener,
-			     EAccount     *account);
-static void account_changed (EAccountList *account_listener,
-			     EAccount     *account);
-static void account_removed (EAccountList *account_listener,
-			     EAccount     *account);
-
-static gboolean exchange_camel_urls_is_equal (const gchar *url1,
-					      const gchar *url2);
-
-static void
-class_init (GObjectClass *object_class)
-{
-	EAccountListClass *e_account_list_class =
-		E_ACCOUNT_LIST_CLASS (object_class);
-
-	parent_class = g_type_class_ref (PARENT_TYPE);
-
-	/* virtual method override */
-	object_class->dispose = dispose;
-	object_class->finalize = finalize;
-
-	e_account_list_class->account_added   = account_added;
-	e_account_list_class->account_changed = account_changed;
-	e_account_list_class->account_removed = account_removed;
-
-	/* signals */
-	signals[EXCHANGE_ACCOUNT_CREATED] =
-		g_signal_new ("exchange_account_created",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (ExchangeConfigListenerClass, exchange_account_created),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_POINTER);
-	signals[EXCHANGE_ACCOUNT_REMOVED] =
-		g_signal_new ("exchange_account_removed",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (ExchangeConfigListenerClass, exchange_account_removed),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_POINTER);
-}
-
-static void
-init (GObject *object)
-{
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (object);
-
-	config_listener->priv = g_new0 (ExchangeConfigListenerPrivate, 1);
-}
-
-static void
-dispose (GObject *object)
-{
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (object);
-
-	if (config_listener->priv->idle_id) {
-		g_source_remove (config_listener->priv->idle_id);
-		config_listener->priv->idle_id = 0;
-	}
-
-	if (config_listener->priv->gconf) {
-		g_object_unref (config_listener->priv->gconf);
-		config_listener->priv->gconf = NULL;
-	}
-
-	G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-finalize (GObject *object)
-{
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (object);
-
-	g_free (config_listener->priv->configured_name);
-	g_free (config_listener->priv->configured_uri);
-	g_free (config_listener->priv);
-
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-E2K_MAKE_TYPE (exchange_config_listener, ExchangeConfigListener, class_init, init, PARENT_TYPE)
-
-#define EVOLUTION_URI_PREFIX     "evolution:/"
-#define EVOLUTION_URI_PREFIX_LEN (sizeof (EVOLUTION_URI_PREFIX) - 1)
-
-static gboolean
-is_active_exchange_account (EAccount *account)
-{
-	if (!account->enabled)
-		return FALSE;
-	if (!account->source || !account->source->url)
-		return FALSE;
-	return (strncmp (account->source->url, EXCHANGE_URI_PREFIX, 11) == 0);
-}
-
-static void
-update_foreign_uri (const gchar *path, const gchar *account_uri)
-{
-	gchar *file_path, *phy_uri, *foreign_uri, *new_phy_uri;
-	GHashTable *old_props = NULL;
-	xmlDoc *old_doc = NULL, *new_doc = NULL;
-
-	if (!path)
-		return;
-
-	file_path = g_build_filename (path, "hierarchy.xml", NULL);
-	if (!g_file_test (file_path, G_FILE_TEST_EXISTS))
-		goto cleanup;
-
-	old_doc = e_xml_parse_file (file_path);
-	if (!old_doc)
-		goto cleanup;
-
-	old_props = e_xml_to_hash (old_doc, E_XML_HASH_TYPE_PROPERTY);
-	xmlFreeDoc (old_doc);
-
-	phy_uri = g_hash_table_lookup (old_props, "physical_uri_prefix");
-	if (!phy_uri)
-		goto cleanup;
-
-	foreign_uri = strstr (phy_uri, "://");
-	if (!foreign_uri)
-		goto cleanup;
-	foreign_uri = strchr (foreign_uri + 3, '/');
-	if (!foreign_uri)
-		goto cleanup;
-
-	if ((foreign_uri + 1) && (*(foreign_uri + 1) == ';'))
-		goto cleanup;
-
-	new_phy_uri = g_strdup_printf ("exchange://%s/;%s", account_uri, foreign_uri + 1);
-	g_hash_table_remove (old_props, "physical_uri_prefix");
-	g_hash_table_insert (old_props, (gchar *)g_strdup ("physical_uri_prefix"), new_phy_uri);
-
-	new_doc = e_xml_from_hash (old_props, E_XML_HASH_TYPE_PROPERTY, "foreign-hierarchy");
-	e_xml_save_file (file_path, new_doc);
-
-	xmlFreeDoc (new_doc);
-	g_free (new_phy_uri);
-cleanup:
-	g_free (file_path);
-	if (old_props)
-		e_xml_destroy_hash (old_props);
-	return;
-}
-
-static void
-migrate_foreign_hierarchy (ExchangeAccount *account)
-{
-	GDir *d;
-	const gchar *dentry;
-	gchar *dir;
-
-	d = g_dir_open (account->storage_dir, 0, NULL);
-	if (d) {
-		while ((dentry = g_dir_read_name (d))) {
-			if (!strchr (dentry, '@'))
-				continue;
-			dir = g_strdup_printf ("%s/%s", account->storage_dir,
-							dentry);
-			update_foreign_uri (dir, account->account_filename);
-			g_free (dir);
-		}
-		g_dir_close (d);
-	}
-}
-
-static void
-ex_set_relative_uri (ESource *source, const gchar *url)
-{
-	const gchar *rel_uri = e_source_peek_relative_uri (source);
-	gchar *folder_name;
-	gchar *new_rel_uri;
-
-	if (!rel_uri)
-		return;
-
-	folder_name = strchr (rel_uri, '/');
-	if (!folder_name)
-		return;
-
-	if ((folder_name + 1) && *(folder_name + 1) == ';')
-		return;
-
-	new_rel_uri = g_strdup_printf ("%s;%s", url, folder_name + 1);
-	e_source_set_relative_uri (source, new_rel_uri);
-	g_free (new_rel_uri);
-}
-
-static void
-migrate_account_esource (EAccount *account,
-			FolderType folder_type)
-{
-	ESourceGroup *group;
-	ESource *source = NULL;
-	GSList *groups;
-	GSList *sources;
-	gboolean found_group;
-	const gchar *user_name, *authtype;
-	GConfClient *client;
-	ESourceList *source_list = NULL;
-	CamelURL *camel_url;
-	gchar *url_string;
-
-	camel_url = camel_url_new (account->source->url, NULL);
-	if (!camel_url)
-		return;
-	user_name = camel_url->user;
-	authtype  = camel_url->authmech;
-	url_string = camel_url_to_string (camel_url, CAMEL_URL_HIDE_PASSWORD | CAMEL_URL_HIDE_PARAMS);
-
-	if (!user_name) {
-		g_free (url_string);
-		camel_url_free (camel_url);
-		return;
-	}
-
-	client = gconf_client_get_default ();
-
-	if (folder_type == EXCHANGE_CONTACTS_FOLDER)
-		source_list = e_source_list_new_for_gconf ( client,
-							CONF_KEY_CONTACTS);
-	else if (folder_type == EXCHANGE_CALENDAR_FOLDER)
-		source_list = e_source_list_new_for_gconf ( client,
-							CONF_KEY_CAL);
-	else if (folder_type == EXCHANGE_TASKS_FOLDER)
-		source_list = e_source_list_new_for_gconf ( client,
-							CONF_KEY_TASKS);
-
-	groups = e_source_list_peek_groups (source_list);
-	found_group = FALSE;
-
-	for (; groups != NULL && !found_group; groups = g_slist_next (groups)) {
-		group = E_SOURCE_GROUP (groups->data);
-
-		if (strcmp (e_source_group_peek_name (group), account->name) == 0
-                    &&
-                    strcmp (e_source_group_peek_base_uri (group), EXCHANGE_URI_PREFIX) == 0) {
-			sources = e_source_group_peek_sources (group);
-
-			found_group = TRUE;
-			for (; sources != NULL; sources = g_slist_next (sources)) {
-				source = E_SOURCE (sources->data);
-
-				ex_set_relative_uri (source, url_string + strlen ("exchange://"));
-				e_source_set_property (source, "username", user_name);
-				e_source_set_property (source, "auth-domain", "Exchange");
-				if (authtype)
-					e_source_set_property (source, "auth-type", authtype);
-				if (folder_type == EXCHANGE_CONTACTS_FOLDER)
-					e_source_set_property (source, "auth", "plain/password");
-				else
-					e_source_set_property (source, "auth", "1");
-				e_source_list_sync (source_list, NULL);
-			}
-		}
-	}
-	g_free (url_string);
-	camel_url_free (camel_url);
-	g_object_unref (source_list);
-	g_object_unref (client);
-}
-
-void
-exchange_config_listener_migrate_esources (ExchangeConfigListener *config_listener)
-{
-	EAccount *account;
-
-	g_return_if_fail (config_listener != NULL);
-
-	account = config_listener->priv->configured_account;
-	migrate_account_esource (account, EXCHANGE_CALENDAR_FOLDER);
-	migrate_account_esource (account, EXCHANGE_TASKS_FOLDER);
-	migrate_account_esource (account, EXCHANGE_CONTACTS_FOLDER);
-	migrate_foreign_hierarchy (config_listener->priv->exchange_account);
-}
-
-static void
-account_added (EAccountList *account_list, EAccount *account)
-{
-	ExchangeConfigListener *config_listener;
-	ExchangeAccount *exchange_account;
-
-	if (!is_active_exchange_account (account))
-		return;
-
-	config_listener = EXCHANGE_CONFIG_LISTENER (account_list);
-	if (config_listener->priv->configured_account) {
-		/* Multiple accounts configured. */
-		return;
-	}
-
-	/* New account! Yippee! */
-	exchange_account = exchange_account_new (account_list, account);
-	if (!exchange_account) {
-		g_warning ("Could not parse exchange uri '%s'",
-			   account->source->url);
-		return;
-	}
-
-	config_listener->priv->exchange_account = exchange_account;
-	config_listener->priv->configured_account = account;
-
-	g_free (config_listener->priv->configured_uri);
-	config_listener->priv->configured_uri = g_strdup (account->source->url);
-	g_free (config_listener->priv->configured_name);
-	config_listener->priv->configured_name = g_strdup (account->name);
-
-	g_signal_emit (config_listener, signals[EXCHANGE_ACCOUNT_CREATED], 0,
-		       exchange_account);
-	exchange_config_listener_migrate_esources (config_listener);
-}
-
-struct account_update_data {
-	EAccountList *account_list;
-	EAccount *account;
-};
-
-static void
-configured_account_destroyed (gpointer user_data, GObject *where_account_was)
-{
-	struct account_update_data *aud = user_data;
-
-	if (!EXCHANGE_CONFIG_LISTENER (aud->account_list)->priv->configured_account)
-		account_added (aud->account_list, aud->account);
-
-	g_object_unref (aud->account_list);
-	g_object_unref (aud->account);
-	g_free (aud);
-}
-
-static gboolean
-requires_relogin (gchar *current_url, gchar *new_url)
-{
-	E2kUri *current_uri, *new_uri;
-	const gchar *current_param_val, *new_param_val;
-	const gchar *params [] = { "owa_url", "ad_server", "use_ssl" };
-	const gint n_params = G_N_ELEMENTS (params);
-	gint i;
-	gboolean relogin = FALSE;
-
-	current_uri = e2k_uri_new (current_url);
-	new_uri = e2k_uri_new (new_url);
-
-	if (strcmp (current_uri->user, new_uri->user) ||
-	    strcmp (current_uri->host, new_uri->host)) {
-		relogin = TRUE;
-		goto end;
-	}
-
-	if (current_uri->authmech || new_uri->authmech) {
-		if (current_uri->authmech && new_uri->authmech) {
-			if (strcmp (current_uri->authmech, new_uri->authmech)) {
-				/* Auth mechanism has changed */
-				relogin = TRUE;
-				goto end;
-			}
-		}
-		else {
-			/* Auth mechanism is set for the first time */
-			relogin = TRUE;
-			goto end;
-		}
-	}
-
-	for (i=0; i<n_params; i++) {
-		current_param_val = e2k_uri_get_param (current_uri, params[i]);
-		new_param_val = e2k_uri_get_param (new_uri, params[i]);
-
-		if (current_param_val && new_param_val) {
-			/* both the urls have params to be compared */
-			if (strcmp (current_param_val, new_param_val)) {
-				relogin = TRUE;
-				break;
-			}
-		}
-		else if (current_param_val || new_param_val) {
-			/* check for added or deleted parameter */
-			relogin = TRUE;
-			break;
-		}
-	}
-end:
-	e2k_uri_free (new_uri);
-	e2k_uri_free (current_uri);
-	return relogin;
-}
-
-static void
-account_changed (EAccountList *account_list, EAccount *account)
-{
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (account_list);
-	ExchangeConfigListenerPrivate *priv = config_listener->priv;
-
-	if (account != config_listener->priv->configured_account) {
-		if (!is_active_exchange_account (account))
-			return;
-
-		/* The user has converted an existing non-Exchange
-		 * account to an Exchange account, so treat it like an
-		 * add.
-		 */
-		account_added (account_list, account);
-		return;
-	} else if (!is_active_exchange_account (account)) {
-		/* The user has disabled the Exchange account or
-		 * converted it to non-Exchange, so treat it like a
-		 * remove.
-		 */
-		account_removed (account_list, account);
-		return;
-	}
-
-	/* FIXME: The order of the parameters in the Camel URL string is not in
-	 * order for the two given strings. So, we will not be able to use
-	 * plain string comparison. Instead compare the parameters one by one.
-	 */
-	if (exchange_camel_urls_is_equal (config_listener->priv->configured_uri,
-					  account->source->url) &&
-	    !strcmp (config_listener->priv->configured_name, account->name)) {
-		/* The user changed something we don't care about. */
-		return;
-	}
-
-	/* OK, so he modified the active account in a way we care
-	 * about. If the user hasn't connected yet, we're still ok.
-	 */
-	if (!exchange_account_get_context (config_listener->priv->exchange_account)) {
-		/* Good. Remove the current account, and wait for it
-		 * to actually go away (which may not happen immediately
-		 * since there may be a function higher up on the stack
-		 * still holding a ref on it). Then create the new one.
-		 * (We have to wait for it to go away because the new
-		 * storage probably still has the same name as the old
-		 * one, so trying to create it before the old one is
-		 * removed would fail.)
-		 */
-		struct account_update_data *aud;
-
-		aud = g_new (struct account_update_data, 1);
-		aud->account = g_object_ref (account);
-		aud->account_list = g_object_ref (account_list);
-		g_object_weak_ref (G_OBJECT (config_listener->priv->exchange_account), configured_account_destroyed, aud);
-
-		account_removed (account_list, account);
-		return;
-	}
-
-	/* If account name has changed, or the url value has changed, which
-	 * could be due to change in hostname or some parameter value,
-	 * remove old e-sources
-	 */
-	if (requires_relogin (config_listener->priv->configured_uri,
-			      account->source->url)) {
-		exchange_account_forget_password (priv->exchange_account);
-	} else if (strcmp (config_listener->priv->configured_name, account->name)) {
-		g_free (config_listener->priv->configured_name);
-		config_listener->priv->configured_name = g_strdup (account->name);
-		return;
-	} else {
-		/* FIXME: Do ESources need to be modified? */
-		return;
-	}
-
-	/* But note the new URI so if he changes something else, we
-	 * only warn again if he changes again.
-	 */
-	g_free (config_listener->priv->configured_uri);
-	config_listener->priv->configured_uri = g_strdup (account->source->url);
-}
-
-static void
-account_removed (EAccountList *account_list, EAccount *account)
-{
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (account_list);
-	ExchangeConfigListenerPrivate *priv = config_listener->priv;
-
-	if (account != priv->configured_account)
-		return;
-
-	exchange_account_forget_password (priv->exchange_account);
-
-	if (!exchange_account_get_context (priv->exchange_account)) {
-		/* The account isn't connected yet, so we can destroy
-		 * it without problems.
-		 */
-		g_signal_emit (config_listener,
-			       signals[EXCHANGE_ACCOUNT_REMOVED], 0,
-			       priv->exchange_account);
-
-		priv->configured_account = NULL;
-		g_free (priv->configured_uri);
-		priv->configured_uri = NULL;
-		g_free (priv->configured_name);
-		priv->configured_name = NULL;
-	}
-}
-
-static gboolean
-idle_construct (gpointer data)
-{
-	ExchangeConfigListener *config_listener = data;
-
-	config_listener->priv->idle_id = 0;
-	e_account_list_construct (E_ACCOUNT_LIST (config_listener),
-				  config_listener->priv->gconf);
-	return FALSE;
-}
-
-/**
- * exchange_config_listener_new:
- *
- * This creates and returns a new #ExchangeConfigListener, which
- * monitors GConf and creates and (theoretically) destroys accounts
- * accordingly. It will emit an %account_created signal when a new
- * account is created (or shortly after the listener itself is created
- * if an account already exists).
- *
- * Due to various constraints, the user is currently limited to a
- * single account, and it is not possible to destroy an existing
- * account. Thus, the %account_created signal will never be emitted
- * more than once currently.
- *
- * Return value: the new config listener.
- **/
-ExchangeConfigListener *
-exchange_config_listener_new (void)
-{
-	ExchangeConfigListener *config_listener;
-
-	config_listener = g_object_new (EXCHANGE_TYPE_CONFIG_LISTENER, NULL);
-	config_listener->priv->gconf = gconf_client_get_default ();
-
-	config_listener->priv->idle_id =
-		g_idle_add (idle_construct, config_listener);
-
-	return config_listener;
-}
-
-GSList *
-exchange_config_listener_get_accounts (ExchangeConfigListener *config_listener)
-{
-	g_return_val_if_fail (EXCHANGE_IS_CONFIG_LISTENER (config_listener), NULL);
-
-	if (config_listener->priv->exchange_account)
-		return g_slist_append (NULL, config_listener->priv->exchange_account);
-	else
-		return NULL;
-}
-
-/**
- * exchange_camel_urls_is_equal
- *
- * @url1: CAMEL URL string 1
- * @url2: CAMEL URL string 2
- *
- * This function checks if the parameters present in two given CAMEL URLS are
- * identical and returns the result.
- *
- * Return Value: Boolean result of the comparision.
- *
- **/
-static gboolean
-exchange_camel_urls_is_equal (const gchar *url1, const gchar *url2)
-{
-	CamelURL *curl1, *curl2;
-	const gchar *param1, *param2;
-	const gchar *params[] = {
-		"auth",
-		"owa_url",
-		"owa_path",
-		"mailbox",
-		"ad_server",
-	};
-	const gint n_params = 5;
-	gint i;
-
-	curl1 = camel_url_new (url1, NULL);
-	curl2 = camel_url_new (url2, NULL);
-
-	for (i = 0; i < n_params; ++i) {
-		param1 = (gchar *) camel_url_get_param (curl1, params[i]);
-		param2 = (gchar *) camel_url_get_param (curl2, params[i]);
-		if ((param1 && !param2) || (!param1 && param2) || /* Missing */
-		    (param1 && param2 && strcmp (param1, param2))) { /* Differing */
-			camel_url_free (curl1);
-			camel_url_free (curl2);
-			return FALSE;
-		}
-	}
-	camel_url_free (curl1);
-	camel_url_free (curl2);
-	return TRUE;
-}
diff --git a/storage/exchange-config-listener.h b/storage/exchange-config-listener.h
deleted file mode 100644
index b2abc14..0000000
--- a/storage/exchange-config-listener.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* Copyright (C) 2001-2004 Novell, Inc. */
-
-#ifndef __EXCHANGE_CONFIG_LISTENER_H__
-#define __EXCHANGE_CONFIG_LISTENER_H__
-
-#include <exchange-types.h>
-#include <exchange-constants.h>
-#include <libedataserver/e-account-list.h>
-#include <libedataserver/e-source-list.h>
-#include <libedataserver/e-source-group.h>
-
-G_BEGIN_DECLS
-
-#define EXCHANGE_TYPE_CONFIG_LISTENER            (exchange_config_listener_get_type ())
-#define EXCHANGE_CONFIG_LISTENER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_CONFIG_LISTENER, ExchangeConfigListener))
-#define EXCHANGE_CONFIG_LISTENER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_CONFIG_LISTENER, ExchangeConfigListenerClass))
-#define EXCHANGE_IS_CONFIG_LISTENER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_CONFIG_LISTENER))
-#define EXCHANGE_IS_CONFIG_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_TYPE_CONFIG_LISTENER))
-
-struct _ExchangeConfigListener {
-	EAccountList parent;
-
-	ExchangeConfigListenerPrivate *priv;
-};
-
-struct _ExchangeConfigListenerClass {
-	EAccountListClass parent_class;
-
-	/* signals */
-	void (*exchange_account_created) (ExchangeConfigListener *,
-					  ExchangeAccount *);
-	void (*exchange_account_removed) (ExchangeConfigListener *,
-					  ExchangeAccount *);
-};
-
-#if 0
-typedef enum {
-	EXCHANGE_CALENDAR_FOLDER,
-	EXCHANGE_TASKS_FOLDER,
-	EXCHANGE_CONTACTS_FOLDER
-}FolderType;
-#endif
-
-#define CONF_KEY_CAL "/apps/evolution/calendar/sources"
-#define CONF_KEY_TASKS "/apps/evolution/tasks/sources"
-#define CONF_KEY_CONTACTS "/apps/evolution/addressbook/sources"
-#define EXCHANGE_URI_PREFIX "exchange://"
-
-GType                   exchange_config_listener_get_type (void);
-ExchangeConfigListener *exchange_config_listener_new      (void);
-
-GSList                 *exchange_config_listener_get_accounts (ExchangeConfigListener *config_listener);
-
-void			exchange_config_listener_migrate_esources (ExchangeConfigListener *config_listener);
-
-void			add_folder_esource (ExchangeAccount *account, FolderType folder_type, const gchar *folder_name, const gchar *physical_uri);
-void			remove_folder_esource (ExchangeAccount *account, FolderType folder_type, const gchar *physical_uri);
-G_END_DECLS
-
-#endif /* __EXCHANGE_CONFIG_LISTENER_H__ */
diff --git a/storage/exchange-migrate.c b/storage/exchange-migrate.c
deleted file mode 100644
index d8fe505..0000000
--- a/storage/exchange-migrate.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2004 Novell, Inc.
- *
- * 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.
- */
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <utime.h>
-#include <string.h>
-
-#include <gtk/gtk.h>
-#include <libedataserver/e-data-server-util.h>
-#include <e-util/e-folder-map.h>
-
-#include <exchange-types.h>
-#include "exchange-migrate.h"
-
-static GtkWidget *window;
-static GtkLabel *label;
-static GtkProgressBar *progress;
-
-CORBA_short maj=0;
-CORBA_short min=0;
-CORBA_short rev=0;
-
-#ifndef G_OS_WIN32
-
-/* No need for migration code from evolution-exchange 1.x on Win32.
- * If and when the same code is partly used for migrating between
- * future evolution-exchange versions, that code will have to be
- * revised and ported as necessary.
- */
-
-gchar *label_string = NULL;
-
-static void
-setup_progress_dialog ()
-{
-	GtkWidget *vbox, *hbox, *w;
-
-	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-	gtk_window_set_title (GTK_WINDOW (window), _("Migrating Exchange Folders..."));
-	gtk_window_set_modal (GTK_WINDOW (window), TRUE);
-	gtk_container_set_border_width (GTK_CONTAINER (window), 6);
-
-	vbox = gtk_vbox_new (FALSE, 6);
-	gtk_widget_show (vbox);
-	gtk_container_add ((GtkContainer *) window, vbox);
-
-	label_string = g_strdup_printf (_("The location and hierarchy of the "
-                     "Evolution exchange account folders are changed "
-                     "since Evolution %d.%d.%d.\n\nPlease be patient while "
-                     "Evolution migrates your folders..."), maj, min, rev);
-
-	w = gtk_label_new (label_string);
-
-	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
-	gtk_widget_show (w);
-	gtk_box_pack_start ((GtkBox *) vbox, w, TRUE, TRUE, 0);
-
-	hbox = gtk_hbox_new (FALSE, 6);
-	gtk_widget_show (hbox);
-	gtk_box_pack_start ((GtkBox *) vbox, hbox, TRUE, TRUE, 0);
-
-	label = (GtkLabel *) gtk_label_new ("");
-	gtk_widget_show ((GtkWidget *) label);
-	gtk_box_pack_start ((GtkBox *) hbox, (GtkWidget *) label, TRUE, TRUE, 0);
-
-	progress = (GtkProgressBar *) gtk_progress_bar_new ();
-	gtk_widget_show ((GtkWidget *) progress);
-	gtk_box_pack_start ((GtkBox *) hbox, (GtkWidget *) progress, TRUE, TRUE, 0);
-
-	gtk_widget_show (window);
-}
-
-static void
-show_error_dialog()
-{
-	GtkWidget *window;
-	GtkWidget *error_dialog;
-	gchar *err_string;
-
-	err_string = g_strdup_printf ( _("Warning: Evolution could not migrate "
-					"all the Exchange account data from "
-					"the version %d.%d.%d. \nThe data "
-					"hasn't been deleted, but will not be "
-					"seen by this version of Evolution"),
-					maj, min, rev);
-
-	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-	error_dialog = gtk_message_dialog_new (GTK_WINDOW (window),
-					       GTK_DIALOG_DESTROY_WITH_PARENT,
-					       GTK_MESSAGE_ERROR,
-					       GTK_BUTTONS_OK,
-					       "%s", err_string);
-	gtk_dialog_run (GTK_DIALOG (error_dialog));
-	gtk_widget_destroy (error_dialog);
-
-	g_free (err_string);
-}
-
-static void
-dialog_close ()
-{
-	gtk_widget_destroy ((GtkWidget *) window);
-	g_free(label_string);
-}
-
-static void
-dialog_set_folder_name (const gchar *folder_name)
-{
-	gchar *text;
-
-	text = g_strdup_printf (_("Migrating `%s':"), folder_name);
-	gtk_label_set_text (label, text);
-	g_free (text);
-
-	gtk_progress_bar_set_fraction (progress, 0.0);
-
-	while (gtk_events_pending ())
-		gtk_main_iteration ();
-}
-
-static void
-dialog_set_progress (double percent)
-{
-	gchar text[5];
-
-	snprintf (text, sizeof (text), "%d%%", (gint) (percent * 100.0f));
-
-	gtk_progress_bar_set_fraction (progress, percent);
-	gtk_progress_bar_set_text (progress, text);
-
-	while (gtk_events_pending ())
-		gtk_main_iteration ();
-}
-
-static gboolean
-cp (const gchar *src, const gchar *dest, gboolean show_progress)
-{
-	guchar readbuf[65536];
-	gssize nread, nwritten;
-	gint errnosav, readfd, writefd;
-	gsize total = 0;
-	struct stat st;
-	struct utimbuf ut;
-
-	/* if the dest file exists and has content, abort - we don't
-	 * want to corrupt their existing data */
-
-        if (stat (dest, &st) == 0 && st.st_size > 0)
-		goto ret;
-
-	if (stat (src, &st) == -1)
-		goto ret;
-
-	if ((readfd = open (src, O_RDONLY)) == -1)
-		goto ret;
-
-	if ((writefd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
-                errnosav = errno;
-                close (readfd);
-                errno = errnosav;
-		goto ret;
-        }
-
-        do {
-                do {
-                        nread = read (readfd, readbuf, sizeof (readbuf));
-                } while (nread == -1 && errno == EINTR);
-
-                if (nread == 0)
-                        break;
-                else if (nread < 0)
-                        goto exception;
-                do {
-                        nwritten = write (writefd, readbuf, nread);
-                } while (nwritten == -1 && errno == EINTR);
-
-                if (nwritten < nread)
-                        goto exception;
-
-                total += nwritten;
-
-                if (show_progress)
-			dialog_set_progress ((((double) total) /
-					      ((double) st.st_size)));
-        } while (total < st.st_size);
-
-        if (fsync (writefd) == -1)
-                goto exception;
-
-        close (readfd);
-        if (close (writefd) == -1)
-                goto failclose;
-
-        ut.actime = st.st_atime;
-        ut.modtime = st.st_mtime;
-        utime (dest, &ut);
-        chmod (dest, st.st_mode);
- ret:
-	return TRUE;
-
- exception:
-
-        errnosav = errno;
-        close (readfd);
-        close (writefd);
-        errno = errnosav;
-
- failclose:
-
-        errnosav = errno;
-        unlink (dest);
-        errno = errnosav;
-
-	return FALSE;
-}
-
-static gboolean
-cp_r (gchar *src, const gchar *dest)
-{
-	GString *srcpath, *destpath;
-	struct dirent *dent;
-	gsize slen, dlen;
-	struct stat st;
-	DIR *dir;
-
-	if (g_mkdir_with_parents (dest, 0777) == -1)
-		return FALSE;
-
-	if (!(dir = opendir (src)))
-		return TRUE;
-
-	srcpath = g_string_new (src);
-	g_string_append_c (srcpath, '/');
-	slen = srcpath->len;
-
-	destpath = g_string_new (dest);
-	g_string_append_c (destpath, '/');
-	dlen = destpath->len;
-
-	dialog_set_folder_name(src);
-
-	while ((dent = readdir (dir))) {
-		if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
-			continue;
-
-		g_string_truncate (srcpath, slen);
-		g_string_truncate (destpath, dlen);
-
-		g_string_append (srcpath, dent->d_name);
-		g_string_append (destpath, dent->d_name);
-		if (stat (srcpath->str, &st) == -1)
-			continue;
-
-		if (S_ISDIR (st.st_mode)) {
-			cp_r (srcpath->str, destpath->str);
-		} else {
-			cp (srcpath->str, destpath->str, TRUE);
-		}
-	}
-
-	closedir (dir);
-
-	g_string_free (destpath, TRUE);
-	g_string_free (srcpath, TRUE);
-
-	return TRUE;
-}
-
-static gchar *
-form_dir_path (gchar *file_name, const gchar *delim)
-{
-	GString *path = g_string_new (NULL);
-	gchar *dir_path;
-	gchar *token;
-
-	token = strtok (file_name, delim);
-	while (token != NULL) {
-		g_string_append (path, token);
-		g_string_append (path, "/subfolders/");
-		token = strtok (NULL, delim);
-	}
-	dir_path = g_strndup(path->str, strlen(path->str) - 12);
-	g_string_free (path, TRUE);
-	return dir_path;
-}
-
-static gchar *
-get_contacts_dir_from_filename(const gchar *migr_file)
-{
-	gchar *file_to_be_migrated = g_strdup (migr_file);
-	gchar *dot, *file_name;
-	const gchar *delim = "_";
-	gchar *dir_path = NULL;
-
-	dot = strchr (file_to_be_migrated, '.');
-	if (dot) {
-		file_name = g_strndup (file_to_be_migrated, dot - file_to_be_migrated);
-		dir_path = form_dir_path (file_name, delim);
-		g_free (file_name);
-	}
-	g_free (file_to_be_migrated);
-	return dir_path;
-}
-
-/*
- * Parse the names of summary and changes files in
- * ~/evolution/exchange/user@exchange-server/Addressbook and
- * copy them into the respective directories under
- * ~/.evolution/exchange/user@exchange-server
- *
- */
-/* FIXME: handling .changes files */
-/* FIXME: handling VCARD attributes changes */
-
-static gboolean
-migrate_contacts (gchar *src_path, const gchar *dest_path)
-{
-	gchar *dest_sub_dir = NULL, *summary_file = NULL;
-	gchar *contacts_dir = NULL, *src_file, *dest_file;
-	struct dirent *dent;
-	DIR *dir;
-	gboolean ret = TRUE;
-
-	setup_progress_dialog ();
-
-	dir = opendir (src_path);
-	if (dir) {
-		while ((dent = readdir (dir))) {
-			if (!strcmp (dent->d_name, ".") ||
-			    !strcmp (dent->d_name, ".."))
-				continue;
-
-			/* Parse the file name and form the dir hierarchy */
-			dest_sub_dir = get_contacts_dir_from_filename (
-								dent->d_name);
-
-			if (dest_sub_dir) {
-				contacts_dir = g_build_filename (
-							dest_path,
-							dest_sub_dir,
-							NULL);
-
-				/* Check if it is a summary file */
-				summary_file = g_strrstr (dent->d_name,
-							  ".summary");
-				if (summary_file)
-					dest_file = g_build_filename (
-							contacts_dir,
-							"summary",
-							NULL);
-				else
-					/* FIXME: replace d_name by change_id */
-					dest_file = g_build_filename (
-							contacts_dir,
-							dent->d_name,
-							NULL);
-
-				/* Create destination dir, and copy the files */
-				if (g_mkdir_with_parents (contacts_dir, 0777) == -1) {
-					ret = FALSE;
-					g_free (dest_file);
-					g_free (contacts_dir);
-					continue;
-				}
-
-				src_file = g_build_filename ( src_path,
-							      dent->d_name,
-							      NULL);
-
-				ret = cp (src_file, dest_file, TRUE);
-				g_free (dest_file);
-				g_free (src_file);
-				g_free (contacts_dir);
-				g_free (dest_sub_dir);
-			}
-			else {
-				ret = FALSE;
-				continue;
-			}
-		}
-		closedir(dir);
-	}
-	dialog_close ();
-	return ret;
-}
-
-/*
- * Copy the summary files from ~/evolution/mail/exchange to
- * ~/.evolution/exchange/
- */
-static gboolean
-migrate_mail (gchar *src_path, const gchar *dest_path)
-{
-	gboolean ret;
-
-	setup_progress_dialog ();
-	ret = cp_r (src_path, dest_path);
-	dialog_close ();
-
-	return ret;
-}
-
-/*
- * copy personal and public folders from ~/evolution/exchange into
- * ~/.evolution/exchange.
- *
- * This includes copying all the folders and metadata.xml files, also
- * Calendar and Tasks, cache files
- */
-static gboolean
-migrate_common (gchar *src_path, const gchar *dest_path)
-{
-	gchar *src_dir, *dest_dir;
-	gboolean ret;
-
-	setup_progress_dialog ();
-
-	src_dir = g_build_filename (src_path, "personal", NULL);
-	dest_dir = g_build_filename(dest_path, "personal", NULL);
-	ret = cp_r (src_dir, dest_dir);
-	g_free (src_dir);
-	g_free (dest_dir);
-
-	src_dir = g_build_filename (src_path, "public", NULL);
-	dest_dir = g_build_filename(dest_path, "public", NULL);
-	ret = cp_r (src_dir, dest_dir);
-	g_free (src_dir);
-	g_free (dest_dir);
-
-	dialog_close ();
-	return ret;
-}
-
-#endif
-
-void
-exchange_migrate (const CORBA_short major,
-		  const CORBA_short minor,
-		  const CORBA_short revision,
-		  const gchar *base_dir,
-		  gchar *account_filename)
-{
-	gboolean ret = TRUE;
-        struct stat st;
-	gchar *src_path = NULL;
-
-	maj = major; min = minor; rev = revision;
-
-	/* FIXME: version check */
-	if (maj == 1 && min <= 5) {
-#ifndef G_OS_WIN32
-		if (!base_dir)
-			return;
-
-		/* This is not needed if done by cp_r() */
-		if (stat (base_dir, &st) == -1) {
-			if (errno != ENOENT ||
-			    g_mkdir_with_parents (base_dir, 0777) == -1) {
-				printf ("Failed to create directory `%s': %s",
-				base_dir, g_strerror (errno));
-				return;
-			}
-		}
-
-		src_path = g_build_filename (g_get_home_dir (),
-					     "evolution",
-					     "exchange",
-					     account_filename,
-					     NULL);
-		ret = migrate_common (src_path, base_dir);
-		g_free (src_path);
-
-		src_path = g_build_filename (g_get_home_dir (),
-					     "evolution",
-					     "exchange",
-					     account_filename,
-					     "Addressbook",
-					     NULL);
-		ret = migrate_contacts ( src_path, base_dir);
-		g_free (src_path);
-
-		src_path = g_build_filename (g_get_home_dir (),
-					     "evolution",
-					     "mail",
-					     "exchange",
-					     account_filename,
-					     NULL);
-		ret = migrate_mail ( src_path, base_dir);
-		g_free (src_path);
-
-		if (ret == FALSE)
-			show_error_dialog ();
-
-#endif
-	}
-}
diff --git a/storage/exchange-migrate.h b/storage/exchange-migrate.h
deleted file mode 100644
index 406c455..0000000
--- a/storage/exchange-migrate.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* Copyright (C) 2004 Novell, Inc. */
-
-#ifndef __EXCHANGE_MIGRATE_H__
-#define __EXCHANGE_MIGRATE_H__
-
-#include "exchange-component.h"
-
-void exchange_migrate (const CORBA_short major, const CORBA_short minor, const CORBA_short revision, const gchar *base_diri, gchar *account_filename);
-
-#endif /* _EXCHANGE_MIGRATE_H_ */
diff --git a/storage/exchange-storage.c b/storage/exchange-storage.c
deleted file mode 100644
index 355e157..0000000
--- a/storage/exchange-storage.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2002-2004 Novell, Inc.
- *
- * 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.
- */
-
-/* ExchangeStorage: EStorage subclass that talks to an ExchangeAccount */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "exchange-storage.h"
-#include "exchange-account.h"
-#include "exchange-hierarchy.h"
-#include "e-folder-exchange.h"
-
-#include <e-util/e-dialog-utils.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-struct _ExchangeStoragePrivate {
-	ExchangeAccount *account;
-	guint idle_id;
-};
-
-#define PARENT_TYPE E_TYPE_STORAGE
-static EStorageClass *parent_class = NULL;
-
-static void finalize (GObject *);
-
-static void create_folder (EStorage *storage,
-			   const gchar *path,
-			   const gchar *type,
-			   EStorageResultCallback callback,
-			   gpointer user_data);
-static void remove_folder (EStorage *storage,
-			   const gchar *path,
-			   EStorageResultCallback callback,
-			   gpointer user_data);
-static void xfer_folder   (EStorage *storage,
-			   const gchar *source_path,
-			   const gchar *destination_path,
-			   const gboolean remove_source,
-			   EStorageResultCallback callback,
-			   gpointer user_data);
-static void open_folder   (EStorage *storage,
-			   const gchar *path,
-			   EStorageDiscoveryCallback callback,
-			   gpointer user_data);
-static gboolean will_accept_folder (EStorage *storage,
-				    EFolder *new_parent,
-				    EFolder *source);
-
-static void discover_shared_folder        (EStorage *storage,
-					   const gchar *owner,
-					   const gchar *folder_name,
-					   EStorageDiscoveryCallback callback,
-					   gpointer user_data);
-static void cancel_discover_shared_folder (EStorage *storage,
-					   const gchar *owner,
-					   const gchar *folder_name);
-static void remove_shared_folder          (EStorage *storage,
-					   const gchar *path,
-					   EStorageResultCallback callback,
-					   gpointer user_data);
-
-static void
-class_init (GObjectClass *object_class)
-{
-	EStorageClass *e_storage_class = E_STORAGE_CLASS (object_class);
-
-	parent_class = g_type_class_ref (PARENT_TYPE);
-
-	/* virtual method override */
-	object_class->finalize = finalize;
-
-	e_storage_class->async_create_folder = create_folder;
-	e_storage_class->async_remove_folder = remove_folder;
-	e_storage_class->async_xfer_folder = xfer_folder;
-	e_storage_class->async_open_folder = open_folder;
-	e_storage_class->will_accept_folder = will_accept_folder;
-	e_storage_class->async_discover_shared_folder = discover_shared_folder;
-	e_storage_class->cancel_discover_shared_folder = cancel_discover_shared_folder;
-	e_storage_class->async_remove_shared_folder = remove_shared_folder;
-}
-
-static void
-init (GObject *object)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (object);
-
-	exstorage->priv = g_new0 (ExchangeStoragePrivate, 1);
-}
-
-static void
-finalize (GObject *object)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (object);
-
-	if (exstorage->priv->idle_id)
-		g_source_remove (exstorage->priv->idle_id);
-
-	g_free (exstorage->priv);
-
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-E2K_MAKE_TYPE (exchange_storage, ExchangeStorage, class_init, init, PARENT_TYPE)
-
-static void
-account_new_folder (ExchangeAccount *account, EFolder *folder,
-		    EStorage *storage)
-{
-	const gchar *path = e_folder_exchange_get_path (folder);
-
-	e_storage_new_folder (storage, path, g_object_ref (folder));
-	if (e_folder_exchange_get_has_subfolders (folder)) {
-		e_storage_declare_has_subfolders (storage, path,
-						  _("Searching..."));
-	}
-}
-
-static void
-account_removed_folder (ExchangeAccount *account, EFolder *folder,
-			EStorage *storage)
-{
-	const gchar *path = e_folder_exchange_get_path (folder);
-
-	e_storage_removed_folder (storage, path);
-}
-
-static EStorageResult
-account_to_storage_result (ExchangeAccountFolderResult result)
-{
-	switch (result) {
-	case EXCHANGE_ACCOUNT_FOLDER_OK:
-		return E_STORAGE_OK;
-	case EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS:
-		return E_STORAGE_EXISTS;
-	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
-		return E_STORAGE_NOTFOUND;
-	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
-		return E_STORAGE_PERMISSIONDENIED;
-	case EXCHANGE_ACCOUNT_FOLDER_OFFLINE:
-		return E_STORAGE_NOTONLINE;
-	case EXCHANGE_ACCOUNT_FOLDER_UNSUPPORTED_OPERATION:
-		return E_STORAGE_UNSUPPORTEDOPERATION;
-	default:
-		return E_STORAGE_GENERICERROR;
-	}
-}
-
-static void
-create_folder (EStorage *storage,
-	       const gchar *path, const gchar *type,
-	       EStorageResultCallback callback,
-	       gpointer user_data)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (storage);
-	ExchangeAccount *account = exstorage->priv->account;
-	ExchangeAccountFolderResult result;
-
-	result = exchange_account_create_folder (account, path, type);
-	callback (storage, account_to_storage_result (result), user_data);
-}
-
-static void
-remove_folder (EStorage *storage, const gchar *path,
-	       EStorageResultCallback callback,
-	       gpointer user_data)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (storage);
-	ExchangeAccount *account = exstorage->priv->account;
-	ExchangeAccountFolderResult result;
-
-	result = exchange_account_remove_folder (account, path);
-	callback (storage, account_to_storage_result (result), user_data);
-}
-
-static void
-xfer_folder (EStorage *storage,
-	     const gchar *source_path, const gchar *dest_path,
-	     const gboolean remove_source,
-	     EStorageResultCallback callback,
-	     gpointer user_data)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (storage);
-	ExchangeAccount *account = exstorage->priv->account;
-	ExchangeAccountFolderResult result;
-
-	result = exchange_account_xfer_folder (account,
-					       source_path, dest_path,
-					       remove_source);
-	callback (storage, account_to_storage_result (result), user_data);
-}
-
-struct open_folder_data {
-	EStorage *storage;
-	gchar *path;
-	EStorageDiscoveryCallback callback;
-	gpointer user_data;
-};
-
-static gboolean
-idle_open_folder (gpointer user_data)
-{
-	struct open_folder_data *ofd = user_data;
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (ofd->storage);
-	ExchangeAccount *account = exstorage->priv->account;
-	ExchangeAccountFolderResult result;
-	ExchangeAccountResult acresult;
-	E2kContext *ctx;
-
-	if (!strcmp (ofd->path, "/")) {
-		ctx = exchange_account_connect (account, NULL, &acresult);
-		result = ctx ?
-			E_STORAGE_OK :
-			E_STORAGE_NOTONLINE;
-	} else
-		result = exchange_account_open_folder (account, ofd->path);
-	ofd->callback (ofd->storage, account_to_storage_result (result),
-		       ofd->path, ofd->user_data);
-
-	g_object_unref (ofd->storage);
-	g_free (ofd->path);
-	g_free (ofd);
-
-	return FALSE;
-}
-
-static void
-open_folder (EStorage *storage, const gchar *path,
-	     EStorageDiscoveryCallback callback, gpointer user_data)
-{
-	struct open_folder_data *ofd;
-
-	/* This needs to actually be done asynchronously, or ETree
-	 * will mess up and duplicate nodes in the tree.
-	 */
-
-	ofd = g_new0 (struct open_folder_data, 1);
-	ofd->storage = g_object_ref (storage);
-	ofd->path = g_strdup (path);
-	ofd->callback = callback;
-	ofd->user_data = user_data;
-
-	g_idle_add (idle_open_folder, ofd);
-}
-
-static gboolean
-will_accept_folder (EStorage *storage,
-		    EFolder *new_parent, EFolder *source)
-{
-	if (!E_IS_FOLDER_EXCHANGE (new_parent) ||
-	    !E_IS_FOLDER_EXCHANGE (source))
-		return FALSE;
-
-	if (e_folder_exchange_get_hierarchy (new_parent) !=
-	    e_folder_exchange_get_hierarchy (source))
-		return FALSE;
-
-	return E_STORAGE_CLASS (parent_class)->will_accept_folder (storage, new_parent, source);
-}
-
-static void
-discover_shared_folder (EStorage *storage,
-			const gchar *owner, const gchar *folder_name,
-			EStorageDiscoveryCallback callback,
-			gpointer user_data)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (storage);
-	ExchangeAccount *account = exstorage->priv->account;
-	ExchangeAccountFolderResult result;
-	EFolder *folder = NULL;
-
-	result = exchange_account_discover_shared_folder (account,
-							  owner, folder_name,
-							  &folder);
-	callback (storage, account_to_storage_result (result),
-		  folder ? e_folder_exchange_get_path (folder) : NULL,
-		  user_data);
-	if (folder)
-		g_object_unref (folder);
-}
-
-static void
-cancel_discover_shared_folder (EStorage *storage, const gchar *owner,
-			       const gchar *folder_name)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (storage);
-	ExchangeAccount *account = exstorage->priv->account;
-
-	exchange_account_cancel_discover_shared_folder (account,
-							owner, folder_name);
-}
-
-static void
-remove_shared_folder (EStorage *storage, const gchar *path,
-		      EStorageResultCallback callback, gpointer user_data)
-{
-	ExchangeStorage *exstorage = EXCHANGE_STORAGE (storage);
-	ExchangeAccount *account = exstorage->priv->account;
-	ExchangeAccountFolderResult result;
-
-	result = exchange_account_remove_shared_folder (account, path);
-	callback (storage, account_to_storage_result (result), user_data);
-}
-
-static gboolean
-idle_fill_storage (gpointer user_data)
-{
-	ExchangeStorage *exstorage = user_data;
-	EStorage *storage = user_data;
-	ExchangeAccount *account = exstorage->priv->account;
-	GPtrArray *folders;
-	gint i;
-
-	exstorage->priv->idle_id = 0;
-
-	if (!exchange_account_get_context (account)) {
-		e_storage_declare_has_subfolders (storage, "/",
-						  _("Connecting..."));
-	} else {
-		folders = exchange_account_get_folders (account);
-		if (folders) {
-			for (i = 0; i < folders->len; i++) {
-				account_new_folder (account, folders->pdata[i],
-						    storage);
-			}
-			g_ptr_array_free (folders, TRUE);
-		}
-	}
-
-	g_signal_connect (account, "new_folder",
-			  G_CALLBACK (account_new_folder), exstorage);
-	g_signal_connect (account, "removed_folder",
-			  G_CALLBACK (account_removed_folder), exstorage);
-
-	g_object_unref (storage);
-
-	return FALSE;
-}
-
-/**
- * exchange_storage_new:
- * @account: the account the storage will represent
- *
- * This creates a storage for @account.
- **/
-EStorage *
-exchange_storage_new (ExchangeAccount *account)
-{
-	ExchangeStorage *exstorage;
-	EStorage *storage;
-	EFolder *root_folder;
-
-	exstorage = g_object_new (EXCHANGE_TYPE_STORAGE, NULL);
-	storage = E_STORAGE (exstorage);
-
-	root_folder = e_folder_new (account->account_name, "noselect", "");
-	e_storage_construct (storage, account->account_name, root_folder);
-
-	exstorage->priv->account = account;
-
-	g_object_ref (exstorage);
-	exstorage->priv->idle_id = g_idle_add (idle_fill_storage, exstorage);
-
-	return storage;
-}
diff --git a/storage/exchange-storage.h b/storage/exchange-storage.h
deleted file mode 100644
index 77a9541..0000000
--- a/storage/exchange-storage.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* Copyright (C) 2001-2004 Novell, Inc. */
-
-#ifndef __EXCHANGE_STORAGE_H__
-#define __EXCHANGE_STORAGE_H__
-
-#include "exchange-types.h"
-#include "e-storage.h"
-
-G_BEGIN_DECLS
-
-#define EXCHANGE_TYPE_STORAGE            (exchange_storage_get_type ())
-#define EXCHANGE_STORAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_STORAGE, ExchangeStorage))
-#define EXCHANGE_STORAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_STORAGE, ExchangeStorageClass))
-#define EXCHANGE_IS_STORAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_STORAGE))
-#define EXCHANGE_IS_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_TYPE_STORAGE))
-
-struct _ExchangeStorage {
-	EStorage parent;
-
-	ExchangeStoragePrivate *priv;
-};
-
-struct _ExchangeStorageClass {
-	EStorageClass parent_class;
-
-};
-
-GType             exchange_storage_get_type (void);
-
-EStorage         *exchange_storage_new      (ExchangeAccount *account);
-
-#ifdef G_OS_WIN32
-
-extern const gchar *_exchange_storage_datadir;
-extern const gchar *_exchange_storage_gladedir;
-extern const gchar *_exchange_storage_imagesdir;
-
-#endif
-
-G_END_DECLS
-
-#endif /* __EXCHANGE_STORAGE_H__ */
diff --git a/storage/ximian-connector.xml b/storage/ximian-connector.xml
deleted file mode 100644
index f0718e3..0000000
--- a/storage/ximian-connector.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<Root>
-    <menu>
-	<submenu name="Actions">
-	    <placeholder name="ComponentActionsPlaceholder">
-		<menuitem name="ExchangePassword" verb=""
-			  _label="_Change Exchange Password..."
-			  _tip="Change your Exchange server password"/>
-
-		<separator f="" name="connector1"/>
-
-		<menuitem name="ExchangeSubscribeUser" verb=""
-			  _label="Subscribe to _Other User's Folder..."
-			  _tip="Subscribe to a folder belonging to some other user on the server"/>
-		<menuitem name="ExchangeUnsubscribeUser" verb=""
-			  _label="_Unsubscribe from Other User's Folder"
-			  _tip="Unsubscribe from a folder added with &quot;Subscribe to Other User's Folder&quot;"/>
-		<menuitem name="ExchangeFolderSize" verb=""
-			  _label="Folder _Size"
-			  _tip="Get the size of personal folders"/>
-	    </placeholder>
-	</submenu>
-	<submenu name="Tools">
-	    <placeholder name="ComponentPlaceholder">
-		<menuitem name="ExchangeOOF" verb=""
-			  _label="_Out of Office Assistant"
-			  _tip="View or change your Out-of-Office status and autoreply message"/>
-		<menuitem name="ExchangeDelegation" verb=""
-			  _label="_Delegation Assistant"
-			  _tip="View or change your Exchange calendar delegation settings"/>
-		<separator f="" name="connector3"/>
-	    </placeholder>
-	</submenu>
-    </menu>
-</Root>
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..6118cf2
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,78 @@
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/camel \
+	-DG_LOG_DOMAIN=\"evolution-exchange-storage\" \
+	$(LIBEXCHANGE_CFLAGS) \
+	$(EXCHANGE_STORAGE_CFLAGS) \
+	$(LDAP_CFLAGS) \
+	-DPREFIX=\"$(prefix)\" \
+	-DSYSCONFDIR=\""$(sysconfdir)"\" \
+	-DDATADIR=\""$(datadir)"\" \
+	-DLIBDIR=\""$(datadir)"\" \
+	-DCONNECTOR_IMAGESDIR=\""$(imagesdir)"\" \
+	-DCONNECTOR_UIDIR=\""$(uidir)"\" \
+	-DCONNECTOR_LOCALEDIR=\""$(localedir)\""
+
+noinst_PROGRAMS = \
+	exchange-connector-setup
+#	migr-test
+
+noinst_LTLIBRARIES = libevolution-exchange-shared.la
+
+libevolution_exchange_shared_la_SOURCES = 	\
+	exchange-share-config-listener.h	\
+	exchange-share-config-listener.c
+
+libevolution_exchange_shared_la_LIBADD = 	\
+	$(EXCHANGE_STORAGE_LIBS)		\
+	$(LIBEXCHANGE_LIBS)
+
+libevolution_exchange_shared_la_LDFLAGS = $(NO_UNDEFINED)
+
+exchange_connector_setup_SOURCES =	\
+	ximian-connector-setup.c	\
+	exchange-autoconfig-wizard.h	\
+	exchange-autoconfig-wizard.c
+
+exchange_connector_setup_LDADD = \
+	$(LDAP_LIBS) \
+	$(EXCHANGE_STORAGE_LIBS) \
+	$(LIBEXCHANGE_LIBS)
+
+install-exec-local: exchange-connector-setup
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) exchange-connector-setup $(DESTDIR)$(bindir)/exchange-connector-setup-$(BASE_VERSION)
+
+uninstall-local:
+	rm -rf $(DESTDIR)$(bindir)/exchange-connector-setup-$(BASE_VERSION)
+
+#migr_test_SOURCES = \
+#	migr-test.c \
+#	exchange-config-listener.c \
+#	exchange-config-listener.h \
+#	exchange-migrate.c \
+#	exchange-migrate.h
+#
+#migr_test_LDADD = \
+#	$(LDAP_LIBS) \
+#	$(EXCHANGE_STORAGE_LIBS) \
+#	$(LIBEXCHANGE_LIBS)
+#
+
+imagesdir = $(CONNECTOR_DATADIR)/images
+images_DATA = \
+	connector.png \
+	connector-mini.png \
+	exchange-delegates-48.png \
+	exchange-oof-48.png
+
+uidir   = $(CONNECTOR_DATADIR)/ui
+ui_DATA = ximian-connector.xml
+
+#DISTCLEANFILES =
+
+EXTRA_DIST = \
+	$(images_DATA) \
+	$(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/tools/exchange-autoconfig-wizard.c b/tools/exchange-autoconfig-wizard.c
new file mode 100644
index 0000000..4929d8c
--- /dev/null
+++ b/tools/exchange-autoconfig-wizard.c
@@ -0,0 +1,759 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2003, 2004 Novell, Inc.
+ *
+ * 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.
+ */
+
+/* exchange-autoconfig-wizard: Automatic account configuration wizard */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "e2k-autoconfig.h"
+#include <e2k-utils.h>
+#include "exchange-autoconfig-wizard.h"
+
+#include <libedataserver/e-account.h>
+#include <libedataserver/e-account-list.h>
+#include <e-util/e-dialog-utils.h>
+#include <libedataserverui/e-passwords.h>
+
+#include <gconf/gconf-client.h>
+#include <gtk/gtk.h>
+
+#ifdef G_OS_WIN32
+
+#undef CONNECTOR_IMAGESDIR
+#define CONNECTOR_IMAGESDIR _exchange_storage_imagesdir
+
+#endif
+
+typedef struct {
+	GtkWidget *assistant;
+	gint active_page;
+	gboolean changing;
+
+	E2kAutoconfig *ac;
+	E2kOperation op;
+
+	/* OWA Page */
+	GtkEntry *owa_uri_entry;
+	GtkEntry *username_entry;
+	GtkEntry *password_entry;
+	GtkToggleButton *remember_password_check;
+
+	/* Global Catalog Page */
+	GtkEntry *gc_server_entry;
+
+	/* Failure Page */
+	GtkBox *failure_vbox;
+	GtkLabel *failure_label;
+	GtkWidget *failure_href;
+
+	/* Verify Page */
+	GtkEntry *name_entry;
+	GtkEntry *email_entry;
+	GtkToggleButton *default_account_check;
+} ExchangeAutoconfigGUI;
+
+enum {
+	EXCHANGE_AUTOCONFIG_PAGE_START,
+	EXCHANGE_AUTOCONFIG_PAGE_OWA,
+	EXCHANGE_AUTOCONFIG_PAGE_GC,
+	EXCHANGE_AUTOCONFIG_PAGE_FAILURE,
+	EXCHANGE_AUTOCONFIG_PAGE_VERIFY,
+	EXCHANGE_AUTOCONFIG_PAGE_FINISH
+};
+
+static void assistant_page_content_changed (GtkWidget *sender, ExchangeAutoconfigGUI *gui);
+
+static inline gboolean
+check_field (GtkEntry *entry)
+{
+	return (*gtk_entry_get_text (entry) != '\0');
+}
+
+static void
+fill_failure_page (ExchangeAutoconfigGUI *gui, const gchar *url, const gchar *fmt, ...)
+{
+	va_list ap;
+	gchar *text;
+
+	va_start (ap, fmt);
+	text = g_strdup_vprintf (fmt, ap);
+	va_end (ap);
+
+	gtk_label_set_text (gui->failure_label, text);
+
+	g_free (text);
+
+	if (gui->failure_href)
+		gtk_widget_destroy (gui->failure_href);
+
+	if (url) {
+		gui->failure_href = gtk_link_button_new (url);
+		gtk_box_pack_start (gui->failure_vbox, gui->failure_href, FALSE, FALSE, 0);
+		gtk_widget_show (gui->failure_href);
+	} else {
+		gui->failure_href = NULL;
+	}
+}
+
+#define CONNECT_CHANGE_SIGNAL(_where,_signal_name) g_signal_connect (_where, _signal_name, G_CALLBACK (assistant_page_content_changed), gui)
+
+static GtkWidget *
+create_page_vbox (GtkAssistant *assistant, GdkPixbuf *logo, const gchar *page_title, const gchar *page_info, GtkAssistantPageType page_type, GtkWidget **page, gint *page_index)
+{
+	GtkWidget *vbox;
+	gboolean is_edge = page_type == GTK_ASSISTANT_PAGE_INTRO || page_type == GTK_ASSISTANT_PAGE_CONFIRM;
+
+	g_return_val_if_fail (assistant != NULL, NULL);
+	g_return_val_if_fail (page != NULL, NULL);
+	g_return_val_if_fail (page_index != NULL, NULL);
+
+	vbox = gtk_vbox_new (FALSE, 0);
+
+	gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+
+	*page = vbox;
+	*page_index = gtk_assistant_append_page (assistant, vbox);
+
+	gtk_assistant_set_page_type (assistant, vbox, page_type);
+	gtk_assistant_set_page_title (assistant, vbox, page_title);
+	gtk_assistant_set_page_complete (assistant, vbox, is_edge);
+	gtk_assistant_set_page_header_image (assistant, vbox, logo);
+
+	if (page_info) {
+		GtkWidget *label;
+
+		label = gtk_label_new (page_info);
+		gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+		gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+		gtk_box_pack_start (GTK_BOX (vbox), label, is_edge, is_edge, 0);
+	}
+
+	return vbox;
+}
+
+static GtkWidget *
+add_table_row (GtkTable *table, gint row, const gchar *label_text, GtkWidget *action_widget)
+{
+	GtkWidget *w;
+
+	w = gtk_label_new_with_mnemonic (label_text);
+	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (w), action_widget);
+	gtk_table_attach (table, w, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
+
+	w = action_widget;
+	gtk_table_attach (table, w, 1, 2, row, row + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+
+	return w;
+}
+
+static void
+start_page_create (ExchangeAutoconfigGUI *gui, GdkPixbuf *logo, GtkWidget **page, gint *page_index)
+{
+	GtkWidget *vbox;
+
+	vbox = create_page_vbox (GTK_ASSISTANT (gui->assistant), logo, _("Welcome"), _("Welcome to Evolution Connector for Microsoft Exchange.\nThe next few screens will help you configure Evolution\nto connect to your Exchange account.\n\nPlease click the \"Forward\" button to continue."), GTK_ASSISTANT_PAGE_INTRO, page, page_index);
+	g_return_if_fail (vbox != NULL);
+
+	gtk_widget_show_all (vbox);
+}
+
+static void
+owa_page_create (ExchangeAutoconfigGUI *gui, GdkPixbuf *logo, GtkWidget **page, gint *page_index)
+{
+	GtkWidget *vbox, *w;
+	GtkTable *table;
+
+	vbox = create_page_vbox (GTK_ASSISTANT (gui->assistant), logo, _("Exchange Configuration"), _("Evolution Connector for Microsoft Exchange can use account information from your existing Outlook Web Access (OWA) account.\n\nEnter your OWA site address (URL), username, and password, then click \"Forward\".\n"), GTK_ASSISTANT_PAGE_CONTENT, page, page_index);
+	g_return_if_fail (vbox != NULL);
+
+	table = GTK_TABLE (gtk_table_new (4, 2, FALSE));
+	gtk_container_set_border_width (GTK_CONTAINER (table), 6);
+	gtk_table_set_row_spacings (table, 6);
+	gtk_table_set_col_spacings (table, 6);
+
+	w = add_table_row (table, 0, _("OWA _URL:"), gtk_entry_new ());
+	CONNECT_CHANGE_SIGNAL (w, "changed");
+	gui->owa_uri_entry = GTK_ENTRY (w);
+
+	w = add_table_row (table, 1, _("User_name:"), gtk_entry_new ());
+	CONNECT_CHANGE_SIGNAL (w, "changed");
+	gui->username_entry = GTK_ENTRY (w);
+
+	w = add_table_row (table, 2, _("_Password:"), gtk_entry_new ());
+	CONNECT_CHANGE_SIGNAL (w, "changed");
+	gui->password_entry = GTK_ENTRY (w);
+	gtk_entry_set_visibility (gui->password_entry, FALSE);
+
+	w = gtk_check_button_new_with_mnemonic (_("_Remember this password"));
+	CONNECT_CHANGE_SIGNAL (w, "toggled");
+	gtk_table_attach (table, w, 0, 2, 3, 4, GTK_FILL, 0, 0, 0);
+
+	gui->remember_password_check = GTK_TOGGLE_BUTTON (w);
+
+	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), TRUE, TRUE, 0);
+
+	gtk_widget_show_all (vbox);
+}
+
+static void
+owa_page_prepare (ExchangeAutoconfigGUI *gui)
+{
+	if (gui->ac->username)
+		gtk_entry_set_text (gui->username_entry, gui->ac->username);
+
+	if (gui->ac->owa_uri)
+		gtk_entry_set_text (gui->owa_uri_entry, gui->ac->owa_uri);
+}
+
+static gboolean
+owa_page_check (ExchangeAutoconfigGUI *gui)
+{
+	return (check_field (gui->owa_uri_entry) &&
+		check_field (gui->username_entry) &&
+		check_field (gui->password_entry));
+}
+
+static gint
+owa_page_get_next (ExchangeAutoconfigGUI *gui)
+{
+	E2kAutoconfigResult result;
+	const gchar *old, *new;
+	gint next_page = EXCHANGE_AUTOCONFIG_PAGE_FAILURE;
+
+	e2k_autoconfig_set_owa_uri (gui->ac, gtk_entry_get_text (gui->owa_uri_entry));
+	e2k_autoconfig_set_username (gui->ac, gtk_entry_get_text (gui->username_entry));
+	e2k_autoconfig_set_password (gui->ac, gtk_entry_get_text (gui->password_entry));
+
+	gtk_widget_set_sensitive (GTK_WIDGET (gui->assistant), FALSE);
+	e2k_operation_init (&gui->op);
+	result = e2k_autoconfig_check_exchange (gui->ac, &gui->op);
+
+	if (result == E2K_AUTOCONFIG_OK) {
+		result = e2k_autoconfig_check_global_catalog (gui->ac, &gui->op);
+		e2k_operation_free (&gui->op);
+		gtk_widget_set_sensitive (GTK_WIDGET (gui->assistant), TRUE);
+
+		if (result == E2K_AUTOCONFIG_OK)
+			next_page = EXCHANGE_AUTOCONFIG_PAGE_VERIFY;
+		else
+			next_page = EXCHANGE_AUTOCONFIG_PAGE_GC;
+
+		return next_page;
+	}
+
+	/* Update the entries with anything we autodetected */
+	owa_page_prepare (gui);
+	e2k_operation_free (&gui->op);
+	gtk_widget_set_sensitive (GTK_WIDGET (gui->assistant), TRUE);
+
+	switch (result) {
+	case E2K_AUTOCONFIG_CANT_CONNECT:
+		if (!strncmp (gui->ac->owa_uri, "http:", 5)) {
+			old = "http";
+			new = "https";
+		} else {
+			old = "https";
+			new = "http";
+		}
+
+		fill_failure_page (gui, NULL,
+			  _("Could not connect to the Exchange "
+			    "server.\nMake sure the URL is correct "
+			    "(try \"%s\" instead of \"%s\"?) "
+			    "and try again."), new, old);
+		break;
+
+	case E2K_AUTOCONFIG_CANT_RESOLVE:
+		fill_failure_page (gui, NULL,
+			  _("Could not locate Exchange server.\n"
+			    "Make sure the server name is spelled correctly "
+			    "and try again."));
+		break;
+
+	case E2K_AUTOCONFIG_AUTH_ERROR:
+	case E2K_AUTOCONFIG_AUTH_ERROR_TRY_NTLM:
+	case E2K_AUTOCONFIG_AUTH_ERROR_TRY_BASIC:
+		fill_failure_page (gui, NULL,
+			  _("Could not authenticate to the Exchange "
+			    "server.\nMake sure the username and "
+			    "password are correct and try again."));
+		break;
+
+	case E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN:
+		fill_failure_page (gui, NULL,
+			  _("Could not authenticate to the Exchange "
+			    "server.\nMake sure the username and "
+			    "password are correct and try again.\n\n"
+			    "You may need to specify the Windows "
+			    "domain name as part of your username "
+			    "(eg, \"MY-DOMAIN\\%s\")."),
+			  gui->ac->username);
+		break;
+
+	case E2K_AUTOCONFIG_NO_OWA:
+	case E2K_AUTOCONFIG_NOT_EXCHANGE:
+		fill_failure_page (gui, NULL,
+			  _("Could not find OWA data at the indicated URL.\n"
+			    "Make sure the URL is correct and try again."));
+		break;
+
+	case E2K_AUTOCONFIG_CANT_BPROPFIND:
+		fill_failure_page (gui, "http://support.novell.com/cgi-bin/search/searchtid.cgi?/ximian/ximian328.html",
+			_("Evolution Connector for Microsoft Exchange requires "
+			  "access to certain functionality on the Exchange "
+			  "server that appears to be disabled or blocked.  "
+			  "(This is usually unintentional.)  Your Exchange "
+			  "administrator will need to enable this "
+			  "functionality in order for you to be able to use "
+			  "the Evolution Connector.\n\n"
+			  "For information to provide to your Exchange "
+			  "administrator, please follow the link below:"));
+		break;
+
+	case E2K_AUTOCONFIG_EXCHANGE_5_5:
+		fill_failure_page (gui, NULL,
+			_("The Exchange server URL you provided is for an "
+			  "Exchange 5.5 server. Evolution Connector for "
+			  "Microsoft Exchange supports Microsoft Exchange 2000 "
+			  "and 2003 only."));
+		break;
+
+	default:
+		fill_failure_page (gui, NULL,
+			  _("Could not configure Exchange account because "
+			    "an unknown error occurred. Check the URL, "
+			    "username, and password, and try again."));
+		break;
+	}
+
+	/* can move forward only when not requested to stay on the actual page */
+	return next_page;
+}
+
+static void
+gc_page_create (ExchangeAutoconfigGUI *gui, GdkPixbuf *logo, GtkWidget **page, gint *page_index)
+{
+	GtkWidget *vbox, *w;
+	GtkTable *table;
+
+	vbox = create_page_vbox (GTK_ASSISTANT (gui->assistant), logo, _("Exchange Configuration"), _("Evolution Connector for Microsoft Exchange could not find the Global Catalog replica for your site. Please enter the name of your Global Catalog server. You may need to ask your system administrator for the correct value."), GTK_ASSISTANT_PAGE_CONTENT, page, page_index);
+	g_return_if_fail (vbox != NULL);
+
+	table = GTK_TABLE (gtk_table_new (1, 2, FALSE));
+	gtk_container_set_border_width (GTK_CONTAINER (table), 6);
+	gtk_table_set_row_spacings (table, 6);
+	gtk_table_set_col_spacings (table, 6);
+
+	w = add_table_row (table, 0, _("GC _Server:"), gtk_entry_new ());
+	CONNECT_CHANGE_SIGNAL (w, "changed");
+	gui->gc_server_entry = GTK_ENTRY (w);
+
+	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), TRUE, TRUE, 0);
+
+	gtk_widget_show_all (vbox);
+}
+
+static gboolean
+gc_page_check (ExchangeAutoconfigGUI *gui)
+{
+	return check_field (gui->gc_server_entry);
+}
+
+static gint
+gc_page_get_next (ExchangeAutoconfigGUI *gui)
+{
+	E2kAutoconfigResult result;
+	gint next_page = EXCHANGE_AUTOCONFIG_PAGE_FAILURE;
+
+	e2k_autoconfig_set_gc_server (gui->ac, gtk_entry_get_text (gui->gc_server_entry), -1, E2K_AUTOCONFIG_USE_GAL_DEFAULT);
+
+	gtk_widget_set_sensitive (GTK_WIDGET (gui->assistant), FALSE);
+	e2k_operation_init (&gui->op);
+	result = e2k_autoconfig_check_global_catalog (gui->ac, &gui->op);
+	e2k_operation_free (&gui->op);
+	gtk_widget_set_sensitive (GTK_WIDGET (gui->assistant), TRUE);
+
+	if (result == E2K_AUTOCONFIG_OK) {
+		next_page = EXCHANGE_AUTOCONFIG_PAGE_VERIFY;
+	} else if (result == E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN) {
+		fill_failure_page (gui, NULL,
+			  _("Could not authenticate to the Global Catalog "
+			    "server. You may need to go back and specify "
+			    "the Windows domain name as part of your "
+			    "username (eg, \"MY-DOMAIN\\%s\")."),
+			  gui->ac->username);
+	} else {
+		fill_failure_page (gui, NULL,
+			  _("Could not connect to specified server.\n"
+			    "Please check the server name and try again."));
+	}
+
+	return next_page;
+}
+
+static void
+failure_page_create (ExchangeAutoconfigGUI *gui, GdkPixbuf *logo, GtkWidget **page, gint *page_index)
+{
+	GtkWidget *vbox, *w;
+
+	vbox = create_page_vbox (GTK_ASSISTANT (gui->assistant), logo, _("Configuration Failed"), _("Evolution Connector for Microsoft Exchange has encountered a problem configuring your Exchange account."), GTK_ASSISTANT_PAGE_CONTENT, page, page_index);
+	g_return_if_fail (vbox != NULL);
+
+	w = gtk_label_new (NULL);
+	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
+	gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
+
+	gui->failure_vbox = GTK_BOX (vbox);
+	gui->failure_label = GTK_LABEL (w);
+
+	gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
+
+	gtk_widget_show_all (vbox);
+}
+
+static gboolean
+failure_page_check (ExchangeAutoconfigGUI *gui)
+{
+	return FALSE;
+}
+
+static void
+verify_page_create (ExchangeAutoconfigGUI *gui, GdkPixbuf *logo, GtkWidget **page, gint *page_index)
+{
+	GtkWidget *vbox, *w;
+	GtkTable *table;
+
+	vbox = create_page_vbox (GTK_ASSISTANT (gui->assistant), logo, _("Exchange Configuration"), _("Your account information is as follows. Please correct any errors, then click \"Forward\"."), GTK_ASSISTANT_PAGE_CONTENT, page, page_index);
+	g_return_if_fail (vbox != NULL);
+
+	table = GTK_TABLE (gtk_table_new (3, 2, FALSE));
+	gtk_container_set_border_width (GTK_CONTAINER (table), 6);
+	gtk_table_set_row_spacings (table, 6);
+	gtk_table_set_col_spacings (table, 6);
+
+	w = add_table_row (table, 0, _("Full _Name:"), gtk_entry_new ());
+	CONNECT_CHANGE_SIGNAL (w, "changed");
+	gui->name_entry = GTK_ENTRY (w);
+
+	w = add_table_row (table, 1, _("_Email Address:"), gtk_entry_new ());
+	CONNECT_CHANGE_SIGNAL (w, "changed");
+	gui->email_entry = GTK_ENTRY (w);
+
+	w = gtk_check_button_new_with_label (_("Make this my _default account"));
+	CONNECT_CHANGE_SIGNAL (w, "toggled");
+	gtk_table_attach (table, w, 0, 2, 2, 3, GTK_FILL, 0, 0, 10);
+
+	gui->default_account_check = GTK_TOGGLE_BUTTON (w);
+
+	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), TRUE, TRUE, 0);
+
+	gtk_widget_show_all (vbox);
+}
+
+static void
+verify_page_prepare (ExchangeAutoconfigGUI *gui)
+{
+	if (gui->ac->display_name)
+		gtk_entry_set_text (gui->name_entry, gui->ac->display_name);
+	else
+		gtk_entry_set_text (gui->name_entry, _("Unknown"));
+	if (gui->ac->email)
+		gtk_entry_set_text (gui->email_entry, gui->ac->email);
+	else
+		gtk_entry_set_text (gui->email_entry, _("Unknown"));
+}
+
+static gboolean
+verify_page_check (ExchangeAutoconfigGUI *gui)
+{
+	const gchar *email;
+
+	g_free (gui->ac->display_name);
+	gui->ac->display_name = g_strdup (gtk_entry_get_text (gui->name_entry));
+	g_free (gui->ac->email);
+	gui->ac->email = g_strdup (gtk_entry_get_text (gui->email_entry));
+
+	email = gtk_entry_get_text (gui->email_entry);
+
+	return (check_field (gui->name_entry) && strchr (email, '@'));
+}
+
+static void
+finish_page_create (ExchangeAutoconfigGUI *gui, GdkPixbuf *logo, GtkWidget **page, gint *page_index)
+{
+	GtkWidget *vbox;
+
+	vbox = create_page_vbox (GTK_ASSISTANT (gui->assistant), logo, _("Done"), _("Your Connector account is now ready to use. Click the \"Apply\" button to save your settings."), GTK_ASSISTANT_PAGE_CONFIRM, page, page_index);
+	g_return_if_fail (vbox != NULL);
+
+	gtk_widget_show_all (vbox);
+}
+
+#undef CONNECT_CHANGE_SIGNAL
+
+static gboolean
+is_active_exchange_account (EAccount *account)
+{
+	if (!account->enabled)
+		return FALSE;
+	if (!account->source || !account->source->url)
+		return FALSE;
+	return (strncmp (account->source->url, "exchange://", 11) == 0);
+}
+
+static void
+autoconfig_gui_apply (ExchangeAutoconfigGUI *gui)
+{
+	EAccountList *list;
+	EAccount *account;
+	EIterator *iter;
+	GConfClient *gconf;
+	gchar *pw_key;
+	gboolean found = FALSE;
+
+	/* Create the account. */
+	gconf = gconf_client_get_default ();
+	list = e_account_list_new (gconf);
+	g_object_unref (gconf);
+	if (!list) {
+		e_notice (gui->assistant, GTK_MESSAGE_ERROR,
+			  _("Configuration system error.\n"
+			    "Unable to create new account."));
+		return;
+	}
+
+	/* Check if any account is already configured, and throw an error if so */
+	/* NOTE: This condition check needs to be removed when we start
+	   supporting multiple accounts */
+	for (iter = e_list_get_iterator ((EList *)list);
+	     e_iterator_is_valid (iter);
+	     e_iterator_next (iter)) {
+		account = (EAccount *)e_iterator_get (iter);
+		if (account && (found = is_active_exchange_account (account))) {
+			e_notice (gui->assistant, GTK_MESSAGE_ERROR,
+			_("You may only configure a single Exchange account"));
+			break;
+		}
+		account = NULL;
+	}
+	g_object_unref(iter);
+	if (found)
+		return;
+
+	account = e_account_new ();
+
+	account->name = g_strdup (gui->ac->email);
+	account->enabled = TRUE;
+	account->pgp_no_imip_sign = TRUE;
+
+	account->id->name = g_strdup (gui->ac->display_name);
+	account->id->address = g_strdup (gui->ac->email);
+
+	account->source->url = g_strdup (gui->ac->account_uri);
+	account->transport->url = g_strdup (gui->ac->account_uri);
+
+	/* Remember the password at least for this session */
+	pw_key = g_strdup_printf ("exchange://%s@%s",
+				  gui->ac->username,
+				  gui->ac->exchange_server);
+	e_passwords_add_password (pw_key, gui->ac->password);
+
+	/* Maybe longer */
+	if (gtk_toggle_button_get_active (gui->remember_password_check)) {
+		account->source->save_passwd = TRUE;
+		e_passwords_remember_password ("Exchange", pw_key);
+	}
+	g_free (pw_key);
+
+	e_account_list_add (list, account);
+	if (gtk_toggle_button_get_active (gui->default_account_check))
+		e_account_list_set_default (list, account);
+	g_object_unref (account);
+	e_account_list_save (list);
+	g_object_unref (list);
+}
+
+static void
+autoconfig_gui_free (ExchangeAutoconfigGUI *gui)
+{
+	e2k_autoconfig_free (gui->ac);
+	g_free (gui);
+}
+
+static struct {
+	GtkWidget *assistant_page;
+	gint assistant_page_index;
+	void (*create_func) (ExchangeAutoconfigGUI *gui, GdkPixbuf *logo, GtkWidget **page, gint *page_index);
+	void (*prepare_func) (ExchangeAutoconfigGUI *gui);
+	gboolean (*check_func) (ExchangeAutoconfigGUI *gui);
+	gint (*get_next_page_func) (ExchangeAutoconfigGUI *gui);
+} autoconfig_pages[] = {
+	{ NULL, -1, start_page_create, NULL, NULL, NULL },
+	{ NULL, -1, owa_page_create,     owa_page_prepare,    owa_page_check,     owa_page_get_next },
+	{ NULL, -1, gc_page_create,      NULL,                gc_page_check,      gc_page_get_next  },
+	{ NULL, -1, failure_page_create, NULL,                failure_page_check, NULL              },
+	{ NULL, -1, verify_page_create,  verify_page_prepare, verify_page_check,  NULL              },
+	{ NULL, -1, finish_page_create, NULL, NULL, NULL }
+};
+
+static const gint num_autoconfig_pages = sizeof (autoconfig_pages) / sizeof (autoconfig_pages[0]);
+
+/* Autoconfig assistant */
+
+static gint
+find_page (ExchangeAutoconfigGUI *gui, GtkWidget *page)
+{
+	gint page_num;
+
+	for (page_num = 0; page_num < num_autoconfig_pages; page_num++) {
+		if (autoconfig_pages[page_num].assistant_page == page)
+			return page_num;
+	}
+
+	return -1;
+}
+
+static void
+assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page, ExchangeAutoconfigGUI *gui)
+{
+	gint page_num = find_page (gui, page);
+
+	if (page_num == -1)
+		return;
+
+	gui->changing = TRUE;
+
+	if (autoconfig_pages[page_num].prepare_func)
+		autoconfig_pages[page_num].prepare_func (gui);
+
+	gtk_assistant_set_page_complete (
+		GTK_ASSISTANT (gui->assistant),
+		autoconfig_pages[page_num].assistant_page,
+		autoconfig_pages[page_num].check_func == NULL || autoconfig_pages[page_num].check_func (gui));
+
+	gui->changing = FALSE;
+	gui->active_page = page_num;
+}
+
+static void
+assistant_page_content_changed (GtkWidget *sender, ExchangeAutoconfigGUI *gui)
+{
+	gint page_num = gtk_assistant_get_current_page (GTK_ASSISTANT (gui->assistant));
+
+	if (page_num == -1)
+		return;
+
+	g_return_if_fail (page_num >= 0 && page_num < num_autoconfig_pages);
+
+	gui->changing = TRUE;
+
+	gtk_assistant_set_page_complete (
+		GTK_ASSISTANT (gui->assistant),
+		autoconfig_pages[page_num].assistant_page,
+		autoconfig_pages[page_num].check_func == NULL || autoconfig_pages[page_num].check_func (gui));
+
+	gui->changing = FALSE;
+}
+
+static void
+assistant_apply_cb (GtkAssistant *assistant, ExchangeAutoconfigGUI *gui)
+{
+	autoconfig_gui_apply (gui);
+}
+
+static void
+assistant_cancel_cb (GtkAssistant *assistant, ExchangeAutoconfigGUI *gui)
+{
+	gtk_widget_destroy (GTK_WIDGET (gui->assistant));
+}
+
+static void
+assistant_destroyed (gpointer gui, GObject *where_druid_was)
+{
+	gtk_main_quit ();
+}
+
+static gint
+assistant_forward_func (gint current_page, gpointer user_data)
+{
+	ExchangeAutoconfigGUI *gui = user_data;
+	gint next_page = current_page + 1;
+
+	if (!gui->changing && gui->active_page == current_page) {
+		gint page_num;
+
+		for (page_num = 0; page_num < num_autoconfig_pages; page_num++) {
+			if (autoconfig_pages[page_num].assistant_page_index == current_page) {
+				if (autoconfig_pages[page_num].get_next_page_func)
+					next_page = autoconfig_pages[page_num].get_next_page_func (gui);
+				break;
+			}
+		}
+	}
+
+	return next_page;
+}
+
+void
+exchange_autoconfig_assistant_run (void)
+{
+	ExchangeAutoconfigGUI *gui;
+	GdkPixbuf *icon;
+	gchar *pngfile;
+	gint i;
+
+	gui = g_new0 (ExchangeAutoconfigGUI, 1);
+	gui->ac = e2k_autoconfig_new (NULL, NULL, NULL, E2K_AUTOCONFIG_USE_EITHER);
+	gui->assistant = gtk_assistant_new ();
+	gui->active_page = EXCHANGE_AUTOCONFIG_PAGE_START;
+	gui->changing = FALSE;
+
+	gtk_window_set_title (GTK_WINDOW (gui->assistant), _("Evolution Connector for Microsoft Exchange Configuration"));
+
+	gtk_assistant_set_forward_page_func (GTK_ASSISTANT (gui->assistant), assistant_forward_func, gui, NULL);
+
+	g_signal_connect (gui->assistant, "cancel", G_CALLBACK (assistant_cancel_cb), gui);
+	g_signal_connect (gui->assistant, "close", G_CALLBACK (assistant_cancel_cb), gui);
+	g_signal_connect (gui->assistant, "apply", G_CALLBACK (assistant_apply_cb), gui);
+	g_signal_connect (gui->assistant, "prepare", G_CALLBACK (assistant_prepare_cb), gui);
+
+	pngfile = g_build_filename (CONNECTOR_IMAGESDIR,
+				    "connector.png",
+				    NULL);
+	icon = gdk_pixbuf_new_from_file (pngfile, NULL);
+	g_free (pngfile);
+
+	for (i = 0; i < num_autoconfig_pages; i++) {
+		autoconfig_pages[i].create_func (gui, icon, &autoconfig_pages[i].assistant_page, &autoconfig_pages[i].assistant_page_index);
+	}
+
+	g_object_unref (icon);
+
+	g_object_weak_ref (G_OBJECT (gui->assistant), assistant_destroyed, gui);
+
+	gtk_widget_show_all (GTK_WIDGET (gui->assistant));
+	gtk_main ();
+	autoconfig_gui_free (gui);
+}
diff --git a/tools/exchange-autoconfig-wizard.h b/tools/exchange-autoconfig-wizard.h
new file mode 100644
index 0000000..59295f1
--- /dev/null
+++ b/tools/exchange-autoconfig-wizard.h
@@ -0,0 +1,19 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* Copyright (C) 2002-2004 Novell, Inc. */
+
+#ifndef __EXCHANGE_AUTOCONFIG_WIZARD_H__
+#define __EXCHANGE_AUTOCONFIG_WIZARD_H__
+
+#include <exchange-types.h>
+
+#include <bonobo/bonobo-object.h>
+
+G_BEGIN_DECLS
+
+BonoboObject *exchange_autoconfig_wizard_new (void);
+
+void          exchange_autoconfig_assistant_run  (void);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_AUTOCONFIG_WIZARD_H__ */
diff --git a/tools/exchange-share-config-listener.c b/tools/exchange-share-config-listener.c
new file mode 100644
index 0000000..499841d
--- /dev/null
+++ b/tools/exchange-share-config-listener.c
@@ -0,0 +1,783 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2001-2004 Novell, Inc.
+ *
+ * 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.
+ */
+
+/* ExchangeShareConfigListener: a class that listens to the config database
+ * and handles creating the ExchangeAccount object and making sure that
+ * default folders are updated as needed.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-source-group.h>
+#include <libedataserver/e-xml-utils.h>
+#include <libedataserver/e-xml-hash-utils.h>
+
+#include <camel/camel-url.h>
+
+#include <e2k-marshal.h>
+#include <e2k-uri.h>
+#include <exchange-account.h>
+#include <e-folder-exchange.h>
+
+#include <e-util/e-dialog-utils.h>
+
+#include "exchange-share-config-listener.h"
+
+struct _ExchangeShareConfigListenerPrivate {
+	GConfClient *gconf;
+
+	gchar *configured_uri, *configured_name;
+	EAccount *configured_account;
+
+	ExchangeAccount *exchange_account;
+};
+
+typedef struct {
+	const gchar *name;
+	const gchar *uri;
+	gint type;
+}FolderInfo;
+
+enum {
+	EXCHANGE_ACCOUNT_CREATED,
+	EXCHANGE_ACCOUNT_REMOVED,
+	LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+#define PARENT_TYPE E_TYPE_ACCOUNT_LIST
+
+#define CONF_KEY_SELECTED_CAL_SOURCES "/apps/evolution/calendar/display/selected_calendars"
+#define CONF_KEY_SELECTED_TASKS_SOURCES "/apps/evolution/calendar/tasks/selected_tasks"
+
+static GStaticMutex ecl_mutex = G_STATIC_MUTEX_INIT;
+
+static EAccountListClass *parent_class = NULL;
+
+static void dispose (GObject *object);
+static void finalize (GObject *object);
+
+static void account_added   (EAccountList *account_listener,
+			     EAccount     *account);
+static void account_changed (EAccountList *account_listener,
+			     EAccount     *account);
+static void account_removed (EAccountList *account_listener,
+			     EAccount     *account);
+
+static gboolean exchange_camel_urls_is_equal (const gchar *url1,
+					      const gchar *url2);
+
+static void
+class_init (GObjectClass *object_class)
+{
+	EAccountListClass *e_account_list_class =
+		E_ACCOUNT_LIST_CLASS (object_class);
+
+	parent_class = g_type_class_ref (PARENT_TYPE);
+
+	/* virtual method override */
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+
+	e_account_list_class->account_added   = account_added;
+	e_account_list_class->account_changed = account_changed;
+	e_account_list_class->account_removed = account_removed;
+
+	/* signals */
+	signals[EXCHANGE_ACCOUNT_CREATED] =
+		g_signal_new ("exchange_account_created",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (ExchangeShareConfigListenerClass, exchange_account_created),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_POINTER);
+	signals[EXCHANGE_ACCOUNT_REMOVED] =
+		g_signal_new ("exchange_account_removed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (ExchangeShareConfigListenerClass, exchange_account_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_POINTER);
+}
+
+static void
+init (GObject *object)
+{
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (object);
+
+	config_listener->priv = g_new0 (ExchangeShareConfigListenerPrivate, 1);
+}
+
+static void
+dispose (GObject *object)
+{
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (object);
+
+	if (config_listener->priv->gconf) {
+		g_object_unref (config_listener->priv->gconf);
+		config_listener->priv->gconf = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (object);
+
+	g_free (config_listener->priv->configured_name);
+	g_free (config_listener->priv->configured_uri);
+	g_free (config_listener->priv);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+E2K_MAKE_TYPE (exchange_share_config_listener, ExchangeShareConfigListener, class_init, init, PARENT_TYPE)
+
+#define EVOLUTION_URI_PREFIX     "evolution:/"
+#define EVOLUTION_URI_PREFIX_LEN (sizeof (EVOLUTION_URI_PREFIX) - 1)
+
+static gboolean
+is_active_exchange_account (EAccount *account)
+{
+	if (!account->enabled)
+		return FALSE;
+	if (!account->source || !account->source->url)
+		return FALSE;
+	return (strncmp (account->source->url, EXCHANGE_URI_PREFIX, 11) == 0);
+}
+
+static void
+update_foreign_uri (const gchar *path, const gchar *account_uri)
+{
+	gchar *file_path, *phy_uri, *foreign_uri, *new_phy_uri;
+	GHashTable *old_props = NULL;
+	xmlDoc *old_doc = NULL, *new_doc = NULL;
+
+	if (!path)
+		return;
+
+	file_path = g_build_filename (path, "hierarchy.xml", NULL);
+	if (!g_file_test (file_path, G_FILE_TEST_EXISTS))
+		goto cleanup;
+
+	old_doc = e_xml_parse_file (file_path);
+	if (!old_doc)
+		goto cleanup;
+
+	old_props = e_xml_to_hash (old_doc, E_XML_HASH_TYPE_PROPERTY);
+	xmlFreeDoc (old_doc);
+
+	phy_uri = g_hash_table_lookup (old_props, "physical_uri_prefix");
+	if (!phy_uri)
+		goto cleanup;
+
+	foreign_uri = strstr (phy_uri, "://");
+	if (!foreign_uri)
+		goto cleanup;
+	foreign_uri = strchr (foreign_uri + 3, '/');
+	if (!foreign_uri)
+		goto cleanup;
+
+	if ((foreign_uri + 1) && (*(foreign_uri + 1) == ';'))
+		goto cleanup;
+
+	new_phy_uri = g_strdup_printf ("exchange://%s/;%s", account_uri, foreign_uri + 1);
+	g_hash_table_remove (old_props, "physical_uri_prefix");
+	g_hash_table_insert (old_props, (gchar *)g_strdup ("physical_uri_prefix"), new_phy_uri);
+
+	new_doc = e_xml_from_hash (old_props, E_XML_HASH_TYPE_PROPERTY, "foreign-hierarchy");
+	e_xml_save_file (file_path, new_doc);
+
+	xmlFreeDoc (new_doc);
+	g_free (new_phy_uri);
+cleanup:
+	g_free (file_path);
+	if (old_props)
+		e_xml_destroy_hash (old_props);
+	return;
+}
+
+static void
+migrate_foreign_hierarchy (ExchangeAccount *account)
+{
+	GDir *d;
+	const gchar *dentry;
+	gchar *dir;
+
+	d = g_dir_open (account->storage_dir, 0, NULL);
+	if (d) {
+		while ((dentry = g_dir_read_name (d))) {
+			if (!strchr (dentry, '@'))
+				continue;
+			dir = g_strdup_printf ("%s/%s", account->storage_dir,
+							dentry);
+			update_foreign_uri (dir, account->account_filename);
+			g_free (dir);
+		}
+		g_dir_close (d);
+	}
+}
+
+static void
+ex_set_relative_uri (ESource *source, const gchar *url)
+{
+	const gchar *rel_uri = e_source_peek_relative_uri (source);
+	gchar *folder_name;
+	gchar *new_rel_uri;
+
+	if (!rel_uri)
+		return;
+
+	folder_name = strchr (rel_uri, '/');
+	if (!folder_name)
+		return;
+
+	if ((folder_name + 1) && *(folder_name + 1) == ';')
+		return;
+
+	new_rel_uri = g_strdup_printf ("%s;%s", url, folder_name + 1);
+	e_source_set_relative_uri (source, new_rel_uri);
+	g_free (new_rel_uri);
+}
+
+static void
+migrate_account_esource (EAccount *account,
+			FolderType folder_type)
+{
+	ESourceGroup *group;
+	ESource *source = NULL;
+	GSList *groups;
+	GSList *sources;
+	gboolean found_group;
+	const gchar *user_name, *authtype;
+	GConfClient *client;
+	ESourceList *source_list = NULL;
+	CamelURL *camel_url;
+	gchar *url_string;
+
+	camel_url = camel_url_new (account->source->url, NULL);
+	if (!camel_url)
+		return;
+	user_name = camel_url->user;
+	authtype  = camel_url->authmech;
+	url_string = camel_url_to_string (camel_url, CAMEL_URL_HIDE_PASSWORD | CAMEL_URL_HIDE_PARAMS);
+
+	if (!user_name) {
+		g_free (url_string);
+		camel_url_free (camel_url);
+		return;
+	}
+
+	client = gconf_client_get_default ();
+
+	if (folder_type == EXCHANGE_CONTACTS_FOLDER)
+		source_list = e_source_list_new_for_gconf ( client,
+							CONF_KEY_CONTACTS);
+	else if (folder_type == EXCHANGE_CALENDAR_FOLDER)
+		source_list = e_source_list_new_for_gconf ( client,
+							CONF_KEY_CAL);
+	else if (folder_type == EXCHANGE_TASKS_FOLDER)
+		source_list = e_source_list_new_for_gconf ( client,
+							CONF_KEY_TASKS);
+
+	groups = e_source_list_peek_groups (source_list);
+	found_group = FALSE;
+
+	for (; groups != NULL && !found_group; groups = g_slist_next (groups)) {
+		group = E_SOURCE_GROUP (groups->data);
+
+		if (strcmp (e_source_group_peek_name (group), account->name) == 0
+                    &&
+                    strcmp (e_source_group_peek_base_uri (group), EXCHANGE_URI_PREFIX) == 0) {
+			sources = e_source_group_peek_sources (group);
+
+			found_group = TRUE;
+			for (; sources != NULL; sources = g_slist_next (sources)) {
+				source = E_SOURCE (sources->data);
+
+				ex_set_relative_uri (source, url_string + strlen ("exchange://"));
+				e_source_set_property (source, "username", user_name);
+				e_source_set_property (source, "auth-domain", "Exchange");
+				if (authtype)
+					e_source_set_property (source, "auth-type", authtype);
+				if (folder_type == EXCHANGE_CONTACTS_FOLDER)
+					e_source_set_property (source, "auth", "plain/password");
+				else
+					e_source_set_property (source, "auth", "1");
+				e_source_list_sync (source_list, NULL);
+			}
+		}
+	}
+	g_free (url_string);
+	camel_url_free (camel_url);
+	g_object_unref (source_list);
+	g_object_unref (client);
+}
+
+void
+exchange_share_config_listener_migrate_esources (ExchangeShareConfigListener *config_listener)
+{
+	EAccount *account;
+
+	g_return_if_fail (config_listener != NULL);
+
+	account = config_listener->priv->configured_account;
+	migrate_account_esource (account, EXCHANGE_CALENDAR_FOLDER);
+	migrate_account_esource (account, EXCHANGE_TASKS_FOLDER);
+	migrate_account_esource (account, EXCHANGE_CONTACTS_FOLDER);
+	migrate_foreign_hierarchy (config_listener->priv->exchange_account);
+}
+
+static void
+account_added (EAccountList *account_list, EAccount *account)
+{
+	ExchangeShareConfigListener *config_listener;
+	ExchangeAccount *exchange_account;
+
+	if (!is_active_exchange_account (account))
+		return;
+
+	config_listener = EXCHANGE_SHARE_CONFIG_LISTENER (account_list);
+	if (config_listener->priv->configured_account) {
+		/* Multiple accounts configured. */
+		return;
+	}
+
+	/* New account! Yippee! */
+	exchange_account = exchange_account_new (account_list, account);
+	if (!exchange_account) {
+		g_warning ("Could not parse exchange uri '%s'",
+			   account->source->url);
+		return;
+	}
+
+	config_listener->priv->exchange_account = exchange_account;
+	config_listener->priv->configured_account = account;
+
+	g_free (config_listener->priv->configured_uri);
+	config_listener->priv->configured_uri = g_strdup (account->source->url);
+	g_free (config_listener->priv->configured_name);
+	config_listener->priv->configured_name = g_strdup (account->name);
+
+	g_signal_emit (config_listener, signals[EXCHANGE_ACCOUNT_CREATED], 0,
+		       exchange_account);
+	exchange_share_config_listener_migrate_esources (config_listener);
+}
+
+struct account_update_data {
+	EAccountList *account_list;
+	EAccount *account;
+};
+
+static void
+configured_account_destroyed (gpointer user_data, GObject *where_account_was)
+{
+	struct account_update_data *aud = user_data;
+
+	if (!EXCHANGE_SHARE_CONFIG_LISTENER (aud->account_list)->priv->configured_account)
+		account_added (aud->account_list, aud->account);
+
+	g_object_unref (aud->account_list);
+	g_object_unref (aud->account);
+	g_free (aud);
+}
+
+static gboolean
+requires_relogin (gchar *current_url, gchar *new_url)
+{
+	E2kUri *current_uri, *new_uri;
+	const gchar *current_param_val, *new_param_val;
+	const gchar *params [] = { "owa_url", "ad_server", "use_ssl" };
+	const gint n_params = G_N_ELEMENTS (params);
+	gint i;
+	gboolean relogin = FALSE;
+
+	current_uri = e2k_uri_new (current_url);
+	new_uri = e2k_uri_new (new_url);
+
+	if (strcmp (current_uri->user, new_uri->user) ||
+	    strcmp (current_uri->host, new_uri->host)) {
+		relogin = TRUE;
+		goto end;
+	}
+
+	if (current_uri->authmech || new_uri->authmech) {
+		if (current_uri->authmech && new_uri->authmech) {
+			if (strcmp (current_uri->authmech, new_uri->authmech)) {
+				/* Auth mechanism has changed */
+				relogin = TRUE;
+				goto end;
+			}
+		}
+		else {
+			/* Auth mechanism is set for the first time */
+			relogin = TRUE;
+			goto end;
+		}
+	}
+
+	for (i=0; i<n_params; i++) {
+		current_param_val = e2k_uri_get_param (current_uri, params[i]);
+		new_param_val = e2k_uri_get_param (new_uri, params[i]);
+
+		if (current_param_val && new_param_val) {
+			/* both the urls have params to be compared */
+			if (strcmp (current_param_val, new_param_val)) {
+				relogin = TRUE;
+				break;
+			}
+		}
+		else if (current_param_val || new_param_val) {
+			/* check for added or deleted parameter */
+			relogin = TRUE;
+			break;
+		}
+	}
+end:
+	e2k_uri_free (new_uri);
+	e2k_uri_free (current_uri);
+	return relogin;
+}
+
+static void
+account_changed (EAccountList *account_list, EAccount *account)
+{
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (account_list);
+	ExchangeShareConfigListenerPrivate *priv = config_listener->priv;
+
+	if (account != config_listener->priv->configured_account) {
+		if (!is_active_exchange_account (account))
+			return;
+
+		/* The user has converted an existing non-Exchange
+		 * account to an Exchange account, so treat it like an
+		 * add.
+		 */
+		account_added (account_list, account);
+		return;
+	} else if (!is_active_exchange_account (account)) {
+		/* The user has disabled the Exchange account or
+		 * converted it to non-Exchange, so treat it like a
+		 * remove.
+		 */
+		account_removed (account_list, account);
+		return;
+	}
+
+	/* FIXME: The order of the parameters in the Camel URL string is not in
+	 * order for the two given strings. So, we will not be able to use
+	 * plain string comparison. Instead compare the parameters one by one.
+	 */
+	if (exchange_camel_urls_is_equal (config_listener->priv->configured_uri,
+					  account->source->url) &&
+	    !strcmp (config_listener->priv->configured_name, account->name)) {
+		/* The user changed something we don't care about. */
+		return;
+	}
+
+	/* OK, so he modified the active account in a way we care
+	 * about. If the user hasn't connected yet, we're still ok.
+	 */
+	if (!exchange_account_get_context (config_listener->priv->exchange_account)) {
+		/* Good. Remove the current account, and wait for it
+		 * to actually go away (which may not happen immediately
+		 * since there may be a function higher up on the stack
+		 * still holding a ref on it). Then create the new one.
+		 * (We have to wait for it to go away because the new
+		 * storage probably still has the same name as the old
+		 * one, so trying to create it before the old one is
+		 * removed would fail.)
+		 */
+		struct account_update_data *aud;
+
+		aud = g_new (struct account_update_data, 1);
+		aud->account = g_object_ref (account);
+		aud->account_list = g_object_ref (account_list);
+		g_object_weak_ref (G_OBJECT (config_listener->priv->exchange_account), configured_account_destroyed, aud);
+
+		account_removed (account_list, account);
+		return;
+	}
+
+	/* If account name has changed, or the url value has changed, which
+	 * could be due to change in hostname or some parameter value,
+	 * remove old e-sources
+	 */
+	if (requires_relogin (config_listener->priv->configured_uri,
+			      account->source->url)) {
+		exchange_account_forget_password (priv->exchange_account);
+	} else if (strcmp (config_listener->priv->configured_name, account->name)) {
+		g_free (config_listener->priv->configured_name);
+		config_listener->priv->configured_name = g_strdup (account->name);
+		return;
+	} else {
+		/* FIXME: Do ESources need to be modified? */
+		return;
+	}
+
+	/* But note the new URI so if he changes something else, we
+	 * only warn again if he changes again.
+	 */
+	g_free (config_listener->priv->configured_uri);
+	config_listener->priv->configured_uri = g_strdup (account->source->url);
+}
+
+static void
+account_removed (EAccountList *account_list, EAccount *account)
+{
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (account_list);
+	ExchangeShareConfigListenerPrivate *priv = config_listener->priv;
+
+	if (account != priv->configured_account)
+		return;
+
+	exchange_account_forget_password (priv->exchange_account);
+
+	if (!exchange_account_get_context (priv->exchange_account)) {
+		/* The account isn't connected yet, so we can destroy
+		 * it without problems.
+		 */
+		g_signal_emit (config_listener,
+			       signals[EXCHANGE_ACCOUNT_REMOVED], 0,
+			       priv->exchange_account);
+
+		priv->configured_account = NULL;
+		g_free (priv->configured_uri);
+		priv->configured_uri = NULL;
+		g_free (priv->configured_name);
+		priv->configured_name = NULL;
+	}
+}
+
+/**
+ * exchange_share_config_listener_new:
+ *
+ * This creates and returns a new #ExchangeShareConfigListener, which
+ * monitors GConf and creates and (theoretically) destroys accounts
+ * accordingly. It will emit an %account_created signal when a new
+ * account is created (or shortly after the listener itself is created
+ * if an account already exists).
+ *
+ * Due to various constraints, the user is currently limited to a
+ * single account, and it is not possible to destroy an existing
+ * account. Thus, the %account_created signal will never be emitted
+ * more than once currently.
+ *
+ * Return value: the new config listener.
+ **/
+ExchangeShareConfigListener *
+exchange_share_config_listener_new (void)
+{
+	ExchangeShareConfigListener *config_listener;
+
+	config_listener = g_object_new (EXCHANGE_TYPE_SHARE_CONFIG_LISTENER, NULL);
+	config_listener->priv->gconf = gconf_client_get_default ();
+
+	e_account_list_construct (E_ACCOUNT_LIST (config_listener),
+				  config_listener->priv->gconf);
+
+	return config_listener;
+}
+
+GSList *
+exchange_share_config_listener_get_accounts (ExchangeShareConfigListener *config_listener)
+{
+	g_return_val_if_fail (EXCHANGE_IS_SHARE_CONFIG_LISTENER (config_listener), NULL);
+
+	if (config_listener->priv->exchange_account)
+		return g_slist_append (NULL, config_listener->priv->exchange_account);
+	else
+		return NULL;
+}
+
+/**
+ * exchange_camel_urls_is_equal
+ *
+ * @url1: CAMEL URL string 1
+ * @url2: CAMEL URL string 2
+ *
+ * This function checks if the parameters present in two given CAMEL URLS are
+ * identical and returns the result.
+ *
+ * Return Value: Boolean result of the comparision.
+ *
+ **/
+static gboolean
+exchange_camel_urls_is_equal (const gchar *url1, const gchar *url2)
+{
+	CamelURL *curl1, *curl2;
+	const gchar *param1, *param2;
+	const gchar *params[] = {
+		"auth",
+		"owa_url",
+		"owa_path",
+		"mailbox",
+		"ad_server",
+	};
+	const gint n_params = 5;
+	gint i;
+
+	curl1 = camel_url_new (url1, NULL);
+	curl2 = camel_url_new (url2, NULL);
+
+	for (i = 0; i < n_params; ++i) {
+		param1 = (gchar *) camel_url_get_param (curl1, params[i]);
+		param2 = (gchar *) camel_url_get_param (curl2, params[i]);
+		if ((param1 && !param2) || (!param1 && param2) || /* Missing */
+		    (param1 && param2 && strcmp (param1, param2))) { /* Differing */
+			camel_url_free (curl1);
+			camel_url_free (curl2);
+			return FALSE;
+		}
+	}
+	camel_url_free (curl1);
+	camel_url_free (curl2);
+	return TRUE;
+}
+
+struct create_excl_struct
+{
+	ExchangeShareConfigListener **excl;
+	GMutex *mutex;
+	GCond *done;
+};
+
+static gboolean
+create_excl_in_main_thread (gpointer data)
+{
+	struct create_excl_struct *ces = (struct create_excl_struct *) data;
+
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	g_mutex_lock (ces->mutex);
+
+	*ces->excl = exchange_share_config_listener_new ();
+	g_cond_signal (ces->done);
+
+	g_mutex_unlock (ces->mutex);
+
+	return FALSE;
+}
+
+ExchangeShareConfigListener *
+exchange_share_config_listener_get_global (void)
+{
+	static ExchangeShareConfigListener *excl = NULL;
+
+	g_static_mutex_lock (&ecl_mutex);
+	if (!excl) {
+		if (!g_main_context_is_owner (g_main_context_default ())) {
+			/* it is called from a thread, do the creation in a main thread;
+			   every other call will wait until it is done */
+			struct create_excl_struct ces;
+
+			ces.excl = &excl;
+			ces.mutex = g_mutex_new ();
+			ces.done = g_cond_new ();
+
+			g_mutex_lock (ces.mutex);
+			g_timeout_add (1, create_excl_in_main_thread, &ces);
+			g_cond_wait (ces.done, ces.mutex);
+			g_mutex_unlock (ces.mutex);
+
+			g_mutex_free (ces.mutex);
+			g_cond_free (ces.done);
+		} else {
+			excl = exchange_share_config_listener_new ();
+		}
+	}
+	g_static_mutex_unlock (&ecl_mutex);
+
+	return excl;
+}
+
+ExchangeAccount *
+exchange_share_config_listener_get_account_for_uri (ExchangeShareConfigListener *excl, const gchar *uri)
+{
+	GSList *accounts, *a;
+	ExchangeAccount *res = NULL;
+
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	if (!excl)
+		excl = exchange_share_config_listener_get_global ();
+
+	g_return_val_if_fail (excl != NULL, NULL);
+
+	accounts = exchange_share_config_listener_get_accounts (excl);
+
+	/* FIXME the hack to return at least something */
+	if (g_slist_length (accounts) == 1) {
+		res = accounts->data;
+		g_slist_free (accounts);
+		return res;
+	}
+
+	for (a = accounts; a; a = a->next) {
+		ExchangeAccount *account = a->data;
+	
+		g_return_val_if_fail (account != NULL, NULL);
+
+		/* Kludge for while we don't support multiple accounts */
+		if (!uri) {
+			res = account;
+			break;
+		}
+
+		if (exchange_account_get_folder (account, uri)) {
+			res = account;
+			break;
+		} else {
+			g_static_mutex_lock (&ecl_mutex);
+			exchange_account_rescan_tree (account);
+			g_static_mutex_unlock (&ecl_mutex);
+			if (exchange_account_get_folder (account, uri)) {
+				res = account;
+				break;
+			}
+		}
+	}
+
+	g_slist_free (accounts);
+
+	return res;
+}
diff --git a/tools/exchange-share-config-listener.h b/tools/exchange-share-config-listener.h
new file mode 100644
index 0000000..30d4745
--- /dev/null
+++ b/tools/exchange-share-config-listener.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* Copyright (C) 2001-2004 Novell, Inc. */
+
+#ifndef __EXCHANGE_SHARE_CONFIG_LISTENER_H__
+#define __EXCHANGE_SHARE_CONFIG_LISTENER_H__
+
+#include <exchange-types.h>
+#include <exchange-constants.h>
+#include <libedataserver/e-account-list.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-source-group.h>
+
+G_BEGIN_DECLS
+
+#define EXCHANGE_TYPE_SHARE_CONFIG_LISTENER            (exchange_share_config_listener_get_type ())
+#define EXCHANGE_SHARE_CONFIG_LISTENER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_SHARE_CONFIG_LISTENER, ExchangeShareConfigListener))
+#define EXCHANGE_SHARE_CONFIG_LISTENER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_SHARE_CONFIG_LISTENER, ExchangeShareConfigListenerClass))
+#define EXCHANGE_IS_SHARE_CONFIG_LISTENER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_SHARE_CONFIG_LISTENER))
+#define EXCHANGE_IS_SHARE_CONFIG_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_TYPE_SHARE_CONFIG_LISTENER))
+
+typedef struct _ExchangeShareConfigListener           ExchangeShareConfigListener;
+typedef struct _ExchangeShareConfigListenerPrivate    ExchangeShareConfigListenerPrivate;
+typedef struct _ExchangeShareConfigListenerClass      ExchangeShareConfigListenerClass;
+
+struct _ExchangeShareConfigListener {
+	EAccountList parent;
+
+	ExchangeShareConfigListenerPrivate *priv;
+};
+
+struct _ExchangeShareConfigListenerClass {
+	EAccountListClass parent_class;
+
+	/* signals */
+	void (*exchange_account_created) (ExchangeShareConfigListener *,
+					  ExchangeAccount *);
+	void (*exchange_account_removed) (ExchangeShareConfigListener *,
+					  ExchangeAccount *);
+};
+
+#if 0
+typedef enum {
+	EXCHANGE_CALENDAR_FOLDER,
+	EXCHANGE_TASKS_FOLDER,
+	EXCHANGE_CONTACTS_FOLDER
+}FolderType;
+#endif
+
+#define CONF_KEY_CAL "/apps/evolution/calendar/sources"
+#define CONF_KEY_TASKS "/apps/evolution/tasks/sources"
+#define CONF_KEY_CONTACTS "/apps/evolution/addressbook/sources"
+#define EXCHANGE_URI_PREFIX "exchange://"
+
+GType                        exchange_share_config_listener_get_type (void);
+ExchangeShareConfigListener *exchange_share_config_listener_new      (void);
+ExchangeShareConfigListener *exchange_share_config_listener_get_global (void);
+
+GSList                 *exchange_share_config_listener_get_accounts (ExchangeShareConfigListener *config_listener);
+
+void			exchange_share_config_listener_migrate_esources (ExchangeShareConfigListener *config_listener);
+
+/*void			add_folder_esource (ExchangeAccount *account, FolderType folder_type, const gchar *folder_name, const gchar *physical_uri);
+void			remove_folder_esource (ExchangeAccount *account, FolderType folder_type, const gchar *physical_uri);*/
+
+ExchangeAccount *exchange_share_config_listener_get_account_for_uri (ExchangeShareConfigListener *excl, const gchar *uri);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_SHARE_CONFIG_LISTENER_H__ */
diff --git a/tools/migr-test.c b/tools/migr-test.c
new file mode 100644
index 0000000..cac401f
--- /dev/null
+++ b/tools/migr-test.c
@@ -0,0 +1,108 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2004 Novell, Inc.
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+
+#include <gdk/gdk.h>
+
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-exception.h>
+
+#include "exchange-types.h"
+#include "exchange-migrate.h"
+
+gint
+main (gint argc, gchar **argv)
+{
+	CORBA_short major=1;
+	CORBA_short minor=4;
+	CORBA_short revision=0;
+	const gchar *source = "~/evolution";
+	const gchar *dest= "/tmp/.evolution-test";
+	gchar *user = NULL, *server = NULL, *base_dir, *uid = NULL;
+	gint opt;
+	gchar optstr[] = "M:m:r:u:h:s:d:";
+
+	g_type_init ();
+	g_thread_init (NULL);
+	gdk_init(&argc, &argv);
+	gtk_init (&argc, &argv);
+
+	if (argc == 1) {
+		printf("Usage: %s [-M major][ -m minor][ -r revision] <-u user> <-h server> [-s source][ -d destination] \n", argv[0]);
+		return 1;
+	}
+
+	if (argc < 5) {
+		printf("Error.. User name and Server name not provided \n");
+		return 1;
+	}
+
+	if (argc < 15) {
+		printf("Warning.. All the arguments not provided, Proceeding with the default values \n");
+	}
+
+	while ((opt = getopt (argc, argv, optstr)) != EOF) {
+		switch (opt) {
+			case 'M':
+				major = atoi(optarg);
+				break;
+			case 'm':
+				minor = atoi(optarg);
+				break;
+			case 'r':
+				revision = atoi(optarg);
+				break;
+			case 'u':
+				user = optarg;
+				break;
+			case 'h':
+				server = optarg;
+				break;
+			case 's':
+				source = optarg;
+				break;
+			case 'd':
+				dest = optarg;
+				break;
+			default:
+				break;
+		}
+	}
+
+	uid = g_strdup_printf ("%s@%s", user, server);
+
+	/* destination path */
+	base_dir = g_build_filename (dest, uid, NULL);
+	printf("base dir is %s; uid = %s; dest = %s; source=%s \n", base_dir, uid, dest, source);
+
+	exchange_migrate (major, minor, revision, base_dir, (gchar *) uid);
+
+	g_free (base_dir);
+	g_free (uid);
+
+	return 0;
+}
diff --git a/tools/ximian-connector-setup.c b/tools/ximian-connector-setup.c
new file mode 100644
index 0000000..5d11274
--- /dev/null
+++ b/tools/ximian-connector-setup.c
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2003, 2004 Novell, Inc.
+ *
+ * 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 <gtk/gtk.h>
+#include <libedataserverui/e-passwords.h>
+
+#include "exchange-autoconfig-wizard.h"
+
+#ifdef G_OS_WIN32
+const gchar *_exchange_storage_datadir;
+const gchar *_exchange_storage_gladedir;
+const gchar *_exchange_storage_imagesdir;
+#endif
+
+gint
+main (gint argc, gchar **argv)
+{
+	GError *error = NULL;
+
+#ifdef G_OS_WIN32
+	{
+		gchar *localedir;
+
+		/* We assume evolution-exchange is installed in the
+		 * same run-time prefix as evolution-data-server.
+		 */
+		_exchange_storage_datadir = e_util_replace_prefix (PREFIX, e_util_get_prefix (), DATADIR);
+		_exchange_storage_gladedir = e_util_replace_prefix (PREFIX, e_util_get_prefix (), CONNECTOR_GLADEDIR);
+		_exchange_storage_imagesdir = e_util_replace_prefix (PREFIX, e_util_get_prefix (), CONNECTOR_IMAGESDIR);
+
+		localedir = e_util_replace_prefix (CONNECTOR_LOCALEDIR, e_util_get_cp_prefix (), CONNECTOR_LOCALEDIR);
+		bindtextdomain (GETTEXT_PACKAGE, localedir);
+	}
+
+/* PREFIX and DATADIR are part of GNOME_PROGRAM_STANDARD_PROPERTIES */
+
+#undef PREFIX
+#define PREFIX e_util_get_prefix ()
+
+#undef DATADIR
+#define DATADIR _exchange_storage_datadir
+
+#else
+	bindtextdomain (GETTEXT_PACKAGE, CONNECTOR_LOCALEDIR);
+#endif
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	g_type_init ();
+	g_thread_init (NULL);
+	gtk_init_with_args (&argc, &argv, NULL, NULL, (char *)GETTEXT_PACKAGE, &error);
+
+	if (error != NULL) {
+		g_printerr ("Failed initialize application, %s\n", error->message);
+		g_error_free (error);
+		return (1);
+	}
+
+	e_passwords_init ();
+
+	exchange_autoconfig_assistant_run ();
+
+	e_passwords_shutdown ();
+
+	return 0;
+}
diff --git a/tools/ximian-connector.xml b/tools/ximian-connector.xml
new file mode 100644
index 0000000..f0718e3
--- /dev/null
+++ b/tools/ximian-connector.xml
@@ -0,0 +1,34 @@
+<Root>
+    <menu>
+	<submenu name="Actions">
+	    <placeholder name="ComponentActionsPlaceholder">
+		<menuitem name="ExchangePassword" verb=""
+			  _label="_Change Exchange Password..."
+			  _tip="Change your Exchange server password"/>
+
+		<separator f="" name="connector1"/>
+
+		<menuitem name="ExchangeSubscribeUser" verb=""
+			  _label="Subscribe to _Other User's Folder..."
+			  _tip="Subscribe to a folder belonging to some other user on the server"/>
+		<menuitem name="ExchangeUnsubscribeUser" verb=""
+			  _label="_Unsubscribe from Other User's Folder"
+			  _tip="Unsubscribe from a folder added with &quot;Subscribe to Other User's Folder&quot;"/>
+		<menuitem name="ExchangeFolderSize" verb=""
+			  _label="Folder _Size"
+			  _tip="Get the size of personal folders"/>
+	    </placeholder>
+	</submenu>
+	<submenu name="Tools">
+	    <placeholder name="ComponentPlaceholder">
+		<menuitem name="ExchangeOOF" verb=""
+			  _label="_Out of Office Assistant"
+			  _tip="View or change your Out-of-Office status and autoreply message"/>
+		<menuitem name="ExchangeDelegation" verb=""
+			  _label="_Delegation Assistant"
+			  _tip="View or change your Exchange calendar delegation settings"/>
+		<separator f="" name="connector3"/>
+	    </placeholder>
+	</submenu>
+    </menu>
+</Root>
